diff --git a/.gitattributes b/.gitattributes index 9fa544d91..c544bf6b3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,7 @@ *.sln eol=crlf *.vcproj eol=crlf *.vcxproj* eol=crlf +*.patch eol=lf # Whitespace rules # strict (no trailing, no tabs) diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 000000000..f35459fcf --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,130 @@ +# List of AUTHORS who contributed over time to the ScriptDev2 project + +## Warning +The code of ScriptDev2 is shipped as it is without any form of warranty, +and - except for third party libraries - licensed under the GPL 2.0, +which you can read from the file "COPYING" + +## Point of current development +The project is currently hosted at http://www.scriptdev2.com and developed under https://github.com/scriptdev2 + +## History of development +Development of this project dates back to 2006, and was developed under various umbrellas over time: +* ScriptDev2 project, 2006-2014, located at http://www.scriptdev2.com + +## Authorship of the code +Authorship is assigned for each commit within the git history, which is stored in these git repositories: +* github.com/scriptdev2/scriptdev2 + +## Exceptions with third party libraries + +## Authors List: + +*Please inform us, if you find somebody who is missing!* + +Abim +Alexluana +Ambal +Amki +antifreak +Anubisss +ApoC +arrai +astriconX +Azelen +Azuritus +balrok +bastii +blueboy +bobi88 +BroodWyrm +Bugfix +burned +cala +Cher0 +Chero +cipherCOM +ckegg +crackm +creakie +Cupcake +Cyberium +DaC +darkman1983 +DasBlub +DasMy +Derex +DiffuSer +drz2002 +dufernst +Dunemaster +etznab +evil-at-wow +foot +Forusim +fr1ge +fra298 +FragFrog +Goaul +greenseed +grz3s +Gurg +hoshie +Hundekuchen +hunuza +Huricane +Insanity Peppers +Janu +Jethro +jotapdiez +Junta +kid 10 +Klark20 +kolomati2 +krofna +Lightguard +Lynx3d +MeanMachine +Meldanor +michalpolko +miebaik +mns +Morpho +NeatElves +Neo2003 +Nighoo +nitka +NoFantasy +Ntsc +NuRRi +Opterman +Panic +Patman128 +paytheo +Peppers +przemratajczak +PSZ +raynar +Reamer +Reve +rise2 +Saeldur +Sattelit +Schmoozerd +Seline +septim +SRobot +stfx +tarwyn +Tassader +truera3or +Turok +UnknowN-TerroR +Vinolentus +virusav +VladimirMangos +Wizz +Xfurry +X-Savior +XTZGZoReX +zergtmn diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e96eba1f..c754226fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2005-2012 MaNGOS +# This file is part of the ScriptDev2 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 General Public License as published by diff --git a/README b/README index eb4be34e7..d5da2d18d 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ == ScriptDev2 README == - Copyright (C) 2006 - 2012 ScriptDev2 + This file is part of the ScriptDev2 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 General Public License as published by the Free Software Foundation; either version 2 of the License, or diff --git a/ScriptMgr.cpp b/ScriptMgr.cpp index 303a3f674..71c274b0e 100644 --- a/ScriptMgr.cpp +++ b/ScriptMgr.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -27,7 +27,7 @@ void LoadDatabase() if (strSD2DBinfo.empty()) { - error_log("SD2: Missing Scriptdev2 database info from configuration file. Load database aborted."); + script_error_log("Missing Scriptdev2 database info from configuration file. Load database aborted."); return; } @@ -37,6 +37,17 @@ void LoadDatabase() outstring_log("SD2: ScriptDev2 database initialized."); outstring_log(""); + // Extract DB-Name + std::string::size_type n = strSD2DBinfo.rfind(';'); + std::string dbname; + if (n != std::string::npos && n + 1 != std::string::npos) + dbname = strSD2DBinfo.substr(n + 1); + else + dbname = "SD2_Database"; + dbname.append(".script_waypoint"); + SetExternalWaypointTable(dbname.c_str()); + + // Load content pSystemMgr.LoadVersion(); pSystemMgr.LoadScriptTexts(); pSystemMgr.LoadScriptTextsCustom(); @@ -45,18 +56,18 @@ void LoadDatabase() } else { - error_log("SD2: Unable to connect to Database. Load database aborted."); + script_error_log("Unable to connect to Database. Load database aborted."); return; } SD2Database.HaltDelayThread(); - } -struct TSpellSummary { +struct TSpellSummary +{ uint8 Targets; // set of enum SelectTarget uint8 Effects; // set of enum SelectEffect -}extern *SpellSummary; +} extern* SpellSummary; MANGOS_DLL_EXPORT void FreeScriptLibrary() @@ -71,6 +82,8 @@ void FreeScriptLibrary() m_scripts.clear(); num_sc_scripts = 0; + + setScriptLibraryErrorFile(NULL, NULL); } MANGOS_DLL_EXPORT @@ -88,14 +101,22 @@ void InitScriptLibrary() outstring_log(""); // Get configuration file + bool configFailure = false; if (!SD2Config.SetSource(_SCRIPTDEV2_CONFIG)) - error_log("SD2: Unable to open configuration file. Database will be unaccessible. Configuration values will use default."); + configFailure = true; else - outstring_log("SD2: Using configuration file %s",_SCRIPTDEV2_CONFIG); + outstring_log("SD2: Using configuration file %s", _SCRIPTDEV2_CONFIG); + + // Set SD2 Error Log File + std::string sd2LogFile = SD2Config.GetStringDefault("SD2ErrorLogFile", "SD2Errors.log"); + setScriptLibraryErrorFile(sd2LogFile.c_str(), "SD2"); + + if (configFailure) + script_error_log("Unable to open configuration file. Database will be unaccessible. Configuration values will use default."); // Check config file version if (SD2Config.GetIntDefault("ConfVersion", 0) != SD2_CONF_VERSION) - error_log("SD2: Configuration file version doesn't match expected version. Some config variables may be wrong or missing."); + script_error_log("Configuration file version doesn't match expected version. Some config variables may be wrong or missing."); outstring_log(""); @@ -118,7 +139,7 @@ void InitScriptLibrary() for (uint32 i = 1; i < GetScriptIdsCount(); ++i) { if (!m_scripts[i]) - error_log("SD2: No script found for ScriptName '%s'.", GetScriptName(i)); + script_error_log("No script found for ScriptName '%s'.", GetScriptName(i)); } outstring_log(">> Loaded %i C++ Scripts.", num_sc_scripts); @@ -138,93 +159,20 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) { if (!pSource) { - error_log("SD2: DoScriptText entry %i, invalid Source pointer.", iTextEntry); + script_error_log("DoScriptText entry %i, invalid Source pointer.", iTextEntry); return; } if (iTextEntry >= 0) { - error_log("SD2: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", - pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); + script_error_log("DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", + pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); return; } - const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); - if (!pData) - { - error_log("SD2: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", - pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry); - - return; - } - - debug_log("SD2: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", - iTextEntry, pData->uiSoundId, pData->uiType, pData->uiLanguage, pData->uiEmote); - - if (pData->uiSoundId) - { - if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) - { - if (pData->uiType == CHAT_TYPE_ZONE_YELL) - pSource->GetMap()->PlayDirectSoundToMap(pData->uiSoundId, pSource->GetZoneId()); - else if (pData->uiType == CHAT_TYPE_WHISPER || pData->uiType == CHAT_TYPE_BOSS_WHISPER) - { - // An error will be displayed for the text - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->PlayDirectSound(pData->uiSoundId, (Player*)pTarget); - } - else - pSource->PlayDirectSound(pData->uiSoundId); - } - else - error_log("SD2: DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); - } - - if (pData->uiEmote) - { - if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER) - ((Unit*)pSource)->HandleEmote(pData->uiEmote); - else - error_log("SD2: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId()); - } - - switch(pData->uiType) - { - case CHAT_TYPE_SAY: - pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget); - break; - case CHAT_TYPE_YELL: - pSource->MonsterYell(iTextEntry, pData->uiLanguage, pTarget); - break; - case CHAT_TYPE_TEXT_EMOTE: - pSource->MonsterTextEmote(iTextEntry, pTarget); - break; - case CHAT_TYPE_BOSS_EMOTE: - pSource->MonsterTextEmote(iTextEntry, pTarget, true); - break; - case CHAT_TYPE_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget); - else - error_log("SD2: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - - break; - } - case CHAT_TYPE_BOSS_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget, true); - else - error_log("SD2: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - - break; - } - case CHAT_TYPE_ZONE_YELL: - pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, pTarget); - break; - } + DoDisplayText(pSource, iTextEntry, pTarget); + // TODO - maybe add some call-stack like error output if above function returns false } /** @@ -240,51 +188,46 @@ void DoOrSimulateScriptTextForMap(int32 iTextEntry, uint32 uiCreatureEntry, Map* { if (!pMap) { - error_log("SD2: DoOrSimulateScriptTextForMap entry %i, invalid Map pointer.", iTextEntry); + script_error_log("DoOrSimulateScriptTextForMap entry %i, invalid Map pointer.", iTextEntry); return; } if (iTextEntry >= 0) { - error_log("SD2: DoOrSimulateScriptTextForMap with source entry %u for map %u attempts to process text entry %i, but text entry must be negative.", uiCreatureEntry, pMap->GetId(), iTextEntry); + script_error_log("DoOrSimulateScriptTextForMap with source entry %u for map %u attempts to process text entry %i, but text entry must be negative.", uiCreatureEntry, pMap->GetId(), iTextEntry); return; } CreatureInfo const* pInfo = GetCreatureTemplateStore(uiCreatureEntry); if (!pInfo) { - error_log("SD2: DoOrSimulateScriptTextForMap has invalid source entry %u for map %u.", uiCreatureEntry, pMap->GetId()); + script_error_log("DoOrSimulateScriptTextForMap has invalid source entry %u for map %u.", uiCreatureEntry, pMap->GetId()); return; } - const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); + MangosStringLocale const* pData = GetMangosStringData(iTextEntry); if (!pData) { - error_log("SD2: DoOrSimulateScriptTextForMap with source entry %u for map %u could not find text entry %i.", uiCreatureEntry, pMap->GetId(), iTextEntry); + script_error_log("DoOrSimulateScriptTextForMap with source entry %u for map %u could not find text entry %i.", uiCreatureEntry, pMap->GetId(), iTextEntry); return; } debug_log("SD2: DoOrSimulateScriptTextForMap: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", - iTextEntry, pData->uiSoundId, pData->uiType, pData->uiLanguage, pData->uiEmote); + iTextEntry, pData->SoundId, pData->Type, pData->LanguageId, pData->Emote); - if (pData->uiType != CHAT_TYPE_ZONE_YELL) + if (pData->Type != CHAT_TYPE_ZONE_YELL) { - error_log("SD2: DoSimulateScriptTextForMap entry %i has not supported chat type %u.", iTextEntry, pData->uiType); + script_error_log("DoSimulateScriptTextForMap entry %i has not supported chat type %u.", iTextEntry, pData->Type); return; } - if (pData->uiSoundId) - { - if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) - pMap->PlayDirectSoundToMap(pData->uiSoundId); - else - error_log("SD2: DoOrSimulateScriptTextForMap entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); - } + if (pData->SoundId) + pMap->PlayDirectSoundToMap(pData->SoundId); if (pCreatureSource) // If provided pointer for sayer, use direct version - pMap->MonsterYellToMap(pCreatureSource->GetObjectGuid(), iTextEntry, pData->uiLanguage, pTarget); + pMap->MonsterYellToMap(pCreatureSource->GetObjectGuid(), iTextEntry, pData->LanguageId, pTarget); else // Simulate yell - pMap->MonsterYellToMap(pInfo, iTextEntry, pData->uiLanguage, pTarget); + pMap->MonsterYellToMap(pInfo, iTextEntry, pData->LanguageId, pTarget); } //********************************* @@ -300,7 +243,7 @@ void Script::RegisterSelf(bool bReportError) else { if (bReportError) - error_log("SD2: Script registering but ScriptName %s is not assigned in database. Script will not be used.", Name.c_str()); + script_error_log("Script registering but ScriptName %s is not assigned in database. Script will not be used.", Name.c_str()); delete this; } @@ -309,12 +252,6 @@ void Script::RegisterSelf(bool bReportError) //******************************** //*** Functions to be Exported *** -MANGOS_DLL_EXPORT -char const* GetScriptLibraryVersion() -{ - return strSD2Version.c_str(); -} - MANGOS_DLL_EXPORT bool GossipHello(Player* pPlayer, Creature* pCreature) { @@ -433,7 +370,7 @@ uint32 GetNPCDialogStatus(Player* pPlayer, Creature* pCreature) Script* pTempScript = m_scripts[pCreature->GetScriptId()]; if (!pTempScript || !pTempScript->pDialogStatusNPC) - return 100; + return DIALOG_STATUS_UNDEFINED; pPlayer->PlayerTalkClass->ClearMenus(); @@ -446,7 +383,7 @@ uint32 GetGODialogStatus(Player* pPlayer, GameObject* pGo) Script* pTempScript = m_scripts[pGo->GetGOInfo()->ScriptId]; if (!pTempScript || !pTempScript->pDialogStatusGO) - return 100; + return DIALOG_STATUS_UNDEFINED; pPlayer->PlayerTalkClass->ClearMenus(); @@ -514,6 +451,17 @@ bool AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) return pTempScript->pAreaTrigger(pPlayer, atEntry); } +MANGOS_DLL_EXPORT +bool NpcSpellClick(Player* pPlayer, Creature* pClickedCreature, uint32 uiSpellId) +{ + Script* pTempScript = m_scripts[pClickedCreature->GetScriptId()]; + + if (!pTempScript || !pTempScript->pNpcSpellClick) + return false; + + return pTempScript->pNpcSpellClick(pPlayer, pClickedCreature, uiSpellId); +} + MANGOS_DLL_EXPORT bool ProcessEvent(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) { @@ -549,36 +497,47 @@ bool ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) } MANGOS_DLL_EXPORT -bool EffectDummyCreature(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget) +bool EffectDummyCreature(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid) { Script* pTempScript = m_scripts[pTarget->GetScriptId()]; if (!pTempScript || !pTempScript->pEffectDummyNPC) return false; - return pTempScript->pEffectDummyNPC(pCaster, spellId, effIndex, pTarget); + return pTempScript->pEffectDummyNPC(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT -bool EffectDummyGameObject(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget) +bool EffectDummyGameObject(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget, ObjectGuid originalCasterGuid) { Script* pTempScript = m_scripts[pTarget->GetGOInfo()->ScriptId]; if (!pTempScript || !pTempScript->pEffectDummyGO) return false; - return pTempScript->pEffectDummyGO(pCaster, spellId, effIndex, pTarget); + return pTempScript->pEffectDummyGO(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT -bool EffectDummyItem(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget) +bool EffectDummyItem(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget, ObjectGuid originalCasterGuid) { Script* pTempScript = m_scripts[pTarget->GetProto()->ScriptId]; if (!pTempScript || !pTempScript->pEffectDummyItem) return false; - return pTempScript->pEffectDummyItem(pCaster, spellId, effIndex, pTarget); + return pTempScript->pEffectDummyItem(pCaster, spellId, effIndex, pTarget, originalCasterGuid); +} + +MANGOS_DLL_EXPORT +bool EffectScriptEffectCreature(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid) +{ + Script* pTempScript = m_scripts[pTarget->GetScriptId()]; + + if (!pTempScript || !pTempScript->pEffectScriptEffectNPC) + return false; + + return pTempScript->pEffectScriptEffectNPC(pCaster, spellId, effIndex, pTarget, originalCasterGuid); } MANGOS_DLL_EXPORT diff --git a/ScriptMgr.h b/ScriptMgr.h index 563d0a7ee..961958299 100644 --- a/ScriptMgr.h +++ b/ScriptMgr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -30,12 +30,6 @@ class ObjectGuid; #define VISIBLE_RANGE (166.0f) // MAX visible range (size of grid) #define DEFAULT_TEXT "" -// Some typedefs for storing Guids -typedef std::list GUIDList; -typedef std::set GUIDSet; -typedef std::vector GUIDVector; -typedef std::map EntryGuidMap; - /* Escort Factions * TODO: find better namings and definitions. * N=Neutral, A=Alliance, H=Horde. @@ -73,37 +67,39 @@ struct Script pDialogStatusNPC(NULL), pDialogStatusGO(NULL), pQuestAcceptNPC(NULL), pQuestAcceptGO(NULL), pQuestAcceptItem(NULL), pQuestRewardedNPC(NULL), pQuestRewardedGO(NULL), - pGOUse(NULL), pItemUse(NULL), pAreaTrigger(NULL), pProcessEventId(NULL), - pEffectDummyNPC(NULL), pEffectDummyGO(NULL), pEffectDummyItem(NULL), pEffectAuraDummy(NULL), - GetAI(NULL), GetInstanceData(NULL) + pGOUse(NULL), pItemUse(NULL), pAreaTrigger(NULL), pNpcSpellClick(NULL), pProcessEventId(NULL), + pEffectDummyNPC(NULL), pEffectDummyGO(NULL), pEffectDummyItem(NULL), pEffectScriptEffectNPC(NULL), + pEffectAuraDummy(NULL), GetAI(NULL), GetInstanceData(NULL) {} std::string Name; - bool (*pGossipHello )(Player*, Creature*); - bool (*pGossipHelloGO )(Player*, GameObject*); - bool (*pGossipSelect )(Player*, Creature*, uint32, uint32); - bool (*pGossipSelectGO )(Player*, GameObject*, uint32, uint32); - bool (*pGossipSelectWithCode )(Player*, Creature*, uint32, uint32, const char*); - bool (*pGossipSelectGOWithCode )(Player*, GameObject*, uint32, uint32, const char*); - uint32 (*pDialogStatusNPC )(Player*, Creature*); - uint32 (*pDialogStatusGO )(Player*, GameObject*); - bool (*pQuestAcceptNPC )(Player*, Creature*, Quest const*); - bool (*pQuestAcceptGO )(Player*, GameObject*, Quest const*); - bool (*pQuestAcceptItem )(Player*, Item*, Quest const*); - bool (*pQuestRewardedNPC )(Player*, Creature*, Quest const*); - bool (*pQuestRewardedGO )(Player*, GameObject*, Quest const*); - bool (*pGOUse )(Player*, GameObject*); - bool (*pItemUse )(Player*, Item*, SpellCastTargets const&); - bool (*pAreaTrigger )(Player*, AreaTriggerEntry const*); - bool (*pProcessEventId )(uint32, Object*, Object*, bool); - bool (*pEffectDummyNPC )(Unit*, uint32, SpellEffectIndex, Creature*); - bool (*pEffectDummyGO )(Unit*, uint32, SpellEffectIndex, GameObject*); - bool (*pEffectDummyItem )(Unit*, uint32, SpellEffectIndex, Item*); - bool (*pEffectAuraDummy )(const Aura*, bool); - - CreatureAI* (*GetAI )(Creature*); - InstanceData* (*GetInstanceData )(Map*); + bool (*pGossipHello)(Player*, Creature*); + bool (*pGossipHelloGO)(Player*, GameObject*); + bool (*pGossipSelect)(Player*, Creature*, uint32, uint32); + bool (*pGossipSelectGO)(Player*, GameObject*, uint32, uint32); + bool (*pGossipSelectWithCode)(Player*, Creature*, uint32, uint32, const char*); + bool (*pGossipSelectGOWithCode)(Player*, GameObject*, uint32, uint32, const char*); + uint32(*pDialogStatusNPC)(Player*, Creature*); + uint32(*pDialogStatusGO)(Player*, GameObject*); + bool (*pQuestAcceptNPC)(Player*, Creature*, Quest const*); + bool (*pQuestAcceptGO)(Player*, GameObject*, Quest const*); + bool (*pQuestAcceptItem)(Player*, Item*, Quest const*); + bool (*pQuestRewardedNPC)(Player*, Creature*, Quest const*); + bool (*pQuestRewardedGO)(Player*, GameObject*, Quest const*); + bool (*pGOUse)(Player*, GameObject*); + bool (*pItemUse)(Player*, Item*, SpellCastTargets const&); + bool (*pAreaTrigger)(Player*, AreaTriggerEntry const*); + bool (*pNpcSpellClick)(Player*, Creature*, uint32); + bool (*pProcessEventId)(uint32, Object*, Object*, bool); + bool (*pEffectDummyNPC)(Unit*, uint32, SpellEffectIndex, Creature*, ObjectGuid); + bool (*pEffectDummyGO)(Unit*, uint32, SpellEffectIndex, GameObject*, ObjectGuid); + bool (*pEffectDummyItem)(Unit*, uint32, SpellEffectIndex, Item*, ObjectGuid); + bool (*pEffectScriptEffectNPC)(Unit*, uint32, SpellEffectIndex, Creature*, ObjectGuid); + bool (*pEffectAuraDummy)(const Aura*, bool); + + CreatureAI* (*GetAI)(Creature*); + InstanceData* (*GetInstanceData)(Map*); void RegisterSelf(bool bReportError = true); }; diff --git a/VC100/100ScriptDev2.vcxproj b/VC100/100ScriptDev2.vcxproj index 952dd856d..06854befb 100644 --- a/VC100/100ScriptDev2.vcxproj +++ b/VC100/100ScriptDev2.vcxproj @@ -107,6 +107,7 @@ true true true + true mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) @@ -138,6 +139,7 @@ true true true + true mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) @@ -153,7 +155,6 @@ - /MP %(AdditionalOptions) ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0;%(PreprocessorDefinitions) false @@ -165,6 +166,7 @@ true true true + true mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) @@ -184,7 +186,6 @@ X64 - /MP %(AdditionalOptions) ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0;%(PreprocessorDefinitions) MultiThreadedDLL @@ -195,6 +196,7 @@ true true true + true mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) @@ -218,7 +220,6 @@ - @@ -243,28 +244,14 @@ - - - - - - - - - - - - - - @@ -314,37 +301,23 @@ + - - - - - - - - - - - - - - - @@ -368,8 +341,6 @@ - - @@ -379,7 +350,6 @@ - @@ -420,20 +390,14 @@ - - - - - - - + @@ -470,6 +434,7 @@ + @@ -479,6 +444,8 @@ + + @@ -542,6 +509,7 @@ + @@ -549,7 +517,9 @@ + + @@ -666,7 +636,9 @@ + + @@ -676,8 +648,6 @@ - - @@ -720,6 +690,7 @@ + @@ -737,6 +708,7 @@ + @@ -753,6 +725,7 @@ + @@ -777,6 +750,7 @@ + diff --git a/VC100/100ScriptDev2.vcxproj.filters b/VC100/100ScriptDev2.vcxproj.filters index 394de55a0..325c42fc5 100644 --- a/VC100/100ScriptDev2.vcxproj.filters +++ b/VC100/100ScriptDev2.vcxproj.filters @@ -324,9 +324,6 @@ scripts\eastern_kingdoms - - scripts\eastern_kingdoms - scripts\eastern_kingdoms @@ -399,9 +396,6 @@ scripts\eastern_kingdoms\blackrock_depths - - scripts\eastern_kingdoms\blackrock_depths - scripts\eastern_kingdoms\blackrock_depths @@ -411,60 +405,21 @@ scripts\eastern_kingdoms\blackrock_depths - - scripts\eastern_kingdoms\blackrock_depths - - - scripts\eastern_kingdoms\blackrock_depths - scripts\eastern_kingdoms\blackrock_depths - - scripts\eastern_kingdoms\blackrock_depths - - - scripts\eastern_kingdoms\blackrock_depths - scripts\eastern_kingdoms\blackrock_depths - - scripts\eastern_kingdoms\blackrock_spire - scripts\eastern_kingdoms\blackrock_spire - - scripts\eastern_kingdoms\blackrock_spire - - - scripts\eastern_kingdoms\blackrock_spire - - - scripts\eastern_kingdoms\blackrock_spire - scripts\eastern_kingdoms\blackrock_spire scripts\eastern_kingdoms\blackrock_spire - - scripts\eastern_kingdoms\blackrock_spire - - - scripts\eastern_kingdoms\blackrock_spire - - - scripts\eastern_kingdoms\blackrock_spire - - - scripts\eastern_kingdoms\blackrock_spire - - - scripts\eastern_kingdoms\blackrock_spire - scripts\eastern_kingdoms\blackrock_spire @@ -612,13 +567,10 @@ scripts\eastern_kingdoms\scarlet_enclave - - scripts\eastern_kingdoms\scarlet_monastery - - - scripts\eastern_kingdoms\scarlet_monastery + + scripts\eastern_kingdoms\scarlet_enclave - + scripts\eastern_kingdoms\scarlet_monastery @@ -627,39 +579,18 @@ scripts\eastern_kingdoms\scarlet_monastery - - scripts\eastern_kingdoms\scarlet_monastery - - - scripts\eastern_kingdoms\scarlet_monastery - - - scripts\eastern_kingdoms\scarlet_monastery - scripts\eastern_kingdoms\scarlet_monastery - - scripts\eastern_kingdoms\scarlet_monastery - scripts\eastern_kingdoms\scarlet_monastery scripts\eastern_kingdoms\scholomance - - scripts\eastern_kingdoms\scholomance - scripts\eastern_kingdoms\scholomance - - scripts\eastern_kingdoms\scholomance - - - scripts\eastern_kingdoms\scholomance - scripts\eastern_kingdoms\scholomance @@ -672,9 +603,6 @@ scripts\eastern_kingdoms\shadowfang_keep - - scripts\eastern_kingdoms\stratholme - scripts\eastern_kingdoms\stratholme @@ -684,27 +612,12 @@ scripts\eastern_kingdoms\stratholme - - scripts\eastern_kingdoms\stratholme - scripts\eastern_kingdoms\stratholme - - scripts\eastern_kingdoms\stratholme - scripts\eastern_kingdoms\stratholme - - scripts\eastern_kingdoms\stratholme - - - scripts\eastern_kingdoms\stratholme - - - scripts\eastern_kingdoms\stratholme - scripts\eastern_kingdoms\stratholme @@ -774,12 +687,6 @@ scripts\eastern_kingdoms\zulgurub - - scripts\eastern_kingdoms\zulgurub - - - scripts\eastern_kingdoms\zulgurub - scripts\eastern_kingdoms\zulgurub @@ -807,9 +714,6 @@ scripts\eastern_kingdoms\zulgurub - - scripts\eastern_kingdoms\zulgurub - scripts\eastern_kingdoms\zulgurub @@ -930,15 +834,6 @@ scripts\kalimdor\caverns_of_time\hyjal - - scripts\kalimdor\caverns_of_time\old_hillsbrad - - - scripts\kalimdor\caverns_of_time\old_hillsbrad - - - scripts\kalimdor\caverns_of_time\old_hillsbrad - scripts\kalimdor\caverns_of_time\old_hillsbrad @@ -951,25 +846,16 @@ scripts\kalimdor\dire_maul - - scripts\kalimdor\maraudon - - - scripts\kalimdor\maraudon - scripts\kalimdor\maraudon - - scripts\kalimdor\maraudon - scripts\kalimdor\onyxias_lair scripts\kalimdor\onyxias_lair - + scripts\kalimdor\razorfen_downs @@ -1080,6 +966,9 @@ scripts\northrend + + scripts\northrend\azjol-nerub\ahnkahet + scripts\northrend\azjol-nerub\ahnkahet @@ -1107,6 +996,12 @@ scripts\northrend\azjol-nerub\azjol-nerub + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + scripts\northrend\crusaders_coliseum\trial_of_the_champion @@ -1218,6 +1113,9 @@ scripts\northrend\nexus\eye_of_eternity + + scripts\northrend\nexus\eye_of_eternity + scripts\northrend\nexus\nexus @@ -1239,9 +1137,15 @@ scripts\northrend\nexus\oculus + + scripts\northrend\nexus\oculus + scripts\northrend\nexus\oculus + + scripts\northrend\nexus\oculus + scripts\northrend\obsidian_sanctum @@ -1653,9 +1557,15 @@ scripts\outland\tempest_keep\arcatraz + + scripts\outland\tempest_keep\arcatraz + scripts\outland\tempest_keep\arcatraz + + scripts\outland\tempest_keep\arcatraz + scripts\outland\tempest_keep\arcatraz @@ -1683,12 +1593,6 @@ scripts\outland\tempest_keep\the_eye - - scripts\outland\tempest_keep\the_eye - - - scripts\outland\tempest_keep\the_mechanar - scripts\outland\tempest_keep\the_mechanar @@ -1803,6 +1707,9 @@ scripts\eastern_kingdoms\molten_core + + scripts\eastern_kingdoms\scarlet_enclave + scripts\eastern_kingdoms\scarlet_monastery @@ -1854,6 +1761,9 @@ scripts\kalimdor\onyxias_lair + + scripts\kalimdor\razorfen_downs + scripts\kalimdor\razorfen_kraul @@ -1902,6 +1812,9 @@ scripts\northrend\naxxramas + + scripts\northrend\nexus\eye_of_eternity + scripts\northrend\nexus\nexus @@ -1974,6 +1887,9 @@ scripts\outland\tempest_keep\the_mechanar + + scripts\world + include diff --git a/VC110/110ScriptDev2.vcxproj b/VC110/110ScriptDev2.vcxproj new file mode 100644 index 000000000..e463c02e2 --- /dev/null +++ b/VC110/110ScriptDev2.vcxproj @@ -0,0 +1,802 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ScriptDev2 + {4295C8A9-79B7-4354-8064-F05FB9CA0C96} + ScriptDev2 + Win32Proj + + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\bin\win32_debug\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + true + ..\..\..\..\bin\x64_debug\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + true + ..\..\..\..\bin\win32_release\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + false + ..\..\..\..\bin\x64_release\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + mangosscript + mangosscript + mangosscript + mangosscript + + + + Disabled + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;MANGOS_DEBUG;_WINDOWS;_USRDLL;SCRIPT;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + /Zm200 %(AdditionalOptions) + true + + + mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC110\mangosd__Win32_Debug;..\..\..\..\win\VC110\framework__Win32_Debug;..\..\..\..\dep\lib\win32_debug\;%(AdditionalLibraryDirectories) + true + Windows + false + + + $(OutDir)mangosscript.lib + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;MANGOS_DEBUG;_WINDOWS;_USRDLL;SCRIPT;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + /Zm200 %(AdditionalOptions) + true + + + mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC110\mangosd__x64_Debug;..\..\..\..\win\VC110\framework__x64_Debug;..\..\..\..\dep\lib\x64_Debug\;%(AdditionalLibraryDirectories) + true + Windows + false + + + $(OutDir)mangosscript.lib + MachineX64 + + + + + /Zm200 %(AdditionalOptions) + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0;%(PreprocessorDefinitions) + false + MultiThreadedDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + true + + + mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC110\mangosd__Win32_Release;..\..\..\..\win\VC110\framework__Win32_Release;..\..\..\..\dep\lib\win32_release\;%(AdditionalLibraryDirectories) + true + Windows + true + true + false + + + $(OutDir)mangosscript.lib + + + + + X64 + + + /Zm200 %(AdditionalOptions) + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + true + + + mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC110\mangosd__x64_Release;..\..\..\..\win\VC110\framework__x64_Release;..\..\..\..\dep\lib\x64_release\;%(AdditionalLibraryDirectories) + true + Windows + true + true + false + + + $(OutDir)mangosscript.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC110\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC110\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC110\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC110\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + + + + + + + + + \ No newline at end of file diff --git a/VC110/110ScriptDev2.vcxproj.filters b/VC110/110ScriptDev2.vcxproj.filters new file mode 100644 index 000000000..325c42fc5 --- /dev/null +++ b/VC110/110ScriptDev2.vcxproj.filters @@ -0,0 +1,1922 @@ + + + + + {3b1307a9-bc58-4773-9a93-0e9ceff55c82} + + + {b7b35df3-4231-4370-aed5-5859ab4c312e} + + + {ced0a1e2-6867-4f01-a762-390a3d1f01d3} + + + {af3d4b4d-a585-41c4-ba95-79669a614ea8} + + + {ca2551e0-68d0-4331-88f3-ab0cdaa2bf9a} + + + {45c59280-02fb-482f-859b-bd47cc230f0f} + + + {5631f38e-66c8-4efd-ad3a-2834fbb49a6e} + + + {31605090-12b9-4d42-a5e9-1cbfac8ab384} + + + {08fb5b22-710d-46d6-9893-f567aa75a5e6} + + + {cef5c3c5-f434-4b9f-9bad-8c106d46c755} + + + {66bc2cec-8372-4191-991c-1c23275fa13c} + + + {af465469-5a16-4908-aa08-39c77d02cd88} + + + {920d1832-b347-4afd-bd05-4c943e5555f0} + + + {6ffd42e5-ac49-4635-8087-77ad2b7b0866} + + + {dd4995a8-6d86-4f21-82bc-a18acc2c688f} + + + {2a3a25e5-51f1-4ab3-a1a0-1b9ec9c45d1a} + + + {7a028ad9-afa1-42ea-b147-20a40c5e716c} + + + {66401dac-d94c-4ed6-b912-229dda0906d6} + + + {385f26dc-dcaf-4022-921d-3a562617bf93} + + + {25be39dd-536d-450d-ac94-6372d37a4fae} + + + {1d718eaa-2a8d-4cb9-9abf-17fcf0d91f83} + + + {c929f54b-22dd-49b4-862c-92dfa9a2d1f7} + + + {60b91cfe-7dff-40de-9957-41f8d03144cc} + + + {22eca3e6-662f-4c53-9344-6e749c09c86b} + + + {070541ef-a813-43f5-a8a6-e6674fe1a47e} + + + {5cda7bda-399b-46b7-8bc2-5786f0202fa2} + + + {226d4dc8-830b-4249-b28a-313ac21080a9} + + + {404b30fd-bdaa-44d1-ab3a-384886ebb8ec} + + + {5833dbce-1fa8-49eb-b678-145a2d58a067} + + + {dc38d3fe-d1fe-49f2-bd8f-758cd270dd62} + + + {2552ab59-1f73-4778-a6db-6f03e405622d} + + + {8206776b-4d43-431d-bca5-5f6cff157ea4} + + + {02135a7c-33cc-444e-af90-48a5193e5a6f} + + + {014ada9a-13bf-4540-a0ce-5132bdc36fcf} + + + {9feb59d0-e6bd-4328-9a50-7ddb9852936e} + + + {00f03f8d-4af1-40d9-a95a-e2dc1a81ca7d} + + + {de2e959a-1ef4-41ef-9235-15a1f3f8a19d} + + + {8f8a60e0-223e-4517-918c-243e523a7892} + + + {416ccfc8-a1bb-43a5-b202-d7656981094a} + + + {ba031a13-787e-41da-bcaf-1986fdea8069} + + + {0412262e-b05b-4827-adef-97507204cb69} + + + {e775610e-fa3c-4355-9c4c-473a6a5e57d5} + + + {6c5f7fd4-671b-4cba-aa95-7758b93dc844} + + + {71e87e58-3b30-41e7-8f8a-16886508a4d9} + + + {3cf8e088-da94-4561-993f-2970908d6642} + + + {bc0156b2-6544-4ebc-9ed6-fe45ac1902a4} + + + {b59c73a8-c480-43b2-8a2e-65f5a54978eb} + + + {5eb6a84a-97e6-477e-97e3-23681f29f675} + + + {d7e0e45a-fd89-48a6-8d24-f4922058160e} + + + {71617682-fe62-4d7c-a2de-7181fb3f46f6} + + + {9c5d9a0f-8967-4cf6-a047-3b724f81dc29} + + + {42501e94-f91e-40be-a02a-472b5ca1e22c} + + + {aac6b8be-6055-4d7d-a50a-41650b8d464e} + + + {e7ee3113-f4d0-4e28-acc7-dc80f42d41df} + + + {e603d4b3-3c2f-4011-aa2b-040243163d3f} + + + {36c79ad7-420c-4909-8da3-c90d3cc83b31} + + + {d47410b0-3184-40e2-8704-cea9b97e20ed} + + + {1b2f0d99-82b0-4a96-aaac-c485830eb1b3} + + + {fd594031-4dc2-40de-b37b-93063ee6e3e9} + + + {ef27a557-e12d-4b02-9e86-c258329f201e} + + + {b7e4ad7d-8515-4981-ae27-9e542c223618} + + + {04b1d59c-38b6-4b5c-a50d-b9ff1d39bb30} + + + {ee364414-732a-4aad-820f-a5b73cb8b093} + + + {638d5426-652e-4d1f-9abe-3ed95d7e7e69} + + + {a21893a5-0f34-4a73-b0aa-49b175822834} + + + {728148f8-18a0-4606-a2ec-2c9eae4e5e7e} + + + {88c327d5-0768-465f-b954-30eca0d31f45} + + + {b20efa19-1e16-42e4-bc29-a9c8e282d17c} + + + {fec1fbfa-5119-4bb0-98bc-f8d4583521f7} + + + {1cb43523-dc33-4c49-a5b7-6e700fe0ecd6} + + + {7289cc07-6956-4b09-8dc5-753c82abe8c9} + + + {e834cf7b-88ad-4bae-9fc8-8e027136c63b} + + + {cfb08e82-63e6-49ca-bff2-533f8647797b} + + + {2be3084e-c5c0-4e2f-bbb4-2ebb22bfff19} + + + {6dc08e92-3e86-4a7f-bab9-9a8cec6a201b} + + + {01da56d1-ee04-455c-846c-4e53869314f6} + + + {5e79ca74-cd29-47ff-a08e-3fada858ddd7} + + + {32b92545-4821-4cc8-ae39-f631b0176d46} + + + {044e4dbc-e2fc-437c-b359-b6fb5a3439ff} + + + {4cbcf193-4d98-4518-a9c4-6c8b4bedbf44} + + + {5c32221e-3532-4c32-bdba-9a85213006af} + + + {2df99085-aee2-4202-b4d1-38a5cc35f3e2} + + + {0a109c31-6dd3-4030-8d6c-6c0e147481be} + + + {ddada980-2eed-4f2b-a9f7-dbb9cca7ca3d} + + + {d6843352-6425-48da-85b6-6b26f6217ba8} + + + {6a68396b-343f-4c79-938c-93741acdeb41} + + + {974fc97c-e585-442c-b35e-b21a17804619} + + + {ba709b56-d5db-4730-9591-79b8f9788ca1} + + + {1fa90250-9c5b-450c-be64-d9eee910c4a8} + + + {7b3c1c18-03e9-493e-a364-5beb1a6936eb} + + + {575420cc-581f-4d08-a9da-7814f221ab47} + + + {9c5997ee-accc-4737-815f-b031d422577b} + + + {579f2f5c-acf1-410a-bce6-d353d6912546} + + + {04e4571d-55ee-4f2e-ac4e-46fc2610341f} + + + {79a3e62b-bd96-4d16-8c23-bda17f968d19} + + + {ca7213e9-56c1-4084-a48b-19ff57dee433} + + + {2fd46769-c050-4e47-9533-461ef8695d6a} + + + {90f3df6a-a1d0-4a6e-b8d7-d1d993fc795b} + + + {e35abead-2389-4eb9-88bd-70e6fe5636b5} + + + + + base + + + base + + + base + + + base + + + scripts\battlegrounds + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\scarlet_enclave + + + scripts\eastern_kingdoms\scarlet_enclave + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\sunken_temple + + + scripts\eastern_kingdoms\sunken_temple + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\examples + + + scripts\examples + + + scripts\examples + + + scripts\examples + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor\blackfathom_deeps + + + scripts\kalimdor\caverns_of_time\culling_of_stratholme + + + scripts\kalimdor\caverns_of_time\culling_of_stratholme + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\old_hillsbrad + + + scripts\kalimdor\caverns_of_time\old_hillsbrad + + + scripts\kalimdor\dire_maul + + + scripts\kalimdor\dire_maul + + + scripts\kalimdor\maraudon + + + scripts\kalimdor\onyxias_lair + + + scripts\kalimdor\onyxias_lair + + + scripts\kalimdor\razorfen_downs + + + scripts\kalimdor\razorfen_downs + + + scripts\kalimdor\razorfen_kraul + + + scripts\kalimdor\razorfen_kraul + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\wailing_caverns + + + scripts\kalimdor\wailing_caverns + + + scripts\kalimdor\zulfarrak + + + scripts\kalimdor\zulfarrak + + + scripts\kalimdor\zulfarrak + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\draktharon_keep + + + scripts\northrend\draktharon_keep + + + scripts\northrend\draktharon_keep + + + scripts\northrend\draktharon_keep + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\nexus\eye_of_eternity + + + scripts\northrend\nexus\eye_of_eternity + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\obsidian_sanctum + + + scripts\northrend\obsidian_sanctum + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\violet_hold + + + scripts\northrend\violet_hold + + + scripts\northrend\violet_hold + + + scripts\northrend\violet_hold + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland\auchindoun\auchenai_crypts + + + scripts\outland\auchindoun\auchenai_crypts + + + scripts\outland\auchindoun\mana_tombs + + + scripts\outland\auchindoun\mana_tombs + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\slave_pens + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\underbog + + + scripts\outland\gruuls_lair + + + scripts\outland\gruuls_lair + + + scripts\outland\gruuls_lair + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\magtheridons_lair + + + scripts\outland\hellfire_citadel\magtheridons_lair + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\botanica + + + scripts\outland\tempest_keep\botanica + + + scripts\outland\tempest_keep\botanica + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + include + + + include + + + include + + + include + + + system + + + system + + + system + + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + + + base + + + base + + + base + + + base + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\scarlet_enclave + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\sunken_temple + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulgurub + + + scripts\kalimdor\blackfathom_deeps + + + scripts\kalimdor\caverns_of_time\culling_of_stratholme + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\old_hillsbrad + + + scripts\kalimdor\dire_maul + + + scripts\kalimdor\onyxias_lair + + + scripts\kalimdor\razorfen_downs + + + scripts\kalimdor\razorfen_kraul + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\wailing_caverns + + + scripts\kalimdor\zulfarrak + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\draktharon_keep + + + scripts\northrend\gundrak + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\naxxramas + + + scripts\northrend\nexus\eye_of_eternity + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\obsidian_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\violet_hold + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\black_temple + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\gruuls_lair + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\magtheridons_lair + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\world + + + include + + + include + + + include + + + include + + + include + + + system + + + system + + + + + + + + + + \ No newline at end of file diff --git a/VC120/120ScriptDev2.vcxproj b/VC120/120ScriptDev2.vcxproj new file mode 100644 index 000000000..843d5e86e --- /dev/null +++ b/VC120/120ScriptDev2.vcxproj @@ -0,0 +1,802 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ScriptDev2 + {4295C8A9-79B7-4354-8064-F05FB9CA0C96} + ScriptDev2 + Win32Proj + + + + DynamicLibrary + MultiByte + v120 + + + DynamicLibrary + MultiByte + v120 + + + DynamicLibrary + MultiByte + v120 + + + DynamicLibrary + MultiByte + v120 + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\bin\win32_debug\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + true + ..\..\..\..\bin\x64_debug\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + true + ..\..\..\..\bin\win32_release\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + false + ..\..\..\..\bin\x64_release\ + .\ScriptDev2__$(Platform)_$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + mangosscript + mangosscript + mangosscript + mangosscript + + + + Disabled + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;MANGOS_DEBUG;_WINDOWS;_USRDLL;SCRIPT;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + /Zm200 %(AdditionalOptions) + true + + + mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC120\mangosd__Win32_Debug;..\..\..\..\win\VC120\framework__Win32_Debug;..\..\..\..\dep\lib\win32_debug\;%(AdditionalLibraryDirectories) + true + Windows + false + + + $(OutDir)mangosscript.lib + MachineX86 + + + + + X64 + + + Disabled + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;MANGOS_DEBUG;_WINDOWS;_USRDLL;SCRIPT;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + /Zm200 %(AdditionalOptions) + true + + + mangosd.lib;ACEd.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC120\mangosd__x64_Debug;..\..\..\..\win\VC120\framework__x64_Debug;..\..\..\..\dep\lib\x64_Debug\;%(AdditionalLibraryDirectories) + true + Windows + false + + + $(OutDir)mangosscript.lib + MachineX64 + + + + + /Zm200 %(AdditionalOptions) + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0;%(PreprocessorDefinitions) + false + MultiThreadedDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + true + + + mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC120\mangosd__Win32_Release;..\..\..\..\win\VC120\framework__Win32_Release;..\..\..\..\dep\lib\win32_release\;%(AdditionalLibraryDirectories) + true + Windows + true + true + false + + + $(OutDir)mangosscript.lib + + + + + X64 + + + /Zm200 %(AdditionalOptions) + ..\..\..\..\dep\include\;..\..\..\shared\;..\..\..\framework\;..\..\..\game\;..\include\;..\base\;..\..\..\..\dep\ACE_wrappers\;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;SCRIPT;_SECURE_SCL=0;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + precompiled.h + Level3 + ProgramDatabase + true + true + true + true + + + mangosd.lib;ACE.lib;framework.lib;%(AdditionalDependencies) + ..\..\..\..\win\VC120\mangosd__x64_Release;..\..\..\..\win\VC120\framework__x64_Release;..\..\..\..\dep\lib\x64_release\;%(AdditionalLibraryDirectories) + true + Windows + true + true + false + + + $(OutDir)mangosscript.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC120\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC120\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC120\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + Extracting revision + cd "$(SolutionDir)" +"$(SolutionDir)..\..\..\win\VC120\genrevision__Win32_$(Configuration)\genrevision.exe" + + .svn/entries;%(AdditionalInputs) + revision.h;%(Outputs) + + + + + + + + + \ No newline at end of file diff --git a/VC120/120ScriptDev2.vcxproj.filters b/VC120/120ScriptDev2.vcxproj.filters new file mode 100644 index 000000000..f4e19f89e --- /dev/null +++ b/VC120/120ScriptDev2.vcxproj.filters @@ -0,0 +1,1922 @@ + + + + + {3b1307a9-bc58-4773-9a93-0e9ceff55c82} + + + {b7b35df3-4231-4370-aed5-5859ab4c312e} + + + {ced0a1e2-6867-4f01-a762-390a3d1f01d3} + + + {af3d4b4d-a585-41c4-ba95-79669a614ea8} + + + {ca2551e0-68d0-4331-88f3-ab0cdaa2bf9a} + + + {45c59280-02fb-482f-859b-bd47cc230f0f} + + + {5631f38e-66c8-4efd-ad3a-2834fbb49a6e} + + + {31605090-12b9-4d42-a5e9-1cbfac8ab384} + + + {08fb5b22-710d-46d6-9893-f567aa75a5e6} + + + {cef5c3c5-f434-4b9f-9bad-8c106d46c755} + + + {66bc2cec-8372-4191-991c-1c23275fa13c} + + + {af465469-5a16-4908-aa08-39c77d02cd88} + + + {920d1832-b347-4afd-bd05-4c943e5555f0} + + + {6ffd42e5-ac49-4635-8087-77ad2b7b0866} + + + {dd4995a8-6d86-4f21-82bc-a18acc2c688f} + + + {2a3a25e5-51f1-4ab3-a1a0-1b9ec9c45d1a} + + + {7a028ad9-afa1-42ea-b147-20a40c5e716c} + + + {66401dac-d94c-4ed6-b912-229dda0906d6} + + + {385f26dc-dcaf-4022-921d-3a562617bf93} + + + {25be39dd-536d-450d-ac94-6372d37a4fae} + + + {1d718eaa-2a8d-4cb9-9abf-17fcf0d91f83} + + + {c929f54b-22dd-49b4-862c-92dfa9a2d1f7} + + + {60b91cfe-7dff-40de-9957-41f8d03144cc} + + + {22eca3e6-662f-4c53-9344-6e749c09c86b} + + + {070541ef-a813-43f5-a8a6-e6674fe1a47e} + + + {5cda7bda-399b-46b7-8bc2-5786f0202fa2} + + + {226d4dc8-830b-4249-b28a-313ac21080a9} + + + {404b30fd-bdaa-44d1-ab3a-384886ebb8ec} + + + {5833dbce-1fa8-49eb-b678-145a2d58a067} + + + {dc38d3fe-d1fe-49f2-bd8f-758cd270dd62} + + + {2552ab59-1f73-4778-a6db-6f03e405622d} + + + {8206776b-4d43-431d-bca5-5f6cff157ea4} + + + {02135a7c-33cc-444e-af90-48a5193e5a6f} + + + {014ada9a-13bf-4540-a0ce-5132bdc36fcf} + + + {9feb59d0-e6bd-4328-9a50-7ddb9852936e} + + + {00f03f8d-4af1-40d9-a95a-e2dc1a81ca7d} + + + {de2e959a-1ef4-41ef-9235-15a1f3f8a19d} + + + {8f8a60e0-223e-4517-918c-243e523a7892} + + + {416ccfc8-a1bb-43a5-b202-d7656981094a} + + + {ba031a13-787e-41da-bcaf-1986fdea8069} + + + {0412262e-b05b-4827-adef-97507204cb69} + + + {e775610e-fa3c-4355-9c4c-473a6a5e57d5} + + + {6c5f7fd4-671b-4cba-aa95-7758b93dc844} + + + {71e87e58-3b30-41e7-8f8a-16886508a4d9} + + + {3cf8e088-da94-4561-993f-2970908d6642} + + + {bc0156b2-6544-4ebc-9ed6-fe45ac1902a4} + + + {b59c73a8-c480-43b2-8a2e-65f5a54978eb} + + + {5eb6a84a-97e6-477e-97e3-23681f29f675} + + + {d7e0e45a-fd89-48a6-8d24-f4922058160e} + + + {71617682-fe62-4d7c-a2de-7181fb3f46f6} + + + {9c5d9a0f-8967-4cf6-a047-3b724f81dc29} + + + {42501e94-f91e-40be-a02a-472b5ca1e22c} + + + {aac6b8be-6055-4d7d-a50a-41650b8d464e} + + + {e7ee3113-f4d0-4e28-acc7-dc80f42d41df} + + + {e603d4b3-3c2f-4011-aa2b-040243163d3f} + + + {36c79ad7-420c-4909-8da3-c90d3cc83b31} + + + {d47410b0-3184-40e2-8704-cea9b97e20ed} + + + {1b2f0d99-82b0-4a96-aaac-c485830eb1b3} + + + {fd594031-4dc2-40de-b37b-93063ee6e3e9} + + + {ef27a557-e12d-4b02-9e86-c258329f201e} + + + {b7e4ad7d-8515-4981-ae27-9e542c223618} + + + {04b1d59c-38b6-4b5c-a50d-b9ff1d39bb30} + + + {ee364414-732a-4aad-820f-a5b73cb8b093} + + + {638d5426-652e-4d1f-9abe-3ed95d7e7e69} + + + {a21893a5-0f34-4a73-b0aa-49b175822834} + + + {728148f8-18a0-4606-a2ec-2c9eae4e5e7e} + + + {88c327d5-0768-465f-b954-30eca0d31f45} + + + {b20efa19-1e16-42e4-bc29-a9c8e282d17c} + + + {fec1fbfa-5119-4bb0-98bc-f8d4583521f7} + + + {1cb43523-dc33-4c49-a5b7-6e700fe0ecd6} + + + {7289cc07-6956-4b09-8dc5-753c82abe8c9} + + + {e834cf7b-88ad-4bae-9fc8-8e027136c63b} + + + {cfb08e82-63e6-49ca-bff2-533f8647797b} + + + {2be3084e-c5c0-4e2f-bbb4-2ebb22bfff19} + + + {6dc08e92-3e86-4a7f-bab9-9a8cec6a201b} + + + {01da56d1-ee04-455c-846c-4e53869314f6} + + + {5e79ca74-cd29-47ff-a08e-3fada858ddd7} + + + {32b92545-4821-4cc8-ae39-f631b0176d46} + + + {044e4dbc-e2fc-437c-b359-b6fb5a3439ff} + + + {4cbcf193-4d98-4518-a9c4-6c8b4bedbf44} + + + {5c32221e-3532-4c32-bdba-9a85213006af} + + + {2df99085-aee2-4202-b4d1-38a5cc35f3e2} + + + {0a109c31-6dd3-4030-8d6c-6c0e147481be} + + + {ddada980-2eed-4f2b-a9f7-dbb9cca7ca3d} + + + {d6843352-6425-48da-85b6-6b26f6217ba8} + + + {6a68396b-343f-4c79-938c-93741acdeb41} + + + {974fc97c-e585-442c-b35e-b21a17804619} + + + {ba709b56-d5db-4730-9591-79b8f9788ca1} + + + {1fa90250-9c5b-450c-be64-d9eee910c4a8} + + + {7b3c1c18-03e9-493e-a364-5beb1a6936eb} + + + {575420cc-581f-4d08-a9da-7814f221ab47} + + + {9c5997ee-accc-4737-815f-b031d422577b} + + + {579f2f5c-acf1-410a-bce6-d353d6912546} + + + {04e4571d-55ee-4f2e-ac4e-46fc2610341f} + + + {79a3e62b-bd96-4d16-8c23-bda17f968d19} + + + {ca7213e9-56c1-4084-a48b-19ff57dee433} + + + {2fd46769-c050-4e47-9533-461ef8695d6a} + + + {90f3df6a-a1d0-4a6e-b8d7-d1d993fc795b} + + + {e35abead-2389-4eb9-88bd-70e6fe5636b5} + + + + + base + + + base + + + base + + + base + + + scripts\battlegrounds + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\scarlet_enclave + + + scripts\eastern_kingdoms\scarlet_enclave + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\sunken_temple + + + scripts\eastern_kingdoms\sunken_temple + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\eastern_kingdoms\zulgurub + + + scripts\examples + + + scripts\examples + + + scripts\examples + + + scripts\examples + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor + + + scripts\kalimdor\blackfathom_deeps + + + scripts\kalimdor\caverns_of_time\culling_of_stratholme + + + scripts\kalimdor\caverns_of_time\culling_of_stratholme + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\old_hillsbrad + + + scripts\kalimdor\caverns_of_time\old_hillsbrad + + + scripts\kalimdor\dire_maul + + + scripts\kalimdor\dire_maul + + + scripts\kalimdor\maraudon + + + scripts\kalimdor\onyxias_lair + + + scripts\kalimdor\onyxias_lair + + + scripts\kalimdor\razorfen_downs + + + scripts\kalimdor\razorfen_downs + + + scripts\kalimdor\razorfen_kraul + + + scripts\kalimdor\razorfen_kraul + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\wailing_caverns + + + scripts\kalimdor\wailing_caverns + + + scripts\kalimdor\zulfarrak + + + scripts\kalimdor\zulfarrak + + + scripts\kalimdor\zulfarrak + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\draktharon_keep + + + scripts\northrend\draktharon_keep + + + scripts\northrend\draktharon_keep + + + scripts\northrend\draktharon_keep + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\gundrak + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\naxxramas + + + scripts\northrend\nexus\eye_of_eternity + + + scripts\northrend\nexus\eye_of_eternity + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\obsidian_sanctum + + + scripts\northrend\obsidian_sanctum + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\violet_hold + + + scripts\northrend\violet_hold + + + scripts\northrend\violet_hold + + + scripts\northrend\violet_hold + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland + + + scripts\outland\auchindoun\auchenai_crypts + + + scripts\outland\auchindoun\auchenai_crypts + + + scripts\outland\auchindoun\mana_tombs + + + scripts\outland\auchindoun\mana_tombs + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\black_temple + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\slave_pens + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\coilfang_reservoir\underbog + + + scripts\outland\gruuls_lair + + + scripts\outland\gruuls_lair + + + scripts\outland\gruuls_lair + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\magtheridons_lair + + + scripts\outland\hellfire_citadel\magtheridons_lair + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\botanica + + + scripts\outland\tempest_keep\botanica + + + scripts\outland\tempest_keep\botanica + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + scripts\world + + + include + + + include + + + include + + + include + + + system + + + system + + + system + + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ruby_sanctum + + + + + base + + + base + + + base + + + base + + + scripts\eastern_kingdoms\blackrock_depths + + + scripts\eastern_kingdoms\blackrock_spire + + + scripts\eastern_kingdoms\blackwing_lair + + + scripts\eastern_kingdoms\deadmines + + + scripts\eastern_kingdoms\gnomeregan + + + scripts\eastern_kingdoms\karazhan + + + scripts\eastern_kingdoms\magisters_terrace + + + scripts\eastern_kingdoms\molten_core + + + scripts\eastern_kingdoms\scarlet_enclave + + + scripts\eastern_kingdoms\scarlet_monastery + + + scripts\eastern_kingdoms\scholomance + + + scripts\eastern_kingdoms\shadowfang_keep + + + scripts\eastern_kingdoms\stratholme + + + scripts\eastern_kingdoms\sunken_temple + + + scripts\eastern_kingdoms\sunwell_plateau + + + scripts\eastern_kingdoms\uldaman + + + scripts\eastern_kingdoms\zulaman + + + scripts\eastern_kingdoms\zulgurub + + + scripts\kalimdor\blackfathom_deeps + + + scripts\kalimdor\caverns_of_time\culling_of_stratholme + + + scripts\kalimdor\caverns_of_time\dark_portal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\hyjal + + + scripts\kalimdor\caverns_of_time\old_hillsbrad + + + scripts\kalimdor\dire_maul + + + scripts\kalimdor\onyxias_lair + + + scripts\kalimdor\razorfen_downs + + + scripts\kalimdor\razorfen_kraul + + + scripts\kalimdor\ruins_of_ahnqiraj + + + scripts\kalimdor\temple_of_ahnqiraj + + + scripts\kalimdor\wailing_caverns + + + scripts\kalimdor\zulfarrak + + + scripts\northrend\azjol-nerub\ahnkahet + + + scripts\northrend\azjol-nerub\azjol-nerub + + + scripts\northrend\crusaders_coliseum\trial_of_the_champion + + + scripts\northrend\crusaders_coliseum\trial_of_the_crusader + + + scripts\northrend\draktharon_keep + + + scripts\northrend\gundrak + + + scripts\northrend\icecrown_citadel\frozen_halls\forge_of_souls + + + scripts\northrend\icecrown_citadel\frozen_halls\halls_of_reflection + + + scripts\northrend\icecrown_citadel\frozen_halls\pit_of_saron + + + scripts\northrend\icecrown_citadel\icecrown_citadel + + + scripts\northrend\naxxramas + + + scripts\northrend\nexus\eye_of_eternity + + + scripts\northrend\nexus\nexus + + + scripts\northrend\nexus\oculus + + + scripts\northrend\obsidian_sanctum + + + scripts\northrend\ruby_sanctum + + + scripts\northrend\ulduar\halls_of_lightning + + + scripts\northrend\ulduar\halls_of_stone + + + scripts\northrend\ulduar\ulduar + + + scripts\northrend\utgarde_keep\utgarde_keep + + + scripts\northrend\utgarde_keep\utgarde_pinnacle + + + scripts\northrend\vault_of_archavon + + + scripts\northrend\violet_hold + + + scripts\outland\auchindoun\sethekk_halls + + + scripts\outland\auchindoun\shadow_labyrinth + + + scripts\outland\black_temple + + + scripts\outland\coilfang_reservoir\serpent_shrine + + + scripts\outland\coilfang_reservoir\steam_vault + + + scripts\outland\gruuls_lair + + + scripts\outland\hellfire_citadel\blood_furnace + + + scripts\outland\hellfire_citadel\hellfire_ramparts + + + scripts\outland\hellfire_citadel\magtheridons_lair + + + scripts\outland\hellfire_citadel\shattered_halls + + + scripts\outland\tempest_keep\arcatraz + + + scripts\outland\tempest_keep\the_eye + + + scripts\outland\tempest_keep\the_mechanar + + + scripts\world + + + include + + + include + + + include + + + include + + + include + + + system + + + system + + + + + + + + + + \ No newline at end of file diff --git a/VC80/80ScriptDev2.vcproj b/VC80/80ScriptDev2.vcproj deleted file mode 100644 index 4e4eb30b7..000000000 --- a/VC80/80ScriptDev2.vcproj +++ /dev/null @@ -1,3145 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/VC90/90ScriptDev2.vcproj b/VC90/90ScriptDev2.vcproj deleted file mode 100644 index 8cebf4c81..000000000 --- a/VC90/90ScriptDev2.vcproj +++ /dev/null @@ -1,3143 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/base/escort_ai.cpp b/base/escort_ai.cpp index 373a60aaa..eec66678b 100644 --- a/base/escort_ai.cpp +++ b/base/escort_ai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -15,19 +15,11 @@ EndScriptData */ const float MAX_PLAYER_DISTANCE = 66.0f; -enum -{ - POINT_LAST_POINT = 0xFFFFFF, - POINT_HOME = 0xFFFFFE -}; - npc_escortAI::npc_escortAI(Creature* pCreature) : ScriptedAI(pCreature), - m_playerGuid(), m_uiPlayerCheckTimer(1000), - m_uiWPWaitTimer(2500), m_uiEscortState(STATE_ESCORT_NONE), - m_bIsRunning(false), m_pQuestForEscort(NULL), + m_bIsRunning(false), m_bCanInstantRespawn(false), m_bCanReturnToStart(false) {} @@ -44,10 +36,8 @@ void npc_escortAI::GetAIInformation(ChatHandler& reader) if (HasEscortState(STATE_ESCORT_ESCORTING)) { - oss << "\nEscortFlags: Escorting" << (HasEscortState(STATE_ESCORT_RETURNING) ? ", Returning" : "") << (HasEscortState(STATE_ESCORT_PAUSED) ? ", Paused" : ""); - - if (CurrentWP != WaypointList.end()) - oss << "\nNext Waypoint Id = " << CurrentWP->uiId << " Position: " << CurrentWP->fX << " " << CurrentWP->fY << " " << CurrentWP->fZ; + oss << "\nEscortFlags: Escorting" << (HasEscortState(STATE_ESCORT_RETURNING) ? ", Returning" : "") << (HasEscortState(STATE_ESCORT_PAUSED) ? ", Paused" : "") << "\n"; + m_creature->GetMotionMaster()->GetWaypointPathInformation(oss); } reader.PSendSysMessage(oss.str().c_str()); @@ -61,48 +51,16 @@ bool npc_escortAI::IsVisible(Unit* pWho) const return m_creature->IsWithinDist(pWho, VISIBLE_RANGE) && pWho->isVisibleForOrDetect(m_creature, m_creature, true); } -void npc_escortAI::AttackStart(Unit* pWho) -{ - if (!pWho) - return; +void npc_escortAI::Aggro(Unit* /*pEnemy*/) {} - if (m_creature->Attack(pWho, true)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); - - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) - m_creature->GetMotionMaster()->MovementExpired(); - - if (IsCombatMovement()) - m_creature->GetMotionMaster()->MoveChase(pWho); - } -} - -void npc_escortAI::EnterCombat(Unit* pEnemy) -{ - // Store combat start position - m_creature->SetCombatStartPosition(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - - if (!pEnemy) - return; - - Aggro(pEnemy); -} - -void npc_escortAI::Aggro(Unit* pEnemy) -{ -} - -//see followerAI +// see followerAI bool npc_escortAI::AssistPlayerInCombat(Unit* pWho) { if (!pWho->getVictim()) return false; // experimental (unknown) flag not present - if (!(m_creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_CAN_ASSIST)) + if (!(m_creature->GetCreatureInfo()->CreatureTypeFlags & CREATURE_TYPEFLAGS_CAN_ASSIST)) return false; // unit state prevents (similar check is done in CanInitiateAttack which also include checking unit_flags. We skip those here) @@ -171,7 +129,7 @@ void npc_escortAI::MoveInLineOfSight(Unit* pWho) } } -void npc_escortAI::JustDied(Unit* pKiller) +void npc_escortAI::JustDied(Unit* /*pKiller*/) { if (!HasEscortState(STATE_ESCORT_ESCORTING) || !m_playerGuid || !m_pQuestForEscort) return; @@ -180,7 +138,7 @@ void npc_escortAI::JustDied(Unit* pKiller) { if (Group* pGroup = pPlayer->GetGroup()) { - for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { if (Player* pMember = pRef->getSource()) { @@ -204,39 +162,6 @@ void npc_escortAI::JustRespawned() if (!IsCombatMovement()) SetCombatMovement(true); - //add a small delay before going to first waypoint, normal in near all cases - m_uiWPWaitTimer = 2500; - - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - - Reset(); -} - -void npc_escortAI::EnterEvadeMode() -{ - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); - m_creature->SetLootRecipient(NULL); - - if (HasEscortState(STATE_ESCORT_ESCORTING)) - { - // We have left our path - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - debug_log("SD2: EscortAI has left combat and is now returning to CombatStartPosition."); - - AddEscortState(STATE_ESCORT_RETURNING); - - float fPosX, fPosY, fPosZ; - m_creature->GetCombatStartPosition(fPosX, fPosY, fPosZ); - m_creature->GetMotionMaster()->MovePoint(POINT_LAST_POINT, fPosX, fPosY, fPosZ); - } - } - else - m_creature->GetMotionMaster()->MoveTargetedHome(); - Reset(); } @@ -262,66 +187,8 @@ bool npc_escortAI::IsPlayerOrGroupInRange() return false; } -// Returns false, if npc is despawned -bool npc_escortAI::MoveToNextWaypoint() -{ - // Do nothing if escorting is paused - if (HasEscortState(STATE_ESCORT_PAUSED)) - return true; - - // Final Waypoint reached (and final wait time waited) - if (CurrentWP == WaypointList.end()) - { - debug_log("SD2: EscortAI reached end of waypoints"); - - if (m_bCanReturnToStart) - { - float fRetX, fRetY, fRetZ; - m_creature->GetRespawnCoord(fRetX, fRetY, fRetZ); - - m_creature->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ); - - m_uiWPWaitTimer = 0; - - debug_log("SD2: EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ); - return true; - } - - if (m_bCanInstantRespawn) - { - m_creature->SetDeathState(JUST_DIED); - m_creature->Respawn(); - } - else - m_creature->ForcedDespawn(); - - return false; - } - - m_creature->GetMotionMaster()->MovePoint(CurrentWP->uiId, CurrentWP->fX, CurrentWP->fY, CurrentWP->fZ); - debug_log("SD2: EscortAI start waypoint %u (%f, %f, %f).", CurrentWP->uiId, CurrentWP->fX, CurrentWP->fY, CurrentWP->fZ); - - WaypointStart(CurrentWP->uiId); - - m_uiWPWaitTimer = 0; - - return true; -} - void npc_escortAI::UpdateAI(const uint32 uiDiff) { - // Waypoint Updating - if (HasEscortState(STATE_ESCORT_ESCORTING) && !m_creature->getVictim() && m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_RETURNING)) - { - if (m_uiWPWaitTimer <= uiDiff) - { - if (!MoveToNextWaypoint()) - return; - } - else - m_uiWPWaitTimer -= uiDiff; - } - // Check if player or any member of his group is within range if (HasEscortState(STATE_ESCORT_ESCORTING) && m_playerGuid && !m_creature->getVictim() && !HasEscortState(STATE_ESCORT_RETURNING)) { @@ -351,7 +218,7 @@ void npc_escortAI::UpdateAI(const uint32 uiDiff) UpdateEscortAI(uiDiff); } -void npc_escortAI::UpdateEscortAI(const uint32 uiDiff) +void npc_escortAI::UpdateEscortAI(const uint32 /*uiDiff*/) { // Check if we have a current target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -360,109 +227,48 @@ void npc_escortAI::UpdateEscortAI(const uint32 uiDiff) DoMeleeAttackIfReady(); } +/// Helper function for transition between old Escort Movment and using WaypointMMGen +bool npc_escortAI::IsSD2EscortMovement(uint32 uiMoveType) const +{ + return uiMoveType >= EXTERNAL_WAYPOINT_MOVE; +} + void npc_escortAI::MovementInform(uint32 uiMoveType, uint32 uiPointId) { - if (uiMoveType != POINT_MOTION_TYPE || !HasEscortState(STATE_ESCORT_ESCORTING)) + if (!IsSD2EscortMovement(uiMoveType) || !HasEscortState(STATE_ESCORT_ESCORTING)) return; - //Combat start position reached, continue waypoint movement - if (uiPointId == POINT_LAST_POINT) - { - debug_log("SD2: EscortAI has returned to original position before combat"); + //uint32 pathId = uiMoveType & 0xFF; - m_creature->SetWalk(!m_bIsRunning); - RemoveEscortState(STATE_ESCORT_RETURNING); - } - else if (uiPointId == POINT_HOME) + if (uiMoveType < EXTERNAL_WAYPOINT_MOVE_START) + WaypointReached(uiPointId); + else if (uiMoveType < EXTERNAL_WAYPOINT_FINISHED_LAST) + WaypointStart(uiPointId); + else // Last WP Reached { - debug_log("SD2: EscortAI has returned to original home location and will continue from beginning of waypoint list."); - - CurrentWP = WaypointList.begin(); - m_uiWPWaitTimer = 0; - } - else - { - //Make sure that we are still on the right waypoint - if (CurrentWP->uiId != uiPointId) + if (m_bCanInstantRespawn) { - error_log("SD2: EscortAI for Npc %u reached waypoint out of order %u, expected %u.", m_creature->GetEntry(), uiPointId, CurrentWP->uiId); - return; + m_creature->SetDeathState(JUST_DIED); + m_creature->Respawn(); } - - debug_log("SD2: EscortAI waypoint %u reached.", CurrentWP->uiId); - - // In case we were moving while in combat, we should evade back to this position - m_creature->SetCombatStartPosition(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - - //Call WP function - WaypointReached(CurrentWP->uiId); - - m_uiWPWaitTimer = CurrentWP->uiWaitTime; - - ++CurrentWP; - } - - if (!m_uiWPWaitTimer) - { - // Continue WP Movement if Can - if (HasEscortState(STATE_ESCORT_ESCORTING) && !HasEscortState(STATE_ESCORT_PAUSED | STATE_ESCORT_RETURNING) && !m_creature->getVictim()) - MoveToNextWaypoint(); else - m_uiWPWaitTimer = 1; - } -} - -/*void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs) -{ - Escort_Waypoint t(id, x, y, z, WaitTimeMs); - - WaypointList.push_back(t); -}*/ - -void npc_escortAI::FillPointMovementListForCreature() -{ - std::vector const &pPointsEntries = pSystemMgr.GetPointMoveList(m_creature->GetEntry()); - - if (pPointsEntries.empty()) - return; - - std::vector::const_iterator itr; - - for (itr = pPointsEntries.begin(); itr != pPointsEntries.end(); ++itr) - { - Escort_Waypoint pPoint(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime); - WaypointList.push_back(pPoint); + m_creature->ForcedDespawn(); } } void npc_escortAI::SetCurrentWaypoint(uint32 uiPointId) { if (!(HasEscortState(STATE_ESCORT_PAUSED))) // Only when paused - return; - - if (uiPointId == CurrentWP->uiId) // Already here - return; - - bool bFoundWaypoint = false; - for (std::list::iterator itr = WaypointList.begin(); itr != WaypointList.end(); ++itr) { - if (itr->uiId == uiPointId) - { - CurrentWP = itr; // Set to found itr - bFoundWaypoint = true; - break; - } + script_error_log("EscortAI for %s tried to set new waypoint %u, but not paused", m_creature->GetGuidStr().c_str(), uiPointId); + return; } - if (!bFoundWaypoint) + if (!m_creature->GetMotionMaster()->SetNextWaypoint(uiPointId)) { - debug_log("SD2: EscortAI current waypoint tried to set to id %u, but doesn't exist in WaypointList", uiPointId); + script_error_log("EscortAI for %s current waypoint tried to set to id %u, but doesn't exist in this path", m_creature->GetGuidStr().c_str(), uiPointId); return; } - - m_uiWPWaitTimer = 1; - - debug_log("SD2: EscortAI current waypoint set to id %u", CurrentWP->uiId); } void npc_escortAI::SetRun(bool bRun) @@ -484,33 +290,28 @@ void npc_escortAI::SetRun(bool bRun) m_bIsRunning = bRun; } -//TODO: get rid of this many variables passed in function. +// TODO: get rid of this many variables passed in function. void npc_escortAI::Start(bool bRun, const Player* pPlayer, const Quest* pQuest, bool bInstantRespawn, bool bCanLoopPath) { if (m_creature->getVictim()) { - error_log("SD2: EscortAI attempt to Start while in combat."); + script_error_log("EscortAI attempt to Start while in combat."); return; } if (HasEscortState(STATE_ESCORT_ESCORTING)) { - error_log("SD2: EscortAI attempt to Start while already escorting."); + script_error_log("EscortAI attempt to Start while already escorting."); return; } - if (!WaypointList.empty()) - WaypointList.clear(); - - FillPointMovementListForCreature(); - - if (WaypointList.empty()) + if (!pSystemMgr.GetPathInfo(m_creature->GetEntry(), 1)) { - error_db_log("SD2: EscortAI Start with 0 waypoints (possible missing entry in script_waypoint)."); + script_error_log("EscortAI attempt to start escorting for %s, but has no waypints loaded", m_creature->GetGuidStr().c_str()); return; } - //set variables + // set variables m_bIsRunning = bRun; m_playerGuid = pPlayer ? pPlayer->GetObjectGuid() : ObjectGuid(); @@ -522,24 +323,19 @@ void npc_escortAI::Start(bool bRun, const Player* pPlayer, const Quest* pQuest, if (m_bCanReturnToStart && m_bCanInstantRespawn) debug_log("SD2: EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn."); - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) - { - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveIdle(); - debug_log("SD2: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle."); - } - - //disable npcflags + // disable npcflags m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); - debug_log("SD2: EscortAI started with " SIZEFMTD " waypoints. Run = %d, PlayerGuid = %s", WaypointList.size(), m_bIsRunning, m_playerGuid.GetString().c_str()); - - CurrentWP = WaypointList.begin(); + AddEscortState(STATE_ESCORT_ESCORTING); - //Set initial speed + // Set initial speed m_creature->SetWalk(!m_bIsRunning); - AddEscortState(STATE_ESCORT_ESCORTING); + m_creature->StopMoving(); + + // Start moving along the path with 2500ms delay + m_creature->GetMotionMaster()->Clear(false, true); + m_creature->GetMotionMaster()->MoveWaypoint(1, 3, 2500); JustStartedEscort(); } @@ -550,7 +346,13 @@ void npc_escortAI::SetEscortPaused(bool bPaused) return; if (bPaused) + { AddEscortState(STATE_ESCORT_PAUSED); + m_creature->addUnitState(UNIT_STAT_WAYPOINT_PAUSED); + } else + { RemoveEscortState(STATE_ESCORT_PAUSED); + m_creature->clearUnitState(UNIT_STAT_WAYPOINT_PAUSED); + } } diff --git a/base/escort_ai.h b/base/escort_ai.h index 564499ef1..282aaa525 100644 --- a/base/escort_ai.h +++ b/base/escort_ai.h @@ -1,72 +1,49 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #ifndef SC_ESCORTAI_H #define SC_ESCORTAI_H -struct Escort_Waypoint -{ - Escort_Waypoint(uint32 uiId, float fX, float fY, float fZ, uint32 uiWaitTime) : - uiId(uiId), - fX(fX), - fY(fY), - fZ(fZ), - uiWaitTime(uiWaitTime) - {} - - uint32 uiId; - float fX; - float fY; - float fZ; - uint32 uiWaitTime; -}; +// Remove this include, when EscortAI stores uint32 quest-id instead of Quest* +#include "ObjectMgr.h" enum EscortState { - STATE_ESCORT_NONE = 0x000, //nothing in progress - STATE_ESCORT_ESCORTING = 0x001, //escort are in progress - STATE_ESCORT_RETURNING = 0x002, //escort is returning after being in combat - STATE_ESCORT_PAUSED = 0x004 //will not proceed with waypoints before state is removed + STATE_ESCORT_NONE = 0x000, // nothing in progress + STATE_ESCORT_ESCORTING = 0x001, // escort are in progress + STATE_ESCORT_RETURNING = 0x002, // escort is returning after being in combat + STATE_ESCORT_PAUSED = 0x004 // will not proceed with waypoints before state is removed }; -struct MANGOS_DLL_DECL npc_escortAI : public ScriptedAI +struct npc_escortAI : public ScriptedAI { public: explicit npc_escortAI(Creature* pCreature); ~npc_escortAI() {} - void GetAIInformation(ChatHandler& reader); + void GetAIInformation(ChatHandler& reader) override; - virtual void Aggro(Unit*); + virtual void Aggro(Unit*) override; - virtual void Reset() = 0; + virtual void Reset() override = 0; // CreatureAI functions - bool IsVisible(Unit*) const; - - void AttackStart(Unit*); - - void EnterCombat(Unit*); + bool IsVisible(Unit*) const override; - void MoveInLineOfSight(Unit*); + void MoveInLineOfSight(Unit*) override; - void JustDied(Unit*); + void JustDied(Unit*) override; - void JustRespawned(); + void JustRespawned() override; - void EnterEvadeMode(); + void UpdateAI(const uint32) override; // the "internal" update, calls UpdateEscortAI() + virtual void UpdateEscortAI(const uint32); // used when it's needed to add code in update (abilities, scripted events, etc) - void UpdateAI(const uint32); //the "internal" update, calls UpdateEscortAI() - virtual void UpdateEscortAI(const uint32); //used when it's needed to add code in update (abilities, scripted events, etc) - - void MovementInform(uint32, uint32); - - // EscortAI functions - //void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs = 0); + void MovementInform(uint32, uint32) override; virtual void WaypointReached(uint32 uiPointId) = 0; - virtual void WaypointStart(uint32 uiPointId) {} + virtual void WaypointStart(uint32 /*uiPointId*/) {} void Start(bool bRun = false, const Player* pPlayer = NULL, const Quest* pQuest = NULL, bool bInstantRespawn = false, bool bCanLoopPath = false); @@ -80,29 +57,25 @@ struct MANGOS_DLL_DECL npc_escortAI : public ScriptedAI protected: Player* GetPlayerForEscort() { return m_creature->GetMap()->GetPlayer(m_playerGuid); } + bool IsSD2EscortMovement(uint32 uiMoveType) const; virtual void JustStartedEscort() {} private: bool AssistPlayerInCombat(Unit* pWho); bool IsPlayerOrGroupInRange(); - bool MoveToNextWaypoint(); - void FillPointMovementListForCreature(); void AddEscortState(uint32 uiEscortState) { m_uiEscortState |= uiEscortState; } void RemoveEscortState(uint32 uiEscortState) { m_uiEscortState &= ~uiEscortState; } ObjectGuid m_playerGuid; - uint32 m_uiWPWaitTimer; uint32 m_uiPlayerCheckTimer; uint32 m_uiEscortState; - const Quest* m_pQuestForEscort; //generally passed in Start() when regular escort script. + const Quest* m_pQuestForEscort; // generally passed in Start() when regular escort script. - std::list WaypointList; - std::list::iterator CurrentWP; - - bool m_bIsRunning; //all creatures are walking by default (has flag SPLINEFLAG_WALKMODE) - bool m_bCanInstantRespawn; //if creature should respawn instantly after escort over (if not, database respawntime are used) - bool m_bCanReturnToStart; //if creature can walk same path (loop) without despawn. Not for regular escort quests. + bool m_bIsRunning; // all creatures are walking by default (has flag SPLINEFLAG_WALKMODE) + bool m_bCanInstantRespawn; // if creature should respawn instantly after escort over (if not, database respawntime are used) + bool m_bCanReturnToStart; // if creature can walk same path (loop) without despawn. Not for regular escort quests. }; + #endif diff --git a/base/follower_ai.cpp b/base/follower_ai.cpp index 26cc67bee..f89f2b514 100644 --- a/base/follower_ai.cpp +++ b/base/follower_ai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -20,10 +20,9 @@ enum }; FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature), - m_leaderGuid(), - m_pQuestForFollow(NULL), m_uiUpdateFollowTimer(2500), - m_uiFollowState(STATE_FOLLOW_NONE) + m_uiFollowState(STATE_FOLLOW_NONE), + m_pQuestForFollow(NULL) {} void FollowerAI::AttackStart(Unit* pWho) @@ -42,15 +41,15 @@ void FollowerAI::AttackStart(Unit* pWho) } } -//This part provides assistance to a player that are attacked by pWho, even if out of normal aggro range -//It will cause m_creature to attack pWho that are attacking _any_ player (which has been confirmed may happen also on offi) +// This part provides assistance to a player that are attacked by pWho, even if out of normal aggro range +// It will cause m_creature to attack pWho that are attacking _any_ player (which has been confirmed may happen also on offi) bool FollowerAI::AssistPlayerInCombat(Unit* pWho) { if (!pWho->getVictim()) return false; // experimental (unknown) flag not present - if (!(m_creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_CAN_ASSIST)) + if (!(m_creature->GetCreatureInfo()->CreatureTypeFlags & CREATURE_TYPEFLAGS_CAN_ASSIST)) return false; // unit state prevents (similar check is done in CanInitiateAttack which also include checking unit_flags. We skip those here) @@ -119,17 +118,17 @@ void FollowerAI::MoveInLineOfSight(Unit* pWho) } } -void FollowerAI::JustDied(Unit* pKiller) +void FollowerAI::JustDied(Unit* /*pKiller*/) { if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || !m_leaderGuid || !m_pQuestForFollow) return; - //TODO: need a better check for quests with time limit. + // TODO: need a better check for quests with time limit. if (Player* pPlayer = GetLeaderForFollower()) { if (Group* pGroup = pPlayer->GetGroup()) { - for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { if (Player* pMember = pRef->getSource()) { @@ -153,15 +152,12 @@ void FollowerAI::JustRespawned() if (!IsCombatMovement()) SetCombatMovement(true); - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - Reset(); } void FollowerAI::EnterEvadeMode() { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->SetLootRecipient(NULL); @@ -214,7 +210,7 @@ void FollowerAI::UpdateAI(const uint32 uiDiff) if (Group* pGroup = pPlayer->GetGroup()) { - for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { Player* pMember = pRef->getSource(); @@ -248,7 +244,7 @@ void FollowerAI::UpdateAI(const uint32 uiDiff) UpdateFollowerAI(uiDiff); } -void FollowerAI::UpdateFollowerAI(const uint32 uiDiff) +void FollowerAI::UpdateFollowerAI(const uint32 /*uiDiff*/) { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -283,15 +279,15 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const if (HasFollowState(STATE_FOLLOW_INPROGRESS)) { - error_log("SD2: FollowerAI attempt to StartFollow while already following."); + script_error_log("FollowerAI attempt to StartFollow while already following."); return; } - //set variables + // set variables m_leaderGuid = pLeader->GetObjectGuid(); if (uiFactionForFollower) - m_creature->setFaction(uiFactionForFollower); + m_creature->SetFactionTemporary(uiFactionForFollower, TEMPFACTION_RESTORE_RESPAWN); m_pQuestForFollow = pQuest; @@ -321,7 +317,7 @@ Player* FollowerAI::GetLeaderForFollower() { if (Group* pGroup = pLeader->GetGroup()) { - for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { Player* pMember = pRef->getSource(); @@ -330,7 +326,6 @@ Player* FollowerAI::GetLeaderForFollower() debug_log("SD2: FollowerAI GetLeader changed and returned new leader."); m_leaderGuid = pMember->GetObjectGuid(); return pMember; - break; } } } diff --git a/base/follower_ai.h b/base/follower_ai.h index 9533a7580..8133bf5a2 100644 --- a/base/follower_ai.h +++ b/base/follower_ai.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,40 +8,40 @@ enum FollowState { STATE_FOLLOW_NONE = 0x000, - STATE_FOLLOW_INPROGRESS = 0x001, //must always have this state for any follow - STATE_FOLLOW_RETURNING = 0x002, //when returning to combat start after being in combat - STATE_FOLLOW_PAUSED = 0x004, //disables following - STATE_FOLLOW_COMPLETE = 0x008, //follow is completed and may end - STATE_FOLLOW_PREEVENT = 0x010, //not implemented (allow pre event to run, before follow is initiated) - STATE_FOLLOW_POSTEVENT = 0x020 //can be set at complete and allow post event to run + STATE_FOLLOW_INPROGRESS = 0x001, // must always have this state for any follow + STATE_FOLLOW_RETURNING = 0x002, // when returning to combat start after being in combat + STATE_FOLLOW_PAUSED = 0x004, // disables following + STATE_FOLLOW_COMPLETE = 0x008, // follow is completed and may end + STATE_FOLLOW_PREEVENT = 0x010, // not implemented (allow pre event to run, before follow is initiated) + STATE_FOLLOW_POSTEVENT = 0x020 // can be set at complete and allow post event to run }; -class MANGOS_DLL_DECL FollowerAI : public ScriptedAI +class FollowerAI : public ScriptedAI { public: explicit FollowerAI(Creature* pCreature); ~FollowerAI() {} - //virtual void WaypointReached(uint32 uiPointId) = 0; + // virtual void WaypointReached(uint32 uiPointId) = 0; - void MovementInform(uint32 uiMotionType, uint32 uiPointId); + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override; - void AttackStart(Unit*); + void AttackStart(Unit*) override; - void MoveInLineOfSight(Unit*); + void MoveInLineOfSight(Unit*) override; - void EnterEvadeMode(); + void EnterEvadeMode() override; - void JustDied(Unit*); + void JustDied(Unit*) override; - void JustRespawned(); + void JustRespawned() override; - void UpdateAI(const uint32); //the "internal" update, calls UpdateFollowerAI() - virtual void UpdateFollowerAI(const uint32); //used when it's needed to add code in update (abilities, scripted events, etc) + void UpdateAI(const uint32) override; // the "internal" update, calls UpdateFollowerAI() + virtual void UpdateFollowerAI(const uint32); // used when it's needed to add code in update (abilities, scripted events, etc) void StartFollow(Player* pPlayer, uint32 uiFactionForFollower = 0, const Quest* pQuest = NULL); - void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow + void SetFollowPaused(bool bPaused); // if special event require follow mode to hold/resume during the follow void SetFollowComplete(bool bWithEndEvent = false); bool HasFollowState(uint32 uiFollowState) { return (m_uiFollowState & uiFollowState); } @@ -59,7 +59,7 @@ class MANGOS_DLL_DECL FollowerAI : public ScriptedAI uint32 m_uiUpdateFollowTimer; uint32 m_uiFollowState; - const Quest* m_pQuestForFollow; //normally we have a quest + const Quest* m_pQuestForFollow; // normally we have a quest }; #endif diff --git a/base/guard_ai.cpp b/base/guard_ai.cpp index 78d292d3d..c6dffc117 100644 --- a/base/guard_ai.cpp +++ b/base/guard_ai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -34,14 +34,14 @@ guardAI::guardAI(Creature* pCreature) : ScriptedAI(pCreature), void guardAI::Reset() { m_uiGlobalCooldown = 0; - m_uiBuffTimer = 0; //Rebuff as soon as we can + m_uiBuffTimer = 0; // Rebuff as soon as we can } -void guardAI::Aggro(Unit *pWho) +void guardAI::Aggro(Unit* pWho) { if (m_creature->GetEntry() == NPC_CENARION_INFANTRY) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_GUARD_SIL_AGGRO1, m_creature, pWho); break; case 1: DoScriptText(SAY_GUARD_SIL_AGGRO2, m_creature, pWho); break; @@ -49,44 +49,44 @@ void guardAI::Aggro(Unit *pWho) } } - if (const SpellEntry *pSpellInfo = m_creature->ReachWithSpellAttack(pWho)) + if (const SpellEntry* pSpellInfo = m_creature->ReachWithSpellAttack(pWho)) DoCastSpell(pWho, pSpellInfo); } -void guardAI::JustDied(Unit *pKiller) +void guardAI::JustDied(Unit* pKiller) { - //Send Zone Under Attack message to the LocalDefense and WorldDefense Channels + // Send Zone Under Attack message to the LocalDefense and WorldDefense Channels if (Player* pPlayer = pKiller->GetCharmerOrOwnerPlayerOrPlayerItself()) m_creature->SendZoneUnderAttackMessage(pPlayer); } void guardAI::UpdateAI(const uint32 uiDiff) { - //Always decrease our global cooldown first + // Always decrease our global cooldown first if (m_uiGlobalCooldown > uiDiff) m_uiGlobalCooldown -= uiDiff; else m_uiGlobalCooldown = 0; - //Buff timer (only buff when we are alive and not in combat + // Buff timer (only buff when we are alive and not in combat if (m_creature->isAlive() && !m_creature->isInCombat()) { if (m_uiBuffTimer < uiDiff) { - //Find a spell that targets friendly and applies an aura (these are generally buffs) - const SpellEntry *pSpellInfo = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA); + // Find a spell that targets friendly and applies an aura (these are generally buffs) + const SpellEntry* pSpellInfo = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA); if (pSpellInfo && !m_uiGlobalCooldown) { - //Cast the buff spell + // Cast the buff spell DoCastSpell(m_creature, pSpellInfo); - //Set our global cooldown + // Set our global cooldown m_uiGlobalCooldown = GENERIC_CREATURE_COOLDOWN; - //Set our timer to 10 minutes before rebuff + // Set our timer to 10 minutes before rebuff m_uiBuffTimer = 600000; - } //Try again in 30 seconds + } // Try again in 30 seconds else m_uiBuffTimer = 30000; } @@ -94,39 +94,39 @@ void guardAI::UpdateAI(const uint32 uiDiff) m_uiBuffTimer -= uiDiff; } - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Make sure our attack is ready and we arn't currently casting if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) { - //If we are within range melee the target + // If we are within range melee the target if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) { bool bHealing = false; - const SpellEntry *pSpellInfo = NULL; + const SpellEntry* pSpellInfo = NULL; - //Select a healing spell if less than 30% hp + // Select a healing spell if less than 30% hp if (m_creature->GetHealthPercent() < 30.0f) pSpellInfo = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); - //No healing spell available, select a hostile spell + // No healing spell available, select a hostile spell if (pSpellInfo) bHealing = true; else pSpellInfo = SelectSpell(m_creature->getVictim(), -1, -1, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE); - //20% chance to replace our white hit with a spell + // 20% chance to replace our white hit with a spell if (pSpellInfo && !urand(0, 4) && !m_uiGlobalCooldown) { - //Cast the spell + // Cast the spell if (bHealing) DoCastSpell(m_creature, pSpellInfo); else DoCastSpell(m_creature->getVictim(), pSpellInfo); - //Set our global cooldown + // Set our global cooldown m_uiGlobalCooldown = GENERIC_CREATURE_COOLDOWN; } else @@ -137,45 +137,44 @@ void guardAI::UpdateAI(const uint32 uiDiff) } else { - //Only run this code if we arn't already casting + // Only run this code if we arn't already casting if (!m_creature->IsNonMeleeSpellCasted(false)) { bool bHealing = false; - const SpellEntry *pSpellInfo = NULL; + const SpellEntry* pSpellInfo = NULL; - //Select a healing spell if less than 30% hp ONLY 33% of the time + // Select a healing spell if less than 30% hp ONLY 33% of the time if (m_creature->GetHealthPercent() < 30.0f && !urand(0, 2)) pSpellInfo = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); - //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) + // No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) if (pSpellInfo) bHealing = true; else pSpellInfo = SelectSpell(m_creature->getVictim(), -1, -1, SELECT_TARGET_ANY_ENEMY, 0, 0, ATTACK_DISTANCE, 0, SELECT_EFFECT_DONTCARE); - //Found a spell, check if we arn't on cooldown + // Found a spell, check if we arn't on cooldown if (pSpellInfo && !m_uiGlobalCooldown) { - //If we are currently moving stop us and set the movement generator + // If we are currently moving stop us and set the movement generator if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE) { m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); } - //Cast spell + // Cast spell if (bHealing) DoCastSpell(m_creature, pSpellInfo); else DoCastSpell(m_creature->getVictim(), pSpellInfo); - //Set our global cooldown + // Set our global cooldown m_uiGlobalCooldown = GENERIC_CREATURE_COOLDOWN; - - } //If no spells available and we arn't moving run to target + } // If no spells available and we arn't moving run to target else if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) { - //Cancel our current spell and then mutate new movement generator + // Cancel our current spell and then mutate new movement generator m_creature->InterruptNonMeleeSpells(false); m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); @@ -186,7 +185,7 @@ void guardAI::UpdateAI(const uint32 uiDiff) void guardAI::DoReplyToTextEmote(uint32 uiTextEmote) { - switch(uiTextEmote) + switch (uiTextEmote) { case TEXTEMOTE_KISS: m_creature->HandleEmote(EMOTE_ONESHOT_BOW); break; case TEXTEMOTE_WAVE: m_creature->HandleEmote(EMOTE_ONESHOT_WAVE); break; diff --git a/base/guard_ai.h b/base/guard_ai.h index c9470f8b4..7e3924c55 100644 --- a/base/guard_ai.h +++ b/base/guard_ai.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -24,7 +24,7 @@ enum eShattrathGuard SPELL_EXILE = 39533 }; -struct MANGOS_DLL_DECL guardAI : public ScriptedAI +struct guardAI : public ScriptedAI { public: explicit guardAI(Creature* pCreature); @@ -33,30 +33,30 @@ struct MANGOS_DLL_DECL guardAI : public ScriptedAI uint32 m_uiGlobalCooldown; // This variable acts like the global cooldown that players have (1.5 seconds) uint32 m_uiBuffTimer; // This variable keeps track of buffs - void Reset(); + void Reset() override; - void Aggro(Unit *pWho); + void Aggro(Unit* pWho) override; - void JustDied(Unit *pKiller); + void JustDied(Unit* /*pKiller*/) override; - void UpdateAI(const uint32 uiDiff); + void UpdateAI(const uint32 uiDiff) override; // Commonly used for guards in main cities void DoReplyToTextEmote(uint32 uiTextEmote); }; -struct MANGOS_DLL_DECL guardAI_orgrimmar : public guardAI +struct guardAI_orgrimmar : public guardAI { guardAI_orgrimmar(Creature* pCreature) : guardAI(pCreature) {} - void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote); + void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) override; }; -struct MANGOS_DLL_DECL guardAI_stormwind : public guardAI +struct guardAI_stormwind : public guardAI { guardAI_stormwind(Creature* pCreature) : guardAI(pCreature) {} - void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote); + void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) override; }; #endif diff --git a/base/pet_ai.cpp b/base/pet_ai.cpp index 8146b8688..769da4753 100644 --- a/base/pet_ai.cpp +++ b/base/pet_ai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -18,7 +18,7 @@ ScriptedPetAI::ScriptedPetAI(Creature* pCreature) : CreatureAI(pCreature) bool ScriptedPetAI::IsVisible(Unit* pWho) const { return pWho && m_creature->IsWithinDist(pWho, VISIBLE_RANGE) - && pWho->isVisibleForOrDetect(m_creature, m_creature, true); + && pWho->isVisibleForOrDetect(m_creature, m_creature, true); } void ScriptedPetAI::MoveInLineOfSight(Unit* pWho) @@ -30,7 +30,7 @@ void ScriptedPetAI::MoveInLineOfSight(Unit* pWho) return; if (m_creature->CanInitiateAttack() && pWho->isTargetableForAttack() && - m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) + m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) { if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) return; @@ -55,7 +55,7 @@ void ScriptedPetAI::AttackedBy(Unit* pAttacker) return; if (m_creature->GetCharmInfo() && !m_creature->GetCharmInfo()->HasReactState(REACT_PASSIVE) && - m_creature->CanReachWithMeleeAttack(pAttacker)) + m_creature->CanReachWithMeleeAttack(pAttacker)) AttackStart(pAttacker); } @@ -79,7 +79,7 @@ void ScriptedPetAI::ResetPetCombat() Reset(); } -void ScriptedPetAI::UpdatePetAI(const uint32 uiDiff) +void ScriptedPetAI::UpdatePetAI(const uint32 /*uiDiff*/) { DoMeleeAttackIfReady(); } diff --git a/base/pet_ai.h b/base/pet_ai.h index a668db5ee..96802a671 100644 --- a/base/pet_ai.h +++ b/base/pet_ai.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -6,7 +6,7 @@ #define SC_PET_H // Using CreatureAI for now. Might change later and use PetAI (need to export for dll first) -class MANGOS_DLL_DECL ScriptedPetAI : public CreatureAI +class ScriptedPetAI : public CreatureAI { public: explicit ScriptedPetAI(Creature* pCreature); @@ -30,7 +30,7 @@ class MANGOS_DLL_DECL ScriptedPetAI : public CreatureAI virtual void UpdatePetAI(const uint32 uiDiff); // while in combat - virtual void UpdatePetOOCAI(const uint32 uiDiff) {} // when not in combat + virtual void UpdatePetOOCAI(const uint32 /*uiDiff*/) {} // when not in combat protected: void ResetPetCombat(); diff --git a/config.h b/config.h index e7d3411c5..3ef426a0f 100644 --- a/config.h +++ b/config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 MaNGOS + * This file is part of the ScriptDev2 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 General Public License as published by @@ -25,35 +25,35 @@ // Format is YYYYMMDDRR where RR is the change in the conf file // for that day. -#define SD2_CONF_VERSION 2010062001 +#define SD2_CONF_VERSION 2012112301 #ifdef WIN32 - #define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport) +#define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport) #elif defined( __GNUC__ ) - #define MANGOS_DLL_EXPORT extern "C" +#define MANGOS_DLL_EXPORT extern "C" #else - #define MANGOS_DLL_EXPORT extern "C" export +#define MANGOS_DLL_EXPORT extern "C" export #endif #ifndef _VERSION - #define _VERSION "Revision [" SD2_REVISION_NR "] (" REVISION_ID ") " REVISION_DATE " " REVISION_TIME +#define _VERSION "Revision [" SD2_REVISION_NR "] (" REVISION_ID ") " REVISION_DATE " " REVISION_TIME #endif // The path to config files #ifndef SYSCONFDIR - #define SYSCONFDIR "" +#define SYSCONFDIR "" #endif #if PLATFORM == PLATFORM_WINDOWS - #ifdef _WIN64 - #define _FULLVERSION _VERSION " (Win64)" - #else - #define _FULLVERSION _VERSION " (Win32)" - #endif - #define _SCRIPTDEV2_CONFIG "scriptdev2.conf" +#ifdef _WIN64 +#define _FULLVERSION _VERSION " (Win64)" #else - #define _FULLVERSION _VERSION " (Unix)" - #define _SCRIPTDEV2_CONFIG SYSCONFDIR"scriptdev2.conf" +#define _FULLVERSION _VERSION " (Win32)" +#endif +#define _SCRIPTDEV2_CONFIG "scriptdev2.conf" +#else +#define _FULLVERSION _VERSION " (Unix)" +#define _SCRIPTDEV2_CONFIG SYSCONFDIR"scriptdev2.conf" #endif #endif diff --git a/config.h.in b/config.h.in index e7d3411c5..50369aee0 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 MaNGOS + * This file is part of the ScriptDev2 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 General Public License as published by diff --git a/docs/ChangeLog.html b/docs/ChangeLog.html new file mode 100644 index 000000000..94eacfd9a --- /dev/null +++ b/docs/ChangeLog.html @@ -0,0 +1,1122 @@ + + + + + +ScriptDev2 Milestones + + + + + +
+
+
+ +

Supports:

+
+
+
+
+

1. Milestone ScriptDev2 - 0.8

+
+
+

1.1. General

+
    +
  • +

    +Implemented various missing quest scripts and similar events +

    +
  • +
  • +

    +Implemented many missing escort quests +

    +
  • +
+
+
+

1.2. WotLK content

+
    +
  • +

    +Implemented full script for Ulduar +

    +
  • +
  • +

    +Implemented full script for Culling of Stratholme +

    +
  • +
+
+
+

1.3. TBC content

+
    +
  • +

    +Implemented script for event boss Headless Horseman +

    +
  • +
  • +

    +Various improvements and bug fixes +

    +
  • +
+
+
+

1.4. Classic content

+
    +
  • +

    +Implemented script for boss Viscidus in AQ40 +

    +
  • +
  • +

    +Various improvements and bug fixes +

    +
  • +
+
+

1.4.1. Statistics

+
    +
  • +

    +Total number of changes: over 144 revisions +

    +
  • +
  • +

    +Fixed many bugs from forum and issues from github +

    +
  • +
+
+
+
+
+
+

2. Milestone ScriptDev2 - 0.7

+
+
+

2.1. General

+
    +
  • +

    +Unify texts loading with the core +

    +
  • +
  • +

    +Implemented support for ScriptEffect spell hooks +

    +
  • +
  • +

    +Implemented various missing quest scripts and similar events +

    +
  • +
+
+
+

2.2. WotLK content

+
    +
  • +

    +Finished script content for Death Knight area and Obsidian Sanctum +

    +
  • +
  • +

    +Implemented full script for Oculus and Pit of Saron instances +

    +
  • +
  • +

    +Improved script for the following dungeons or bosses: Ruby Sanctum, Halls of Stone, Ormorok, Hadronox, Herald Volazj, Skadi and Sapphiron +

    +
  • +
  • +

    +Implemented various missing achievements +

    +
  • +
+
+
+

2.3. TBC content

+
    +
  • +

    +Implemented script support for the Chess event, SSC water and Simon game +

    +
  • +
  • +

    +Improved script for the following dungeons or bosses: Felmyst, Kil’jaeden, Zul’jin, Al’ar, Shadow Labyrinth, Black Temple, Nazan and Vazruden and Netherspite +

    +
  • +
  • +

    +Implemented Year event boss - Ahune +

    +
  • +
  • +

    +Implemented Zul’Aman and Shattered Halls loot modes. +

    +
  • +
+
+
+

2.4. Classic content

+
    +
  • +

    +Improve script for the following dungeons or bosses: Razorgore, Archaedas, Zul’farrak, Ruins of AQ, Baroness Anastari and Zul’gurub +

    +
  • +
  • +

    +Implemented Dire Maul loot modes (tribute run event) +

    +
  • +
+
+

2.4.1. Statistics

+
    +
  • +

    +Total number of changes: over 166 revisions (183 commits) +

    +
  • +
  • +

    +Lots of bugs from forum and issues from github fixed +

    +
  • +
+
+
+
+
+
+

3. Milestone ScriptDev2 - 0.6

+
+
+

3.1. General

+
    +
  • +

    +Added distinct script library support for all the server versions +

    +
  • +
  • +

    +Unified instance handling and added some generic patterns +

    +
  • +
  • +

    +Added support for spell scripts +

    +
  • +
  • +

    +Added support for world scripts for more complicated events +

    +
  • +
  • +

    +Codestyle cleanup on all scripts +

    +
  • +
  • +

    +Convert many old scripts to EventAI +

    +
  • +
  • +

    +Convert many old gossip scripts to DB-gossip system +

    +
  • +
  • +

    +Added script placeholders for future 4.x content +

    +
  • +
  • +

    +Implemented various missing quest scripts and similar events +

    +
  • +
+
+
+

3.2. WotLK content

+
    +
  • +

    +Added script content for the following dungeons: Azjol Nerub, Ahn-Kahet, Drak’tharon Keep, Gundrak, Halls of Stone, Oculus, Utgarde Keep, Utgarde Pinnacle, Violet Hold, Nexus +

    +
  • +
  • +

    +Finished raid script for Naxxramas and Onyxia +

    +
  • +
  • +

    +Added partial script content for the following: Eye of Eternity, Ruby Sanctum, Trial of the Crusader, Ulduar, Death Knight area quests. +

    +
  • +
  • +

    +Added some basic script support for all bosses in Icecrown Citadel +

    +
  • +
  • +

    +Implemented Year event boss - Apothecary Hummel +

    +
  • +
+
+
+

3.3. TBC content

+
    +
  • +

    +Cleanup and improve all the existing scripts by removing workarounds and adding missing content for all dungeons and raids. +

    +
  • +
  • +

    +Added script for the following dungeons or bosses: Arcatraz, Blood Furnace, Sunwell Plateau, A’lar, The Lurker Below, Malacras, Zul’jin. +

    +
  • +
  • +

    +Improve scripts for: Auchenai Crypts, Sethekk Halls, Shadow Labyrinth, Black Morass, Old Hillsbrad Foothills, Steamvault, Shattered Halls, Botanica, Mechanar, Karazhan, Black Temple, The Eye, Serperntshrine Cavern, Zul’Aman. +

    +
  • +
  • +

    +Properly downgraded Naxxramas and Onyxia for TBC and Classic versions +

    +
  • +
  • +

    +Implemented Year event boss - Coren Direbrew +

    +
  • +
+
+
+

3.4. Classic content

+
    +
  • +

    +Implemented epic quests script for the opening of Ahn’Qiraj and Onyxia events. +

    +
  • +
  • +

    +Cleanup and improve all the existing scripts by removing workarounds and adding missing content for all dungeons and raids. +

    +
  • +
  • +

    +Added or substantially improved script for the following dungeons: Blackrock Depths, Deathmines, Dire Maul, Gnomeregan, Razorfen Kraul, Shadowfang Keep, Sunken Temple, Wailing Caverns, Uldaman, Ruins of AQ +

    +
  • +
  • +

    +Improve script for the following dungeons: Blackrock Spire, Blackfathom Deeps, Marauudon, Scholomance, Stratholme, Blackwing Lair, Molten Core, Emerald Dragons, Temple of AQ, Zul’Gurub +

    +
  • +
  • +

    +Properly downgraded Lord Kazzak for Classic version +

    +
  • +
+
+

3.4.1. Statistics

+
    +
  • +

    +Total number of changes: over 1300 revisions (1300 commits) +

    +
  • +
  • +

    +Lots of bugs from forum and issues from github fixed +

    +
  • +
+
+
+
+
+
+

+ + + diff --git a/docs/ChangeLog.txt b/docs/ChangeLog.txt new file mode 100644 index 000000000..6c0eaef8c --- /dev/null +++ b/docs/ChangeLog.txt @@ -0,0 +1,100 @@ += ScriptDev2 Milestones = + +*Current Version: <>* + +*Supports:* + +* Classic (1.12.1), see https://github.com/scriptdev2/scriptdev2-classic +* TBC (2.4.3), see https://github.com/scriptdev2/scriptdev2-tbc +* WotLK (3.3.5a), see https://github.com/scriptdev2/scriptdev2 +* Cata (4.3.4), see https://github.com/scriptdev2/scriptdev2-cata + +[[currentMS]] +== Milestone ScriptDev2 - 0.8 == + +=== General === +* Implemented various missing quest scripts and similar events +* Implemented many missing escort quests + +=== WotLK content === +* Implemented full script for Ulduar +* Implemented full script for Culling of Stratholme + +=== TBC content === +* Implemented script for event boss Headless Horseman +* Various improvements and bug fixes + +=== Classic content === +* Implemented script for boss Viscidus in AQ40 +* Various improvements and bug fixes + +==== Statistics ==== +* Total number of changes: over 144 revisions +* Fixed many bugs from forum and issues from github + + +== Milestone ScriptDev2 - 0.7 == + +=== General === +* Unify texts loading with the core +* Implemented support for ScriptEffect spell hooks +* Implemented various missing quest scripts and similar events + +=== WotLK content === +* Finished script content for Death Knight area and Obsidian Sanctum +* Implemented full script for Oculus and Pit of Saron instances +* Improved script for the following dungeons or bosses: Ruby Sanctum, Halls of Stone, Ormorok, Hadronox, Herald Volazj, Skadi and Sapphiron +* Implemented various missing achievements + +=== TBC content === +* Implemented script support for the Chess event, SSC water and Simon game +* Improved script for the following dungeons or bosses: Felmyst, Kil'jaeden, Zul'jin, Al'ar, Shadow Labyrinth, Black Temple, Nazan and Vazruden and Netherspite +* Implemented Year event boss - Ahune +* Implemented Zul'Aman and Shattered Halls loot modes. + +=== Classic content === +* Improve script for the following dungeons or bosses: Razorgore, Archaedas, Zul'farrak, Ruins of AQ, Baroness Anastari and Zul'gurub +* Implemented Dire Maul loot modes (tribute run event) + +==== Statistics ==== +* Total number of changes: over 166 revisions (183 commits) +* Lots of bugs from forum and issues from github fixed + + +== Milestone ScriptDev2 - 0.6 == + +=== General === +* Added distinct script library support for all the server versions +* Unified instance handling and added some generic patterns +* Added support for spell scripts +* Added support for world scripts for more complicated events +* Codestyle cleanup on all scripts +* Convert many old scripts to EventAI +* Convert many old gossip scripts to DB-gossip system +* Added script placeholders for future 4.x content +* Implemented various missing quest scripts and similar events + +=== WotLK content === +* Added script content for the following dungeons: Azjol Nerub, Ahn-Kahet, Drak'tharon Keep, Gundrak, Halls of Stone, Oculus, Utgarde Keep, Utgarde Pinnacle, Violet Hold, Nexus +* Finished raid script for Naxxramas and Onyxia +* Added partial script content for the following: Eye of Eternity, Ruby Sanctum, Trial of the Crusader, Ulduar, Death Knight area quests. +* Added some basic script support for all bosses in Icecrown Citadel +* Implemented Year event boss - Apothecary Hummel + +=== TBC content === +* Cleanup and improve all the existing scripts by removing workarounds and adding missing content for all dungeons and raids. +* Added script for the following dungeons or bosses: Arcatraz, Blood Furnace, Sunwell Plateau, A'lar, The Lurker Below, Malacras, Zul'jin. +* Improve scripts for: Auchenai Crypts, Sethekk Halls, Shadow Labyrinth, Black Morass, Old Hillsbrad Foothills, Steamvault, Shattered Halls, Botanica, Mechanar, Karazhan, Black Temple, The Eye, Serperntshrine Cavern, Zul'Aman. +* Properly downgraded Naxxramas and Onyxia for TBC and Classic versions +* Implemented Year event boss - Coren Direbrew + +=== Classic content === +* Implemented epic quests script for the opening of Ahn'Qiraj and Onyxia events. +* Cleanup and improve all the existing scripts by removing workarounds and adding missing content for all dungeons and raids. +* Added or substantially improved script for the following dungeons: Blackrock Depths, Deathmines, Dire Maul, Gnomeregan, Razorfen Kraul, Shadowfang Keep, Sunken Temple, Wailing Caverns, Uldaman, Ruins of AQ +* Improve script for the following dungeons: Blackrock Spire, Blackfathom Deeps, Marauudon, Scholomance, Stratholme, Blackwing Lair, Molten Core, Emerald Dragons, Temple of AQ, Zul'Gurub +* Properly downgraded Lord Kazzak for Classic version + +==== Statistics ==== +* Total number of changes: over 1300 revisions (1300 commits) +* Lots of bugs from forum and issues from github fixed diff --git a/docs/GIT_guide_1_easy_use.html b/docs/GIT_guide_1_easy_use.html new file mode 100644 index 000000000..84a2de4ee --- /dev/null +++ b/docs/GIT_guide_1_easy_use.html @@ -0,0 +1,801 @@ + + + + + +[Git GUIDE] Easy use + + + + + +
+
+
+

This assumes you have already cloned the SD2-repository.

+

If not, please follow the installation instructions how to do so:

+ +
+
+
+

1. Graphical user Interfaces for Windows

+
+
+
+
+
+

2. Updateting

+
+

The word to look for is "Pull", both GUIs have this option.

+

For Command-line fans, simple right-click ScriptDev2-directory, choose "Git Bash here" and then type
+$ git pull
+to Update

+
+
+
+

3. Restoring

+
+

In case you polluted something in your working directory open the Git bash, and type
+$ git reset --hard origin/master

+

Warning: This will remove every custom changes

+
+
+
+

+ + + diff --git a/docs/GIT_guide_1_easy_use.txt b/docs/GIT_guide_1_easy_use.txt new file mode 100644 index 000000000..6cf316717 --- /dev/null +++ b/docs/GIT_guide_1_easy_use.txt @@ -0,0 +1,32 @@ +[Git GUIDE] Easy use +==================== + +This assumes you have already cloned the SD2-repository. + +If not, please follow the _installation instructions_ how to do so: + +* link:How_to_install.html[Installation instructions] +* http://www.scriptdev2.com/showthread.php?t=4[Installation instructions on SD2 Forum] + +Graphical user Interfaces for Windows +------------------------------------- + +* http://code.google.com/p/tortoisegit[TortoiseGIT] - Similar to TortoiseSVN Shell-Extention based GUI +* http://www.syntevo.com/smartgit/index.html[SmartGit] + +Updateting +---------- + +The word to look for is "Pull", both GUIs have this option. + +For Command-line fans, simple right-click ScriptDev2-directory, choose "Git Bash here" and then type + +`$ git pull` + +to Update + +Restoring +--------- + +In case you polluted something in your working directory open the Git bash, and type + +`$ git reset --hard origin/master` + +Warning: This will remove *every* custom changes diff --git a/docs/GIT_guide_2_normal_use.html b/docs/GIT_guide_2_normal_use.html new file mode 100644 index 000000000..bbab3f663 --- /dev/null +++ b/docs/GIT_guide_2_normal_use.html @@ -0,0 +1,827 @@ + + + + + +[Git GUIDE] Normal use + + + + + +
+
+
+

This topic is for people who want to do a little work with SD2.

+

In this topic I assume that you are familar with basic use of Git and also that you are familiar with your GUI (if you use any).

+

If you are not, maybe you should start with the Easy use guide, see:

+ +

In this topic I will describe the needed steps to test other people’s patches, and how to create some own patches. However based on the Command-line tool.

+

For Windows users you can start the command line with right-clicking the ScriptDev2 directory and selecting "Git Bash Here".

+
+
+
+

1. Basic concepts in Git

+
+

Git has a working directory, these are the actual files you edit, compile and work with.

+

Git has a "index" which is the history information.+

+

By default the working directory is clean related to the index.

+

For this topic I assume that your working-tree is clean.

+

You can check this with $ git status .

+

Clean results in nothing to commit (working directory clean) .

+

If your working directory is not clean, you can either commit your changes (if they were good) with $ git commit -a .

+

or remove your changes with $ git reset --hard ,

+

or reset your working dir to default state with $ git reset -hard origin/master .

+
+
+
+

2. Testing ("applying") patches from other people

+
+

You can apply a git patch (located in fileName.patch) with
+$ git apply fileName.patch
+or
+$ git am fileName.patch

+

The second expects a patch that includes history information, so if this fails, the first way must work (or it is no proper patch)

+
+
+
+

3. Creating own patches

+
+

You have spotted a bug, fixed it, and now you wonder how you can share this fix with other people.

+

The recommanded way is, to commit your change locally and create a patch file from your commit

+

To commit your patch locally, you simple need to
+$ git commit -a -m "Make Illidan more powerfull"

+

Then you can create a patch with
+$ git format-patch HEAD^ --stdout > IllidanFix.patch
+which will create a patch for the top-most commit into the file IllidanFix.patch

+

You can also create a patch with
+$ git format-patch HEAD~n --stdout > IllidanFix.patch
+HEAD^ == HEAD~1 and is the previous commit, HEAD~n is the n-th commit before the current

+

A very usefull way to create a patch is based on clean ScriptDev2, with
+$ git format-patch origin/master --stdout > IllidanFix.patch

+
+
+
+

4. Branching projects, and tests

+
+

This is actually the part, where Git has its power. If you don’t use branches, you prevent yourself from using the best within Git!

+

The main idea is to test patches, to create patches always into special branches, and this way they won’t interfere with the main-branch.

+

Assuming you are on clean master, you create and checkout into a new branch with
+$ git checkout -b IlllidanFixes
+(the -b is for "create", whereas the normal checkout means switching between branches)
+so, you can edit, commit, apply patches as often as you want in your branch.

+

To compare what actually happend in this branch relative to ie your master branch, simply do
+$ git diff master
+and to create a patch do
+$ git format-patch master --stdout > IllidanFix.patch

+

And the best thing: You can create as many branches as you wish - which makes separating different projects, tests and so on a piece of cake :)

+
+
+
+

+ + + diff --git a/docs/GIT_guide_2_normal_use.txt b/docs/GIT_guide_2_normal_use.txt new file mode 100644 index 000000000..0078281d3 --- /dev/null +++ b/docs/GIT_guide_2_normal_use.txt @@ -0,0 +1,86 @@ +[Git GUIDE] Normal use +====================== + +This topic is for people who want to do a little work with SD2. + +In this topic I assume that you are familar with basic use of Git and also that you are familiar with your GUI (if you use any). + +If you are not, maybe you should start with the _Easy use_ guide, see: + +* link:GIT_guide_1_easy_use.html[Git GUIDE - Easy use] +* http://www.scriptdev2.com/showthread.php?t=5637[Git GUIDE - Easy use on SD2 Forums] + +In this topic I will describe the needed steps to test other people's patches, and how to create some own patches. However based on the Command-line tool. + +For Windows users you can start the command line with right-clicking the ScriptDev2 directory and selecting "Git Bash Here". + +Basic concepts in Git +--------------------- + +Git has a working directory, these are the actual files you edit, compile and work with. + +Git has a "index" which is the history information.+ + +By default the working directory is clean related to the index. + +For this topic I assume that your working-tree is clean. + +You can check this with `$ git status` . + +Clean results in `nothing to commit (working directory clean)` . + +If your working directory is not clean, you can either commit your changes (if they were good) with `$ git commit -a` . + +or remove your changes with `$ git reset --hard` , + +or reset your working dir to default state with `$ git reset -hard origin/master` . + +Testing ("applying") patches from other people +---------------------------------------------- + +You can apply a git patch (located in fileName.patch) with + +`$ git apply fileName.patch` + +or + +`$ git am fileName.patch` + +The second expects a patch that includes history information, so if this fails, the first way must work (or it is no proper patch) + +Creating own patches +-------------------- + +You have spotted a bug, fixed it, and now you wonder how you can share this fix with other people. + +The recommanded way is, to commit your change locally and create a patch file from your commit + +To commit your patch locally, you simple need to + +`$ git commit -a -m "Make Illidan more powerfull"` + +Then you can create a patch with + +`$ git format-patch HEAD^ --stdout > IllidanFix.patch` + +which will create a patch for the top-most commit into the file IllidanFix.patch + +You can also create a patch with + +`$ git format-patch HEAD~n --stdout > IllidanFix.patch` + +`HEAD^ == HEAD~1` and is the previous commit, `HEAD~n` is the n-th commit before the current + +A very usefull way to create a patch is based on clean ScriptDev2, with + +`$ git format-patch origin/master --stdout > IllidanFix.patch` + +Branching projects, and tests +----------------------------- + +This is actually the part, where Git has its power. If you don't use branches, you prevent yourself from using the best within Git! + +The main idea is to test patches, to create patches always into special branches, and this way they won't interfere with the main-branch. + +Assuming you are on clean master, you create and checkout into a new branch with + +`$ git checkout -b IlllidanFixes` + +(the -b is for "create", whereas the normal checkout means switching between branches) + +so, you can edit, commit, apply patches as often as you want in your branch. + +To compare what actually happend in this branch relative to ie your master branch, simply do + +`$ git diff master` + +and to create a patch do + +`$ git format-patch master --stdout > IllidanFix.patch` + +And the best thing: You can create as many branches as you wish - which makes separating different projects, tests and so on a piece of cake :) diff --git a/docs/GIT_guide_3_advanced_use.html b/docs/GIT_guide_3_advanced_use.html new file mode 100644 index 000000000..96c942eac --- /dev/null +++ b/docs/GIT_guide_3_advanced_use.html @@ -0,0 +1,1179 @@ + + + + + +[Git GUIDE] Advanced use + + + + + +
+
+
+

This guide is meant to help and provide information for those who want dig into the Git depths and explore its mysteries!

+

It is likely very much possible, that many of these things can be done with GUIs, but this topic expects that the command line interfact (Git Bash) is used!

+

Have phun with Git :)

+
+
+
+

1. Setup Git for ScriptDev2

+
+
+

1.1. "Copy" the offical branch to your system

+

Execute this within your <MaNGOS>/src/bindings directory

+

$ git clone git://github.com/scriptdev2/scriptdev2.git ScriptDev2
+and $ cd into it.

+
+
+

1.2. Setup some individual configuration

+
+

1.2.1. Username and Email

+

$ git config --global user.name "Your (Nick)Name"
+$ git config --global user.email "some@email.adress"

+
+
+

1.2.2. Make life more colorful

+

$ git config --global color.ui "auto"

+
+
+

1.2.3. Change the default editor

+

Thanks to DasBlub and Zor for help with this. This is just an example for notepad++, so you might need to adapt to your needs (especially the path)

+

$ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"

+
+
+

1.2.4. Lineendings-configuration

+

This is actually fairly dependend from own wishes - if you feel uneasy, stay with default values

+
+
Windows
+

$ git config core.autocrlf true
+$ git config core.eol native

+
+
+
*nix
+

$ git config core.autocrlf input
+$ git config core.eol native

+
+
+
+

1.2.5. Whitespace pre-commit hook

+

This is really nice to force you to not commit code with corrupt whitespace (Needs to be set-up for every repository individually)

+

$ cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
+This activates the default pre-commit hook, if the file doesn’t exist, update your git-version (and after your repo)

+
+
+
+

1.3. Use an external merge-tool

+ +
+

1.3.1. KDiff3 (not kdiff or kdiff2)

+

Reasons why to use KDiff3:

+
    +
  • +

    +has a fairly good visual interface and works on both windows and linux +

    +
  • +
  • +

    +you can get it from TODO +

    +
  • +
  • +

    +to make sure git can find it, for example on windows if you installed it to c:/Program Files/KDiff3
    +$ git config mergetool.kdiff3.path "c:/Program Files/KDiff3/kdiff3.exe" ← either that or you could add c:/Program Files/KDiff3 to your path +

    +
  • +
  • +

    +make it the default mergetool:
    +$ git config merge.tool kdiff3 +

    +
  • +
+
+
+

1.3.2. Tortoise(Git) Merge

+

Reasons why to use TortoiseGit:

+
    +
  • +

    +similar to well known TortoiseSVN software (a nice GUI tool for Git anyways) +

    +
  • +
  • +

    +does not require any further configuration to work as default merge tool (provided no other is installed) +

    +
  • +
+
+
+

1.3.3. Tortoise Merge

+

Reasons why to use TortoiseMerge

+
    +
  • +

    +Good visual interface, only works on windows +

    +
  • +
  • +

    +Download and install TortoiseSVN +

    +
  • +
  • +

    +In C:\Program Files\TortoiseSVN\bin create a file named TortMer.bat and add the following: +

    +
    +
    +
    @ECHO OFF
    +TortoiseMerge.exe /base:"%PWD%/%1" /theirs:"%PWD%/%2" /mine:"%PWD%/%3" /merged:"%PWD%/%4"
    +
    +
  • +
  • +

    +add a custom merge tool to git that runs this batch file
    +$ git config mergetool.tortoise.cmd ' "cmd.exe" "/CTortMer.bat" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" ' +

    +
  • +
  • +

    +make it the default mergetool
    +$ git config merge.tool tortoise +

    +
  • +
+
+
+
+
+
+ +
+

http://git-scm.com/ - Contains nearly everything one might want :)

+
+

2.1. Obtaining Git

+

For *nix you should get Git from your distribution software repository.

+

For Windows yout can get mysysgit - you would probably want Git-w.x.y.z.previewYYYYMMDD.exe

+
+
+

2.2. Some Graphical User-Interfaces

+

(Not recommanded, but might make you happy)

+

TortoiseGit - Similar to TortoiseSVN Shell-Extention based GUI

+

SmartGit - More classical GUI, looks nice

+
+
+ + +

http://git-scm.com/course/svn.html - SVN Crash Course, especially for *nix user

+

http://book.git-scm.com/ - Very nice, including flash videos about most topics

+

http://progit.org/book/ - A bit more detailed

+ +
+ +
+
+
+

3. Most important Git-commands

+
+

Based on Freghar's Thread

+

Remark that all these commands display a very exhaustive help page with ` --help`

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+$ git clone +
+
+

+downloads a fresh repo. +

+
+$ git pull +
+
+

+is a shortcut for fetch and merge. +

+
+$ git log +
+
+

+displays the history +

+
+$ git show +
+
+

+shows the most recent commit +

+
+$ git commit +
+
+

+commits your changes (always local) +

+
+$ git checkout +
+
+

+switches the source to a specific version (local branch or commit) +

+
+$ git merge +
+
+

+merges changes from one point into current branch +

+
+$ git reset +
+
+

+leaves you on the current branch but changes what the branch "points to". +

+
+
+
+
+

4. Workflow with Git

+
+

Commit early, commit often

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+$ git pull +
+
+

+to be on recent version +

+
+$ git checkout -b <NewBranchName> +
+
+

+create a new branch for the work +

+
+Suggestion +
+
+

+Create for every project an own branch, this makes maintaining way easier! +

+
+<edit some files> +
+
+
+$ git diff +
+
+

+see what is done since last commit +

+
+$ git commit -a -m "Some Commit Message" +
+
+

+this is only locally +

+
+<edit and commit more> +
+
+
+$ git diff master +
+
+

+see what is done compared to master branch +

+
+$ git checkout master +
+
+

+change to master branch +

+
+$ git pull +
+
+

+there was an update in master, now we pulled this, tested it, and now we want to get our working branch up-to-date +

+
+$ git checkout <BranchName> +
+
+

+switch back to our working branch +

+
+$ git rebase master +
+
+

+set to state of master and rebase the own commits on top +

+
+$ git format-patch master --stdout > fileName.patch +
+
+

+Creates a nice formated patch into file "fileName.patch" +

+
+
+
+
+

5. Create and apply patches

+
+
+

5.1. Create patches

+

$ git format-patch master - creates a patchfile for every commit that diffs from master (includes author information)

+

$ git format-patch master --std.out > someFilename.patch - creates an incremental patchfile, containing information of each individual commit

+
+
+

5.2. Apply patches

+

$ patch -X -d. < someFilename.patch - applies a patch in Git(X = 1) or SVN (X = 0) format to current workspace

+

$ git apply someFilename.patch - applies a Git-patch to current workspace

+

$ git am someFilename.patch - applies and commits a Git-patch with commit information (created by format-patch)

+
+
+
+
+

+ + + diff --git a/docs/GIT_guide_3_advanced_use.txt b/docs/GIT_guide_3_advanced_use.txt new file mode 100644 index 000000000..a783c9bcc --- /dev/null +++ b/docs/GIT_guide_3_advanced_use.txt @@ -0,0 +1,211 @@ +[Git GUIDE] Advanced use +======================== + +This guide is meant to help and provide information for those who want dig into the Git depths and explore its mysteries! + +It is likely very much possible, that many of these things can be done with GUIs, but this topic expects that the command line interfact (Git Bash) is used! + +Have phun with Git :) + +Setup Git for ScriptDev2 +------------------------ + +"Copy" the offical branch to your system +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Execute this within your /src/bindings directory + +`$ git clone git://github.com/scriptdev2/scriptdev2.git ScriptDev2` + +and `$ cd` into it. + +Setup some individual configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Username and Email +^^^^^^^^^^^^^^^^^^ + +`$ git config --global user.name "Your (Nick)Name"` + +`$ git config --global user.email "some@email.adress"` + +Make life more colorful +^^^^^^^^^^^^^^^^^^^^^^^ + +`$ git config --global color.ui "auto"` + +Change the default editor +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Thanks to DasBlub and Zor for help with this. This is just an example for notepad++, so you might need to adapt to your needs (especially the path) + +`$ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"` + +Lineendings-configuration +^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is actually fairly dependend from own wishes - if you feel uneasy, stay with default values + +Windows ++++++++ + +`$ git config core.autocrlf true` + +`$ git config core.eol native` + +*nix +++++ + +`$ git config core.autocrlf input` + +`$ git config core.eol native` + +Whitespace pre-commit hook +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is really nice to force you to not commit code with corrupt whitespace (Needs to be set-up for every repository individually) + +`$ cp .git/hooks/pre-commit.sample .git/hooks/pre-commit` + +This activates the default pre-commit hook, if the file doesn't exist, update your git-version (and after your repo) + +Use an external merge-tool +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +see http://getmangos.com/community/forum/27/source-code-management/TODOTODO[_Freghar_'s Thread] + +KDiff3 (not kdiff or kdiff2) +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Reasons why to use http://kdiff3.sourceforge.net/doc/merging.html[KDiff3]: + +- has a fairly good visual interface and works on both windows and linux +- you can get it from http://sourceforge.net/project/showf...ease_id=501369[TODO] +- to make sure git can find it, for example on windows if you installed it to `c:/Program Files/KDiff3` + +`$ git config mergetool.kdiff3.path "c:/Program Files/KDiff3/kdiff3.exe"` <- either that or you could add `c:/Program Files/KDiff3` to your path +- make it the default mergetool: + +`$ git config merge.tool kdiff3` + +Tortoise(Git) Merge +^^^^^^^^^^^^^^^^^^^ + +Reasons why to use http://code.google.com/p/tortoisegit/[TortoiseGit]: + +- similar to well known TortoiseSVN software (a nice GUI tool for Git anyways) +- does not require any further configuration to work as default merge tool (provided no other is installed) + +Tortoise Merge +^^^^^^^^^^^^^^ + +Reasons why to use http://tortoisesvn.tigris.org/TortoiseMerge.html[TortoiseMerge] + +- Good visual interface, only works on windows +- Download and install http://tortoisesvn.net/downloads[TortoiseSVN] +- In `C:\Program Files\TortoiseSVN\bin` create a file named TortMer.bat and add the following: ++ +---- +@ECHO OFF +TortoiseMerge.exe /base:"%PWD%/%1" /theirs:"%PWD%/%2" /mine:"%PWD%/%3" /merged:"%PWD%/%4" +---- ++ +- add a custom merge tool to git that runs this batch file + +`$ git config mergetool.tortoise.cmd ' "cmd.exe" "/CTortMer.bat" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" '` +- make it the default mergetool + +`$ git config merge.tool tortoise` + +Some Links +---------- + +http://git-scm.com/ - Contains nearly everything one might want :) + +Obtaining Git +~~~~~~~~~~~~~ + +For *nix you should get Git from your distribution software repository. + +For Windows yout can get http://code.google.com/p/msysgit/downloads/list[mysysgit] - you would probably want Git-w.x.y.z.previewYYYYMMDD.exe + +Some Graphical User-Interfaces +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +(Not recommanded, but might make you happy) + +http://code.google.com/p/tortoisegit/[TortoiseGit] - Similar to TortoiseSVN Shell-Extention based GUI + +http://www.syntevo.com/smartgit/index.html[SmartGit] - More classical GUI, looks nice + +Documentation-Links +~~~~~~~~~~~~~~~~~~~ + +http://www.kernel.org/pub/software/scm/git/docs/everyday.html - Small overview of common commands + +http://git-scm.com/course/svn.html - SVN Crash Course, especially for *nix user + +http://book.git-scm.com/ - Very nice, including flash videos about most topics + +http://progit.org/book/ - A bit more detailed + + +http://getmangos.com/community/forum/27/source-code-management/ - Collection of various topics on MaNGOS + +What is this Git about? +~~~~~~~~~~~~~~~~~~~~~~ + +http://www.youtube.com/watch?v=4XpnKHJAok8[Google TechTalk by _L. Torvalds_] + +http://www.youtube.com/watch?v=8dhZ9BXQgc4[Google TechTalk by _R. Schwartz_] + +https://git.wiki.kernel.org/index.php/GitSvnComparison[Compate Git vs. SVN] + +Most important Git-commands +--------------------------- + +Based on _Freghar_'s Thread + +Remark that all these commands display a very exhaustive help page with ` --help` + +[horizontal] +`$ git clone` :: downloads a fresh repo. +`$ git pull` :: is a shortcut for fetch and merge. +`$ git log` :: displays the history +`$ git show` :: shows the most recent commit +`$ git commit` :: commits your changes (always local) +`$ git checkout` :: switches the source to a specific version (local branch or commit) +`$ git merge` :: merges changes from one point into current branch +`$ git reset` :: leaves you on the current branch but changes what the branch "points to". + +Workflow with Git +----------------- + +*Commit early, commit often* + +[horizontal] +`$ git pull` :: to be on recent version +`$ git checkout -b ` :: create a new branch for the work +Suggestion:: Create for _every_ project an own branch, this makes maintaining way easier! + :: ++ +`$ git diff` :: see what is done since last commit +`$ git commit -a -m "Some Commit Message"` :: this is only locally + :: ++ +`$ git diff master` :: see what is done compared to master branch +`$ git checkout master` :: change to master branch +`$ git pull` :: there was an update in master, now we pulled this, tested it, and now we want to get our working branch up-to-date +`$ git checkout ` :: switch back to our working branch +`$ git rebase master` :: set to state of master and rebase the own commits on top +`$ git format-patch master --stdout > fileName.patch` :: Creates a nice formated patch into file "fileName.patch" + +Create and apply patches +------------------------ + +Create patches +~~~~~~~~~~~~~~ + +`$ git format-patch master` - creates a patchfile for every commit that diffs from master (includes author information) + +`$ git format-patch master --std.out > someFilename.patch` - creates an incremental patchfile, containing information of each individual commit + +Apply patches +~~~~~~~~~~~~~ + +`$ patch -X -d. < someFilename.patch` - applies a patch in Git(X = 1) or SVN (X = 0) format to current workspace + +`$ git apply someFilename.patch` - applies a Git-patch to current workspace + +`$ git am someFilename.patch` - applies and commits a Git-patch with commit information (created by format-patch) diff --git a/docs/How to install.txt b/docs/How to install.txt deleted file mode 100644 index e8e3578cd..000000000 --- a/docs/How to install.txt +++ /dev/null @@ -1,45 +0,0 @@ - ---- How to install ScriptDev2 --- - -1) Download MaNGOS (using git clone) -See their forum/ wiki for more details - -2) Do the source stuff: -- Clone ScriptDev2 "git clone git://github.com/scriptdev2/scriptdev2.git ScriptDev2" - execute from within src/bindings directory - -MS Windows: -- Compile ScriptDev2 using the scriptVC80, scriptVC90 or scriptVC100 Solution within the ScriptDev2 folder (this will overwrite the Mangoscript dll in the output directory) - -GNU/Linux or CMake: -- Apply the Git patch to Mangos - "git am src/bindings/ScriptDev2/patches/MaNGOS-XXXX-ScriptDev2.patch" -- Compile MaNGOS (ScriptDev2 will automatically be built when compiling Mangos from here on) - - -3) Create the default ScriptDev2 database using - "sql\scriptdev2_create_database.sql", then execute - "sql\scriptdev2_create_structure.sql" on that database. - -4) Execute the following on your ScriptDev2 database. -- sql\scriptdev2_script_full.sql - -5) Execute the following file on your MaNGOS database. -- sql\mangos_scriptname_full.sql - -6) Place the included "scriptdev2.conf" file within the directory containing your "mangosd.conf" and "realmd.conf" files. You may need to change this file to match the database you created and any custom settings you wish to use. Note this file will be different created for Unix based systems. - -7) Run mangosd from your output directory - - -To update ScriptDev2: -- Enter src/bindings/ScriptDev2 directory (with git-bash) -- Update ScriptDev2 - "git pull" - -MS Windows: -- You must still compile MaNGOS before ScriptDev2 when on the Windows platform. - -To update your Database with new Scriptdev2 SQL changes you can either: -a) apply only the changes that were made during that revision by looking in the sql\update folder or (files named rXXX_scriptdev2.sql should be executed on the scriptdev2 db while rXXX_mangos.sql should be executed on your mangos db) -b) reapply "mangos_scriptname_full.sql" to your MaNGOS database. - WARNING this will NOT include removed script names! - -You can view the ScriptDev2 Change Log at: -https://github.com/scriptdev2/scriptdev2/commits/master diff --git a/docs/How_to_install.html b/docs/How_to_install.html new file mode 100644 index 000000000..7fbdc4f81 --- /dev/null +++ b/docs/How_to_install.html @@ -0,0 +1,854 @@ + + + + + +Installation Instructions + + + + + +
+
+

1. Clean install of ScriptDev2

+
+
+

1.1. Download MaNGOS (using git clone)

+

See their forum or wiki for more details

+
+
+

1.2. Get the sources

+

Clone ScriptDev2 git clone git://github.com/scriptdev2/scriptdev2.git ScriptDev2 - execute from within src/bindings directory

+

MS Windows:
+Compile ScriptDev2 using the scriptVC80, scriptVC90 or scriptVC100 Solution within the ScriptDev2 folder (this will overwrite the Mangoscript dll in the output directory)

+

GNU/Linux or CMake:
+When running CMake on MaNGOS, make sure to set -D INCLUDE_BINDINGS_DIR=ScriptDev2
+Compile MaNGOS (ScriptDev2 will automatically be built when compiling Mangos from here on)

+
+
+

1.3. Handle the databases

+
+
+Create ScriptDev2-Database +
+
+

+Execute sql\scriptdev2_create_database.sql , then execute
+sql\scriptdev2_create_structure.sql on that database. +

+
+
+Add content to ScriptDev2-Database +
+
+

+Execute sql\scriptdev2_script_full.sql on scriptdev2 databse +

+
+
+Update ScriptNames +
+
+

+Execute sql\mangos_scriptname_full.sql on your MaNGOS world Database +

+
+
+
+
+

1.4. Configuration files

+

Place the included "scriptdev2.conf" file within the directory containing your "mangosd.conf" and "realmd.conf" files.

+

You may need to change this file to match the database you created and any custom settings you wish to use.

+

Note this file will be differently created for Unix based systems.

+
+
+

1.5. Run mangosd

+

Run mangosd from your output directory. If you use another directory to run mangos, you need (on windows) copy the mangosscript.dll to that directory before starting mangosd.

+
+
+
+
+

2. How to Update ScriptDev2

+
+
    +
  1. +

    +Enter src/bindings/ScriptDev2 directory (with git-bash) +

    +
  2. +
  3. +

    +Update ScriptDev2 with git pull +

    +
  4. +
  5. +

    +Compile ScriptDev2
    + On windows you must still compile MaNGOS before ScriptDev2 +

    +
  6. +
  7. +

    +Update your Database with new Scriptdev2 SQL changes. For this you can either: +

    +
      +
    • +

      +apply only the changes that were made during that revision by looking in the sql\update folder or (files named rXXX_scriptdev2.sql should be executed on the scriptdev2 db while rXXX_mangos.sql should be executed on your mangos db) +

      +
    • +
    • +

      +reapply "mangos_scriptname_full.sql" to your MaNGOS database. - WARNING this will NOT include removed script names! +

      +
    • +
    +
  8. +
+
+
+
+

3. ScriptDev2 Change Log

+
+

You can view the ScriptDev2 change log on the ScriptDev2 Github Repository.

+

Or of course locally with your Git GUI tools or with git log (Note that it should be up to date before looking into your local log)

+
+
+
+

+ + + diff --git a/docs/How_to_install.txt b/docs/How_to_install.txt new file mode 100644 index 000000000..4bb7211cf --- /dev/null +++ b/docs/How_to_install.txt @@ -0,0 +1,67 @@ +Installation Instructions +========================= + +Clean install of ScriptDev2 +--------------------------- + +Download MaNGOS (using git clone) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See their http://getmangos.com/community[forum] or http://getmangos.com/wiki[wiki] for more details + +Get the sources +~~~~~~~~~~~~~~~ + +Clone ScriptDev2 `git clone git://github.com/scriptdev2/scriptdev2.git ScriptDev2` - execute from within src/bindings directory + +*MS Windows:* + +Compile ScriptDev2 using the scriptVC80, scriptVC90 or scriptVC100 Solution within the ScriptDev2 folder (this will overwrite the Mangoscript dll in the output directory) + +*GNU/Linux or CMake:* + +When running CMake on MaNGOS, make sure to set `-D INCLUDE_BINDINGS_DIR=ScriptDev2` +Compile MaNGOS (ScriptDev2 will automatically be built when compiling Mangos from here on) + + +Handle the databases +~~~~~~~~~~~~~~~~~~~~ + +Create ScriptDev2-Database:: +Execute `sql\scriptdev2_create_database.sql` , then execute + +`sql\scriptdev2_create_structure.sql` on that database. +Add content to ScriptDev2-Database:: +Execute `sql\scriptdev2_script_full.sql` on scriptdev2 databse +Update ScriptNames:: +Execute `sql\mangos_scriptname_full.sql` on your MaNGOS world Database + +Configuration files +~~~~~~~~~~~~~~~~~~~ + +Place the included "scriptdev2.conf" file within the directory containing your "mangosd.conf" and "realmd.conf" files. + +You may need to change this file to match the database you created and any custom settings you wish to use. + +Note this file will be differently created for Unix based systems. + +Run mangosd +~~~~~~~~~~~ + +Run mangosd from your output directory. If you use another directory to run mangos, you need (on windows) copy the mangosscript.dll to that directory before starting mangosd. + + +How to Update ScriptDev2 +------------------------ + +. Enter src/bindings/ScriptDev2 directory (with git-bash) +. Update ScriptDev2 with `git pull` +. Compile ScriptDev2 + + On _windows_ you must still compile MaNGOS before ScriptDev2 +. Update your Database with new Scriptdev2 SQL changes. For this you can either: + * apply only the changes that were made during that revision by looking in the sql\update folder or (files named rXXX_scriptdev2.sql should be executed on the scriptdev2 db while rXXX_mangos.sql should be executed on your mangos db) + * reapply "mangos_scriptname_full.sql" to your MaNGOS database. - WARNING this will NOT include removed script names! + +ScriptDev2 Change Log +--------------------- + +You can view the ScriptDev2 change log on the https://github.com/scriptdev2/scriptdev2/commits/master[ScriptDev2 Github Repository]. + +Or of course locally with your Git GUI tools or with `git log` (Note that it should be up to date before looking into your local log) diff --git a/docs/SQL_guide.html b/docs/SQL_guide.html new file mode 100644 index 000000000..bc528524c --- /dev/null +++ b/docs/SQL_guide.html @@ -0,0 +1,1154 @@ + + + + + +[GUIDE] Introduction to Database content for SD2 + + + + + +
+
+
+

This guide is intended to help people

+
    +
  • +

    +to understand which information of the database is used with SD2 +

    +
  • +
  • +

    +who want to contribute their patches as complete as possible +

    +
  • +
+

All sql-related files are located in the ScriptDev2/sql and subsequent directories.

+
+
+
+

1. SQL-Files

+
+
+

1.1. Files that contain full SD2-Database content

+

For a script we usually have to take care of these files:

+
    +
  • +

    +mangos_scriptname_full.sql +

    +

    This file is applied to the world database (default: mangos), and contains the ScriptNames

    +
  • +
  • +

    +scriptdev2_script_full.sql +

    +

    This file is applied to the sd2 database (default: scriptdev2), and contains texts, gossip-items and waypoints

    +
  • +
+
+
+

1.2. Patchfiles for incremental Updates

+

Patches for the databases are stored in the files:

+
    +
  • +

    +Updates/rXXXX_mangos.sql +

    +

    This file contains the changes that should be done with the patch to the world-databse

    +
  • +
  • +

    +Updates/rXXXX_scriptdev2.sql +

    +

    This file contains the changes that should be done with the patch to the scriptdev2-database

    +
  • +
+
+
+
+
+

2. World-Database

+
+
+

2.1. ScriptNames of NPCs:

+

If we need to assign a ScriptName to a NPC (GameObject-Scripts are similar) the statement is:

+
+
+
UPDATE creature_template SET ScriptName='npc_and_his_name' WHERE entry=XYZ;
+
+

or

+
+
+
UPDATE creature_template SET ScriptName='npc_something_identifying' WHERE entry IN (XYZ, ZYX);
+
+

Remark: For creatures with many difficulty entries, only the one for normal difficulty needs the ScriptName.

+
+
+

2.2. ScriptNames for scripted_areatrigger:

+

For Areatriggers (or scripted_event_id) we usally cannot use UPDATE, hence we need to DELETE possible old entries first:

+
+
+
DELETE FROM scripted_areatrigger WHERE entry=XYZ;
+INSERT INTO scripted_areatrigger VALUES (XYZ, at_some_place);
+
+
+
+
+
+

3. ScriptDev2-Database

+
+
+

3.1. entry-Format for texts and for gossip-texts:

+

The to be used entry is a combination of the number depending on the map and a counter.

+
    +
  • +

    +This is for texts: -1<MapId><three-digit-counter> +

    +
  • +
  • +

    +For gossip-texts: -3<MapId><three-digit-counter> +

    +

    where <MapId> is the ID of the map for instances, or 000 for all other maps.

    +
  • +
+
+

3.1.1. Example: Text on WorldMap

+

Let’s say we want to add a new text to a NPC on Kalimdor (no instance), +then we need to look which is the last text entry of the format -1000XYZ +(this one can be found in scriptdev2_script_full.sql).

+

On the moment where I write this guide this is:

+
+
+
(-1000589,'Kroshius live? Kroshius crush!',0,1,0,0,'SAY_KROSHIUS_REVIVE');
+
+

so our first text entry will be -1000590.

+
+
+

3.1.2. Example: Gossip-Item in Instance

+

Let’s say we want to add a new gossip item to a NPC in Culling of Stratholme, this map has the ID 595. +At this moment there is already some gossip_text, and the last one is

+
+
+
(-3595005,'So how does the Infinite Dragonflight plan to interfere?','chromie GOSSIP_ITEM_INN_3');
+
+

so our first gossip-text entry will be -3595006.

+
+
+
+

3.2. Format for texts

+

The format is (entry,content_default,sound,type,language,emote,comment) with these meanings:

+
+
+entry +
+
+

+should now be clear ;) +

+
+
+content_default +
+
+

+is the text (in english) enclosed with '.
+ There are a few placeholders that can be used: +
+

+
+ + + + + + + + + + + + + + + + + + + + +
+%s +
+
+

+self, is the name of the Unit saying the text
+The $-placeholders work only if you use DoScriptText with a target. +

+
+$N, $n +
+
+

+the [N, n]ame of the target +

+
+$C, $c +
+
+

+the [C, c]lass of the target +

+
+$R, $r +
+
+

+the [R, r]ace of the target +

+
+$GA:B; +
+
+

+if the target is male then A else B is displayed, Example: +

+
+
+
'Time to teach you a lesson in manners, little $Gboy:girl;!'
+
+

Remember to escape ' with \', Example:

+
+
+
'That \'s my favourite chocolate bar'.
+
+
+
+
+sound +
+
+

+is the sound ID that shall be played on saying, they are stored in SoundEntries.dbc +

+
+
+

Sound Ids are stored within the SoundEntries.dbc file. Within that dbc file you will find a reference to the actual file that is played. We cannot help you with reading these files so please do not ask how.

+
+
+— Ntsc +
+
+
+type +
+
+

+is the type of the text, there are these possibilities: +

+
+
+
0 CHAT_TYPE_SAY - 'white' text
+1 CHAT_TYPE_YELL - 'red' text
+2 CHAT_TYPE_TEXT_EMOTE - 'yellow' emote-text (no <Name>... )
+3 CHAT_TYPE_BOSS_EMOTE - 'big yellow' emote-text displayed in the center of the screen
+4 CHAT_TYPE_WHISPER - whisper, needs a target
+5 CHAT_TYPE_BOSS_WHISPER - whipser, needs a target
+6 CHAT_TYPE_ZONE_YELL - 'red' text, displayed to everyone in the zone
+
+
+
+language +
+
+

+is the language of the text (like LANG_GNOMISH), see enum Language in game/SharedDefines.h — usually zero (LANG_UNIVERSAL) +

+
+
+emote +
+
+

+is the emote the npc shall perform on saying the text, can be found in enum Emote in game/SharedDefines.h +

+
+
+comment +
+
+

+is a comment to this text, usually the used enum of the script, like SAY_KROSHIUS_REVIVE, if this enum is not identifying the npc, then the name of the npc is put before. +

+
+
+
+
+

3.3. Format for gossip-texts

+

The format for gossip texts is (entry,content_default,comment)
+The fields have the same meaning as for script-texts.

+
+
+

3.4. Format for waypoints

+

The format for waypoints is (entry,pointid,location_x,location_y,location_z,waittime,point_comment) with these meanings:

+
+
+entry +
+
+

+is the entry of the scripted NPC +

+
+
+pointid +
+
+

+is the ID of the point, usally starting with 01, and increasing +

+
+
+location_* +
+
+

+describes the position of the waypoint +

+
+
+waittime +
+
+

+is the time, the mob will wait after reaching this waypoint, before he continues to go to the next +

+
+
+point_comment +
+
+

+is used to note if something special is happening at this point, like quest credit +

+
+
+
+
+
+
+

4. Creating the Patch

+
+

There are different ways to get to a patch, I prefer this workflow:

+
+

4.1. For the scriptdev2 database (patch files):

+

Open scriptdev2_script_full.txt
+scroll to the right place for the needed SQL-statements, to note the entry.
+(for texts depending on mapId, and to the last counter, for waypoints behind the last inserted waypoint)

+
+

4.1.1. Example for normal world text:

+

Assume the last entry in your map (here world-map) was:

+
+
+
(-1000589,'Kroshius live? Kroshius crush!',0,1,0,0,'SAY_KROSHIUS_REVIVE');
+
+

Now create a new file: Updates/r0000_scriptdev2.sql +Add there:

+
+
+
DELETE FROM script_texts WHERE entry=-1000590;
+INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES
+(-1000590,'My fancy aggro-text',0,1,0,0,'boss_hogger SAY_AGGRO');
+
+

or

+
+
+
DELETE FROM script_texts WHERE entry BETWEEN -1000592 AND -1000590;
+INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES
+(-1000590,'My fancy aggro-text1',0,1,0,0,'boss_hogger SAY_AGGRO1'),
+(-1000591,'My fancy aggro-text2',0,1,0,0,'boss_hogger SAY_AGGRO2'),
+(-1000592,'My fancy aggro-text3',0,1,0,0,'boss_hogger SAY_AGGRO3');
+
+

Hint: the INSERT statements can also be copied from the scriptdev2_script_full.sql

+
+
+

4.1.2. Example for waypoints:

+

The required SQL code to add a waypoint is:

+
+
+
DELETE FROM script_waypoint WHERE entry=<MyNpcEntry>;
+INSERT INTO script_waypoint VALUES
+(<MyNpcEntry>, 1, 4013.51,6390.33, 29.970, 0, '<MyNPCName> - start escort'),
+(<MyNpcEntry>, 2, 4060.51,6400.33, 20.970, 0, '<MyNPCName> - finish escort');
+
+

When the Update file is done, append an additional empty line
+And test these lines for correctness!

+
+
+
+

4.2. For the scriptdev2 database (full files):

+

If everything works alright, and you finally intend to prepare the full-patch, copy the SQL-Code that is needed to the proper place in scriptdev2_script_full.sql, +(for a new npc add an empty line), and change the semicolon to a comma:

+
+

4.2.1. Example for world text:

+
+
+
(-1000589,'Kroshius live? Kroshius crush!',0,1,0,0,'SAY_KROSHIUS_REVIVE'),
+
+(-1000590,'My fancy aggro-text',0,1,0,0,'boss_hogger SAY_AGGRO');
+
+

The waypoints are added behind the last waypoint, after an empty line.

+
+
+
+

4.3. For the world database:

+

Create a new file: Updates/r0000_mangos.sql
+In this file put the needed statements for your ScriptNames, append an empty line, convert lineendings to Unix, and then test it for correctness.

+

If everything is alright, open mangos_scriptname_full.sql and go to the right place (this is usally sorted alphabetically by zone).
+Insert the needed statement where it fits (usally again ordered alphabetically)

+

After this is done, Create a patch including the (untracked) files in Update/
+then you have all information in the created patch, and anyone who wants to test your patch just needs to apply the created files from Updates/

+
+
+
+
+

+ + + diff --git a/docs/SQL_guide.txt b/docs/SQL_guide.txt new file mode 100644 index 000000000..3e27507e5 --- /dev/null +++ b/docs/SQL_guide.txt @@ -0,0 +1,257 @@ +[GUIDE] Introduction to Database content for SD2 +================================================ + +This guide is intended to help people + +* to understand which information of the database is used with SD2 +* who want to contribute their patches as complete as possible + +All sql-related files are located in the ScriptDev2/sql and subsequent directories. + +SQL-Files +--------- + +Files that contain full SD2-Database content +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For a script we usually have to take care of these files: + +* mangos_scriptname_full.sql ++ +This file is applied to the world database (default: mangos), and contains the ScriptNames ++ +* scriptdev2_script_full.sql ++ +This file is applied to the sd2 database (default: scriptdev2), and contains texts, gossip-items and waypoints + +Patchfiles for incremental Updates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Patches for the databases are stored in the files: + +* Updates/rXXXX_mangos.sql ++ +This file contains the changes that should be done with the patch to the world-databse ++ +* Updates/rXXXX_scriptdev2.sql ++ +This file contains the changes that should be done with the patch to the scriptdev2-database + +World-Database +-------------- + +ScriptNames of NPCs: +~~~~~~~~~~~~~~~~~~~~ + +If we need to assign a ScriptName to a NPC (GameObject-Scripts are similar) the statement is: + +----------- +UPDATE creature_template SET ScriptName='npc_and_his_name' WHERE entry=XYZ; +----------- +or +----------- +UPDATE creature_template SET ScriptName='npc_something_identifying' WHERE entry IN (XYZ, ZYX); +----------- + +'Remark:' For creatures with many difficulty entries, only the one for normal difficulty needs the ScriptName. + +ScriptNames for scripted_areatrigger: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Areatriggers (or scripted_event_id) we usally cannot use UPDATE, hence we need to DELETE possible old entries first: + +----------- +DELETE FROM scripted_areatrigger WHERE entry=XYZ; +INSERT INTO scripted_areatrigger VALUES (XYZ, at_some_place); +----------- + +ScriptDev2-Database +------------------- + +entry-Format for texts and for gossip-texts: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The to be used entry is a combination of the number depending on the map and a counter. + +* This is for texts: -1 +* For gossip-texts: -3 ++ +where is the ID of the map for instances, or 000 for all other maps. + +Example: Text on WorldMap +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's say we want to add a new text to a NPC on Kalimdor (no instance), +then we need to look which is the last text entry of the format -1000XYZ +(this one can be found in scriptdev2_script_full.sql). + +On the moment where I write this guide this is: + +---------- +(-1000589,'Kroshius live? Kroshius crush!',0,1,0,0,'SAY_KROSHIUS_REVIVE'); +---------- + +so our first text entry will be -1000590. + +Example: Gossip-Item in Instance +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let's say we want to add a new gossip item to a NPC in Culling of Stratholme, this map has the ID 595. +At this moment there is already some gossip_text, and the last one is + +------------ +(-3595005,'So how does the Infinite Dragonflight plan to interfere?','chromie GOSSIP_ITEM_INN_3'); +------------ + +so our first gossip-text entry will be -3595006. + +Format for texts +~~~~~~~~~~~~~~~~ + +The format is `(entry,content_default,sound,type,language,emote,comment)` with these meanings: + +entry:: should now be clear ;) +content_default:: is the text (in english) enclosed with '. + + There are a few placeholders that can be used: + + +[horizontal] +%s;; self, is the name of the Unit saying the text + +The $-placeholders work only if you use DoScriptText with a 'target'. +$N, $n;; the [N, n]ame of the target +$C, $c;; the [C, c]lass of the target +$R, $r;; the [R, r]ace of the target +$GA:B; ;; if the target is male then A else B is displayed, Example: ++ +-------------------------------- +'Time to teach you a lesson in manners, little $Gboy:girl;!' +-------------------------------- ++ +Remember to escape [red]#\'# with [red]#\'#, Example: ++ +-------------------------------- +'That \'s my favourite chocolate bar'. +-------------------------------- +sound:: is the sound ID that shall be played on saying, they are stored in SoundEntries.dbc ++ +[quote, Ntsc] +_____________________________ +Sound Ids are stored within the SoundEntries.dbc file. Within that dbc file you will find a reference to the actual file that is played. We cannot help you with reading these files so please do not ask how. +_____________________________ ++ +type:: is the type of the text, there are these possibilities: ++ +------------- +0 CHAT_TYPE_SAY - 'white' text +1 CHAT_TYPE_YELL - 'red' text +2 CHAT_TYPE_TEXT_EMOTE - 'yellow' emote-text (no ... ) +3 CHAT_TYPE_BOSS_EMOTE - 'big yellow' emote-text displayed in the center of the screen +4 CHAT_TYPE_WHISPER - whisper, needs a target +5 CHAT_TYPE_BOSS_WHISPER - whipser, needs a target +6 CHAT_TYPE_ZONE_YELL - 'red' text, displayed to everyone in the zone +-------------- ++ +language:: is the language of the text (like LANG_GNOMISH), see +enum Language+ in `game/SharedDefines.h` -- usually zero (LANG_UNIVERSAL) +emote:: is the emote the npc shall perform on saying the text, can be found in +enum Emote+ in `game/SharedDefines.h` +comment:: is a comment to this text, usually the used enum of the script, like SAY_KROSHIUS_REVIVE, if this enum is not identifying the npc, then the name of the npc is put before. + +Format for gossip-texts +~~~~~~~~~~~~~~~~~~~~~~~ + +The format for gossip texts is `(entry,content_default,comment)` + +The fields have the same meaning as for script-texts. + +Format for waypoints +~~~~~~~~~~~~~~~~~~~~ + +The format for waypoints is `(entry,pointid,location_x,location_y,location_z,waittime,point_comment)` with these meanings: + +entry:: is the entry of the scripted NPC +pointid:: is the ID of the point, usally starting with 01, and increasing +location_*:: describes the position of the waypoint +waittime:: is the time, the mob will wait after reaching _this_ waypoint, before he continues to go to the next +point_comment:: is used to note if something special is happening at this point, like quest credit + + +Creating the Patch +------------------ + +There are different ways to get to a patch, I prefer this workflow: + +For the scriptdev2 database (patch files): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Open scriptdev2_script_full.txt + +scroll to the right place for the needed SQL-statements, to note the entry. + +(for texts depending on mapId, and to the last counter, for waypoints behind the last inserted waypoint) + +Example for normal world text: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Assume the last entry in your map (here world-map) was: + +-------------- +(-1000589,'Kroshius live? Kroshius crush!',0,1,0,0,'SAY_KROSHIUS_REVIVE'); +-------------- + +Now create a new file: Updates/r0000_scriptdev2.sql +Add there: + +----------- +DELETE FROM script_texts WHERE entry=-1000590; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000590,'My fancy aggro-text',0,1,0,0,'boss_hogger SAY_AGGRO'); +----------- +or +----------- +DELETE FROM script_texts WHERE entry BETWEEN -1000592 AND -1000590; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000590,'My fancy aggro-text1',0,1,0,0,'boss_hogger SAY_AGGRO1'), +(-1000591,'My fancy aggro-text2',0,1,0,0,'boss_hogger SAY_AGGRO2'), +(-1000592,'My fancy aggro-text3',0,1,0,0,'boss_hogger SAY_AGGRO3'); +----------- + +Hint: the INSERT statements can also be copied from the scriptdev2_script_full.sql + +Example for waypoints: +^^^^^^^^^^^^^^^^^^^^^^ + +The required SQL code to add a waypoint is: + +---------- +DELETE FROM script_waypoint WHERE entry=; +INSERT INTO script_waypoint VALUES +(, 1, 4013.51,6390.33, 29.970, 0, ' - start escort'), +(, 2, 4060.51,6400.33, 20.970, 0, ' - finish escort'); +---------- + +When the Update file is done, append an additional empty line + +And test these lines for correctness! + +For the scriptdev2 database (full files): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If everything works alright, and you finally intend to prepare the full-patch, copy the SQL-Code that is needed to the proper place in scriptdev2_script_full.sql, +(for a new npc add an empty line), and change the semicolon to a comma: + +Example for world text: +^^^^^^^^^^^^^^^^^^^^^^ + +----------- +(-1000589,'Kroshius live? Kroshius crush!',0,1,0,0,'SAY_KROSHIUS_REVIVE'), + +(-1000590,'My fancy aggro-text',0,1,0,0,'boss_hogger SAY_AGGRO'); +----------- + +The waypoints are added behind the last waypoint, after an empty line. + +For the world database: +~~~~~~~~~~~~~~~~~~~~~~~ + +Create a new file: Updates/r0000_mangos.sql + +In this file put the needed statements for your ScriptNames, append an empty line, convert lineendings to Unix, and then test it for correctness. + +If everything is alright, open mangos_scriptname_full.sql and go to the right place (this is usally sorted alphabetically by zone). + +Insert the needed statement where it fits (usally again ordered alphabetically) + +After this is done, Create a patch including the (untracked) files in Update/ + +then you have all information in the created patch, and anyone who wants to test your patch just needs to apply the created files from Updates/ diff --git a/docs/Script Layout.txt b/docs/Script_Layout.txt similarity index 100% rename from docs/Script Layout.txt rename to docs/Script_Layout.txt diff --git a/docs/Text-tables.txt b/docs/Text-tables.txt index 11c419720..75188ecbf 100644 --- a/docs/Text-tables.txt +++ b/docs/Text-tables.txt @@ -12,11 +12,12 @@ The different tables has ranges of entries allowed for that table. Reserved EventAI in Mangos entry -1 -> -999999 script_texts: entry -1000000 -> -1999999 custom_texts: entry -2000000 -> -2999999 +gossip_texts: entry -3000000 -> -3999999 Any entry out of range for that table will display a start-up error. ========================================= -Basic Structure of script_texts and custom_texts +Basic Structure of script_texts, custom_texts and gossip_texts ========================================= Below is a the list of current fields within the texts tables. @@ -38,8 +39,10 @@ sound This value is the Sound ID that corresponds to the actual type Variables used to define type of text (Say/Yell/Textemote/Whisper). language This value is the Language that the text is native in (Defined in Languages.dbc). emote Value from enum Emote (defined in Emotes.dbc). Only source of text will play this emote (not target, if target are defined in DoScriptText) + comment This is a comment regarding the text entry (For ACID, accepted format is to use Creature ID of NPC using it). +Note: sound, type, language and emote exist only in tables script_texts and custom_texts Note: Fields `content_loc1` to `content_loc8` are NULL values by default and are handled by separate localization projects. diff --git a/docs/ToDo.html b/docs/ToDo.html new file mode 100644 index 000000000..2c47a6819 --- /dev/null +++ b/docs/ToDo.html @@ -0,0 +1,817 @@ + + + + + +ScriptDev2 TODO Points + + + + + +
+
+

1. Cataclysm content

+
+
    +
  • +

    +Start implementing 4.x scripts for dungeons and quests +

    +
  • +
+
+
+
+

2. WotLK content

+
+
    +
  • +

    +Finish script for Trial of the Crusader, Icecrown Citadel, Eye of Eternity and Ruby Sanctum +

    +
  • +
  • +

    +Implement dungeon scripts for Halls of Reflection and Trial of the Champion +

    +
  • +
  • +

    +Implement various missing quest scripts +

    +
  • +
+
+
+
+

3. TBC content

+
+
    +
  • +

    +Various quests which still require script (examples: 5821, 5943, 10985) +

    +
  • +
  • +

    +Hyjal Summit - Optimize game event. +

    +
  • +
  • +

    +Black Temple - Teron Gorefiend script improvement (requires core proper mind control support) +

    +
  • +
+
+
+
+

4. Classic content

+
+
    +
  • +

    +Various quests which still require script (examples: 5721) +

    +
  • +
+
+
+
+

+ + + diff --git a/docs/ToDo.txt b/docs/ToDo.txt index 5df315da0..7ccd350b2 100644 --- a/docs/ToDo.txt +++ b/docs/ToDo.txt @@ -1,14 +1,17 @@ ---- TO DO --- -Simple list of things we need to do. += ScriptDev2 TODO Points = ---- ScriptDev2 Framework --- -Move all text out of C++ code and into SD2 database. +== Cataclysm content == +* Start implementing 4.x scripts for dungeons and quests ---- Scripting with Priorities --- -1) Boss AI and Boss Event scripts -2) Specific NPC AI, Gossip, Quest, Event scripts -3) Spell and Item scripts +== WotLK content == +* Finish script for Trial of the Crusader, Icecrown Citadel, Eye of Eternity and Ruby Sanctum +* Implement dungeon scripts for Halls of Reflection and Trial of the Champion +* Implement various missing quest scripts ---- Core Problems --- +== TBC content == +* Various quests which still require script (examples: 5821, 5943, 10985) +* Hyjal Summit - Optimize game event. +* Black Temple - Teron Gorefiend script improvement (requires core proper mind control support) -- Spell scripts are only scriptable within the core. Spell scripts should be done in SD2 since they are very specialized. \ No newline at end of file +== Classic content == +* Various quests which still require script (examples: 5721) diff --git a/docs/aaa_Overview.html b/docs/aaa_Overview.html new file mode 100644 index 000000000..c8f68e400 --- /dev/null +++ b/docs/aaa_Overview.html @@ -0,0 +1,806 @@ + + + + + +Overview of ScriptDev2 Documentation Section + + + + + +
+
+

1. License

+
+

ScriptDev2 is GPL Software, you can find the GNU General Public License here.

+
+
+
+

2. Basic Installation instructions

+
+

See How to install for basic instructions

+
+
+
+

3. ScriptDev2 ChangeLog and TODO list

+
+

See Changelog for basic points reached with the last milestones

+

See TODO List for rough points that the SD2-Team wants to be adressed in the next milestones

+
+
+
+ +
+

Easy use of Git - Look here if you are new to Git

+

Normal use of Git - Look here if you want to do basic work with Git

+

Advanced use of Git - Look here if you want to dig deeper into Git, this also contains some configuration settings for Git

+
+
+
+

5. Database content used with SD2

+
+

Guide for SD2 SQL-Files - Look here for an overview how to manipulate the database content in SD2

+

Text-tables.txt - Manual like documentation for the tables `script_texts` and `custom_texts`

+
+
+
+

6. Old documentation files

+
+
+
+Script_Layout.txt +
+
+

+Information about the subfolders of the scripts directory +

+
+
+Text-tables.txt +
+
+

+Documentation of the layout of the tables `script_texts`, `custom_texts` and `gossip_texts` +

+
+
+
+
+
+

+ + + diff --git a/docs/aaa_Overview.txt b/docs/aaa_Overview.txt new file mode 100644 index 000000000..a9c618062 --- /dev/null +++ b/docs/aaa_Overview.txt @@ -0,0 +1,42 @@ +Overview of ScriptDev2 Documentation Section +============================================ + +License +------- + +ScriptDev2 is GPL Software, you can find the link:LICENSE.txt[GNU General Public License] here. + + +Basic Installation instructions +------------------------------- + +See link:How_to_install.html[How to install] for basic instructions + +ScriptDev2 ChangeLog and TODO list +---------------------------------- +See link:ChangeLog.html[Changelog] for basic points reached with the last milestones + +See link:ToDo.html[TODO List] for rough points that the SD2-Team wants to be adressed in the next milestones + +Various Guides related to Git +----------------------------- + +link:GIT_guide_1_easy_use.html[Easy use of Git] - Look here if you are new to Git + +link:GIT_guide_2_normal_use.html[Normal use of Git] - Look here if you want to do basic work with Git + +link:GIT_guide_3_advanced_use.html[Advanced use of Git] - Look here if you want to dig deeper into Git, this also contains some configuration settings for Git + +Database content used with SD2 +------------------------------ + +link:SQL_guide.html[Guide for SD2 SQL-Files] - Look here for an overview how to manipulate the database content in SD2 + +link:Text-tables.txt[] - Manual like documentation for the tables \`script_texts` and \`custom_texts` + +Old documentation files +----------------------- + +link:Script_Layout.txt[] :: Information about the subfolders of the `scripts` directory + +link:Text-tables.txt[] :: Documentation of the layout of the tables \`script_texts`, \`custom_texts` and \`gossip_texts` diff --git a/include/precompiled.cpp b/include/precompiled.cpp index 082bcd937..1fcb4b009 100644 --- a/include/precompiled.cpp +++ b/include/precompiled.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/include/precompiled.h b/include/precompiled.h index c401b4072..53549fd3e 100644 --- a/include/precompiled.h +++ b/include/precompiled.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -19,10 +19,10 @@ #ifdef WIN32 # include - BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) - { - return true; - } +BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + return true; +} #endif #endif diff --git a/include/sc_creature.cpp b/include/sc_creature.cpp index 4db83aac4..59aadb7cf 100644 --- a/include/sc_creature.cpp +++ b/include/sc_creature.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -17,17 +17,16 @@ struct TSpellSummary { uint8 Targets; // set of enum SelectTarget uint8 Effects; // set of enum SelectEffect -} *SpellSummary; +}* SpellSummary; ScriptedAI::ScriptedAI(Creature* pCreature) : CreatureAI(pCreature), - m_bCombatMovement(true), m_uiEvadeCheckCooldown(2500) {} /// This function shows if combat movement is enabled, overwrite for more info void ScriptedAI::GetAIInformation(ChatHandler& reader) { - reader.PSendSysMessage("ScriptedAI, combat movement is %s", reader.GetOnOffStr(m_bCombatMovement)); + reader.PSendSysMessage("ScriptedAI, combat movement is %s", reader.GetOnOffStr(IsCombatMovement())); } /// Return if the creature can "see" pWho @@ -51,7 +50,7 @@ bool ScriptedAI::IsVisible(Unit* pWho) const void ScriptedAI::MoveInLineOfSight(Unit* pWho) { if (m_creature->CanInitiateAttack() && pWho->isTargetableForAttack() && - m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) + m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) { if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) return; @@ -78,14 +77,16 @@ void ScriptedAI::MoveInLineOfSight(Unit* pWho) */ void ScriptedAI::AttackStart(Unit* pWho) { + if (!m_creature->CanAttackByItself()) + return; + if (pWho && m_creature->Attack(pWho, true)) // The Attack function also uses basic checks if pWho can be attacked { m_creature->AddThreat(pWho); m_creature->SetInCombatWith(pWho); pWho->SetInCombatWith(m_creature); - if (IsCombatMovement()) - m_creature->GetMotionMaster()->MoveChase(pWho); + HandleMovementOnAttackStart(pWho); } } @@ -104,9 +105,9 @@ void ScriptedAI::EnterCombat(Unit* pEnemy) * Handle (if required) melee attack with DoMeleeAttackIfReady() * This is usally overwritten to support timers for ie spells */ -void ScriptedAI::UpdateAI(const uint32 uiDiff) +void ScriptedAI::UpdateAI(const uint32 /*uiDiff*/) { - //Check if we have a current target + // Check if we have a current target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -125,11 +126,12 @@ void ScriptedAI::UpdateAI(const uint32 uiDiff) */ void ScriptedAI::EnterEvadeMode() { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); - if (m_creature->isAlive()) + // only alive creatures that are not on transport can return to home position + if (m_creature->isAlive() && !m_creature->IsBoarded()) m_creature->GetMotionMaster()->MoveTargetedHome(); m_creature->SetLootRecipient(NULL); @@ -187,7 +189,7 @@ void ScriptedAI::DoPlaySoundToSet(WorldObject* pSource, uint32 uiSoundId) if (!GetSoundEntriesStore()->LookupEntry(uiSoundId)) { - error_log("SD2: Invalid soundId %u used in DoPlaySoundToSet (Source: TypeId %u, GUID %u)", uiSoundId, pSource->GetTypeId(), pSource->GetGUIDLow()); + script_error_log("Invalid soundId %u used in DoPlaySoundToSet (Source: TypeId %u, GUID %u)", uiSoundId, pSource->GetTypeId(), pSource->GetGUIDLow()); return; } @@ -196,116 +198,116 @@ void ScriptedAI::DoPlaySoundToSet(WorldObject* pSource, uint32 uiSoundId) Creature* ScriptedAI::DoSpawnCreature(uint32 uiId, float fX, float fY, float fZ, float fAngle, uint32 uiType, uint32 uiDespawntime) { - return m_creature->SummonCreature(uiId,m_creature->GetPositionX()+fX, m_creature->GetPositionY()+fY, m_creature->GetPositionZ()+fZ, fAngle, (TempSummonType)uiType, uiDespawntime); + return m_creature->SummonCreature(uiId, m_creature->GetPositionX() + fX, m_creature->GetPositionY() + fY, m_creature->GetPositionZ() + fZ, fAngle, (TempSummonType)uiType, uiDespawntime); } SpellEntry const* ScriptedAI::SelectSpell(Unit* pTarget, int32 uiSchool, int32 iMechanic, SelectTarget selectTargets, uint32 uiPowerCostMin, uint32 uiPowerCostMax, float fRangeMin, float fRangeMax, SelectEffect selectEffects) { - //No target so we can't cast + // No target so we can't cast if (!pTarget) - return false; + return NULL; - //Silenced so we can't cast + // Silenced so we can't cast if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) - return false; + return NULL; - //Using the extended script system we first create a list of viable spells + // Using the extended script system we first create a list of viable spells SpellEntry const* apSpell[4]; - memset(apSpell, 0, sizeof(SpellEntry*)*4); + memset(apSpell, 0, sizeof(SpellEntry*) * 4); uint32 uiSpellCount = 0; SpellEntry const* pTempSpell; SpellRangeEntry const* pTempRange; - //Check if each spell is viable(set it to null if not) + // Check if each spell is viable(set it to null if not) for (uint8 i = 0; i < 4; ++i) { pTempSpell = GetSpellStore()->LookupEntry(m_creature->m_spells[i]); - //This spell doesn't exist + // This spell doesn't exist if (!pTempSpell) continue; // Targets and Effects checked first as most used restrictions - //Check the spell targets if specified - if (selectTargets && !(SpellSummary[m_creature->m_spells[i]].Targets & (1 << (selectTargets-1)))) + // Check the spell targets if specified + if (selectTargets && !(SpellSummary[m_creature->m_spells[i]].Targets & (1 << (selectTargets - 1)))) continue; - //Check the type of spell if we are looking for a specific spell type - if (selectEffects && !(SpellSummary[m_creature->m_spells[i]].Effects & (1 << (selectEffects-1)))) + // Check the type of spell if we are looking for a specific spell type + if (selectEffects && !(SpellSummary[m_creature->m_spells[i]].Effects & (1 << (selectEffects - 1)))) continue; - //Check for school if specified + // Check for school if specified if (uiSchool >= 0 && pTempSpell->SchoolMask & uiSchool) continue; - //Check for spell mechanic if specified + // Check for spell mechanic if specified if (iMechanic >= 0 && pTempSpell->Mechanic != (uint32)iMechanic) continue; - //Make sure that the spell uses the requested amount of power + // Make sure that the spell uses the requested amount of power if (uiPowerCostMin && pTempSpell->manaCost < uiPowerCostMin) continue; if (uiPowerCostMax && pTempSpell->manaCost > uiPowerCostMax) continue; - //Continue if we don't have the mana to actually cast this spell + // Continue if we don't have the mana to actually cast this spell if (pTempSpell->manaCost > m_creature->GetPower((Powers)pTempSpell->powerType)) continue; - //Get the Range + // Get the Range pTempRange = GetSpellRangeStore()->LookupEntry(pTempSpell->rangeIndex); - //Spell has invalid range store so we can't use it + // Spell has invalid range store so we can't use it if (!pTempRange) continue; - //Check if the spell meets our range requirements + // Check if the spell meets our range requirements if (fRangeMin && pTempRange->maxRange < fRangeMin) continue; if (fRangeMax && pTempRange->maxRange > fRangeMax) continue; - //Check if our target is in range + // Check if our target is in range if (m_creature->IsWithinDistInMap(pTarget, pTempRange->minRange) || !m_creature->IsWithinDistInMap(pTarget, pTempRange->maxRange)) continue; - //All good so lets add it to the spell list + // All good so lets add it to the spell list apSpell[uiSpellCount] = pTempSpell; ++uiSpellCount; } - //We got our usable spells so now lets randomly pick one + // We got our usable spells so now lets randomly pick one if (!uiSpellCount) return NULL; - return apSpell[urand(0, uiSpellCount -1)]; + return apSpell[urand(0, uiSpellCount - 1)]; } bool ScriptedAI::CanCast(Unit* pTarget, SpellEntry const* pSpellEntry, bool bTriggered) { - //No target so we can't cast + // No target so we can't cast if (!pTarget || !pSpellEntry) return false; - //Silenced so we can't cast + // Silenced so we can't cast if (!bTriggered && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) return false; - //Check for power + // Check for power if (!bTriggered && m_creature->GetPower((Powers)pSpellEntry->powerType) < pSpellEntry->manaCost) return false; SpellRangeEntry const* pTempRange = GetSpellRangeStore()->LookupEntry(pSpellEntry->rangeIndex); - //Spell has invalid range store so we can't use it + // Spell has invalid range store so we can't use it if (!pTempRange) return false; - //Unit is out of range of this spell + // Unit is out of range of this spell if (!m_creature->IsInRange(pTarget, pTempRange->minRange, pTempRange->maxRange)) return false; @@ -324,75 +326,75 @@ void FillSpellSummary() SpellSummary[i].Targets = 0; pTempSpell = GetSpellStore()->LookupEntry(i); - //This spell doesn't exist + // This spell doesn't exist if (!pTempSpell) continue; for (uint8 j = 0; j < 3; ++j) { - //Spell targets self + // Spell targets self if (pTempSpell->EffectImplicitTargetA[j] == TARGET_SELF) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF - 1); - //Spell targets a single enemy + // Spell targets a single enemy if (pTempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || - pTempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); + pTempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY - 1); - //Spell targets AoE at enemy + // Spell targets AoE at enemy if (pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || - pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || - pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES || - pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); + pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || + pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES || + pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY - 1); - //Spell targets an enemy + // Spell targets an enemy if (pTempSpell->EffectImplicitTargetA[j] == TARGET_CHAIN_DAMAGE || - pTempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES || - pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || - pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || - pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES || - pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); - - //Spell targets a single friend(or self) + pTempSpell->EffectImplicitTargetA[j] == TARGET_CURRENT_ENEMY_COORDINATES || + pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA || + pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || + pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES || + pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY - 1); + + // Spell targets a single friend(or self) if (pTempSpell->EffectImplicitTargetA[j] == TARGET_SELF || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); + pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND - 1); - //Spell targets aoe friends + // Spell targets aoe friends if (pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); + pTempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND - 1); - //Spell targets any friend(or self) + // Spell targets any friend(or self) if (pTempSpell->EffectImplicitTargetA[j] == TARGET_SELF || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); - - //Make sure that this spell includes a damage effect + pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_FRIEND || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SINGLE_PARTY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_ALL_PARTY_AROUND_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_AREAEFFECT_PARTY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_CASTER_COORDINATES) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND - 1); + + // Make sure that this spell includes a damage effect if (pTempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || - pTempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || - pTempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || - pTempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1); + pTempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || + pTempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + pTempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE - 1); - //Make sure that this spell includes a healing effect (or an apply aura with a periodic heal) + // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal) if (pTempSpell->Effect[j] == SPELL_EFFECT_HEAL || - pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || - pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || - (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && pTempSpell->EffectApplyAuraName[j]== 8)) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); + pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || + pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || + (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && pTempSpell->EffectApplyAuraName[j] == 8)) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING - 1); - //Make sure that this spell applies an aura + // Make sure that this spell applies an aura if (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA - 1); } } } @@ -401,12 +403,12 @@ void ScriptedAI::DoResetThreat() { if (!m_creature->CanHaveThreatList() || m_creature->getThreatManager().isThreatListEmpty()) { - error_log("SD2: DoResetThreat called for creature that either cannot have threat list or has empty threat list (m_creature entry = %d)", m_creature->GetEntry()); + script_error_log("DoResetThreat called for creature that either cannot have threat list or has empty threat list (m_creature entry = %d)", m_creature->GetEntry()); return; } ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + for (ThreatList::const_iterator itr = tList.begin(); itr != tList.end(); ++itr) { Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); @@ -422,7 +424,7 @@ void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float fX, float fY, float fZ, flo if (pUnit->GetTypeId() != TYPEID_PLAYER) { - error_log("SD2: %s tried to teleport non-player (%s) to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGuidStr().c_str(), pUnit->GetGuidStr().c_str(), fX, fY, fZ, fO); + script_error_log("%s tried to teleport non-player (%s) to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGuidStr().c_str(), pUnit->GetGuidStr().c_str(), fX, fY, fZ, fO); return; } @@ -481,7 +483,7 @@ void ScriptedAI::SetEquipmentSlots(bool bLoadDefault, int32 iMainHand, int32 iOf { if (bLoadDefault) { - m_creature->LoadEquipment(m_creature->GetCreatureInfo()->equipmentId, true); + m_creature->LoadEquipment(m_creature->GetCreatureInfo()->EquipmentTemplateId, true); return; } @@ -495,11 +497,6 @@ void ScriptedAI::SetEquipmentSlots(bool bLoadDefault, int32 iMainHand, int32 iOf m_creature->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, iRanged); } -void ScriptedAI::SetCombatMovement(bool bCombatMove) -{ - m_bCombatMovement = bCombatMove; -} - // Hacklike storage used for misc creatures that are expected to evade of outside of a certain area. // It is assumed the information is found elswehere and can be handled by mangos. So far no luck finding such information/way to extract it. enum @@ -511,6 +508,8 @@ enum NPC_TALON_KING_IKISS = 18473, NPC_KARGATH_BLADEFIST = 16808, NPC_ANUBARAK = 29120, + NPC_SINDRAGOSA = 36853, + NPC_ZARITHRIAN = 39746, }; bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) @@ -530,7 +529,7 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) float fY = m_creature->GetPositionY(); float fZ = m_creature->GetPositionZ(); - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case NPC_BROODLORD: // broodlord (not move down stairs) if (fZ > 448.60f) @@ -564,8 +563,16 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) if (fY < 281.0f && fY > 228.0f) return false; break; + case NPC_SINDRAGOSA: + if (fX > 4314.0f) + return false; + break; + case NPC_ZARITHRIAN: + if (fZ > 87.0f) + return false; + break; default: - error_log("SD2: EnterEvadeIfOutOfCombatArea used for creature entry %u, but does not have any definition.", m_creature->GetEntry()); + script_error_log("EnterEvadeIfOutOfCombatArea used for creature entry %u, but does not have any definition.", m_creature->GetEntry()); return false; } @@ -580,6 +587,9 @@ void Scripted_NoMovementAI::GetAIInformation(ChatHandler& reader) void Scripted_NoMovementAI::AttackStart(Unit* pWho) { + if (!m_creature->CanAttackByItself()) + return; + if (pWho && m_creature->Attack(pWho, true)) { m_creature->AddThreat(pWho); diff --git a/include/sc_creature.h b/include/sc_creature.h index e5eb5075e..b76b0ba98 100644 --- a/include/sc_creature.h +++ b/include/sc_creature.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -6,30 +6,31 @@ #define SC_CREATURE_H #include "Chat.h" +#include "DBCStores.h" // Mostly only used the Lookup acces, but a few cases really do use the DBC-Stores -//Spell targets used by SelectSpell +// Spell targets used by SelectSpell enum SelectTarget { - SELECT_TARGET_DONTCARE = 0, //All target types allowed + SELECT_TARGET_DONTCARE = 0, // All target types allowed - SELECT_TARGET_SELF, //Only Self casting + SELECT_TARGET_SELF, // Only Self casting - SELECT_TARGET_SINGLE_ENEMY, //Only Single Enemy - SELECT_TARGET_AOE_ENEMY, //Only AoE Enemy - SELECT_TARGET_ANY_ENEMY, //AoE or Single Enemy + SELECT_TARGET_SINGLE_ENEMY, // Only Single Enemy + SELECT_TARGET_AOE_ENEMY, // Only AoE Enemy + SELECT_TARGET_ANY_ENEMY, // AoE or Single Enemy - SELECT_TARGET_SINGLE_FRIEND, //Only Single Friend - SELECT_TARGET_AOE_FRIEND, //Only AoE Friend - SELECT_TARGET_ANY_FRIEND, //AoE or Single Friend + SELECT_TARGET_SINGLE_FRIEND, // Only Single Friend + SELECT_TARGET_AOE_FRIEND, // Only AoE Friend + SELECT_TARGET_ANY_FRIEND, // AoE or Single Friend }; -//Spell Effects used by SelectSpell +// Spell Effects used by SelectSpell enum SelectEffect { - SELECT_EFFECT_DONTCARE = 0, //All spell effects allowed - SELECT_EFFECT_DAMAGE, //Spell does damage - SELECT_EFFECT_HEALING, //Spell does healing - SELECT_EFFECT_AURA, //Spell applies an aura + SELECT_EFFECT_DONTCARE = 0, // All spell effects allowed + SELECT_EFFECT_DAMAGE, // Spell does damage + SELECT_EFFECT_HEALING, // Spell does healing + SELECT_EFFECT_AURA, // Spell applies an aura }; enum SCEquip @@ -40,7 +41,7 @@ enum SCEquip /// Documentation of CreatureAI functions can be found in MaNGOS source // Only list them here again to ensure that the interface between SD2 and the core is not changed unnoticed -struct MANGOS_DLL_DECL ScriptedAI : public CreatureAI +struct ScriptedAI : public CreatureAI { public: explicit ScriptedAI(Creature* pCreature); @@ -68,44 +69,44 @@ struct MANGOS_DLL_DECL ScriptedAI : public CreatureAI // Called when reached home after MoveTargetHome (in evade) void JustReachedHome() override {} - // Called at any heal cast/item used (call non implemented in mangos) - // void HealBy(Unit* pHealer, uint32 uiAmountHealed) override {} + // Called at any Heal received + void HealedBy(Unit* /*pHealer*/, uint32& /*uiHealedAmount*/) override {} // Called at any Damage to any victim (before damage apply) - void DamageDeal(Unit* pDoneTo, uint32& uiDamage) override {} + void DamageDeal(Unit* /*pDoneTo*/, uint32& /*uiDamage*/) override {} // Called at any Damage from any attacker (before damage apply) - void DamageTaken(Unit* pDealer, uint32& uiDamage) override {} + void DamageTaken(Unit* /*pDealer*/, uint32& /*uiDamage*/) override {} // Called at creature death - void JustDied(Unit* pKiller) override {} + void JustDied(Unit* /*pKiller*/) override {} // Called when the corpse of this creature gets removed - void CorpseRemoved(uint32& uiRespawnDelay) override {} + void CorpseRemoved(uint32& /*uiRespawnDelay*/) override {} // Called when a summoned creature is killed - void SummonedCreatureJustDied(Creature* pSummoned) {} + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override {} // Called at creature killing another unit - void KilledUnit(Unit* pVictim) override {} + void KilledUnit(Unit* /*pVictim*/) override {} // Called when owner of m_creature (if m_creature is PROTECTOR_PET) kills a unit - void OwnerKilledUnit(Unit* pVictim) override {} + void OwnerKilledUnit(Unit* /*pVictim*/) override {} // Called when the creature successfully summons a creature - void JustSummoned(Creature* pSummoned) override {} + void JustSummoned(Creature* /*pSummoned*/) override {} // Called when the creature successfully summons a gameobject - void JustSummoned(GameObject* pGo) override {} + void JustSummoned(GameObject* /*pGo*/) override {} // Called when a summoned creature gets TemporarySummon::UnSummon ed - void SummonedCreatureDespawn(Creature* pSummoned) override {} + void SummonedCreatureDespawn(Creature* /*pSummoned*/) override {} // Called when hit by a spell - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override {} + void SpellHit(Unit* /*pCaster*/, const SpellEntry* /*pSpell*/) override {} // Called when spell hits creature's target - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override {} + void SpellHitTarget(Unit* /*pTarget*/, const SpellEntry* /*pSpell*/) override {} // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc) /// This will by default result in reattacking, if the creature has no victim @@ -115,13 +116,13 @@ struct MANGOS_DLL_DECL ScriptedAI : public CreatureAI void JustRespawned() override; // Called at waypoint reached or point movement finished - void MovementInform(uint32 uiMovementType, uint32 uiData) override {} + void MovementInform(uint32 /*uiMovementType*/, uint32 /*uiData*/) override {} // Called if a temporary summoned of m_creature reach a move point - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiData) override {} + void SummonedMovementInform(Creature* /*pSummoned*/, uint32 /*uiMotionType*/, uint32 /*uiData*/) override {} // Called at text emote receive from player - void ReceiveEmote(Player* pPlayer, uint32 uiEmote) override {} + void ReceiveEmote(Player* /*pPlayer*/, uint32 /*uiEmote*/) override {} // Called at each attack of m_creature by any victim void AttackStart(Unit* pWho) override; @@ -129,6 +130,9 @@ struct MANGOS_DLL_DECL ScriptedAI : public CreatureAI // Called at World update tick void UpdateAI(const uint32) override; + // Called when an AI Event is received + void ReceiveAIEvent(AIEventType /*eventType*/, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override {} + // == State checks ================================= // Check if unit is visible for MoveInLineOfSight @@ -158,7 +162,7 @@ struct MANGOS_DLL_DECL ScriptedAI : public CreatureAI * This is a SD2 internal function * Called by default on creature EnterCombat with an enemy */ - virtual void Aggro(Unit*) {} + virtual void Aggro(Unit* /*pWho*/) {} // ************* // AI Helper Functions @@ -211,25 +215,23 @@ struct MANGOS_DLL_DECL ScriptedAI : public CreatureAI void SetEquipmentSlots(bool bLoadDefault, int32 iMainHand = EQUIP_NO_CHANGE, int32 iOffHand = EQUIP_NO_CHANGE, int32 iRanged = EQUIP_NO_CHANGE); - // Generally used to control if MoveChase() is to be used or not in AttackStart(). Some creatures do not chase victims - void SetCombatMovement(bool bCombatMove); - bool IsCombatMovement() { return m_bCombatMovement; } - bool EnterEvadeIfOutOfCombatArea(const uint32 uiDiff); private: - bool m_bCombatMovement; uint32 m_uiEvadeCheckCooldown; }; -struct MANGOS_DLL_DECL Scripted_NoMovementAI : public ScriptedAI +struct Scripted_NoMovementAI : public ScriptedAI { - Scripted_NoMovementAI(Creature* pCreature) : ScriptedAI(pCreature) {} + Scripted_NoMovementAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + } - void GetAIInformation(ChatHandler& reader); + void GetAIInformation(ChatHandler& reader) override; // Called at each attack of m_creature by any victim - void AttackStart(Unit* pWho); + void AttackStart(Unit* pWho) override; }; #endif diff --git a/include/sc_gossip.h b/include/sc_gossip.h index 513cd7a1b..4fa2ef566 100644 --- a/include/sc_gossip.h +++ b/include/sc_gossip.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/include/sc_grid_searchers.cpp b/include/sc_grid_searchers.cpp index 733aa8202..f7ce1107e 100644 --- a/include/sc_grid_searchers.cpp +++ b/include/sc_grid_searchers.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -9,8 +9,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" - -//return closest GO in grid, with range from pSource +// return closest GO in grid, with range from pSource GameObject* GetClosestGameObjectWithEntry(WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange) { GameObject* pGo = NULL; @@ -23,12 +22,12 @@ GameObject* GetClosestGameObjectWithEntry(WorldObject* pSource, uint32 uiEntry, return pGo; } -//return closest creature alive in grid, with range from pSource -Creature* GetClosestCreatureWithEntry(WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange, bool bOnlyAlive/*=true*/, bool bOnlyDead/*=false*/) +// return closest creature alive in grid, with range from pSource +Creature* GetClosestCreatureWithEntry(WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange, bool bOnlyAlive/*=true*/, bool bOnlyDead/*=false*/, bool bExcludeSelf/*=false*/) { Creature* pCreature = NULL; - MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*pSource, uiEntry, bOnlyAlive, bOnlyDead, fMaxSearchRange); + MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*pSource, uiEntry, bOnlyAlive, bOnlyDead, fMaxSearchRange, bExcludeSelf); MaNGOS::CreatureLastSearcher searcher(pCreature, creature_check); Cell::VisitGridObjects(pSource, searcher, fMaxSearchRange); diff --git a/include/sc_grid_searchers.h b/include/sc_grid_searchers.h index 9290acced..cd9365e41 100644 --- a/include/sc_grid_searchers.h +++ b/include/sc_grid_searchers.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -34,12 +34,12 @@ struct ObjectDistanceOrderReversed : public std::binary_function& lList , WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange); void GetCreatureListWithEntryInGrid(std::list& lList, WorldObject* pSource, uint32 uiEntry, float fMaxSearchRange); -//Used in: hyjalAI.cpp +// Used in: hyjalAI.cpp /* class AllFriendlyCreaturesInGrid { diff --git a/include/sc_instance.cpp b/include/sc_instance.cpp index c7939126d..0926adb21 100644 --- a/include/sc_instance.cpp +++ b/include/sc_instance.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -18,7 +18,7 @@ void ScriptedInstance::DoUseDoorOrButton(ObjectGuid guid, uint32 uiWithRestoreTi if (GameObject* pGo = instance->GetGameObject(guid)) { - if (pGo->GetGoType() == GAMEOBJECT_TYPE_DOOR || pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON) + if (pGo->GetGoType() == GAMEOBJECT_TYPE_DOOR || pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGo->GetGoType() == GAMEOBJECT_TYPE_TRAPDOOR) { if (pGo->getLootState() == GO_READY) pGo->UseDoorOrButton(uiWithRestoreTime, bUseAlternativeState); @@ -26,7 +26,7 @@ void ScriptedInstance::DoUseDoorOrButton(ObjectGuid guid, uint32 uiWithRestoreTi pGo->ResetDoorOrButton(); } else - error_log("SD2: Script call DoUseDoorOrButton, but gameobject entry %u is type %u.", pGo->GetEntry(), pGo->GetGoType()); + script_error_log("Script call DoUseDoorOrButton, but gameobject entry %u is type %u.", pGo->GetEntry(), pGo->GetGoType()); } } @@ -54,9 +54,9 @@ void ScriptedInstance::DoRespawnGameObject(ObjectGuid guid, uint32 uiTimeToDespa if (GameObject* pGo = instance->GetGameObject(guid)) { - //not expect any of these should ever be handled + // not expect any of these should ever be handled if (pGo->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || pGo->GetGoType() == GAMEOBJECT_TYPE_DOOR || - pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGo->GetGoType() == GAMEOBJECT_TYPE_TRAP) + pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON) return; if (pGo->isSpawned()) @@ -99,7 +99,6 @@ void ScriptedInstance::DoToggleGameObjectFlags(ObjectGuid guid, uint32 uiGOflags } } - /// Function that respawns a despawned GO that is stored in m_mGoEntryGuidStore void ScriptedInstance::DoRespawnGameObject(uint32 uiEntry, uint32 uiTimeToDespawn) { @@ -123,7 +122,7 @@ void ScriptedInstance::DoUpdateWorldState(uint32 uiStateId, uint32 uiStateData) if (!lPlayers.isEmpty()) { - for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { if (Player* pPlayer = itr->getSource()) pPlayer->SendUpdateWorldState(uiStateId, uiStateData); @@ -138,7 +137,7 @@ Player* ScriptedInstance::GetPlayerInMap(bool bOnlyAlive /*=false*/, bool bCanBe { Map::PlayerList const& lPlayers = instance->GetPlayers(); - for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { Player* pPlayer = itr->getSource(); if (pPlayer && (!bOnlyAlive || pPlayer->isAlive()) && (bCanBeGamemaster || !pPlayer->isGameMaster())) @@ -156,7 +155,7 @@ GameObject* ScriptedInstance::GetSingleGameObjectFromStorage(uint32 uiEntry) return instance->GetGameObject(find->second); // Output log, possible reason is not added GO to map, or not yet loaded; - debug_log("SD2: Script requested gameobject with entry %u, but no gameobject of this entry was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); + script_error_log("Script requested gameobject with entry %u, but no gameobject of this entry was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); return NULL; } @@ -170,7 +169,7 @@ Creature* ScriptedInstance::GetSingleCreatureFromStorage(uint32 uiEntry, bool bS // Output log, possible reason is not added GO to map, or not yet loaded; if (!bSkipDebugLog) - debug_log("SD2: Script requested creature with entry %u, but no npc of this entry was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); + script_error_log("Script requested creature with entry %u, but no npc of this entry was created yet, or it was not stored by script for map %u.", uiEntry, instance->GetId()); return NULL; } @@ -187,7 +186,7 @@ void ScriptedInstance::DoStartTimedAchievement(AchievementCriteriaTypes criteria if (!lPlayers.isEmpty()) { - for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { if (Player* pPlayer = itr->getSource()) pPlayer->StartTimedAchievementCriteria(criteriaType, uiTimedCriteriaMiscId); @@ -203,14 +202,14 @@ void ScriptedInstance::DoStartTimedAchievement(AchievementCriteriaTypes criteria @param pDialogueArray The static const array of DialogueEntry holding the information about the dialogue. This array MUST be terminated by {0,0,0} */ DialogueHelper::DialogueHelper(DialogueEntry const* pDialogueArray) : - m_pDialogueArray(pDialogueArray), - m_pDialogueTwoSideArray(NULL), m_pInstance(NULL), + m_pDialogueArray(pDialogueArray), m_pCurrentEntry(NULL), + m_pDialogueTwoSideArray(NULL), m_pCurrentEntryTwoSide(NULL), m_uiTimer(0), - m_bCanSimulate(false), - m_bIsFirstSide(true) + m_bIsFirstSide(true), + m_bCanSimulate(false) {} /** @@ -219,14 +218,14 @@ DialogueHelper::DialogueHelper(DialogueEntry const* pDialogueArray) : @param pDialogueTwoSideArray The static const array of DialogueEntryTwoSide holding the information about the dialogue. This array MUST be terminated by {0,0,0,0,0} */ DialogueHelper::DialogueHelper(DialogueEntryTwoSide const* pDialogueTwoSideArray) : - m_pDialogueArray(NULL), - m_pDialogueTwoSideArray(pDialogueTwoSideArray), m_pInstance(NULL), + m_pDialogueArray(NULL), m_pCurrentEntry(NULL), + m_pDialogueTwoSideArray(pDialogueTwoSideArray), m_pCurrentEntryTwoSide(NULL), m_uiTimer(0), - m_bCanSimulate(false), - m_bIsFirstSide(true) + m_bIsFirstSide(true), + m_bCanSimulate(false) {} /** @@ -266,7 +265,7 @@ void DialogueHelper::StartNextDialogueText(int32 iTextEntry) if (!bFound) { - error_log("SD2: Script call DialogueHelper::StartNextDialogueText, but textEntry %i is not in provided dialogue (on map id %u)", iTextEntry, m_pInstance ? m_pInstance->instance->GetId() : 0); + script_error_log("Script call DialogueHelper::StartNextDialogueText, but textEntry %i is not in provided dialogue (on map id %u)", iTextEntry, m_pInstance ? m_pInstance->instance->GetId() : 0); return; } @@ -277,7 +276,7 @@ void DialogueHelper::StartNextDialogueText(int32 iTextEntry) void DialogueHelper::DoNextDialogueStep() { // Last Dialogue Entry done? - if (m_pCurrentEntry && !m_pCurrentEntry->iTextEntry || m_pCurrentEntryTwoSide && !m_pCurrentEntryTwoSide->iTextEntry) + if ((m_pCurrentEntry && !m_pCurrentEntry->iTextEntry) || (m_pCurrentEntryTwoSide && !m_pCurrentEntryTwoSide->iTextEntry)) { m_uiTimer = 0; return; diff --git a/include/sc_instance.h b/include/sc_instance.h index e1469e5d0..2da2174c1 100644 --- a/include/sc_instance.h +++ b/include/sc_instance.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -21,9 +21,9 @@ enum EncounterState #define OUT_SAVE_INST_DATA_COMPLETE debug_log("SD2: Saving Instance Data for Instance %s (Map %d, Instance Id %d) completed.", instance->GetMapName(), instance->GetId(), instance->GetInstanceId()) #define OUT_LOAD_INST_DATA(a) debug_log("SD2: Loading Instance Data for Instance %s (Map %d, Instance Id %d). Input is '%s'", instance->GetMapName(), instance->GetId(), instance->GetInstanceId(), a) #define OUT_LOAD_INST_DATA_COMPLETE debug_log("SD2: Instance Data Load for Instance %s (Map %d, Instance Id: %d) is complete.", instance->GetMapName(), instance->GetId(), instance->GetInstanceId()) -#define OUT_LOAD_INST_DATA_FAIL error_log("SD2: Unable to load Instance Data for Instance %s (Map %d, Instance Id: %d).", instance->GetMapName(), instance->GetId(), instance->GetInstanceId()) +#define OUT_LOAD_INST_DATA_FAIL script_error_log("Unable to load Instance Data for Instance %s (Map %d, Instance Id: %d).", instance->GetMapName(), instance->GetId(), instance->GetInstanceId()) -class MANGOS_DLL_DECL ScriptedInstance : public InstanceData +class ScriptedInstance : public InstanceData { public: ScriptedInstance(Map* pMap) : InstanceData(pMap) {} @@ -63,12 +63,13 @@ class MANGOS_DLL_DECL ScriptedInstance : public InstanceData protected: // Storage for GO-Guids and NPC-Guids + typedef std::map EntryGuidMap; EntryGuidMap m_mGoEntryGuidStore; ///< Store unique GO-Guids by entry EntryGuidMap m_mNpcEntryGuidStore; ///< Store unique NPC-Guids by entry }; // Class for world maps (May need additional zone-wide functions later on) -class MANGOS_DLL_DECL ScriptedMap : public ScriptedInstance +class ScriptedMap : public ScriptedInstance { public: ScriptedMap(Map* pMap) : ScriptedInstance(pMap) {} @@ -112,9 +113,9 @@ class DialogueHelper protected: /// Will be called when a dialogue step was done - virtual void JustDidDialogueStep(int32 iEntry) {} + virtual void JustDidDialogueStep(int32 /*iEntry*/) {} /// Will be called to get a speaker, MUST be implemented if not used in instances - virtual Creature* GetSpeakerByEntry(uint32 uiEntry) { return NULL; } + virtual Creature* GetSpeakerByEntry(uint32 /*uiEntry*/) { return NULL; } private: void DoNextDialogueStep(); diff --git a/patches/MaNGOS-11167-ScriptDev2.patch b/patches/MaNGOS-11167-ScriptDev2.patch deleted file mode 100644 index c0388de94..000000000 --- a/patches/MaNGOS-11167-ScriptDev2.patch +++ /dev/null @@ -1,22 +0,0 @@ -From bdaa99630113b7cb9d5e564a5777497d7530b490 Mon Sep 17 00:00:00 2001 -From: VladimirMangos -Date: Tue, 15 Feb 2011 02:15:26 +0100 -Subject: [PATCH] ScriptDev2 patch - ---- - src/bindings/CMakeLists.txt | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt -index fc13e3a..592d773 100644 ---- a/src/bindings/CMakeLists.txt -+++ b/src/bindings/CMakeLists.txt -@@ -16,4 +16,4 @@ - # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - # - --# add_subdirectory(universal) -+add_subdirectory(ScriptDev2) --- -1.7.3.1.msysgit.0 - diff --git a/scriptVC80.sln b/scriptVC110.sln similarity index 87% rename from scriptVC80.sln rename to scriptVC110.sln index 420b4d657..3f7645b70 100644 --- a/scriptVC80.sln +++ b/scriptVC110.sln @@ -1,6 +1,6 @@ -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScriptDev2", "VC80\80ScriptDev2.vcproj", "{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScriptDev2", "VC110\110ScriptDev2.vcxproj", "{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/scriptVC90.sln b/scriptVC120.sln similarity index 87% rename from scriptVC90.sln rename to scriptVC120.sln index 9507f49df..e44c9add3 100644 --- a/scriptVC90.sln +++ b/scriptVC120.sln @@ -1,6 +1,6 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScriptDev2", "VC90\90ScriptDev2.vcproj", "{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScriptDev2", "VC120\120ScriptDev2.vcxproj", "{4295C8A9-79B7-4354-8064-F05FB9CA0C96}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/scriptdev2.conf.dist.in b/scriptdev2.conf.dist.in index b25d9d9df..a97fde04f 100644 --- a/scriptdev2.conf.dist.in +++ b/scriptdev2.conf.dist.in @@ -2,7 +2,7 @@ # This file must be placed within the directory which holds mangosd.conf and realmd.conf [ScriptDev2Conf] -ConfVersion=2010062001 +ConfVersion=2012112301 # Database connection settings for the world server. # Default: hostname;port;username;password;database @@ -11,3 +11,6 @@ ConfVersion=2010062001 # .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux # Unix sockets: experimental, not tested ScriptDev2DatabaseInfo = "127.0.0.1;3306;mangos;mangos;scriptdev2" + +# Log File for SD2-Errors +SD2ErrorLogFile = "SD2Errors.log" diff --git a/scripts/battlegrounds/battleground.cpp b/scripts/battlegrounds/battleground.cpp index eb95391a0..146debd2b 100644 --- a/scripts/battlegrounds/battleground.cpp +++ b/scripts/battlegrounds/battleground.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -45,22 +45,24 @@ enum SPELL_WAITING_TO_RESURRECT = 2584 // players who cancel this aura don't want a resurrection }; -struct MANGOS_DLL_DECL npc_spirit_guideAI : public ScriptedAI +struct npc_spirit_guideAI : public ScriptedAI { - npc_spirit_guideAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() + npc_spirit_guideAI(Creature* pCreature) : ScriptedAI(pCreature) { + pCreature->SetActiveObjectState(true); + Reset(); } - void UpdateAI(const uint32 uiDiff) + void Reset() override {} + + void UpdateAI(const uint32 /*uiDiff*/) override { // auto cast the whole time this spell if (!m_creature->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) m_creature->CastSpell(m_creature, SPELL_SPIRIT_HEAL_CHANNEL, false); } - void CorpseRemoved(uint32 &) + void CorpseRemoved(uint32&) override { // TODO: would be better to cast a dummy spell Map* pMap = m_creature->GetMap(); @@ -68,9 +70,9 @@ struct MANGOS_DLL_DECL npc_spirit_guideAI : public ScriptedAI if (!pMap || !pMap->IsBattleGround()) return; - Map::PlayerList const &PlayerList = pMap->GetPlayers(); + Map::PlayerList const& PlayerList = pMap->GetPlayers(); - for(Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) { Player* pPlayer = itr->getSource(); if (!pPlayer || !pPlayer->IsWithinDistInMap(m_creature, 20.0f) || !pPlayer->HasAura(SPELL_WAITING_TO_RESURRECT)) @@ -81,15 +83,15 @@ struct MANGOS_DLL_DECL npc_spirit_guideAI : public ScriptedAI } } - void SpellHitTarget (Unit* pUnit, const SpellEntry* pSpellEntry) + void SpellHitTarget(Unit* pUnit, const SpellEntry* pSpellEntry) override { if (pSpellEntry->Id == SPELL_SPIRIT_HEAL && pUnit->GetTypeId() == TYPEID_PLAYER - && pUnit->HasAura(SPELL_WAITING_TO_RESURRECT)) + && pUnit->HasAura(SPELL_WAITING_TO_RESURRECT)) pUnit->CastSpell(pUnit, SPELL_SPIRIT_HEAL_MANA, true); } }; -bool GossipHello_npc_spirit_guide(Player* pPlayer, Creature* pCreature) +bool GossipHello_npc_spirit_guide(Player* pPlayer, Creature* /*pCreature*/) { pPlayer->CastSpell(pPlayer, SPELL_WAITING_TO_RESURRECT, true); return true; diff --git a/scripts/eastern_kingdoms/alterac_mountains.cpp b/scripts/eastern_kingdoms/alterac_mountains.cpp index d2f182b11..0d2f6e40c 100644 --- a/scripts/eastern_kingdoms/alterac_mountains.cpp +++ b/scripts/eastern_kingdoms/alterac_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,6 @@ EndContentData */ #include "precompiled.h" -/*void AddSC_alterac_mountains() +void AddSC_alterac_mountains() { - Script* pNewScript; -}*/ +} diff --git a/scripts/eastern_kingdoms/arathi_highlands.cpp b/scripts/eastern_kingdoms/arathi_highlands.cpp index 4bf7206fe..d1c9ef06a 100644 --- a/scripts/eastern_kingdoms/arathi_highlands.cpp +++ b/scripts/eastern_kingdoms/arathi_highlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,12 +17,13 @@ /* ScriptData SDName: Arathi Highlands SD%Complete: 100 -SDComment: Quest support: 665 +SDComment: Quest support: 660, 665 SDCategory: Arathi Highlands EndScriptData */ /* ContentData npc_professor_phizzlethorpe +npc_kinelory EndContentData */ #include "precompiled.h" @@ -49,27 +50,27 @@ enum ENTRY_VENGEFUL_SURGE = 2776 }; -struct MANGOS_DLL_DECL npc_professor_phizzlethorpeAI : public npc_escortAI +struct npc_professor_phizzlethorpeAI : public npc_escortAI { npc_professor_phizzlethorpeAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(uiPointId) + switch (uiPointId) { case 4: DoScriptText(SAY_PROGRESS_2, m_creature, pPlayer); break; case 5: DoScriptText(SAY_PROGRESS_3, m_creature, pPlayer); break; case 8: DoScriptText(EMOTE_PROGRESS_4, m_creature); break; case 9: - m_creature->SummonCreature(ENTRY_VENGEFUL_SURGE, -2056.41f, -2144.01f, 20.59f, 5.70f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000); - m_creature->SummonCreature(ENTRY_VENGEFUL_SURGE, -2050.17f, -2140.02f, 19.54f, 5.17f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000); + m_creature->SummonCreature(ENTRY_VENGEFUL_SURGE, -2056.41f, -2144.01f, 20.59f, 5.70f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 600000); + m_creature->SummonCreature(ENTRY_VENGEFUL_SURGE, -2050.17f, -2140.02f, 19.54f, 5.17f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 600000); break; case 10: DoScriptText(SAY_PROGRESS_5, m_creature, pPlayer); break; case 11: @@ -85,12 +86,12 @@ struct MANGOS_DLL_DECL npc_professor_phizzlethorpeAI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } @@ -100,7 +101,7 @@ bool QuestAccept_npc_professor_phizzlethorpe(Player* pPlayer, Creature* pCreatur { if (pQuest->GetQuestId() == QUEST_SUNKEN_TREASURE) { - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_PROGRESS_1, pCreature, pPlayer); if (npc_professor_phizzlethorpeAI* pEscortAI = dynamic_cast(pCreature->AI())) @@ -114,6 +115,138 @@ CreatureAI* GetAI_npc_professor_phizzlethorpe(Creature* pCreature) return new npc_professor_phizzlethorpeAI(pCreature); } +/*###### +## npc_kinelory +######*/ + +enum +{ + SAY_START = -1000948, + SAY_REACH_BOTTOM = -1000949, + SAY_AGGRO_KINELORY = -1000950, + SAY_AGGRO_JORELL = -1000951, + SAY_WATCH_BACK = -1000952, + EMOTE_BELONGINGS = -1000953, + SAY_DATA_FOUND = -1000954, + SAY_ESCAPE = -1000955, + SAY_FINISH = -1000956, + EMOTE_HAND_PACK = -1000957, + + SPELL_REJUVENATION = 3627, + SPELL_BEAR_FORM = 4948, + + NPC_JORELL = 2733, + NPC_QUAE = 2712, + + QUEST_HINTS_NEW_PLAGUE = 660 +}; + +struct npc_kineloryAI : public npc_escortAI +{ + npc_kineloryAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiBearFormTimer; + uint32 m_uiHealTimer; + + void Reset() override + { + m_uiBearFormTimer = urand(5000, 7000); + m_uiHealTimer = urand(2000, 5000); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 9: + DoScriptText(SAY_REACH_BOTTOM, m_creature); + break; + case 16: + DoScriptText(SAY_WATCH_BACK, m_creature); + DoScriptText(EMOTE_BELONGINGS, m_creature); + break; + case 17: + DoScriptText(SAY_DATA_FOUND, m_creature); + break; + case 18: + DoScriptText(SAY_ESCAPE, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + SetRun(); + break; + case 33: + DoScriptText(SAY_FINISH, m_creature); + if (Creature* pQuae = GetClosestCreatureWithEntry(m_creature, NPC_QUAE, 10.0f)) + { + DoScriptText(EMOTE_HAND_PACK, m_creature, pQuae); + m_creature->SetFacingToObject(pQuae); + } + break; + case 34: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_HINTS_NEW_PLAGUE, m_creature); + break; + } + } + + void Aggro(Unit* pWho) override + { + if (pWho->GetEntry() == NPC_JORELL) + DoScriptText(SAY_AGGRO_JORELL, pWho, m_creature); + else if (roll_chance_i(10)) + DoScriptText(SAY_AGGRO_KINELORY, m_creature); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_START, m_creature); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue), true); + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBearFormTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BEAR_FORM) == CAST_OK) + m_uiBearFormTimer = urand(25000, 30000); + } + else + m_uiBearFormTimer -= uiDiff; + + if (m_uiHealTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(40.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_REJUVENATION) == CAST_OK) + m_uiHealTimer = urand(15000, 25000); + } + } + else + m_uiHealTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_kinelory(Creature* pCreature) +{ + return new npc_kineloryAI(pCreature); +} + +bool QuestAccept_npc_kinelory(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_HINTS_NEW_PLAGUE) + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + void AddSC_arathi_highlands() { Script* pNewScript; @@ -123,4 +256,10 @@ void AddSC_arathi_highlands() pNewScript->GetAI = &GetAI_npc_professor_phizzlethorpe; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_professor_phizzlethorpe; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_kinelory"; + pNewScript->GetAI = &GetAI_npc_kinelory; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kinelory; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp b/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp index 6332c0fdf..eb2373590 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Blackrock_Depths SD%Complete: 80 -SDComment: Quest support: 4001, 4342, 7604, 9015. Vendor Lokhtos Darkbargainer. +SDComment: Quest support: 4001, 4322, 4342, 7604, 9015. SDCategory: Blackrock Depths EndScriptData */ @@ -26,9 +26,11 @@ go_shadowforge_brazier go_relic_coffer_door at_ring_of_law npc_grimstone -mob_phalanx npc_kharan_mighthammer -npc_lokhtos_darkbargainer +npc_marshal_windsor +npc_dughal_stormwing +npc_tobias_seecher +boss_doomrel EndContentData */ #include "precompiled.h" @@ -39,7 +41,7 @@ EndContentData */ ## go_shadowforge_brazier ######*/ -bool GOUse_go_shadowforge_brazier(Player* pPlayer, GameObject* pGo) +bool GOUse_go_shadowforge_brazier(Player* /*pPlayer*/, GameObject* pGo) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) { @@ -55,7 +57,7 @@ bool GOUse_go_shadowforge_brazier(Player* pPlayer, GameObject* pGo) ## go_relic_coffer_door ######*/ -bool GOUse_go_relic_coffer_door(Player* pPlayer, GameObject* pGo) +bool GOUse_go_relic_coffer_door(Player* /*pPlayer*/, GameObject* pGo) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) { @@ -90,19 +92,20 @@ enum NPC_GRIMSTONE = 10096, DATA_BANNER_BEFORE_EVENT = 5, - //4 or 6 in total? 1+2+1 / 2+2+2 / 3+3. Depending on this, code should be changed. + // 4 or 6 in total? 1+2+1 / 2+2+2 / 3+3. Depending on this, code should be changed. MAX_MOB_AMOUNT = 4, MAX_THELDREN_ADDS = 4, MAX_POSSIBLE_THELDREN_ADDS = 8, SPELL_SUMMON_THELRIN_DND = 27517, - /* Other spells used by Grimstone - SPELL_ASHCROMBES_TELEPORT_A = 15742 + // Other spells used by Grimstone + SPELL_ASHCROMBES_TELEPORT_A = 15742, SPELL_ASHCROMBES_TELEPORT_B = 6422, SPELL_ARENA_FLASH_A = 15737, SPELL_ARENA_FLASH_B = 15739, - */ - + SPELL_ARENA_FLASH_C = 15740, + SPELL_ARENA_FLASH_D = 15741, + QUEST_THE_CHALLENGE = 9015, NPC_THELDREN_QUEST_CREDIT = 16166, }; @@ -156,7 +159,7 @@ bool AreaTrigger_at_ring_of_law(Player* pPlayer, AreaTriggerEntry const* pAt) ## npc_grimstone ######*/ -struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI +struct npc_grimstoneAI : public npc_escortAI { npc_grimstoneAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -188,9 +191,10 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI uint32 m_uiGladiatorId[MAX_THELDREN_ADDS]; - GUIDList m_lSummonedGUIDList; + GuidList m_lSummonedGUIDList; + GuidSet m_lArenaCrowd; - void Reset() + void Reset() override { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -201,7 +205,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI m_uiPhase = PHASE_MOBS; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (!m_pInstance) return; @@ -218,7 +222,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI void DoChallengeQuestCredit() { - Map::PlayerList const &PlayerList = m_creature->GetMap()->GetPlayers(); + Map::PlayerList const& PlayerList = m_creature->GetMap()->GetPlayers(); for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) { @@ -228,7 +232,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override { ++m_uiMobDeadCount; @@ -268,12 +272,12 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: // Middle reached first time - DoScriptText(urand(0, 1) ? SAY_START_1 : SAY_START_2, m_creature); + DoScriptText(SAY_START_1, m_creature); SetEscortPaused(true); m_uiEventTimer = 5000; break; @@ -286,7 +290,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI SetEscortPaused(true); break; case 3: // Middle reached second time - DoScriptText(urand(0, 1) ? SAY_SUMMON_BOSS_1 : SAY_SUMMON_BOSS_2, m_creature); + DoScriptText(SAY_SUMMON_BOSS_1, m_creature); break; case 4: // Reached North Gate DoScriptText(SAY_OPEN_NORTH_GATE, m_creature); @@ -303,7 +307,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_pInstance) return; @@ -311,7 +315,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI if (m_pInstance->GetData(TYPE_RING_OF_LAW) == FAIL) { // Reset Doors - if (m_uiEventPhase >= 9) // North Gate is opened + if (m_uiEventPhase >= 10) // North Gate is opened { m_pInstance->DoUseDoorOrButton(GO_ARENA_2); m_pInstance->DoUseDoorOrButton(GO_ARENA_4); @@ -323,7 +327,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI } // Despawn Summoned Mobs - for (GUIDList::const_iterator itr = m_lSummonedGUIDList.begin(); itr != m_lSummonedGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lSummonedGUIDList.begin(); itr != m_lSummonedGUIDList.end(); ++itr) { if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) pSummoned->ForcedDespawn(); @@ -339,12 +343,24 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI { if (m_uiEventTimer <= uiDiff) { - switch(m_uiEventPhase) + switch (m_uiEventPhase) { case 0: // Shortly after spawn, start walking - //DoScriptText(-1000000, m_creature); // no more text on spawn + m_creature->CastSpell(m_creature, SPELL_ASHCROMBES_TELEPORT_A, true); + DoScriptText(SAY_START_2, m_creature); m_pInstance->DoUseDoorOrButton(GO_ARENA_4); + // Some of the NPCs in the crowd do cheer emote at event start + // we randomly select 25% of the NPCs to do this + m_pInstance->GetArenaCrowdGuid(m_lArenaCrowd); + for (GuidSet::const_iterator itr = m_lArenaCrowd.begin(); itr != m_lArenaCrowd.end(); ++itr) + { + if (Creature* pSpectator = m_creature->GetMap()->GetCreature(*itr)) + { + if (urand(0, 1) < 0.25) + pSpectator->HandleEmote(EMOTE_ONESHOT_CHEER); + } + } Start(false); SetEscortPaused(false); m_uiEventTimer = 0; @@ -359,41 +375,56 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI break; case 3: // Open East Gate + m_creature->CastSpell(m_creature, SPELL_ARENA_FLASH_A, true); + m_creature->CastSpell(m_creature, SPELL_ARENA_FLASH_B, true); m_pInstance->DoUseDoorOrButton(GO_ARENA_1); m_uiEventTimer = 3000; break; case 4: - SetEscortPaused(false); + // timer for teleport out spell which has 2000 ms cast time + m_creature->CastSpell(m_creature, SPELL_ASHCROMBES_TELEPORT_B, true); + m_uiEventTimer = 2500; + break; + case 5: m_creature->SetVisibility(VISIBILITY_OFF); + SetEscortPaused(false); // Summon Ring Mob(s) SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); m_uiEventTimer = 8000; break; - case 5: + case 6: // Summon Ring Mob(s) SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); m_uiEventTimer = 8000; break; - case 6: + case 7: // Summon Ring Mob(s) SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); m_uiEventTimer = 0; break; - case 7: + case 8: // Summoned Mobs are dead, continue event + DoScriptText(SAY_SUMMON_BOSS_2, m_creature); m_creature->SetVisibility(VISIBILITY_ON); + m_creature->CastSpell(m_creature, SPELL_ASHCROMBES_TELEPORT_A, true); m_pInstance->DoUseDoorOrButton(GO_ARENA_1); - //DoScriptText(-1000000, m_creature); // after killed the mobs, no say here SetEscortPaused(false); m_uiEventTimer = 0; break; - case 8: + case 9: // Open North Gate + m_creature->CastSpell(m_creature, SPELL_ARENA_FLASH_C, true); + m_creature->CastSpell(m_creature, SPELL_ARENA_FLASH_D, true); m_pInstance->DoUseDoorOrButton(GO_ARENA_2); m_uiEventTimer = 5000; break; - case 9: + case 10: + // timer for teleport out spell which has 2000 ms cast time + m_creature->CastSpell(m_creature, SPELL_ASHCROMBES_TELEPORT_B, true); + m_uiEventTimer = 2500; + break; + case 11: // Summon Boss m_creature->SetVisibility(VISIBILITY_OFF); // If banner summoned after start, then summon Thelden after the creatures are dead @@ -411,7 +442,7 @@ struct MANGOS_DLL_DECL npc_grimstoneAI : public npc_escortAI } m_uiEventTimer = 0; break; - case 10: + case 12: // Boss dead m_lSummonedGUIDList.clear(); m_pInstance->DoUseDoorOrButton(GO_ARENA_2); @@ -434,89 +465,19 @@ CreatureAI* GetAI_npc_grimstone(Creature* pCreature) return new npc_grimstoneAI(pCreature); } -bool EffectDummyCreature_spell_banner_of_provocation(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_spell_banner_of_provocation(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiSpellId == SPELL_SUMMON_THELRIN_DND && uiEffIndex != EFFECT_INDEX_0) { instance_blackrock_depths* pInstance = (instance_blackrock_depths*)pCreatureTarget->GetInstanceData(); if (pInstance && pInstance->GetData(TYPE_RING_OF_LAW) != DONE && pInstance->GetData(TYPE_RING_OF_LAW) != SPECIAL) - pInstance->SetData(TYPE_RING_OF_LAW, pInstance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS ? SPECIAL : DATA_BANNER_BEFORE_EVENT); + pInstance->SetData(TYPE_RING_OF_LAW, pInstance->GetData(TYPE_RING_OF_LAW) == IN_PROGRESS ? uint32(SPECIAL) : uint32(DATA_BANNER_BEFORE_EVENT)); return true; } return false; } -/*###### -## mob_phalanx -######*/ - -enum -{ - SPELL_THUNDERCLAP = 15588, - SPELL_FIREBALLVOLLEY = 15285, - SPELL_MIGHTYBLOW = 14099 -}; - -struct MANGOS_DLL_DECL mob_phalanxAI : public ScriptedAI -{ - mob_phalanxAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiThunderClapTimer; - uint32 m_uiFireballVolleyTimer; - uint32 m_uiMightyBlowTimer; - - void Reset() - { - m_uiThunderClapTimer = 12000; - m_uiFireballVolleyTimer = 0; - m_uiMightyBlowTimer = 15000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // ThunderClap - if (m_uiThunderClapTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_THUNDERCLAP); - m_uiThunderClapTimer = 10000; - } - else - m_uiThunderClapTimer -= uiDiff; - - // FireballVolley - if (m_creature->GetHealthPercent() < 51.0f) - { - if (m_uiFireballVolleyTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALLVOLLEY); - m_uiFireballVolleyTimer = 15000; - } - else - m_uiFireballVolleyTimer -= uiDiff; - } - - // MightyBlow - if (m_uiMightyBlowTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTYBLOW); - m_uiMightyBlowTimer = 10000; - } - else - m_uiMightyBlowTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_phalanx(Creature* pCreature) -{ - return new mob_phalanxAI(pCreature); -} - /*###### ## npc_kharan_mighthammer ######*/ @@ -544,10 +505,10 @@ bool GossipHello_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(QUEST_WHAT_IS_GOING_ON) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); if (pPlayer->GetQuestStatus(QUEST_KHARANS_TALE) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); if (pPlayer->GetTeam() == HORDE) pPlayer->SEND_GOSSIP_MENU(2473, pCreature->GetObjectGuid()); @@ -557,41 +518,41 @@ bool GossipHello_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(2475, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); pPlayer->SEND_GOSSIP_MENU(2476, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); pPlayer->SEND_GOSSIP_MENU(2477, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); pPlayer->SEND_GOSSIP_MENU(2478, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); pPlayer->SEND_GOSSIP_MENU(2479, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_8, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_8, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); pPlayer->SEND_GOSSIP_MENU(2480, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_9, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+8); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_9, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); pPlayer->SEND_GOSSIP_MENU(2481, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+8: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_10, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KHARAN_10, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); pPlayer->SEND_GOSSIP_MENU(2482, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+9: @@ -605,62 +566,6 @@ bool GossipSelect_npc_kharan_mighthammer(Player* pPlayer, Creature* pCreature, u return true; } -/*###### -## npc_lokhtos_darkbargainer -######*/ - -enum -{ - FACTION_THORIUM_BROTHERHOOD = 59, - - ITEM_THRORIUM_BROTHERHOOD_CONTRACT = 18628, - ITEM_SULFURON_INGOT = 17203, - - QUEST_A_BINDING_CONTRACT = 7604, - - SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT = 23059 -}; - -#define GOSSIP_ITEM_SHOW_ACCESS "Show me what I have access to, Lothos." -#define GOSSIP_ITEM_GET_CONTRACT "Get Thorium Brotherhood Contract" - -bool GossipHello_npc_lokhtos_darkbargainer(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pCreature->isVendor() && pPlayer->GetReputationRank(FACTION_THORIUM_BROTHERHOOD) >= REP_FRIENDLY) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_ITEM_SHOW_ACCESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if (!pPlayer->GetQuestRewardStatus(QUEST_A_BINDING_CONTRACT) && - !pPlayer->HasItemCount(ITEM_THRORIUM_BROTHERHOOD_CONTRACT, 1, true) && - pPlayer->HasItemCount(ITEM_SULFURON_INGOT, 1)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GET_CONTRACT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - } - - if (pPlayer->GetReputationRank(FACTION_THORIUM_BROTHERHOOD) < REP_FRIENDLY) - pPlayer->SEND_GOSSIP_MENU(3673, pCreature->GetObjectGuid()); - else - pPlayer->SEND_GOSSIP_MENU(3677, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_lokhtos_darkbargainer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT, false); - } - - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - /*###### ## npc_rocknot ######*/ @@ -674,7 +579,7 @@ enum QUEST_ALE = 4295 }; -struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI +struct npc_rocknotAI : public npc_escortAI { npc_rocknotAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -687,7 +592,7 @@ struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI uint32 m_uiBreakKegTimer; uint32 m_uiBreakDoorTimer; - void Reset() + void Reset() override { if (HasEscortState(STATE_ESCORT_ESCORTING)) return; @@ -702,12 +607,12 @@ struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI pGo->SetGoState(GOState(state)); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { if (!m_pInstance) return; - switch(uiPointId) + switch (uiPointId) { case 1: m_creature->HandleEmote(EMOTE_ONESHOT_KICK); @@ -728,7 +633,7 @@ struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_pInstance) return; @@ -750,11 +655,11 @@ struct MANGOS_DLL_DECL npc_rocknotAI : public npc_escortAI if (m_uiBreakDoorTimer <= uiDiff) { DoGo(GO_BAR_DOOR, 2); - DoGo(GO_BAR_KEG_TRAP, 0); //doesn't work very well, leaving code here for future - //spell by trap has effect61, this indicate the bar go hostile + DoGo(GO_BAR_KEG_TRAP, 0); // doesn't work very well, leaving code here for future + // spell by trap has effect61, this indicate the bar go hostile if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_PHALANX)) - pTmp->setFaction(14); + pTmp->SetFactionTemporary(14, TEMPFACTION_NONE); // for later, this event(s) has alot more to it. // optionally, DONE can trigger bar to go hostile. @@ -773,7 +678,7 @@ CreatureAI* GetAI_npc_rocknot(Creature* pCreature) return new npc_rocknotAI(pCreature); } -bool QuestRewarded_npc_rocknot(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool QuestRewarded_npc_rocknot(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) { ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); @@ -786,9 +691,9 @@ bool QuestRewarded_npc_rocknot(Player* pPlayer, Creature* pCreature, Quest const if (pQuest->GetQuestId() == QUEST_ALE) { if (pInstance->GetData(TYPE_BAR) != IN_PROGRESS) - pInstance->SetData(TYPE_BAR,IN_PROGRESS); + pInstance->SetData(TYPE_BAR, IN_PROGRESS); - pInstance->SetData(TYPE_BAR,SPECIAL); + pInstance->SetData(TYPE_BAR, SPECIAL); // keep track of amount in instance script, returns SPECIAL if amount ok and event in progress if (pInstance->GetData(TYPE_BAR) == SPECIAL) @@ -804,6 +709,372 @@ bool QuestRewarded_npc_rocknot(Player* pPlayer, Creature* pCreature, Quest const return true; } +/*###### +## npc_marshal_windsor +######*/ + +enum +{ + // Windsor texts + SAY_WINDSOR_AGGRO1 = -1230011, + SAY_WINDSOR_AGGRO2 = -1230012, + SAY_WINDSOR_AGGRO3 = -1230013, + SAY_WINDSOR_START = -1230014, + SAY_WINDSOR_CELL_DUGHAL_1 = -1230015, + SAY_WINDSOR_CELL_DUGHAL_3 = -1230016, + SAY_WINDSOR_EQUIPMENT_1 = -1230017, + SAY_WINDSOR_EQUIPMENT_2 = -1230018, + SAY_WINDSOR_EQUIPMENT_3 = -1230019, + SAY_WINDSOR_EQUIPMENT_4 = -1230020, + SAY_WINDSOR_CELL_JAZ_1 = -1230021, + SAY_WINDSOR_CELL_JAZ_2 = -1230022, + SAY_WINDSOR_CELL_SHILL_1 = -1230023, + SAY_WINDSOR_CELL_SHILL_2 = -1230024, + SAY_WINDSOR_CELL_SHILL_3 = -1230025, + SAY_WINDSOR_CELL_CREST_1 = -1230026, + SAY_WINDSOR_CELL_CREST_2 = -1230027, + SAY_WINDSOR_CELL_TOBIAS_1 = -1230028, + SAY_WINDSOR_CELL_TOBIAS_2 = -1230029, + SAY_WINDSOR_FREE_1 = -1230030, + SAY_WINDSOR_FREE_2 = -1230031, + + // Additional gossips + SAY_DUGHAL_FREE = -1230010, + GOSSIP_ID_DUGHAL = -3230000, + GOSSIP_TEXT_ID_DUGHAL = 2846, + + SAY_TOBIAS_FREE_1 = -1230032, + SAY_TOBIAS_FREE_2 = -1230033, + GOSSIP_ID_TOBIAS = -3230001, + GOSSIP_TEXT_ID_TOBIAS = 2847, + + NPC_REGINALD_WINDSOR = 9682, + + QUEST_JAIL_BREAK = 4322 +}; + +struct npc_marshal_windsorAI : public npc_escortAI +{ + npc_marshal_windsorAI(Creature* m_creature) : npc_escortAI(m_creature) + { + m_pInstance = (instance_blackrock_depths*)m_creature->GetInstanceData(); + Reset(); + } + + instance_blackrock_depths* m_pInstance; + + uint8 m_uiEventPhase; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_uiEventPhase = 0; + } + + void Aggro(Unit* pWho) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_WINDSOR_AGGRO1, m_creature, pWho); break; + case 1: DoScriptText(SAY_WINDSOR_AGGRO2, m_creature); break; + case 2: DoScriptText(SAY_WINDSOR_AGGRO3, m_creature, pWho); break; + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 1: + if (m_pInstance) + m_pInstance->SetData(TYPE_QUEST_JAIL_BREAK, IN_PROGRESS); + + DoScriptText(SAY_WINDSOR_START, m_creature); + break; + case 7: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_WINDSOR_CELL_DUGHAL_1, m_creature, pPlayer); + if (m_pInstance) + { + if (Creature* pDughal = m_pInstance->GetSingleCreatureFromStorage(NPC_DUGHAL)) + { + pDughal->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetFacingToObject(pDughal); + } + } + ++m_uiEventPhase; + SetEscortPaused(true); + break; + case 9: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_WINDSOR_CELL_DUGHAL_3, m_creature, pPlayer); + break; + case 14: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_WINDSOR_EQUIPMENT_1, m_creature, pPlayer); + break; + case 15: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_USESTANDING); + break; + case 16: + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_JAIL_DOOR_SUPPLY); + break; + case 18: + DoScriptText(SAY_WINDSOR_EQUIPMENT_2, m_creature); + break; + case 19: + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_USESTANDING); + break; + case 20: + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_JAIL_SUPPLY_CRATE); + break; + case 21: + m_creature->UpdateEntry(NPC_REGINALD_WINDSOR); + break; + case 22: + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_WINDSOR_EQUIPMENT_3, m_creature, pPlayer); + m_creature->SetFacingToObject(pPlayer); + } + break; + case 23: + DoScriptText(SAY_WINDSOR_EQUIPMENT_4, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + break; + case 30: + if (m_pInstance) + { + if (Creature* pJaz = m_pInstance->GetSingleCreatureFromStorage(NPC_JAZ)) + m_creature->SetFacingToObject(pJaz); + } + DoScriptText(SAY_WINDSOR_CELL_JAZ_1, m_creature); + ++m_uiEventPhase; + SetEscortPaused(true); + break; + case 32: + DoScriptText(SAY_WINDSOR_CELL_JAZ_2, m_creature); + break; + case 35: + if (m_pInstance) + { + if (Creature* pShill = m_pInstance->GetSingleCreatureFromStorage(NPC_SHILL)) + m_creature->SetFacingToObject(pShill); + } + DoScriptText(SAY_WINDSOR_CELL_SHILL_1, m_creature); + ++m_uiEventPhase; + SetEscortPaused(true); + break; + case 37: + DoScriptText(SAY_WINDSOR_CELL_SHILL_2, m_creature); + break; + case 38: + DoScriptText(SAY_WINDSOR_CELL_SHILL_3, m_creature); + break; + case 45: + if (m_pInstance) + { + if (Creature* pCrest = m_pInstance->GetSingleCreatureFromStorage(NPC_CREST)) + m_creature->SetFacingToObject(pCrest); + } + DoScriptText(SAY_WINDSOR_CELL_CREST_1, m_creature); + ++m_uiEventPhase; + SetEscortPaused(true); + break; + case 47: + DoScriptText(SAY_WINDSOR_CELL_CREST_2, m_creature); + break; + case 49: + DoScriptText(SAY_WINDSOR_CELL_TOBIAS_1, m_creature); + if (m_pInstance) + { + if (Creature* pTobias = m_pInstance->GetSingleCreatureFromStorage(NPC_TOBIAS)) + { + pTobias->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetFacingToObject(pTobias); + } + } + ++m_uiEventPhase; + SetEscortPaused(true); + break; + case 51: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_WINDSOR_CELL_TOBIAS_2, m_creature, pPlayer); + break; + case 57: + DoScriptText(SAY_WINDSOR_FREE_1, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + break; + case 58: + DoScriptText(SAY_WINDSOR_FREE_2, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_QUEST_JAIL_BREAK, DONE); + + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_JAIL_BREAK, m_creature); + break; + } + } + + void UpdateEscortAI(const uint32 /*uiDiff*/) override + { + // Handle escort resume events + if (m_pInstance && m_pInstance->GetData(TYPE_QUEST_JAIL_BREAK) == SPECIAL) + { + switch (m_uiEventPhase) + { + case 1: // Dughal + case 3: // Ograbisi + case 4: // Crest + case 5: // Shill + case 6: // Tobias + SetEscortPaused(false); + break; + case 2: // Jaz + ++m_uiEventPhase; + break; + } + + m_pInstance->SetData(TYPE_QUEST_JAIL_BREAK, IN_PROGRESS); + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_marshal_windsor(Creature* pCreature) +{ + return new npc_marshal_windsorAI(pCreature); +} + +bool QuestAccept_npc_marshal_windsor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_JAIL_BREAK) + { + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + + if (npc_marshal_windsorAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest); + + return true; + } + + return false; +} + +/*###### +## npc_dughal_stormwing +######*/ + +bool GossipHello_npc_dughal_stormwing(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_JAIL_BREAK) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ID_DUGHAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_DUGHAL, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_dughal_stormwing(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + // Set instance data in order to allow the quest to continue + if (instance_blackrock_depths* pInstance = (instance_blackrock_depths*)pCreature->GetInstanceData()) + pInstance->SetData(TYPE_QUEST_JAIL_BREAK, SPECIAL); + + DoScriptText(SAY_DUGHAL_FREE, pCreature, pPlayer); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + pCreature->SetWalk(false); + pCreature->GetMotionMaster()->MoveWaypoint(); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## npc_tobias_seecher +######*/ + +bool GossipHello_npc_tobias_seecher(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_JAIL_BREAK) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ID_TOBIAS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_TOBIAS, pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_tobias_seecher(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + // Set instance data in order to allow the quest to continue + if (instance_blackrock_depths* pInstance = (instance_blackrock_depths*)pCreature->GetInstanceData()) + pInstance->SetData(TYPE_QUEST_JAIL_BREAK, SPECIAL); + + DoScriptText(urand(0, 1) ? SAY_TOBIAS_FREE_1 : SAY_TOBIAS_FREE_2, pCreature); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + pCreature->SetWalk(false); + pCreature->GetMotionMaster()->MoveWaypoint(); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## boss_doomrel +######*/ + +enum +{ + SAY_DOOMREL_START_EVENT = -1230003, + GOSSIP_ITEM_CHALLENGE = -3230002, + GOSSIP_TEXT_ID_CHALLENGE = 2601, +}; + +bool GossipHello_boss_doomrel(Player* pPlayer, Creature* pCreature) +{ + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_TOMB_OF_SEVEN) == NOT_STARTED || pInstance->GetData(TYPE_TOMB_OF_SEVEN) == FAIL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CHALLENGE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_CHALLENGE, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_boss_doomrel(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->CLOSE_GOSSIP_MENU(); + DoScriptText(SAY_DOOMREL_START_EVENT, pCreature); + // start event + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + pInstance->SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS); + + break; + } + return true; +} + void AddSC_blackrock_depths() { Script* pNewScript; @@ -833,26 +1104,39 @@ void AddSC_blackrock_depths() pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_banner_of_provocation; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "mob_phalanx"; - pNewScript->GetAI = &GetAI_mob_phalanx; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_kharan_mighthammer"; pNewScript->pGossipHello = &GossipHello_npc_kharan_mighthammer; pNewScript->pGossipSelect = &GossipSelect_npc_kharan_mighthammer; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_lokhtos_darkbargainer"; - pNewScript->pGossipHello = &GossipHello_npc_lokhtos_darkbargainer; - pNewScript->pGossipSelect = &GossipSelect_npc_lokhtos_darkbargainer; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_rocknot"; pNewScript->GetAI = &GetAI_npc_rocknot; pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_rocknot; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_marshal_windsor"; + pNewScript->GetAI = &GetAI_npc_marshal_windsor; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_marshal_windsor; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tobias_seecher"; + pNewScript->pGossipHello = &GossipHello_npc_tobias_seecher; + pNewScript->pGossipSelect = &GossipSelect_npc_tobias_seecher; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dughal_stormwing"; + pNewScript->pGossipHello = &GossipHello_npc_dughal_stormwing; + pNewScript->pGossipSelect = &GossipSelect_npc_dughal_stormwing; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_doomrel"; + pNewScript->pGossipHello = &GossipHello_boss_doomrel; + pNewScript->pGossipSelect = &GossipSelect_boss_doomrel; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h b/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h index 99c01f717..dbea998cb 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h +++ b/scripts/eastern_kingdoms/blackrock_depths/blackrock_depths.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,8 +7,10 @@ enum { - MAX_ENCOUNTER = 6, + MAX_ENCOUNTER = 8, MAX_RELIC_DOORS = 12, + MAX_DWARFS = 7, + MAX_DWARF_RUNES = 7, TYPE_RING_OF_LAW = 1, TYPE_VAULT = 2, @@ -16,20 +18,41 @@ enum TYPE_TOMB_OF_SEVEN = 4, TYPE_LYCEUM = 5, TYPE_IRON_HALL = 6, + TYPE_QUEST_JAIL_BREAK = 7, + TYPE_FLAMELASH = 8, NPC_EMPEROR = 9019, NPC_PRINCESS = 8929, + NPC_PRIESTESS = 10076, NPC_PHALANX = 9502, NPC_HATEREL = 9034, NPC_ANGERREL = 9035, NPC_VILEREL = 9036, NPC_GLOOMREL = 9037, NPC_SEETHREL = 9038, - // NPC_DOOMREL = 9039, + NPC_DOOMREL = 9039, NPC_DOPEREL = 9040, + NPC_MAGMUS = 9938, NPC_WATCHER_DOOMGRIP = 9476, NPC_WARBRINGER_CONST = 8905, // Four of them in Relict Vault are related to Doomgrip summon event + // Jail Break event related + NPC_OGRABISI = 9677, + NPC_SHILL = 9678, + NPC_CREST = 9680, + NPC_JAZ = 9681, + NPC_TOBIAS = 9679, + NPC_DUGHAL = 9022, + + // Arena crowd + NPC_ARENA_SPECTATOR = 8916, + NPC_SHADOWFORGE_PEASANT = 8896, + NPC_SHADOWFORGE_CITIZEN = 8902, + NPC_SHADOWFORGE_SENATOR = 8904, + NPC_ANVILRAGE_SOLDIER = 8893, + NPC_ANVILRAGE_MEDIC = 8894, + NPC_ANVILRAGE_OFFICER = 8895, + GO_ARENA_1 = 161525, GO_ARENA_2 = 161522, GO_ARENA_3 = 161524, @@ -53,10 +76,40 @@ enum GO_CHEST_SEVEN = 169243, GO_ARENA_SPOILS = 181074, GO_SECRET_DOOR = 174553, + GO_SECRET_SAFE = 161495, + + // Jail break event related + GO_JAIL_DOOR_SUPPLY = 170561, + GO_JAIL_SUPPLY_CRATE = 166872, + + GO_DWARFRUNE_A01 = 170578, + GO_DWARFRUNE_B01 = 170579, + GO_DWARFRUNE_C01 = 170580, + GO_DWARFRUNE_D01 = 170581, + GO_DWARFRUNE_E01 = 170582, + GO_DWARFRUNE_F01 = 170583, + GO_DWARFRUNE_G01 = 170584, + + QUEST_ROYAL_RESCUE = 4003, // horde quest + QUEST_FATE_KINGDOM = 4362, // alliance quest SPELL_STONED = 10255, // Aura of Warbringer Constructs in Relict Vault + + FACTION_DWARF_HOSTILE = 754, // Hostile faction for the Tomb of the Seven dwarfs + FACTION_ARENA_NEUTRAL = 15, // Neutral faction for NPC in top of Arena after event complete +}; + +struct ArenaCylinder +{ + float m_fCenterX; + float m_fCenterY; + float m_fCenterZ; + uint32 m_uiRadius; + uint32 m_uiHeight; }; +static const ArenaCylinder aArenaCrowdVolume[] = {595.78f, -188.65f, -38.63f, 69, 10}; + enum ArenaNPCs { // Gladiators @@ -98,39 +151,53 @@ static const uint32 aArenaNPCs[] = // Used to summon Watcher Doomgrip static const float aVaultPositions[4] = {821.905f, -338.382f, -50.134f, 3.78736f}; -class MANGOS_DLL_DECL instance_blackrock_depths : public ScriptedInstance +// Tomb of the Seven dwarfs +static const uint32 aTombDwarfes[MAX_DWARFS] = {NPC_ANGERREL, NPC_SEETHREL, NPC_DOPEREL, NPC_GLOOMREL, NPC_VILEREL, NPC_HATEREL, NPC_DOOMREL}; + +class instance_blackrock_depths : public ScriptedInstance { public: instance_blackrock_depths(Map* pMap); ~instance_blackrock_depths() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); - void OnCreatureEvade(Creature* pCreature); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; // Arena Event void SetArenaCenterCoords(float fX, float fY, float fZ) { m_fArenaCenterX = fX; m_fArenaCenterY = fY; m_fArenaCenterZ = fZ; } - void GetArenaCenterCoords(float &fX, float &fY, float &fZ) { fX = m_fArenaCenterX; fY = m_fArenaCenterY; fZ = m_fArenaCenterZ; } + void GetArenaCenterCoords(float& fX, float& fY, float& fZ) { fX = m_fArenaCenterX; fY = m_fArenaCenterY; fZ = m_fArenaCenterZ; } + void GetArenaCrowdGuid(GuidSet& sCrowdSet) { sCrowdSet = m_sArenaCrowdNpcGuids; } private: + void DoCallNextDwarf(); + bool CanReplacePrincess(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; uint32 m_uiBarAleCount; uint8 m_uiCofferDoorsOpened; + uint8 m_uiDwarfRound; + uint32 m_uiDwarfFightTimer; + float m_fArenaCenterX, m_fArenaCenterY, m_fArenaCenterZ; - GUIDSet m_sVaultNpcGuids; + GuidSet m_sVaultNpcGuids; + GuidSet m_sArenaCrowdNpcGuids; }; #endif diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp index b071ad1fd..47e1e614f 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/boss_ambassador_flamelash.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss_Ambassador_Flamelash -SD%Complete: 80 -SDComment: Texts missing, Add handling rather guesswork, Add spell Burning Spirit likely won't work +SD%Complete: 90 +SDComment: Texts probably missing; Spirits handling could be improved. SDCategory: Blackrock Depths EndScriptData */ #include "precompiled.h" +#include "blackrock_depths.h" enum { @@ -32,69 +33,99 @@ enum NPC_BURNING_SPIRIT = 9178, }; -struct MANGOS_DLL_DECL boss_ambassador_flamelashAI : public ScriptedAI +struct boss_ambassador_flamelashAI : public ScriptedAI { - boss_ambassador_flamelashAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_ambassador_flamelashAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; - uint32 m_uiSpiritTimer; - int Rand; - int RandX; - int RandY; + uint32 m_uiSpiritTimer[MAX_DWARF_RUNES]; - void Reset() + GuidSet m_sSpiritsGuidsSet; + + void Reset() override { - m_uiSpiritTimer = 12000; + for (uint8 i = 0; i < MAX_DWARF_RUNES; ++i) + m_uiSpiritTimer[i] = urand(0, 1000); + + m_sSpiritsGuidsSet.clear(); + } + + // function that will summon spirits periodically + void DoSummonSpirit(uint8 uiIndex) + { + if (!m_pInstance) + return; + + if (GameObject* pRune = m_pInstance->GetSingleGameObjectFromStorage(GO_DWARFRUNE_A01 + uiIndex)) + m_creature->SummonCreature(NPC_BURNING_SPIRIT, pRune->GetPositionX(), pRune->GetPositionY(), pRune->GetPositionZ(), m_creature->GetAngle(m_creature), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); } - void SummonSpirits() + void MoveInLineOfSight(Unit* pWho) override { - float fX, fY, fZ; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 30.0f, fX, fY, fZ); - m_creature->SummonCreature(NPC_BURNING_SPIRIT, fX, fY, fZ, m_creature->GetAngle(fX, fY)+M_PI_F, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + ScriptedAI::MoveInLineOfSight(pWho); + + if (pWho->GetEntry() == NPC_BURNING_SPIRIT && pWho->isAlive() && m_sSpiritsGuidsSet.find(pWho->GetObjectGuid()) != m_sSpiritsGuidsSet.end() && + pWho->IsWithinDistInMap(m_creature, 2 * CONTACT_DISTANCE)) + { + pWho->CastSpell(m_creature, SPELL_BURNING_SPIRIT, true); + m_sSpiritsGuidsSet.erase(pWho->GetObjectGuid()); + } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, SPELL_FIREBLAST); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FLAMELASH, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustDied(Unit* /*pKiller*/) override { - pSummoned->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + if (m_pInstance) + m_pInstance->SetData(TYPE_FLAMELASH, DONE); } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void JustReachedHome() override { - if (uiPointId != 1) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_FLAMELASH, FAIL); + } - pSummoned->CastSpell(m_creature, SPELL_BURNING_SPIRIT, true); + void JustSummoned(Creature* pSummoned) override + { + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + m_sSpiritsGuidsSet.insert(pSummoned->GetObjectGuid()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiSpiritTimer - if (m_uiSpiritTimer < uiDiff) + // m_uiSpiritTimer + for (uint8 i = 0; i < MAX_DWARF_RUNES; ++i) { - SummonSpirits(); - SummonSpirits(); - SummonSpirits(); - SummonSpirits(); - - m_uiSpiritTimer = 20000; + if (m_uiSpiritTimer[i] < uiDiff) + { + DoSummonSpirit(i); + m_uiSpiritTimer[i] = urand(15000, 30000); + } + else + m_uiSpiritTimer[i] -= uiDiff; } - else - m_uiSpiritTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -bool EffectDummyCreature_spell_boss_ambassador_flamelash(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_spell_boss_ambassador_flamelash(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiSpellId == SPELL_BURNING_SPIRIT && uiEffIndex == EFFECT_INDEX_1) { diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp deleted file mode 100644 index 870d20f5c..000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_anubshiah.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Anubshiah -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_SHADOWBOLT = 17228, - SPELL_CURSEOFTONGUES = 15470, - SPELL_CURSEOFWEAKNESS = 17227, - SPELL_DEMONARMOR = 11735, - SPELL_ENVELOPINGWEB = 15471 -}; - -struct MANGOS_DLL_DECL boss_anubshiahAI : public ScriptedAI -{ - boss_anubshiahAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 m_uiShadowBoltTimer; - uint32 m_uiCurseOfTonguesTimer; - uint32 m_uiCurseOfWeaknessTimer; - uint32 m_uiDemonArmorTimer; - uint32 m_uiEnvelopingWebTimer; - - void Reset() - { - m_uiShadowBoltTimer = 7000; - m_uiCurseOfTonguesTimer = 24000; - m_uiCurseOfWeaknessTimer = 12000; - m_uiDemonArmorTimer = 3000; - m_uiEnvelopingWebTimer = 16000; - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowBolt_Timer - if (m_uiShadowBoltTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWBOLT); - m_uiShadowBoltTimer = 7000; - } - else - m_uiShadowBoltTimer -= uiDiff; - - //CurseOfTongues_Timer - if (m_uiCurseOfTonguesTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_CURSEOFTONGUES); - m_uiCurseOfTonguesTimer = 18000; - } - else - m_uiCurseOfTonguesTimer -= uiDiff; - - //CurseOfWeakness_Timer - if (m_uiCurseOfWeaknessTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CURSEOFWEAKNESS); - m_uiCurseOfWeaknessTimer = 45000; - } - else - m_uiCurseOfWeaknessTimer -= uiDiff; - - //DemonArmor_Timer - if (m_uiDemonArmorTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_DEMONARMOR); - m_uiDemonArmorTimer = 300000; - } - else - m_uiDemonArmorTimer -= uiDiff; - - //EnvelopingWeb_Timer - if (m_uiEnvelopingWebTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_ENVELOPINGWEB); - m_uiEnvelopingWebTimer = 12000; - } - else - m_uiEnvelopingWebTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_anubshiah(Creature* pCreature) -{ - return new boss_anubshiahAI(pCreature); -} - -void AddSC_boss_anubshiah() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_anubshiah"; - pNewScript->GetAI = &GetAI_boss_anubshiah; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_coren_direbrew.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_coren_direbrew.cpp index c7aaf79fb..6031fe6fe 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_coren_direbrew.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/boss_coren_direbrew.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,166 @@ /* ScriptData SDName: boss_coren_direbrew -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 75 +SDComment: Some parts are not complete - requires additional research. Brewmaidens scripts handled in eventAI. SDCategory: Blackrock Depths EndScriptData */ #include "precompiled.h" +enum +{ + SAY_AGGRO = -1230034, + + // spells + SPELL_DIREBREW_DISARM = 47310, + SPELL_SUMMON_DIREBREW_MINION = 47375, + SPELL_DIREBREW_CHARGE = 47718, + SPELL_SUMMON_MOLE_MACHINE = 47691, // triggers 47690 + + // summoned auras + SPELL_PORT_TO_COREN = 52850, + + // other summoned spells - currently not used in script + // SPELL_CHUCK_MUG = 50276, + // SPELL_BARRELED_AURA = 50278, // used by Ursula + // SPELL_HAS_BREW = 47331, // triggers 47344 - aura which asks for the second brew on item expire + // SPELL_SEND_FIRST_MUG = 47333, // triggers 47345 + // SPELL_SEND_SECOND_MUG = 47339, // triggers 47340 - spell triggered by 47344 + // SPELL_BREWMAIDEN_DESPAWN_AURA = 48186, // purpose unk + + // npcs + NPC_DIREBREW_MINION = 26776, + NPC_ILSA_DIREBREW = 26764, + NPC_URSULA_DIREBREW = 26822, + + // other + FACTION_HOSTILE = 736, + + QUEST_INSULT_COREN = 12062, + + MAX_DIREBREW_MINIONS = 3, +}; + +struct boss_coren_direbrewAI : public ScriptedAI +{ + boss_coren_direbrewAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiDisarmTimer; + uint32 m_uiChargeTimer; + uint32 m_uiSummonTimer; + uint8 m_uiPhase; + + void Reset() override + { + m_uiDisarmTimer = 10000; + m_uiChargeTimer = 5000; + m_uiSummonTimer = 15000; + m_uiPhase = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + // Spawn 3 minions on aggro + for (uint8 i = 0; i < MAX_DIREBREW_MINIONS; ++i) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DIREBREW_MINION, CAST_TRIGGERED); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_ILSA_DIREBREW: + case NPC_URSULA_DIREBREW: + pSummoned->CastSpell(m_creature, SPELL_PORT_TO_COREN, true); + break; + } + + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Spawn Ilsa + if (m_creature->GetHealthPercent() < 66.0f && m_uiPhase == 0) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10, fX, fY, fZ); + m_creature->SummonCreature(NPC_ILSA_DIREBREW, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiPhase = 1; + } + + // Spawn Ursula + if (m_creature->GetHealthPercent() < 33.0f && m_uiPhase == 1) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10, fX, fY, fZ); + m_creature->SummonCreature(NPC_URSULA_DIREBREW, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiPhase = 2; + } + + if (m_uiDisarmTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DIREBREW_DISARM) == CAST_OK) + m_uiDisarmTimer = 15000; + } + else + m_uiDisarmTimer -= uiDiff; + + if (m_uiChargeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_DIREBREW_CHARGE, SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DIREBREW_CHARGE) == CAST_OK) + m_uiChargeTimer = urand(5000, 10000); + } + } + else + m_uiChargeTimer -= uiDiff; + + if (m_uiSummonTimer < uiDiff) + { + for (uint8 i = 0; i < MAX_DIREBREW_MINIONS; ++i) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DIREBREW_MINION, CAST_TRIGGERED); + + m_uiSummonTimer = 15000; + } + else + m_uiSummonTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_coren_direbrew(Creature* pCreature) +{ + return new boss_coren_direbrewAI(pCreature); +} + +bool QuestRewarded_npc_coren_direbrew(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_INSULT_COREN) + { + DoScriptText(SAY_AGGRO, pCreature, pPlayer); + + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + pCreature->AI()->AttackStart(pPlayer); + } + + return true; +} + void AddSC_boss_coren_direbrew() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_coren_direbrew"; + pNewScript->GetAI = &GetAI_boss_coren_direbrew; + pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_coren_direbrew; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp index 0755cce51..57ed0ecb3 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/boss_emperor_dagran_thaurissan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -34,7 +34,7 @@ enum eEmperor SPELL_AVATAROFFLAME = 15636 }; -struct MANGOS_DLL_DECL boss_emperor_dagran_thaurissanAI : public ScriptedAI +struct boss_emperor_dagran_thaurissanAI : public ScriptedAI { boss_emperor_dagran_thaurissanAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -44,76 +44,69 @@ struct MANGOS_DLL_DECL boss_emperor_dagran_thaurissanAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiHandOfThaurissan_Timer; - uint32 m_uiAvatarOfFlame_Timer; - //uint32 m_uiCounter; + uint32 m_uiHandOfThaurissanTimer; + uint32 m_uiAvatarOfFlameTimer; - void Reset() + void Reset() override { - m_uiHandOfThaurissan_Timer = 4000; - m_uiAvatarOfFlame_Timer = 25000; - //m_uiCounter = 0; + m_uiHandOfThaurissanTimer = 4000; + m_uiAvatarOfFlameTimer = 25000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); m_creature->CallForHelp(VISIBLE_RANGE); } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { if (!m_pInstance) return; if (Creature* pPrincess = m_pInstance->GetSingleCreatureFromStorage(NPC_PRINCESS)) { + // check if we didn't update the entry + if (pPrincess->GetEntry() != NPC_PRINCESS) + return; + if (pPrincess->isAlive()) { - pPrincess->setFaction(FACTION_NEUTRAL); + pPrincess->SetFactionTemporary(FACTION_NEUTRAL, TEMPFACTION_NONE); pPrincess->AI()->EnterEvadeMode(); } } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiHandOfThaurissan_Timer < uiDiff) + if (m_uiHandOfThaurissanTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget,SPELL_HANDOFTHAURISSAN); - - //3 Hands of Thaurissan will be casted - //if (m_uiCounter < 3) - //{ - // m_uiHandOfThaurissan_Timer = 1000; - // ++m_uiCounter; - //} - //else - //{ - m_uiHandOfThaurissan_Timer = 5000; - //m_uiCounter = 0; - //} + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HANDOFTHAURISSAN) == CAST_OK) + m_uiHandOfThaurissanTimer = 5000; + } } else - m_uiHandOfThaurissan_Timer -= uiDiff; + m_uiHandOfThaurissanTimer -= uiDiff; - //AvatarOfFlame_Timer - if (m_uiAvatarOfFlame_Timer < uiDiff) + // AvatarOfFlame_Timer + if (m_uiAvatarOfFlameTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_AVATAROFFLAME); - m_uiAvatarOfFlame_Timer = 18000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_AVATAROFFLAME) == CAST_OK) + m_uiAvatarOfFlameTimer = 18000; } else - m_uiAvatarOfFlame_Timer -= uiDiff; + m_uiAvatarOfFlameTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -140,7 +133,7 @@ enum ePrincess SPELL_OPEN_PORTAL = 13912 }; -struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI +struct boss_moira_bronzebeardAI : public ScriptedAI { boss_moira_bronzebeardAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -150,20 +143,20 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiHeal_Timer; - uint32 m_uiMindBlast_Timer; - uint32 m_uiShadowWordPain_Timer; - uint32 m_uiSmite_Timer; + uint32 m_uiHealTimer; + uint32 m_uiMindBlastTimer; + uint32 m_uiShadowWordPainTimer; + uint32 m_uiSmiteTimer; - void Reset() + void Reset() override { - m_uiHeal_Timer = 12000; //These times are probably wrong - m_uiMindBlast_Timer = 16000; - m_uiShadowWordPain_Timer = 2000; - m_uiSmite_Timer = 8000; + m_uiHealTimer = 12000; // These times are probably wrong + m_uiMindBlastTimer = 16000; + m_uiShadowWordPainTimer = 2000; + m_uiSmiteTimer = 8000; } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, false)) { @@ -175,7 +168,7 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -183,59 +176,60 @@ struct MANGOS_DLL_DECL boss_moira_bronzebeardAI : public ScriptedAI { // if evade, then check if he is alive. If not, start make portal if (!pEmperor->isAlive()) - m_creature->CastSpell(m_creature, SPELL_OPEN_PORTAL, false); + DoCastSpellIfCan(m_creature, SPELL_OPEN_PORTAL); } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //MindBlast_Timer - if (m_uiMindBlast_Timer < uiDiff) + // MindBlast_Timer + if (m_uiMindBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MINDBLAST); - m_uiMindBlast_Timer = 14000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MINDBLAST) == CAST_OK) + m_uiMindBlastTimer = 14000; } else - m_uiMindBlast_Timer -= uiDiff; + m_uiMindBlastTimer -= uiDiff; - //ShadowWordPain_Timer - if (m_uiShadowWordPain_Timer < uiDiff) + // ShadowWordPain_Timer + if (m_uiShadowWordPainTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - m_uiShadowWordPain_Timer = 18000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWWORDPAIN) == CAST_OK) + m_uiShadowWordPainTimer = 18000; } else - m_uiShadowWordPain_Timer -= uiDiff; + m_uiShadowWordPainTimer -= uiDiff; - //Smite_Timer - if (m_uiSmite_Timer < uiDiff) + // Smite_Timer + if (m_uiSmiteTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SMITE); - m_uiSmite_Timer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SMITE) == CAST_OK) + m_uiSmiteTimer = 10000; } else - m_uiSmite_Timer -= uiDiff; + m_uiSmiteTimer -= uiDiff; - //Heal_Timer - if (m_uiHeal_Timer < uiDiff) + // Heal_Timer + if (m_uiHealTimer < uiDiff) { if (Creature* pEmperor = m_pInstance->GetSingleCreatureFromStorage(NPC_EMPEROR)) { if (pEmperor->isAlive() && pEmperor->GetHealthPercent() != 100.0f) - DoCastSpellIfCan(pEmperor, SPELL_HEAL); + { + if (DoCastSpellIfCan(pEmperor, SPELL_HEAL) == CAST_OK) + m_uiHealTimer = 10000; + } } - - m_uiHeal_Timer = 10000; } else - m_uiHeal_Timer -= uiDiff; + m_uiHealTimer -= uiDiff; - //No meele? + // No meele? } }; diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp index 2c20c7120..85d83a2b6 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/boss_general_angerforge.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,101 +25,84 @@ EndScriptData */ enum { - SPELL_MIGHTYBLOW = 14099, - SPELL_HAMSTRING = 9080, - SPELL_CLEAVE = 20691, + EMOTE_ALARM = -1230035, + + SPELL_FLURRY = 15088, + SPELL_ENRAGE = 15097, + SPELL_SUNDER_ARMOR = 15572, - NPC_ANVILRAGE_RESERVIST = 8901, NPC_ANVILRAGE_MEDIC = 8894, + NPC_ANVILRAGE_RESERVIST = 8901, + + NPC_ELITE_AMOUNT = 2, + NPC_NORMAL_AMOUNT = 8, }; -struct MANGOS_DLL_DECL boss_general_angerforgeAI : public ScriptedAI +static const float aAlarmPoint[4] = {717.343f, 22.116f, -45.4321f, 3.1415f}; + +struct boss_general_angerforgeAI : public ScriptedAI { boss_general_angerforgeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 m_uiMightyBlowTimer; - uint32 m_uiHamStringTimer; - uint32 m_uiCleaveTimer; - uint32 m_uiAddsTimer; - bool m_bSummonedMedics; + uint32 m_uiSunderArmorTimer; + uint32 m_uiAlarmTimer; - void Reset() + void Reset() override { - m_uiMightyBlowTimer = 8000; - m_uiHamStringTimer = 12000; - m_uiCleaveTimer = 16000; - m_uiAddsTimer = 0; - m_bSummonedMedics = false; + m_uiSunderArmorTimer = urand(5 * IN_MILLISECONDS, 10 * IN_MILLISECONDS); + m_uiAlarmTimer = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_FLURRY, CAST_AURA_NOT_PRESENT | CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_AURA_NOT_PRESENT | CAST_TRIGGERED); } void SummonAdd(uint32 uiEntry) { float fX, fY, fZ; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); - m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + m_creature->GetRandomPoint(aAlarmPoint[0], aAlarmPoint[1], aAlarmPoint[2], 1.0f, fX, fY, fZ); + m_creature->SummonCreature(uiEntry, fX, fY, fZ, aAlarmPoint[3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30 * IN_MILLISECONDS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //MightyBlow_Timer - if (m_uiMightyBlowTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTYBLOW); - m_uiMightyBlowTimer = 18000; - } - else - m_uiMightyBlowTimer -= uiDiff; - - //HamString_Timer - if (m_uiHamStringTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING); - m_uiHamStringTimer = 15000; - } - else - m_uiHamStringTimer -= uiDiff; - - //Cleave_Timer - if (m_uiCleaveTimer < uiDiff) + // Sunder_Armor-Timer + if (m_uiSunderArmorTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 9000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR) == CAST_OK) + m_uiSunderArmorTimer = urand(5 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); } else - m_uiCleaveTimer -= uiDiff; + m_uiSunderArmorTimer -= uiDiff; - //Adds_Timer - if (m_creature->GetHealthPercent() < 21.0f) + // Alarm-Timer + if (m_creature->GetHealthPercent() < 30.0f) { - if (m_uiAddsTimer < uiDiff) + if (m_uiAlarmTimer < uiDiff) { - // summon 3 Adds every 25s - SummonAdd(NPC_ANVILRAGE_RESERVIST); - SummonAdd(NPC_ANVILRAGE_RESERVIST); - SummonAdd(NPC_ANVILRAGE_RESERVIST); + DoScriptText(EMOTE_ALARM, m_creature); + + for (int i = 0; i < NPC_NORMAL_AMOUNT; i++) + SummonAdd(NPC_ANVILRAGE_RESERVIST); + for (int i = 0; i < NPC_ELITE_AMOUNT; i++) + SummonAdd(NPC_ANVILRAGE_MEDIC); - m_uiAddsTimer = 25000; + m_uiAlarmTimer = 3 * MINUTE * IN_MILLISECONDS; } else - m_uiAddsTimer -= uiDiff; - } - - //Summon Medics - if (!m_bSummonedMedics && m_creature->GetHealthPercent() < 21.0f) - { - SummonAdd(NPC_ANVILRAGE_MEDIC); - SummonAdd(NPC_ANVILRAGE_MEDIC); - m_bSummonedMedics = true; + m_uiAlarmTimer -= uiDiff; } DoMeleeAttackIfReady(); diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp deleted file mode 100644 index df22713fd..000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_gorosh_the_dervish.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Gorosh_the_Dervish -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_WHIRLWIND = 15589, - SPELL_MORTALSTRIKE = 24573, -}; - -struct MANGOS_DLL_DECL boss_gorosh_the_dervishAI : public ScriptedAI -{ - boss_gorosh_the_dervishAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiWhirlWindTimer; - uint32 m_uiMortalStrikeTimer; - - void Reset() - { - m_uiWhirlWindTimer = 12000; - m_uiMortalStrikeTimer = 22000; - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //WhirlWind_Timer - if (m_uiWhirlWindTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlWindTimer = 15000; - } - else - m_uiWhirlWindTimer -= uiDiff; - - //MortalStrike_Timer - if (m_uiMortalStrikeTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTALSTRIKE); - m_uiMortalStrikeTimer = 15000; - } - else - m_uiMortalStrikeTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_gorosh_the_dervish(Creature* pCreature) -{ - return new boss_gorosh_the_dervishAI(pCreature); -} - -void AddSC_boss_gorosh_the_dervish() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_gorosh_the_dervish"; - pNewScript->GetAI = &GetAI_boss_gorosh_the_dervish; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp deleted file mode 100644 index d89545bea..000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_grizzle.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Grizzle -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" - -enum -{ - EMOTE_GENERIC_FRENZY_KILL = -1000001, - - SPELL_GROUNDTREMOR = 6524, - SPELL_FRENZY = 28371, -}; - -struct MANGOS_DLL_DECL boss_grizzleAI : public ScriptedAI -{ - boss_grizzleAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 m_uiGroundTremorTimer; - uint32 m_uiFrenzyTimer; - - void Reset() - { - m_uiGroundTremorTimer = 12000; - m_uiFrenzyTimer = 0; - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //GroundTremor_Timer - if (m_uiGroundTremorTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_GROUNDTREMOR); - m_uiGroundTremorTimer = 8000; - } - else - m_uiGroundTremorTimer -= uiDiff; - - //Frenzy_Timer - if (m_creature->GetHealthPercent() < 51.0f) - { - if (m_uiFrenzyTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - m_uiFrenzyTimer = 15000; - } - } - else - m_uiFrenzyTimer -= uiDiff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_grizzle(Creature* pCreature) -{ - return new boss_grizzleAI(pCreature); -} - -void AddSC_boss_grizzle() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_grizzle"; - pNewScript->GetAI = &GetAI_boss_grizzle; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp index ca649875e..8a261259e 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/boss_high_interrogator_gerstahn.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_SHADOWSHIELD = 12040 }; -struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI +struct boss_high_interrogator_gerstahnAI : public ScriptedAI { boss_high_interrogator_gerstahnAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -40,7 +40,7 @@ struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI uint32 m_uiPsychicScreamTimer; uint32 m_uiShadowShieldTimer; - void Reset() + void Reset() override { m_uiShadowWordPainTimer = 4000; m_uiManaBurnTimer = 14000; @@ -48,13 +48,13 @@ struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI m_uiShadowShieldTimer = 8000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //ShadowWordPain_Timer + // ShadowWordPain_Timer if (m_uiShadowWordPainTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) @@ -65,7 +65,7 @@ struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI else m_uiShadowWordPainTimer -= uiDiff; - //ManaBurn_Timer + // ManaBurn_Timer if (m_uiManaBurnTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANABURN, SELECT_FLAG_POWER_MANA)) @@ -76,7 +76,7 @@ struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI else m_uiManaBurnTimer -= uiDiff; - //PsychicScream_Timer + // PsychicScream_Timer if (m_uiPsychicScreamTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_PSYCHICSCREAM); @@ -85,7 +85,7 @@ struct MANGOS_DLL_DECL boss_high_interrogator_gerstahnAI : public ScriptedAI else m_uiPsychicScreamTimer -= uiDiff; - //ShadowShield_Timer + // ShadowShield_Timer if (m_uiShadowShieldTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_SHADOWSHIELD); diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp deleted file mode 100644 index 25dc1a2ca..000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_magmus.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Magmus -SD%Complete: 80 -SDComment: Missing pre-event to open doors -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" -#include "blackrock_depths.h" - -enum -{ - SPELL_FIERYBURST = 13900, - SPELL_WARSTOMP = 24375 -}; - -struct MANGOS_DLL_DECL boss_magmusAI : public ScriptedAI -{ - boss_magmusAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiFieryBurstTimer; - uint32 m_uiWarStompTimer; - - void Reset() - { - m_uiFieryBurstTimer = 5000; - m_uiWarStompTimer = 0; - } - - void Aggro(Unit* pWho) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_IRON_HALL, IN_PROGRESS); - } - - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_IRON_HALL, FAIL); - } - - void JustDied(Unit* pVictim) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_IRON_HALL, DONE); - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //FieryBurst_Timer - if (m_uiFieryBurstTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIERYBURST); - m_uiFieryBurstTimer = 6000; - } - else - m_uiFieryBurstTimer -= uiDiff; - - //WarStomp_Timer - if (m_creature->GetHealthPercent() < 51.0f) - { - if (m_uiWarStompTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_WARSTOMP); - m_uiWarStompTimer = 8000; - } - else - m_uiWarStompTimer -= uiDiff; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_magmus(Creature* pCreature) -{ - return new boss_magmusAI(pCreature); -} - -void AddSC_boss_magmus() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_magmus"; - pNewScript->GetAI = &GetAI_boss_magmus; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp b/scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp deleted file mode 100644 index c8096a9f3..000000000 --- a/scripts/eastern_kingdoms/blackrock_depths/boss_tomb_of_seven.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Tomb_Of_Seven -SD%Complete: 90 -SDComment: Learning Smelt Dark Iron if tribute quest rewarded. Basic event implemented. Correct order and timing of event is unknown. -SDCategory: Blackrock Depths -EndScriptData */ - -#include "precompiled.h" -#include "blackrock_depths.h" - -enum -{ - FACTION_NEUTRAL = 734, - FACTION_HOSTILE = 754, - - SPELL_SMELT_DARK_IRON = 14891, - SPELL_LEARN_SMELT = 14894, - QUEST_SPECTRAL_CHALICE = 4083, - SKILLPOINT_MIN = 230 -}; - -#define GOSSIP_ITEM_TEACH_1 "Teach me the art of smelting dark iron" -#define GOSSIP_ITEM_TEACH_2 "Continue..." -#define GOSSIP_ITEM_TRIBUTE "I want to pay tribute" - -bool GossipHello_boss_gloomrel(Player* pPlayer, Creature* pCreature) -{ - if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) - { - if (pInstance->GetData(TYPE_TOMB_OF_SEVEN) == NOT_STARTED) - { - if (pPlayer->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) && - pPlayer->GetSkillValue(SKILL_MINING) >= SKILLPOINT_MIN && - !pPlayer->HasSpell(SPELL_SMELT_DARK_IRON)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TEACH_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if (!pPlayer->GetQuestRewardStatus(QUEST_SPECTRAL_CHALICE) && - pPlayer->GetSkillValue(SKILL_MINING) >= SKILLPOINT_MIN) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TRIBUTE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - } - } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_boss_gloomrel(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TEACH_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - pPlayer->SEND_GOSSIP_MENU(2606, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, SPELL_LEARN_SMELT, false); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] Continue...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 22); - pPlayer->SEND_GOSSIP_MENU(2604, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+22: - pPlayer->CLOSE_GOSSIP_MENU(); - if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) - { - //are 5 minutes expected? go template may have data to despawn when used at quest - pInstance->DoRespawnGameObject(GO_SPECTRAL_CHALICE, MINUTE*5); - } - break; - } - return true; -} - -enum -{ - SPELL_SHADOWBOLTVOLLEY = 15245, - SPELL_IMMOLATE = 12742, - SPELL_CURSEOFWEAKNESS = 12493, - SPELL_DEMONARMOR = 13787, - SPELL_SUMMON_VOIDWALKERS = 15092, - - SAY_DOOMREL_START_EVENT = -1230003, - - MAX_DWARF = 7 -}; - -#define GOSSIP_ITEM_CHALLENGE "Your bondage is at an end, Doom'rel. I challenge you!" - -struct MANGOS_DLL_DECL boss_doomrelAI : public ScriptedAI -{ - boss_doomrelAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiShadowVolley_Timer; - uint32 m_uiImmolate_Timer; - uint32 m_uiCurseOfWeakness_Timer; - uint32 m_uiDemonArmor_Timer; - uint32 m_uiCallToFight_Timer; - uint8 m_uiDwarfRound; - bool m_bHasSummoned; - - void Reset() - { - m_uiShadowVolley_Timer = 10000; - m_uiImmolate_Timer = 18000; - m_uiCurseOfWeakness_Timer = 5000; - m_uiDemonArmor_Timer = 16000; - m_uiCallToFight_Timer = 0; - m_uiDwarfRound = 0; - m_bHasSummoned = false; - } - - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_TOMB_OF_SEVEN, FAIL); - } - - void JustDied(Unit *victim) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_TOMB_OF_SEVEN, DONE); - } - - void JustSummoned(Creature* pSummoned) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - pSummoned->AI()->AttackStart(pTarget); - } - - Creature* GetDwarfForPhase(uint8 uiPhase) - { - switch(uiPhase) - { - case 0: - return m_pInstance->GetSingleCreatureFromStorage(NPC_ANGERREL); - case 1: - return m_pInstance->GetSingleCreatureFromStorage(NPC_SEETHREL); - case 2: - return m_pInstance->GetSingleCreatureFromStorage(NPC_DOPEREL); - case 3: - return m_pInstance->GetSingleCreatureFromStorage(NPC_GLOOMREL); - case 4: - return m_pInstance->GetSingleCreatureFromStorage(NPC_VILEREL); - case 5: - return m_pInstance->GetSingleCreatureFromStorage(NPC_HATEREL); - case 6: - return m_creature; - } - return NULL; - } - - void CallToFight(bool bStartFight) - { - if (Creature* pDwarf = GetDwarfForPhase(m_uiDwarfRound)) - { - if (bStartFight && pDwarf->isAlive()) - { - pDwarf->setFaction(FACTION_HOSTILE); - pDwarf->SetInCombatWithZone(); // attackstart - } - else - { - if (!pDwarf->isAlive() || pDwarf->isDead()) - pDwarf->Respawn(); - - pDwarf->setFaction(FACTION_NEUTRAL); - } - } - } - - void UpdateAI(const uint32 diff) - { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_TOMB_OF_SEVEN) == IN_PROGRESS) - { - if (m_uiDwarfRound < MAX_DWARF) - { - if (m_uiCallToFight_Timer < diff) - { - CallToFight(true); - ++m_uiDwarfRound; - m_uiCallToFight_Timer = 30000; - } - else - m_uiCallToFight_Timer -= diff; - } - } - else if (m_pInstance->GetData(TYPE_TOMB_OF_SEVEN) == FAIL) - { - for (m_uiDwarfRound = 0; m_uiDwarfRound < MAX_DWARF; ++m_uiDwarfRound) - CallToFight(false); - - m_uiDwarfRound = 0; - m_uiCallToFight_Timer = 0; - - if (m_pInstance) - m_pInstance->SetData(TYPE_TOMB_OF_SEVEN, NOT_STARTED); - } - } - - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowVolley_Timer - if (m_uiShadowVolley_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWBOLTVOLLEY); - m_uiShadowVolley_Timer = 12000; - } - else - m_uiShadowVolley_Timer -= diff; - - //Immolate_Timer - if (m_uiImmolate_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_IMMOLATE); - - m_uiImmolate_Timer = 25000; - } - else - m_uiImmolate_Timer -= diff; - - //CurseOfWeakness_Timer - if (m_uiCurseOfWeakness_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); - m_uiCurseOfWeakness_Timer = 45000; - } - else - m_uiCurseOfWeakness_Timer -= diff; - - //DemonArmor_Timer - if (m_uiDemonArmor_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_DEMONARMOR); - m_uiDemonArmor_Timer = 300000; - } - else - m_uiDemonArmor_Timer -= diff; - - //Summon Voidwalkers - if (!m_bHasSummoned && m_creature->GetHealthPercent() <= 50.0f) - { - m_creature->CastSpell(m_creature, SPELL_SUMMON_VOIDWALKERS, true); - m_bHasSummoned = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_doomrel(Creature* pCreature) -{ - return new boss_doomrelAI(pCreature); -} - -bool GossipHello_boss_doomrel(Player* pPlayer, Creature* pCreature) -{ - if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) - { - if (pInstance->GetData(TYPE_TOMB_OF_SEVEN) == NOT_STARTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CHALLENGE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - } - - pPlayer->SEND_GOSSIP_MENU(2601, pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_boss_doomrel(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->CLOSE_GOSSIP_MENU(); - DoScriptText(SAY_DOOMREL_START_EVENT, pCreature, pPlayer); - // start event - if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) - pInstance->SetData(TYPE_TOMB_OF_SEVEN, IN_PROGRESS); - - break; - } - return true; -} - -void AddSC_boss_tomb_of_seven() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_gloomrel"; - pNewScript->pGossipHello = &GossipHello_boss_gloomrel; - pNewScript->pGossipSelect = &GossipSelect_boss_gloomrel; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_doomrel"; - pNewScript->GetAI = &GetAI_boss_doomrel; - pNewScript->pGossipHello = &GossipHello_boss_doomrel; - pNewScript->pGossipSelect = &GossipSelect_boss_doomrel; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp b/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp index 690884554..5334bec27 100644 --- a/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp +++ b/scripts/eastern_kingdoms/blackrock_depths/instance_blackrock_depths.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -27,6 +27,8 @@ EndScriptData */ instance_blackrock_depths::instance_blackrock_depths(Map* pMap) : ScriptedInstance(pMap), m_uiBarAleCount(0), m_uiCofferDoorsOpened(0), + m_uiDwarfRound(0), + m_uiDwarfFightTimer(0), m_fArenaCenterX(0.0f), m_fArenaCenterY(0.0f), @@ -42,17 +44,27 @@ void instance_blackrock_depths::Initialize() void instance_blackrock_depths::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - case NPC_EMPEROR: case NPC_PRINCESS: + // replace the princess if required + if (CanReplacePrincess()) + pCreature->UpdateEntry(NPC_PRIESTESS); + // no break; + case NPC_EMPEROR: case NPC_PHALANX: case NPC_HATEREL: case NPC_ANGERREL: case NPC_VILEREL: case NPC_GLOOMREL: case NPC_SEETHREL: + case NPC_DOOMREL: case NPC_DOPEREL: + case NPC_SHILL: + case NPC_CREST: + case NPC_JAZ: + case NPC_TOBIAS: + case NPC_DUGHAL: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; @@ -66,12 +78,27 @@ void instance_blackrock_depths::OnCreatureCreate(Creature* pCreature) case NPC_WATCHER_DOOMGRIP: m_sVaultNpcGuids.insert(pCreature->GetObjectGuid()); break; + // Arena crowd + case NPC_ARENA_SPECTATOR: + case NPC_SHADOWFORGE_PEASANT: + case NPC_SHADOWFORGE_CITIZEN: + case NPC_SHADOWFORGE_SENATOR: + case NPC_ANVILRAGE_SOLDIER: + case NPC_ANVILRAGE_MEDIC: + case NPC_ANVILRAGE_OFFICER: + if (pCreature->GetPositionZ() < aArenaCrowdVolume->m_fCenterZ || pCreature->GetPositionZ() > aArenaCrowdVolume->m_fCenterZ + aArenaCrowdVolume->m_uiHeight || + !pCreature->IsWithinDist2d(aArenaCrowdVolume->m_fCenterX, aArenaCrowdVolume->m_fCenterY, aArenaCrowdVolume->m_uiRadius)) + break; + m_sArenaCrowdNpcGuids.insert(pCreature->GetObjectGuid()); + if (m_auiEncounter[0] == DONE) + pCreature->SetFactionTemporary(FACTION_ARENA_NEUTRAL, TEMPFACTION_RESTORE_RESPAWN); + break; } } void instance_blackrock_depths::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_ARENA_1: case GO_ARENA_2: @@ -94,6 +121,16 @@ void instance_blackrock_depths::OnObjectCreate(GameObject* pGo) case GO_CHEST_SEVEN: case GO_ARENA_SPOILS: case GO_SECRET_DOOR: + case GO_SECRET_SAFE: + case GO_JAIL_DOOR_SUPPLY: + case GO_JAIL_SUPPLY_CRATE: + case GO_DWARFRUNE_A01: + case GO_DWARFRUNE_B01: + case GO_DWARFRUNE_C01: + case GO_DWARFRUNE_D01: + case GO_DWARFRUNE_E01: + case GO_DWARFRUNE_F01: + case GO_DWARFRUNE_G01: break; default: @@ -104,12 +141,20 @@ void instance_blackrock_depths::OnObjectCreate(GameObject* pGo) void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_RING_OF_LAW: // If finished the arena event after theldren fight if (uiData == DONE && m_auiEncounter[0] == SPECIAL) DoRespawnGameObject(GO_ARENA_SPOILS, HOUR); + else if (uiData == DONE) + { + for (GuidSet::const_iterator itr = m_sArenaCrowdNpcGuids.begin(); itr != m_sArenaCrowdNpcGuids.end(); ++itr) + { + if (Creature* pSpectator = instance->GetCreature(*itr)) + pSpectator->SetFactionTemporary(FACTION_ARENA_NEUTRAL, TEMPFACTION_RESTORE_RESPAWN); + } + } m_auiEncounter[0] = uiData; break; case TYPE_VAULT: @@ -124,9 +169,10 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) Creature* pConstruct = NULL; // Activate vault constructs - for (GUIDSet::const_iterator itr = m_sVaultNpcGuids.begin(); itr != m_sVaultNpcGuids.end(); ++itr) + for (GuidSet::const_iterator itr = m_sVaultNpcGuids.begin(); itr != m_sVaultNpcGuids.end(); ++itr) { - if (pConstruct = instance->GetCreature(*itr)) + pConstruct = instance->GetCreature(*itr); + if (pConstruct) pConstruct->RemoveAurasDueToSpell(SPELL_STONED); } @@ -140,7 +186,10 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) return; } if (uiData == DONE) + { DoUseDoorOrButton(GO_SECRET_DOOR); + DoToggleGameObjectFlags(GO_SECRET_SAFE, GO_FLAG_NO_INTERACT, false); + } m_auiEncounter[1] = uiData; break; case TYPE_BAR: @@ -150,20 +199,33 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[2] = uiData; break; case TYPE_TOMB_OF_SEVEN: - switch(uiData) + // Don't set the same data twice + if (uiData == m_auiEncounter[3]) + break; + // Combat door + DoUseDoorOrButton(GO_TOMB_ENTER); + // Start the event + if (uiData == IN_PROGRESS) + DoCallNextDwarf(); + if (uiData == FAIL) { - case IN_PROGRESS: - DoUseDoorOrButton(GO_TOMB_ENTER); - break; - case FAIL: - if (m_auiEncounter[3] == IN_PROGRESS) // Prevent use more than one time - DoUseDoorOrButton(GO_TOMB_ENTER); - break; - case DONE: - DoRespawnGameObject(GO_CHEST_SEVEN, HOUR); - DoUseDoorOrButton(GO_TOMB_EXIT); - DoUseDoorOrButton(GO_TOMB_ENTER); - break; + // Reset dwarfes + for (uint8 i = 0; i < MAX_DWARFS; ++i) + { + if (Creature* pDwarf = GetSingleCreatureFromStorage(aTombDwarfes[i])) + { + if (!pDwarf->isAlive()) + pDwarf->Respawn(); + } + } + + m_uiDwarfRound = 0; + m_uiDwarfFightTimer = 0; + } + if (uiData == DONE) + { + DoRespawnGameObject(GO_CHEST_SEVEN, HOUR); + DoUseDoorOrButton(GO_TOMB_EXIT); } m_auiEncounter[3] = uiData; break; @@ -176,7 +238,7 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[4] = uiData; break; case TYPE_IRON_HALL: - switch(uiData) + switch (uiData) { case IN_PROGRESS: DoUseDoorOrButton(GO_GOLEM_ROOM_N); @@ -194,6 +256,13 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) } m_auiEncounter[5] = uiData; break; + case TYPE_QUEST_JAIL_BREAK: + m_auiEncounter[6] = uiData; + return; + case TYPE_FLAMELASH: + for (int i = 0; i < MAX_DWARF_RUNES; ++i) + DoUseDoorOrButton(GO_DWARFRUNE_A01 + i); + return; } if (uiData == DONE) @@ -202,7 +271,8 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7]; m_strInstData = saveStream.str(); @@ -211,9 +281,9 @@ void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_blackrock_depths::GetData(uint32 uiType) +uint32 instance_blackrock_depths::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_RING_OF_LAW: return m_auiEncounter[0]; @@ -230,6 +300,10 @@ uint32 instance_blackrock_depths::GetData(uint32 uiType) return m_auiEncounter[4]; case TYPE_IRON_HALL: return m_auiEncounter[5]; + case TYPE_QUEST_JAIL_BREAK: + return m_auiEncounter[6]; + case TYPE_FLAMELASH: + return m_auiEncounter[7]; default: return 0; } @@ -247,33 +321,56 @@ void instance_blackrock_depths::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; OUT_LOAD_INST_DATA_COMPLETE; } +void instance_blackrock_depths::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_MAGMUS) + SetData(TYPE_IRON_HALL, IN_PROGRESS); +} + void instance_blackrock_depths::OnCreatureEvade(Creature* pCreature) { if (GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || GetData(TYPE_RING_OF_LAW) == SPECIAL) { - for (uint8 i = 0; i < sizeof(aArenaNPCs)/sizeof(uint32); ++i) + for (uint8 i = 0; i < countof(aArenaNPCs); ++i) { if (pCreature->GetEntry() == aArenaNPCs[i]) { - SetData(TYPE_RING_OF_LAW, FAIL); - return; - } + SetData(TYPE_RING_OF_LAW, FAIL); + return; + } } } + + switch (pCreature->GetEntry()) + { + // Handle Tomb of the Seven reset in case of wipe + case NPC_HATEREL: + case NPC_ANGERREL: + case NPC_VILEREL: + case NPC_GLOOMREL: + case NPC_SEETHREL: + case NPC_DOPEREL: + case NPC_DOOMREL: + SetData(TYPE_TOMB_OF_SEVEN, FAIL); + break; + case NPC_MAGMUS: + SetData(TYPE_IRON_HALL, FAIL); + break; + } } void instance_blackrock_depths::OnCreatureDeath(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_WARBRINGER_CONST: case NPC_WATCHER_DOOMGRIP: @@ -286,6 +383,87 @@ void instance_blackrock_depths::OnCreatureDeath(Creature* pCreature) SetData(TYPE_VAULT, DONE); } break; + case NPC_OGRABISI: + case NPC_SHILL: + case NPC_CREST: + case NPC_JAZ: + if (GetData(TYPE_QUEST_JAIL_BREAK) == IN_PROGRESS) + SetData(TYPE_QUEST_JAIL_BREAK, SPECIAL); + break; + // Handle Tomb of the Seven dwarf death event + case NPC_HATEREL: + case NPC_ANGERREL: + case NPC_VILEREL: + case NPC_GLOOMREL: + case NPC_SEETHREL: + case NPC_DOPEREL: + // Only handle the event when event is in progress + if (GetData(TYPE_TOMB_OF_SEVEN) != IN_PROGRESS) + return; + // Call the next dwarf only if it's the last one which joined the fight + if (pCreature->GetEntry() == aTombDwarfes[m_uiDwarfRound - 1]) + DoCallNextDwarf(); + break; + case NPC_DOOMREL: + SetData(TYPE_TOMB_OF_SEVEN, DONE); + break; + case NPC_MAGMUS: + SetData(TYPE_IRON_HALL, DONE); + break; + } +} + +void instance_blackrock_depths::DoCallNextDwarf() +{ + if (Creature* pDwarf = GetSingleCreatureFromStorage(aTombDwarfes[m_uiDwarfRound])) + { + if (Player* pPlayer = GetPlayerInMap()) + { + pDwarf->SetFactionTemporary(FACTION_DWARF_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_REACH_HOME); + pDwarf->AI()->AttackStart(pPlayer); + } + } + m_uiDwarfFightTimer = 30000; + ++m_uiDwarfRound; +} + +// function that replaces the princess if requirements are met +bool instance_blackrock_depths::CanReplacePrincess() +{ + Map::PlayerList const& players = instance->GetPlayers(); + if (players.isEmpty()) + return false; + + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + // if at least one player didn't complete the quest, return false + if ((pPlayer->GetTeam() == ALLIANCE && !pPlayer->GetQuestRewardStatus(QUEST_FATE_KINGDOM)) + || (pPlayer->GetTeam() == HORDE && !pPlayer->GetQuestRewardStatus(QUEST_ROYAL_RESCUE))) + return false; + } + } + + return true; +} + +void instance_blackrock_depths::Update(uint32 uiDiff) +{ + if (m_uiDwarfFightTimer) + { + if (m_uiDwarfFightTimer <= uiDiff) + { + if (m_uiDwarfRound < MAX_DWARFS) + { + DoCallNextDwarf(); + m_uiDwarfFightTimer = 30000; + } + else + m_uiDwarfFightTimer = 0; + } + else + m_uiDwarfFightTimer -= uiDiff; } } diff --git a/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h b/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h index 145dab9db..f5195869d 100644 --- a/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h +++ b/scripts/eastern_kingdoms/blackrock_spire/blackrock_spire.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,23 +7,26 @@ enum { - MAX_ENCOUNTER = 5, + MAX_ENCOUNTER = 6, MAX_ROOMS = 7, - TYPE_ROOM_EVENT = 1, - TYPE_EMBERSEER = 2, - TYPE_FLAMEWREATH = 3, // Only summon once per instance - TYPE_STADIUM = 4, + TYPE_ROOM_EVENT = 0, + TYPE_EMBERSEER = 1, + TYPE_FLAMEWREATH = 2, // Only summon once per instance + TYPE_STADIUM = 3, + TYPE_DRAKKISATH = 4, TYPE_VALTHALAK = 5, // Only summon once per instance NPC_SCARSHIELD_INFILTRATOR = 10299, NPC_BLACKHAND_SUMMONER = 9818, NPC_BLACKHAND_VETERAN = 9819, NPC_PYROGUARD_EMBERSEER = 9816, + NPC_SOLAKAR_FLAMEWREATH = 10264, NPC_BLACKHAND_INCARCERATOR = 10316, NPC_LORD_VICTOR_NEFARIUS = 10162, NPC_REND_BLACKHAND = 10429, NPC_GYTH = 10339, + NPC_THE_BEAST = 10430, NPC_DRAKKISATH = 10363, NPC_CHROMATIC_WHELP = 10442, // related to Gyth arena event NPC_CHROMATIC_DRAGON = 10447, @@ -33,6 +36,7 @@ enum GO_EMBERSEER_IN = 175244, GO_DOORS = 175705, GO_EMBERSEER_OUT = 175153, + GO_FATHER_FLAME = 175245, GO_GYTH_ENTRY_DOOR = 164726, GO_GYTH_COMBAT_DOOR = 175185, GO_GYTH_EXIT_DOOR = 175186, @@ -91,53 +95,57 @@ static const uint32 aStadiumEventNpcs[MAX_STADIUM_WAVES][5] = {NPC_CHROMATIC_WHELP, NPC_CHROMATIC_WHELP, NPC_CHROMATIC_DRAGON, NPC_CHROMATIC_DRAGON, NPC_BLACKHAND_HANDLER}, }; -class MANGOS_DLL_DECL instance_blackrock_spire : public ScriptedInstance, private DialogueHelper +class instance_blackrock_spire : public ScriptedInstance, private DialogueHelper { public: instance_blackrock_spire(Map* pMap); ~instance_blackrock_spire() {} - void Initialize(); + void Initialize() override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); - void OnCreatureEvade(Creature* pCreature); - void OnCreatureEnterCombat(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - void SetData64(uint32 uiType, uint64 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDespawn(Creature* pCreature) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; void DoUseEmberseerRunes(bool bReset = false); void DoProcessEmberseerEvent(); void DoSortRoomEventMobs(); - void GetIncarceratorGUIDList(GUIDList &lList) { lList = m_lIncarceratorGUIDList; } - void GetRookeryEggGUIDList(GUIDList &lList) { lList = m_lRookeryEggGUIDList; } + void GetIncarceratorGUIDList(GuidList& lList) { lList = m_lIncarceratorGUIDList; } + + void StartflamewreathEventIfCan(); - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; private: - void JustDidDialogueStep(int32 iEntry); + void JustDidDialogueStep(int32 iEntry) override; void DoSendNextStadiumWave(); + void DoSendNextFlamewreathWave(); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + uint32 m_uiFlamewreathEventTimer; + uint32 m_uiFlamewreathWaveCount; uint32 m_uiStadiumEventTimer; uint8 m_uiStadiumWaves; uint8 m_uiStadiumMobsAlive; ObjectGuid m_aRoomRuneGuid[MAX_ROOMS]; - GUIDList m_alRoomEventMobGUIDSorted[MAX_ROOMS]; - GUIDList m_lRoomEventMobGUIDList; - GUIDList m_lIncarceratorGUIDList; - GUIDList m_lRookeryEggGUIDList; - GUIDList m_lEmberseerRunesGUIDList; + GuidList m_alRoomEventMobGUIDSorted[MAX_ROOMS]; + GuidList m_lRoomEventMobGUIDList; + GuidList m_lIncarceratorGUIDList; + GuidList m_lEmberseerRunesGUIDList; }; #endif diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp deleted file mode 100644 index 6f8813738..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_drakkisath.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Drakkisath -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_FIRENOVA = 23462, - SPELL_CLEAVE = 20691, - SPELL_CONFLIGURATION = 16805, - SPELL_THUNDERCLAP = 15548 //Not sure if right ID. 23931 would be a harder possibility. -}; - -struct MANGOS_DLL_DECL boss_drakkisathAI : public ScriptedAI -{ - boss_drakkisathAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiFireNovaTimer; - uint32 m_uiCleaveTimer; - uint32 m_uiConfligurationTimer; - uint32 m_uiThunderclapTimer; - - void Reset() - { - m_uiFireNovaTimer = 6000; - m_uiCleaveTimer = 8000; - m_uiConfligurationTimer = 15000; - m_uiThunderclapTimer = 17000; - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // FireNova - if (m_uiFireNovaTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FIRENOVA); - m_uiFireNovaTimer = 10000; - } - else - m_uiFireNovaTimer -= uiDiff; - - // Cleave - if (m_uiCleaveTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 8000; - } - else - m_uiCleaveTimer -= uiDiff; - - // Confliguration - if (m_uiConfligurationTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONFLIGURATION, 0, m_creature->getVictim()->GetObjectGuid()); - m_uiConfligurationTimer = 18000; - } - else - m_uiConfligurationTimer -= uiDiff; - - // Thunderclap - if (m_uiThunderclapTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_THUNDERCLAP); - m_uiThunderclapTimer = 20000; - } - else - m_uiThunderclapTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_drakkisath(Creature* pCreature) -{ - return new boss_drakkisathAI(pCreature); -} - -void AddSC_boss_drakkisath() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_drakkisath"; - pNewScript->GetAI = &GetAI_boss_drakkisath; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp index 7e7c4ec0c..5d8f86726 100644 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp +++ b/scripts/eastern_kingdoms/blackrock_spire/boss_gyth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ enum SPELL_KNOCK_AWAY = 10101, }; -struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI +struct boss_gythAI : public ScriptedAI { boss_gythAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -51,29 +51,31 @@ struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI uint32 uiCorrosiveAcidTimer; uint32 uiFreezeTimer; uint32 uiFlamebreathTimer; + uint32 uiKnockAwayTimer; bool m_bSummonedRend; bool m_bHasChromaticChaos; - void Reset() + void Reset() override { uiCorrosiveAcidTimer = 8000; uiFreezeTimer = 11000; uiFlamebreathTimer = 4000; + uiKnockAwayTimer = 23000; m_bSummonedRend = false; m_bHasChromaticChaos = false; DoCastSpellIfCan(m_creature, SPELL_REND_MOUNTS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { DoScriptText(EMOTE_KNOCKED_OFF, pSummoned); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -118,6 +120,14 @@ struct MANGOS_DLL_DECL boss_gythAI : public ScriptedAI else uiFlamebreathTimer -= uiDiff; + if (uiKnockAwayTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KNOCK_AWAY) == CAST_OK) + uiKnockAwayTimer = 23000; + } + else + uiKnockAwayTimer -= uiDiff; + // Summon Rend if (!m_bSummonedRend && m_creature->GetHealthPercent() < 11.0f) { diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp deleted file mode 100644 index e40f2627c..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_halycon.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Halycon -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_CROWDPUMMEL 10887 -#define SPELL_MIGHTYBLOW 14099 - -#define ADD_1X -169.839203f -#define ADD_1Y -324.961395f -#define ADD_1Z 64.401443f -#define ADD_1O 3.124724f - -struct MANGOS_DLL_DECL boss_halyconAI : public ScriptedAI -{ - boss_halyconAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 CrowdPummel_Timer; - uint32 MightyBlow_Timer; - bool Summoned; - - void Reset() - { - CrowdPummel_Timer = 8000; - MightyBlow_Timer = 14000; - Summoned = false; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //CrowdPummel_Timer - if (CrowdPummel_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CROWDPUMMEL); - CrowdPummel_Timer = 14000; - }else CrowdPummel_Timer -= diff; - - //MightyBlow_Timer - if (MightyBlow_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MIGHTYBLOW); - MightyBlow_Timer = 10000; - }else MightyBlow_Timer -= diff; - - //Summon Gizrul - if (!Summoned && m_creature->GetHealthPercent() < 25.0f) - { - m_creature->SummonCreature(10268,ADD_1X,ADD_1Y,ADD_1Z,ADD_1O,TEMPSUMMON_TIMED_DESPAWN,300000); - Summoned = true; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_halycon(Creature* pCreature) -{ - return new boss_halyconAI(pCreature); -} - -void AddSC_boss_halycon() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_halycon"; - pNewScript->GetAI = &GetAI_boss_halycon; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp deleted file mode 100644 index 57d65d297..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_highlord_omokk.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Highlord_Omokk -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_WARSTOMP = 24375, - SPELL_STRIKE = 18368, - SPELL_REND = 18106, - SPELL_SUNDERARMOR = 24317, - SPELL_KNOCKAWAY = 20686, - SPELL_SLOW = 22356 -}; - -struct MANGOS_DLL_DECL boss_highlordomokkAI : public ScriptedAI -{ - boss_highlordomokkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiWarStompTimer; - uint32 m_uiStrikeTimer; - uint32 m_uiRendTimer; - uint32 m_uiSunderArmorTimer; - uint32 m_uiKnockAwayTimer; - uint32 m_uiSlowTimer; - - void Reset() - { - m_uiWarStompTimer = 15000; - m_uiStrikeTimer = 10000; - m_uiRendTimer = 14000; - m_uiSunderArmorTimer = 2000; - m_uiKnockAwayTimer = 18000; - m_uiSlowTimer = 24000; - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // WarStomp - if (m_uiWarStompTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_WARSTOMP); - m_uiWarStompTimer = 14000; - } - else - m_uiWarStompTimer -= uiDiff; - - // Strike - if (m_uiStrikeTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRIKE); - m_uiStrikeTimer = 10000; - } - else - m_uiStrikeTimer -= uiDiff; - - // Rend - if (m_uiRendTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_REND); - m_uiRendTimer = 18000; - } - else - m_uiRendTimer -= uiDiff; - - // Sunder Armor - if (m_uiSunderArmorTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDERARMOR); - m_uiSunderArmorTimer = 25000; - } - else - m_uiSunderArmorTimer -= uiDiff; - - // KnockAway - if (m_uiKnockAwayTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_KNOCKAWAY); - m_uiKnockAwayTimer = 12000; - } - else - m_uiKnockAwayTimer -= uiDiff; - - // Slow - if (m_uiSlowTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_SLOW); - m_uiSlowTimer = 18000; - } - else - m_uiSlowTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_highlordomokk(Creature* pCreature) -{ - return new boss_highlordomokkAI(pCreature); -} - -void AddSC_boss_highlordomokk() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_highlord_omokk"; - pNewScript->GetAI = &GetAI_boss_highlordomokk; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp deleted file mode 100644 index 25a1e66b1..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_mother_smolderweb.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Mother_Smolderweb -SD%Complete: 100 -SDComment: Uncertain how often mother's milk is casted -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_CRYSTALIZE = 16104, - SPELL_MOTHERSMILK = 16468, - SPELL_SUMMON_SPIRE_SPIDERLING = 16103 -}; - -struct MANGOS_DLL_DECL boss_mothersmolderwebAI : public ScriptedAI -{ - boss_mothersmolderwebAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiCrystalizeTimer; - uint32 m_uiMothersMilkTimer; - - void Reset() - { - m_uiCrystalizeTimer = 20000; - m_uiMothersMilkTimer = 10000; - } - - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) - { - if (m_creature->GetHealth() <= uiDamage) - DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIRE_SPIDERLING, CAST_TRIGGERED); - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Crystalize - if (m_uiCrystalizeTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_CRYSTALIZE); - m_uiCrystalizeTimer = 15000; - } - else - m_uiCrystalizeTimer -= uiDiff; - - // Mothers Milk - if (m_uiMothersMilkTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_MOTHERSMILK); - m_uiMothersMilkTimer = urand(5000, 12500); - } - else - m_uiMothersMilkTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_mothersmolderweb(Creature* pCreature) -{ - return new boss_mothersmolderwebAI(pCreature); -} - -void AddSC_boss_mothersmolderweb() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_mother_smolderweb"; - pNewScript->GetAI = &GetAI_boss_mothersmolderweb; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp index fa8256101..92b0ace4c 100644 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp +++ b/scripts/eastern_kingdoms/blackrock_spire/boss_overlord_wyrmthalak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -32,16 +32,15 @@ enum NPC_SPIRESTONE_WARLORD = 9216, NPC_SMOLDERTHORN_BERSERKER = 9268 - }; -const float afLocations[2][4]= +const float afLocations[2][4] = { - {-39.355381f, -513.456482f, 88.472046f, 4.679872f}, - {-49.875881f, -511.896942f, 88.195160f, 4.613114f} + { -39.355381f, -513.456482f, 88.472046f, 4.679872f}, + { -49.875881f, -511.896942f, 88.195160f, 4.613114f} }; -struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI +struct boss_overlordwyrmthalakAI : public ScriptedAI { boss_overlordwyrmthalakAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -51,7 +50,7 @@ struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI uint32 m_uiKnockawayTimer; bool m_bSummoned; - void Reset() + void Reset() override { m_uiBlastWaveTimer = 20000; m_uiShoutTimer = 2000; @@ -60,7 +59,7 @@ struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI m_bSummoned = false; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() != NPC_SPIRESTONE_WARLORD && pSummoned->GetEntry() != NPC_SMOLDERTHORN_BERSERKER) return; @@ -72,7 +71,7 @@ struct MANGOS_DLL_DECL boss_overlordwyrmthalakAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp index 9c46e5e1b..94853e071 100644 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp +++ b/scripts/eastern_kingdoms/blackrock_spire/boss_pyroguard_emberseer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum SPELL_PYROBLAST = 20228 // guesswork, but best fitting in spells-area, was 17274 (has mana cost) }; -struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI +struct boss_pyroguard_emberseerAI : public ScriptedAI { boss_pyroguard_emberseerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -66,7 +66,7 @@ struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI uint32 m_uiPyroBlastTimer; uint8 m_uiGrowingStacks; - void Reset() + void Reset() override { m_uiEncageTimer = 10000; m_uiFireNovaTimer = 6000; @@ -77,13 +77,13 @@ struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_EMBERSEER, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_EMBERSEER, FAIL); @@ -94,7 +94,7 @@ struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI { ++m_uiGrowingStacks; - if (m_uiGrowingStacks == MAX_GROWING_STACKS*0.5f) + if (m_uiGrowingStacks == MAX_GROWING_STACKS * 0.5f) DoScriptText(EMOTE_NEAR, m_creature); else if (m_uiGrowingStacks == MAX_GROWING_STACKS) { @@ -118,17 +118,23 @@ struct MANGOS_DLL_DECL boss_pyroguard_emberseerAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Cast Encage spell on OOC timer if (m_uiEncageTimer) { if (m_uiEncageTimer <= uiDiff) { - GUIDList m_lIncarceratorsGuid; + if (!m_pInstance) + { + script_error_log("Instance Blackrock Spire: ERROR Failed to load instance data for this instace."); + return; + } + + GuidList m_lIncarceratorsGuid; m_pInstance->GetIncarceratorGUIDList(m_lIncarceratorsGuid); - for (GUIDList::const_iterator itr = m_lIncarceratorsGuid.begin(); itr != m_lIncarceratorsGuid.end(); ++itr) + for (GuidList::const_iterator itr = m_lIncarceratorsGuid.begin(); itr != m_lIncarceratorsGuid.end(); ++itr) { if (Creature* pIncarcerator = m_creature->GetMap()->GetCreature(*itr)) pIncarcerator->CastSpell(m_creature, SPELL_ENCAGE_EMBERSEER, false); @@ -183,9 +189,9 @@ CreatureAI* GetAI_boss_pyroguard_emberseer(Creature* pCreature) return new boss_pyroguard_emberseerAI(pCreature); } -bool EffectDummyCreature_pyroguard_emberseer(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_pyroguard_emberseer(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_GROWING && uiEffIndex == EFFECT_INDEX_0) { if (boss_pyroguard_emberseerAI* pEmberseerAI = dynamic_cast(pCreatureTarget->AI())) diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp deleted file mode 100644 index 25c8be0d4..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_quartermaster_zigris.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Quartmaster_Zigris -SD%Complete: 100 -SDComment: Needs revision -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_SHOOT = 16496, - SPELL_STUNBOMB = 16497, - SPELL_HEALING_POTION = 15504, - SPELL_HOOKEDNET = 15609 -}; - -struct MANGOS_DLL_DECL boss_quatermasterzigrisAI : public ScriptedAI -{ - boss_quatermasterzigrisAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiShootTimer; - uint32 m_uiStunBombTimer; - //uint32 HelingPotion_Timer; - - void Reset() - { - m_uiShootTimer = 1000; - m_uiStunBombTimer = 16000; - //HelingPotion_Timer = 25000; - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Shoot - if (m_uiShootTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOOT); - m_uiShootTimer = 500; - } - else - m_uiShootTimer -= uiDiff; - - // StunBomb - if (m_uiStunBombTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_STUNBOMB); - m_uiStunBombTimer = 14000; - } - else - m_uiStunBombTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_quatermasterzigris(Creature* pCreature) -{ - return new boss_quatermasterzigrisAI(pCreature); -} - -void AddSC_boss_quatermasterzigris() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "quartermaster_zigris"; - pNewScript->GetAI = &GetAI_boss_quatermasterzigris; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp deleted file mode 100644 index be09d1955..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_rend_blackhand.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Rend_Blackhand -SD%Complete: 100 -SDComment: Intro event NYI -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_WHIRLWIND = 26038, - SPELL_CLEAVE = 20691, - SPELL_THUNDERCLAP = 23931 //Not sure if he cast this spell -}; - -struct MANGOS_DLL_DECL boss_rend_blackhandAI : public ScriptedAI -{ - boss_rend_blackhandAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiWhirlWindTimer; - uint32 m_uiCleaveTimer; - uint32 m_uiThunderclapTimer; - - void Reset() - { - m_uiWhirlWindTimer = 20000; - m_uiCleaveTimer = 5000; - m_uiThunderclapTimer = 9000; - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // WhirlWind - if (m_uiWhirlWindTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlWindTimer = 18000; - } - else - m_uiWhirlWindTimer -= uiDiff; - - // Cleave - if (m_uiCleaveTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 10000; - } - else - m_uiCleaveTimer -= uiDiff; - - // Thunderclap - if (m_uiThunderclapTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_THUNDERCLAP); - m_uiThunderclapTimer = 16000; - } - else - m_uiThunderclapTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_rend_blackhand(Creature* pCreature) -{ - return new boss_rend_blackhandAI(pCreature); -} - -void AddSC_boss_rend_blackhand() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_rend_blackhand"; - pNewScript->GetAI = &GetAI_boss_rend_blackhand; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp deleted file mode 100644 index 1a9cd75c9..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_shadow_hunter_voshgajin.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Shadow_Hunter_Voshgajin -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_CURSEOFBLOOD = 24673, - SPELL_HEX = 16708, - SPELL_CLEAVE = 20691 -}; - -struct MANGOS_DLL_DECL boss_shadowvoshAI : public ScriptedAI -{ - boss_shadowvoshAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiCurseOfBloodTimer; - uint32 m_uiHexTimer; - uint32 m_uiCleaveTimer; - - void Reset() - { - m_uiCurseOfBloodTimer = 2000; - m_uiHexTimer = 8000; - m_uiCleaveTimer = 14000; - - //m_creature->CastSpell(m_creature,SPELL_ICEARMOR,true); - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Curse Of Blood - if (m_uiCurseOfBloodTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_CURSEOFBLOOD); - m_uiCurseOfBloodTimer = 45000; - } - else - m_uiCurseOfBloodTimer -= uiDiff; - - // Hex - if (m_uiHexTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_HEX); - m_uiHexTimer = 15000; - } - else - m_uiHexTimer -= uiDiff; - - // Cleave - if (m_uiCleaveTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 7000; - } - else - m_uiCleaveTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_shadowvosh(Creature* pCreature) -{ - return new boss_shadowvoshAI(pCreature); -} - -void AddSC_boss_shadowvosh() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_shadow_hunter_voshgajin"; - pNewScript->GetAI = &GetAI_boss_shadowvosh; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp deleted file mode 100644 index 6329f878a..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_the_beast.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_The_Best -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_FLAMEBREAK = 16785, - SPELL_IMMOLATE = 20294, - SPELL_TERRIFYINGROAR = 14100 -}; - -struct MANGOS_DLL_DECL boss_thebeastAI : public ScriptedAI -{ - boss_thebeastAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiFlamebreakTimer; - uint32 m_uiImmolateTimer; - uint32 m_uiTerrifyingRoarTimer; - - void Reset() - { - m_uiFlamebreakTimer = 12000; - m_uiImmolateTimer = 3000; - m_uiTerrifyingRoarTimer = 23000; - } - - void UpdateAI(const uint32 uiDiff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Flamebreak - if (m_uiFlamebreakTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAMEBREAK); - m_uiFlamebreakTimer = 10000; - } - else - m_uiFlamebreakTimer -= uiDiff; - - // Immolate - if (m_uiImmolateTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_IMMOLATE); - - m_uiImmolateTimer = 8000; - } - else - m_uiImmolateTimer -= uiDiff; - - // Terrifying Roar - if (m_uiTerrifyingRoarTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_TERRIFYINGROAR); - m_uiTerrifyingRoarTimer = 20000; - } - else - m_uiTerrifyingRoarTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_thebeast(Creature* pCreature) -{ - return new boss_thebeastAI(pCreature); -} - -void AddSC_boss_thebeast() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_the_beast"; - pNewScript->GetAI = &GetAI_boss_thebeast; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp b/scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp deleted file mode 100644 index a6728b67e..000000000 --- a/scripts/eastern_kingdoms/blackrock_spire/boss_warmaster_voone.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Warmaster_Voone -SD%Complete: 100 -SDComment: -SDCategory: Blackrock Spire -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SNAPKICK 15618 -#define SPELL_CLEAVE 15284 -#define SPELL_UPPERCUT 10966 -#define SPELL_MORTALSTRIKE 15708 -#define SPELL_PUMMEL 15615 -#define SPELL_THROWAXE 16075 - -struct MANGOS_DLL_DECL boss_warmastervooneAI : public ScriptedAI -{ - boss_warmastervooneAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Snapkick_Timer; - uint32 Cleave_Timer; - uint32 Uppercut_Timer; - uint32 MortalStrike_Timer; - uint32 Pummel_Timer; - uint32 ThrowAxe_Timer; - - void Reset() - { - Snapkick_Timer = 8000; - Cleave_Timer = 14000; - Uppercut_Timer = 20000; - MortalStrike_Timer = 12000; - Pummel_Timer = 32000; - ThrowAxe_Timer = 1000; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Snapkick_Timer - if (Snapkick_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SNAPKICK); - Snapkick_Timer = 6000; - }else Snapkick_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 12000; - }else Cleave_Timer -= diff; - - //Uppercut_Timer - if (Uppercut_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 14000; - }else Uppercut_Timer -= diff; - - //MortalStrike_Timer - if (MortalStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTALSTRIKE); - MortalStrike_Timer = 10000; - }else MortalStrike_Timer -= diff; - - //Pummel_Timer - if (Pummel_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_PUMMEL); - Pummel_Timer = 16000; - }else Pummel_Timer -= diff; - - //ThrowAxe_Timer - if (ThrowAxe_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_THROWAXE); - ThrowAxe_Timer = 8000; - }else ThrowAxe_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_warmastervoone(Creature* pCreature) -{ - return new boss_warmastervooneAI(pCreature); -} - -void AddSC_boss_warmastervoone() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_warmaster_voone"; - pNewScript->GetAI = &GetAI_boss_warmastervoone; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp b/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp index 095eff522..01cec4892 100644 --- a/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp +++ b/scripts/eastern_kingdoms/blackrock_spire/instance_blackrock_spire.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -47,8 +47,15 @@ enum // Emberseer event EMOTE_BEGIN = -1229000, - SPELL_EMBERSEER_GROWING = 16048, + + // Solakar Flamewreath Event + SAY_ROOKERY_EVENT_START = -1229020, + NPC_ROOKERY_GUARDIAN = 10258, + NPC_ROOKERY_HATCHER = 10683, + + // Spells + SPELL_FINKLE_IS_EINHORN = 16710, }; /* Areatrigger @@ -79,10 +86,14 @@ static const DialogueEntry aStadiumDialogue[] = {0, 0, 0}, }; +static const float rookeryEventSpawnPos[3] = {43.7685f, -259.82f, 91.6483f}; + instance_blackrock_spire::instance_blackrock_spire(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aStadiumDialogue), + m_uiFlamewreathEventTimer(0), + m_uiFlamewreathWaveCount(0), m_uiStadiumEventTimer(0), - m_uiStadiumMobsAlive(0), - m_uiStadiumWaves(0) + m_uiStadiumWaves(0), + m_uiStadiumMobsAlive(0) { Initialize(); } @@ -96,7 +107,7 @@ void instance_blackrock_spire::Initialize() void instance_blackrock_spire::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_EMBERSEER_IN: if (GetData(TYPE_ROOM_EVENT) == DONE) @@ -108,6 +119,7 @@ void instance_blackrock_spire::OnObjectCreate(GameObject* pGo) if (GetData(TYPE_EMBERSEER) == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + case GO_FATHER_FLAME: case GO_GYTH_ENTRY_DOOR: case GO_GYTH_COMBAT_DOOR: case GO_DRAKKISATH_DOOR_1: @@ -126,8 +138,6 @@ void instance_blackrock_spire::OnObjectCreate(GameObject* pGo) case GO_ROOM_6_RUNE: m_aRoomRuneGuid[5] = pGo->GetObjectGuid(); return; case GO_ROOM_7_RUNE: m_aRoomRuneGuid[6] = pGo->GetObjectGuid(); return; - case GO_ROOKERY_EGG: m_lRookeryEggGUIDList.push_back(pGo->GetObjectGuid()); return; - case GO_EMBERSEER_RUNE_1: case GO_EMBERSEER_RUNE_2: case GO_EMBERSEER_RUNE_3: @@ -146,9 +156,10 @@ void instance_blackrock_spire::OnObjectCreate(GameObject* pGo) void instance_blackrock_spire::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_PYROGUARD_EMBERSEER: + case NPC_SOLAKAR_FLAMEWREATH: case NPC_LORD_VICTOR_NEFARIUS: case NPC_GYTH: case NPC_REND_BLACKHAND: @@ -164,23 +175,23 @@ void instance_blackrock_spire::OnCreatureCreate(Creature* pCreature) void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ROOM_EVENT: if (uiData == DONE) DoUseDoorOrButton(GO_EMBERSEER_IN); - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_EMBERSEER: // Don't set the same data twice - if (m_auiEncounter[1] == uiData) + if (m_auiEncounter[uiType] == uiData) break; // Combat door DoUseDoorOrButton(GO_DOORS); // Respawn all incarcerators and reset the runes on FAIL if (uiData == FAIL) { - for (GUIDList::const_iterator itr = m_lIncarceratorGUIDList.begin(); itr != m_lIncarceratorGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lIncarceratorGUIDList.begin(); itr != m_lIncarceratorGUIDList.end(); ++itr) { if (Creature* pIncarcerator = instance->GetCreature(*itr)) { @@ -197,14 +208,19 @@ void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) DoUseEmberseerRunes(); DoUseDoorOrButton(GO_EMBERSEER_OUT); } - m_auiEncounter[1] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_FLAMEWREATH: - m_auiEncounter[2] = uiData; + if (uiData == FAIL) + { + m_uiFlamewreathEventTimer = 0; + m_uiFlamewreathWaveCount = 0; + } + m_auiEncounter[uiType] = uiData; break; case TYPE_STADIUM: // Don't set the same data twice - if (m_auiEncounter[3] == uiData) + if (m_auiEncounter[uiType] == uiData) break; // Combat door DoUseDoorOrButton(GO_GYTH_ENTRY_DOOR); @@ -227,10 +243,11 @@ void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) m_uiStadiumMobsAlive = 0; m_uiStadiumWaves = 0; } - m_auiEncounter[3] = uiData; + m_auiEncounter[uiType] = uiData; break; + case TYPE_DRAKKISATH: case TYPE_VALTHALAK: - m_auiEncounter[4] = uiData; + m_auiEncounter[uiType] = uiData; break; } @@ -239,7 +256,7 @@ void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " << m_auiEncounter[4]; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; m_strInstData = saveStream.str(); @@ -248,30 +265,6 @@ void instance_blackrock_spire::SetData(uint32 uiType, uint32 uiData) } } -void instance_blackrock_spire::SetData64(uint32 uiType, uint64 uiData) -{ - if (uiType == TYPE_ROOM_EVENT && GetData(TYPE_ROOM_EVENT) == IN_PROGRESS) - { - uint8 uiNotEmptyRoomsCount = 0; - for (uint8 i = 0; i < MAX_ROOMS; ++i) - { - if (m_aRoomRuneGuid[i]) // This check is used, to ensure which runes still need processing - { - m_alRoomEventMobGUIDSorted[i].remove(ObjectGuid(uiData)); - if (m_alRoomEventMobGUIDSorted[i].empty()) - { - DoUseDoorOrButton(m_aRoomRuneGuid[i]); - m_aRoomRuneGuid[i].Clear(); - } - else - ++uiNotEmptyRoomsCount; // found an not empty room - } - } - if (!uiNotEmptyRoomsCount) - SetData(TYPE_ROOM_EVENT, DONE); - } -} - void instance_blackrock_spire::Load(const char* chrIn) { if (!chrIn) @@ -283,9 +276,9 @@ void instance_blackrock_spire::Load(const char* chrIn) OUT_LOAD_INST_DATA(chrIn); std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -294,16 +287,11 @@ void instance_blackrock_spire::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_blackrock_spire::GetData(uint32 uiType) +uint32 instance_blackrock_spire::GetData(uint32 uiType) const { - switch(uiType) - { - case TYPE_ROOM_EVENT: return m_auiEncounter[0]; - case TYPE_EMBERSEER: return m_auiEncounter[1]; - case TYPE_FLAMEWREATH: return m_auiEncounter[2]; - case TYPE_STADIUM: return m_auiEncounter[3]; - case TYPE_VALTHALAK: return m_auiEncounter[4]; - } + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + return 0; } @@ -316,7 +304,7 @@ void instance_blackrock_spire::DoSortRoomEventMobs() { if (GameObject* pRune = instance->GetGameObject(m_aRoomRuneGuid[i])) { - for (GUIDList::const_iterator itr = m_lRoomEventMobGUIDList.begin(); itr != m_lRoomEventMobGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lRoomEventMobGUIDList.begin(); itr != m_lRoomEventMobGUIDList.end(); ++itr) { Creature* pCreature = instance->GetCreature(*itr); if (pCreature && pCreature->isAlive() && pCreature->GetDistance(pRune) < 10.0f) @@ -332,8 +320,35 @@ void instance_blackrock_spire::OnCreatureDeath(Creature* pCreature) { switch (pCreature->GetEntry()) { + case NPC_BLACKHAND_SUMMONER: + case NPC_BLACKHAND_VETERAN: + // Handle Runes + if (m_auiEncounter[TYPE_ROOM_EVENT] == IN_PROGRESS) + { + uint8 uiNotEmptyRoomsCount = 0; + for (uint8 i = 0; i < MAX_ROOMS; ++i) + { + if (m_aRoomRuneGuid[i]) // This check is used, to ensure which runes still need processing + { + m_alRoomEventMobGUIDSorted[i].remove(pCreature->GetObjectGuid()); + if (m_alRoomEventMobGUIDSorted[i].empty()) + { + DoUseDoorOrButton(m_aRoomRuneGuid[i]); + m_aRoomRuneGuid[i].Clear(); + } + else + ++uiNotEmptyRoomsCount; // found an not empty room + } + } + if (!uiNotEmptyRoomsCount) + SetData(TYPE_ROOM_EVENT, DONE); + } + break; + case NPC_SOLAKAR_FLAMEWREATH: + SetData(TYPE_FLAMEWREATH, DONE); + break; case NPC_DRAKKISATH: - // Just open the doors, don't save anything because it's the last boss + SetData(TYPE_DRAKKISATH, DONE); DoUseDoorOrButton(GO_DRAKKISATH_DOOR_1); DoUseDoorOrButton(GO_DRAKKISATH_DOOR_2); break; @@ -360,11 +375,16 @@ void instance_blackrock_spire::OnCreatureEvade(Creature* pCreature) { switch (pCreature->GetEntry()) { - // Emberseer should evade if the incarcerators evade + // Emberseer should evade if the incarcerators evade case NPC_BLACKHAND_INCARCERATOR: if (Creature* pEmberseer = GetSingleCreatureFromStorage(NPC_PYROGUARD_EMBERSEER)) pEmberseer->AI()->EnterEvadeMode(); break; + case NPC_SOLAKAR_FLAMEWREATH: + case NPC_ROOKERY_GUARDIAN: + case NPC_ROOKERY_HATCHER: + SetData(TYPE_FLAMEWREATH, FAIL); + break; case NPC_CHROMATIC_WHELP: case NPC_CHROMATIC_DRAGON: case NPC_BLACKHAND_HANDLER: @@ -383,13 +403,19 @@ void instance_blackrock_spire::OnCreatureEnterCombat(Creature* pCreature) { switch (pCreature->GetEntry()) { - // Once one of the Incarcerators gets Aggro, the door should close + // Once one of the Incarcerators gets Aggro, the door should close case NPC_BLACKHAND_INCARCERATOR: SetData(TYPE_EMBERSEER, IN_PROGRESS); break; } } +void instance_blackrock_spire::OnCreatureDespawn(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_THE_BEAST) + pCreature->CastSpell(pCreature, SPELL_FINKLE_IS_EINHORN, true); +} + void instance_blackrock_spire::DoProcessEmberseerEvent() { if (GetData(TYPE_EMBERSEER) == DONE || GetData(TYPE_EMBERSEER) == IN_PROGRESS) @@ -397,7 +423,7 @@ void instance_blackrock_spire::DoProcessEmberseerEvent() if (m_lIncarceratorGUIDList.empty()) { - error_log("SD2: Npc %u couldn't be found. Please check your DB content!", NPC_BLACKHAND_INCARCERATOR); + script_error_log("Npc %u couldn't be found. Please check your DB content!", NPC_BLACKHAND_INCARCERATOR); return; } @@ -413,7 +439,7 @@ void instance_blackrock_spire::DoProcessEmberseerEvent() } // remove the incarcerators flags and stop casting - for (GUIDList::const_iterator itr = m_lIncarceratorGUIDList.begin(); itr != m_lIncarceratorGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lIncarceratorGUIDList.begin(); itr != m_lIncarceratorGUIDList.end(); ++itr) { if (Creature* pCreature = instance->GetCreature(*itr)) { @@ -431,7 +457,7 @@ void instance_blackrock_spire::DoUseEmberseerRunes(bool bReset) if (m_lEmberseerRunesGUIDList.empty()) return; - for (GUIDList::const_iterator itr = m_lEmberseerRunesGUIDList.begin(); itr != m_lEmberseerRunesGUIDList.end(); itr++) + for (GuidList::const_iterator itr = m_lEmberseerRunesGUIDList.begin(); itr != m_lEmberseerRunesGUIDList.end(); ++itr) { if (bReset) { @@ -476,7 +502,6 @@ void instance_blackrock_spire::JustDidDialogueStep(int32 iEntry) pNefarius->GetMotionMaster()->MovePoint(0, aStadiumLocs[6].m_fX, aStadiumLocs[6].m_fY, aStadiumLocs[6].m_fZ); } break; - } } @@ -484,7 +509,7 @@ void instance_blackrock_spire::DoSendNextStadiumWave() { if (m_uiStadiumWaves < MAX_STADIUM_WAVES) { - // Send current wave mobs + // Send current wave mobs if (Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) { float fX, fY, fZ; @@ -494,12 +519,12 @@ void instance_blackrock_spire::DoSendNextStadiumWave() continue; pNefarius->GetRandomPoint(aStadiumLocs[0].m_fX, aStadiumLocs[0].m_fY, aStadiumLocs[0].m_fZ, 7.0f, fX, fY, fZ); - fX = std::min(aStadiumLocs[0].m_fX, fX); // Halfcircle - suits better the rectangular form + fX = std::min(aStadiumLocs[0].m_fX, fX); // Halfcircle - suits better the rectangular form if (Creature* pTemp = pNefarius->SummonCreature(aStadiumEventNpcs[m_uiStadiumWaves][i], fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0)) { // Get some point in the center of the stadium pTemp->GetRandomPoint(aStadiumLocs[2].m_fX, aStadiumLocs[2].m_fY, aStadiumLocs[2].m_fZ, 5.0f, fX, fY, fZ); - fX = std::min(aStadiumLocs[2].m_fX, fX); // Halfcircle - suits better the rectangular form + fX = std::min(aStadiumLocs[2].m_fX, fX);// Halfcircle - suits better the rectangular form pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); ++m_uiStadiumMobsAlive; @@ -514,7 +539,7 @@ void instance_blackrock_spire::DoSendNextStadiumWave() StartNextDialogueText(SAY_NEFARIUS_LOSE_4); else { - // Send Gyth + // Send Gyth if (Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS)) { if (Creature* pTemp = pNefarius->SummonCreature(NPC_GYTH, aStadiumLocs[1].m_fX, aStadiumLocs[1].m_fY, aStadiumLocs[1].m_fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0)) @@ -536,6 +561,50 @@ void instance_blackrock_spire::DoSendNextStadiumWave() m_uiStadiumEventTimer = 60000; } +void instance_blackrock_spire::DoSendNextFlamewreathWave() +{ + GameObject* pSummoner = GetSingleGameObjectFromStorage(GO_FATHER_FLAME); + if (!pSummoner) + return; + + // TODO - The npcs would move nicer if they had DB waypoints, so i suggest to change their default movement to DB waypoints, and random movement when they reached their goal + + if (m_uiFlamewreathWaveCount < 6) // Send two adds (6 waves, then boss) + { + Creature* pSummoned = NULL; + for (uint8 i = 0; i < 2; ++i) + { + float fX, fY, fZ; + pSummoner->GetRandomPoint(rookeryEventSpawnPos[0], rookeryEventSpawnPos[1], rookeryEventSpawnPos[2], 2.5f, fX, fY, fZ); + // Summon Rookery Hatchers in first wave, else random + if (pSummoned = pSummoner->SummonCreature(urand(0, 1) && m_uiFlamewreathWaveCount ? NPC_ROOKERY_GUARDIAN : NPC_ROOKERY_HATCHER, + fX, fY, fZ, 0.0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000)) + { + pSummoner->GetContactPoint(pSummoned, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, pSummoner->GetPositionZ()); + } + } + if (pSummoned && m_uiFlamewreathWaveCount == 0) + DoScriptText(SAY_ROOKERY_EVENT_START, pSummoned); + + if (m_uiFlamewreathWaveCount < 4) + m_uiFlamewreathEventTimer = 30000; + else if (m_uiFlamewreathWaveCount < 6) + m_uiFlamewreathEventTimer = 40000; + else + m_uiFlamewreathEventTimer = 10000; + + ++m_uiFlamewreathWaveCount; + } + else // Send Flamewreath + { + if (Creature* pSolakar = pSummoner->SummonCreature(NPC_SOLAKAR_FLAMEWREATH, rookeryEventSpawnPos[0], rookeryEventSpawnPos[1], rookeryEventSpawnPos[2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, HOUR * IN_MILLISECONDS)) + pSolakar->GetMotionMaster()->MovePoint(1, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ()); + SetData(TYPE_FLAMEWREATH, SPECIAL); + m_uiFlamewreathEventTimer = 0; + } +} + void instance_blackrock_spire::Update(uint32 uiDiff) { DialogueUpdate(uiDiff); @@ -547,6 +616,29 @@ void instance_blackrock_spire::Update(uint32 uiDiff) else m_uiStadiumEventTimer -= uiDiff; } + + if (m_uiFlamewreathEventTimer) + { + if (m_uiFlamewreathEventTimer <= uiDiff) + DoSendNextFlamewreathWave(); + else + m_uiFlamewreathEventTimer -= uiDiff; + } +} + +void instance_blackrock_spire::StartflamewreathEventIfCan() +{ + // Already done or currently in progress - or endboss done + if (m_auiEncounter[TYPE_FLAMEWREATH] == DONE || m_auiEncounter[TYPE_FLAMEWREATH] == IN_PROGRESS || m_auiEncounter[TYPE_DRAKKISATH] == DONE) + return; + + // Boss still around + if (GetSingleCreatureFromStorage(NPC_SOLAKAR_FLAMEWREATH, true)) + return; + + // Start summoning of mobs + m_uiFlamewreathEventTimer = 1; + m_uiFlamewreathWaveCount = 0; } InstanceData* GetInstanceData_instance_blackrock_spire(Map* pMap) @@ -574,7 +666,7 @@ bool AreaTrigger_at_blackrock_spire(Player* pPlayer, AreaTriggerEntry const* pAt // Summon Nefarius and Rend for the dialogue event // Note: Nefarius and Rend need to be hostile and not attackable if (Creature* pNefarius = pPlayer->SummonCreature(NPC_LORD_VICTOR_NEFARIUS, aStadiumLocs[3].m_fX, aStadiumLocs[3].m_fY, aStadiumLocs[3].m_fZ, aStadiumLocs[3].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) - pNefarius->setFaction(FACTION_BLACK_DRAGON); + pNefarius->SetFactionTemporary(FACTION_BLACK_DRAGON, TEMPFACTION_NONE); if (Creature* pRend = pPlayer->SummonCreature(NPC_REND_BLACKHAND, aStadiumLocs[4].m_fX, aStadiumLocs[4].m_fY, aStadiumLocs[4].m_fZ, aStadiumLocs[4].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) pRend->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); @@ -585,7 +677,7 @@ bool AreaTrigger_at_blackrock_spire(Player* pPlayer, AreaTriggerEntry const* pAt return false; } -bool ProcessEventId_event_spell_altar_emberseer(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_spell_altar_emberseer(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) { if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { @@ -598,6 +690,14 @@ bool ProcessEventId_event_spell_altar_emberseer(uint32 uiEventId, Object* pSourc return false; } +bool GOUse_go_father_flame(Player* /*pPlayer*/, GameObject* pGo) +{ + if (instance_blackrock_spire* pInstance = (instance_blackrock_spire*)pGo->GetInstanceData()) + pInstance->StartflamewreathEventIfCan(); + + return true; +} + void AddSC_instance_blackrock_spire() { Script* pNewScript; @@ -616,4 +716,9 @@ void AddSC_instance_blackrock_spire() pNewScript->Name = "event_spell_altar_emberseer"; pNewScript->pProcessEventId = &ProcessEventId_event_spell_altar_emberseer; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_father_flame"; + pNewScript->pGOUse = &GOUse_go_father_flame; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackwing_lair/blackwing_lair.h b/scripts/eastern_kingdoms/blackwing_lair/blackwing_lair.h index bf7a31aa4..695add9ff 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/blackwing_lair.h +++ b/scripts/eastern_kingdoms/blackwing_lair/blackwing_lair.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -18,6 +18,8 @@ enum TYPE_CHROMAGGUS = 6, TYPE_NEFARIAN = 7, + DATA_DRAGON_EGG = 1, // track the used eggs + NPC_RAZORGORE = 12435, NPC_VAELASTRASZ = 13020, NPC_LASHLAYER = 12017, @@ -28,51 +30,77 @@ enum NPC_NEFARIAN = 11583, NPC_LORD_VICTOR_NEFARIUS = 10162, NPC_BLACKWING_TECHNICIAN = 13996, // Flees at Vael intro event + + // Razorgore event related NPC_GRETHOK_CONTROLLER = 12557, NPC_BLACKWING_ORB_TRIGGER = 14449, + NPC_NEFARIANS_TROOPS = 14459, NPC_MONSTER_GENERATOR = 12434, + NPC_BLACKWING_LEGIONNAIRE = 12416, // one spawn per turn + NPC_BLACKWING_MAGE = 12420, // one spawn per turn + NPC_DRAGONSPAWN = 12422, // two spawns per turn GO_DOOR_RAZORGORE_ENTER = 176964, GO_DOOR_RAZORGORE_EXIT = 176965, GO_DOOR_NEFARIAN = 176966, - //GO_DOOR_CHROMAGGUS_ENTER = 179115, - //GO_DOOR_CHROMAGGUS_SIDE = 179116, + // GO_DOOR_CHROMAGGUS_ENTER = 179115, + // GO_DOOR_CHROMAGGUS_SIDE = 179116, GO_DOOR_CHROMAGGUS_EXIT = 179117, GO_DOOR_VAELASTRASZ = 179364, GO_DOOR_LASHLAYER = 179365, GO_ORB_OF_DOMINATION = 177808, // trigger 19832 on Razorgore GO_BLACK_DRAGON_EGG = 177807, + GO_DRAKONID_BONES = 179804, + + EMOTE_ORB_SHUT_OFF = -1469035, + EMOTE_TROOPS_FLEE = -1469033, // emote by Nefarian's Troops npc + + MAX_EGGS_DEFENDERS = 4, }; // Coords used to spawn Nefarius at the throne -static const float aNefariusSpawnLoc[4] = {-7466.16f, -1040.80f, 412.053f, 2.14675f}; +static const float aNefariusSpawnLoc[4] = { -7466.16f, -1040.80f, 412.053f, 2.14675f}; + +static const uint32 aRazorgoreSpawns[MAX_EGGS_DEFENDERS] = {NPC_BLACKWING_LEGIONNAIRE, NPC_BLACKWING_MAGE, NPC_DRAGONSPAWN, NPC_DRAGONSPAWN}; -class MANGOS_DLL_DECL instance_blackwing_lair : public ScriptedInstance +class instance_blackwing_lair : public ScriptedInstance { public: instance_blackwing_lair(Map* pMap); ~instance_blackwing_lair() {} - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void SetData64(uint32 uiData, uint64 uiGuid) override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; protected: std::string m_strInstData; uint32 m_auiEncounter[MAX_ENCOUNTER]; - GUIDList m_lTechnicianGuids; - GUIDList m_lGeneratorGuids; - GUIDList m_lDragonEggGuids; + uint32 m_uiResetTimer; + uint32 m_uiDefenseTimer; + + GuidList m_lTechnicianGuids; + GuidList m_lDragonEggsGuids; + GuidList m_lDrakonidBonesGuids; + GuidList m_lDefendersGuids; + GuidList m_lUsedEggsGuids; + GuidVector m_vGeneratorGuids; }; #endif diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp index 29b704867..fa3ad707c 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_broodlord_lashlayer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,7 +35,7 @@ enum SPELL_KNOCK_AWAY = 25778 }; -struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI +struct boss_broodlordAI : public ScriptedAI { boss_broodlordAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -50,7 +50,7 @@ struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI uint32 m_uiMortalStrikeTimer; uint32 m_uiKnockAwayTimer; - void Reset() + void Reset() override { m_uiCleaveTimer = 8000; // These times are probably wrong m_uiBlastWaveTimer = 12000; @@ -58,7 +58,7 @@ struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI m_uiKnockAwayTimer = 30000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LASHLAYER, IN_PROGRESS); @@ -66,19 +66,19 @@ struct MANGOS_DLL_DECL boss_broodlordAI : public ScriptedAI DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LASHLAYER, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_LASHLAYER, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp index d28654262..4968a0242 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_chromaggus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -61,7 +61,7 @@ enum static const uint32 aPossibleBreaths[MAX_BREATHS] = {SPELL_INCINERATE, SPELL_TIME_LAPSE, SPELL_CORROSIVE_ACID, SPELL_IGNITE_FLESH, SPELL_FROST_BURN}; -struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI +struct boss_chromaggusAI : public ScriptedAI { boss_chromaggusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -92,7 +92,7 @@ struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI uint32 m_uiFrenzyTimer; bool m_bEnraged; - void Reset() + void Reset() override { m_uiCurrentVulnerabilitySpell = 0; // We use this to store our last vulnerability spell so we can remove it later @@ -105,25 +105,25 @@ struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI m_bEnraged = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_CHROMAGGUS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_CHROMAGGUS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_CHROMAGGUS, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -173,7 +173,7 @@ struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI { uint32 m_uiSpellAfflict = 0; - switch(urand(0, 4)) + switch (urand(0, 4)) { case 0: m_uiSpellAfflict = SPELL_BROODAF_BLUE; break; case 1: m_uiSpellAfflict = SPELL_BROODAF_BLACK; break; @@ -182,9 +182,9 @@ struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI case 4: m_uiSpellAfflict = SPELL_BROODAF_GREEN; break; } - std::vector vGuids; + GuidVector vGuids; m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) + for (GuidVector::const_iterator i = vGuids.begin(); i != vGuids.end(); ++i) { Unit* pUnit = m_creature->GetMap()->GetUnit(*i); @@ -195,13 +195,13 @@ struct MANGOS_DLL_DECL boss_chromaggusAI : public ScriptedAI // Chromatic mutation if target is effected by all afflictions if (pUnit->HasAura(SPELL_BROODAF_BLUE, EFFECT_INDEX_0) - && pUnit->HasAura(SPELL_BROODAF_BLACK, EFFECT_INDEX_0) - && pUnit->HasAura(SPELL_BROODAF_RED, EFFECT_INDEX_0) - && pUnit->HasAura(SPELL_BROODAF_BRONZE, EFFECT_INDEX_0) - && pUnit->HasAura(SPELL_BROODAF_GREEN, EFFECT_INDEX_0)) + && pUnit->HasAura(SPELL_BROODAF_BLACK, EFFECT_INDEX_0) + && pUnit->HasAura(SPELL_BROODAF_RED, EFFECT_INDEX_0) + && pUnit->HasAura(SPELL_BROODAF_BRONZE, EFFECT_INDEX_0) + && pUnit->HasAura(SPELL_BROODAF_GREEN, EFFECT_INDEX_0)) { - //target->RemoveAllAuras(); - //DoCastSpellIfCan(target,SPELL_CHROMATIC_MUT_1); + // target->RemoveAllAuras(); + // DoCastSpellIfCan(target,SPELL_CHROMATIC_MUT_1); // Chromatic mutation is causing issues // Assuming it is caused by a lack of core support for Charm diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp index b68dfc3e9..7b0e0bd2c 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_ebonroc.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -32,7 +32,7 @@ enum SPELL_THRASH = 3391, // TODO missing }; -struct MANGOS_DLL_DECL boss_ebonrocAI : public ScriptedAI +struct boss_ebonrocAI : public ScriptedAI { boss_ebonrocAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -46,32 +46,32 @@ struct MANGOS_DLL_DECL boss_ebonrocAI : public ScriptedAI uint32 m_uiWingBuffetTimer; uint32 m_uiShadowOfEbonrocTimer; - void Reset() + void Reset() override { m_uiShadowFlameTimer = 15000; // These times are probably wrong m_uiWingBuffetTimer = 30000; m_uiShadowOfEbonrocTimer = 45000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_EBONROC, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_EBONROC, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_EBONROC, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp index 0550af3ce..50b4b390d 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_firemaw.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -32,7 +32,7 @@ enum SPELL_THRASH = 3391, // TODO, missing }; -struct MANGOS_DLL_DECL boss_firemawAI : public ScriptedAI +struct boss_firemawAI : public ScriptedAI { boss_firemawAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -46,32 +46,32 @@ struct MANGOS_DLL_DECL boss_firemawAI : public ScriptedAI uint32 m_uiWingBuffetTimer; uint32 m_uiFlameBuffetTimer; - void Reset() + void Reset() override { m_uiShadowFlameTimer = 30000; // These times are probably wrong m_uiWingBuffetTimer = 24000; m_uiFlameBuffetTimer = 5000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_FIREMAW, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_FIREMAW, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_FIREMAW, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp index efc1f5c04..32b807a28 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_flamegor.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -34,7 +34,7 @@ enum SPELL_THRASH = 3391, // TODO missing }; -struct MANGOS_DLL_DECL boss_flamegorAI : public ScriptedAI +struct boss_flamegorAI : public ScriptedAI { boss_flamegorAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -48,32 +48,32 @@ struct MANGOS_DLL_DECL boss_flamegorAI : public ScriptedAI uint32 m_uiWingBuffetTimer; uint32 m_uiFrenzyTimer; - void Reset() + void Reset() override { m_uiShadowFlameTimer = 21000; // These times are probably wrong m_uiWingBuffetTimer = 35000; m_uiFrenzyTimer = 10000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_FLAMEGOR, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_FLAMEGOR, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_FLAMEGOR, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp index 1396274d4..ba1443739 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_nefarian.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum SPELL_VEIL_OF_SHADOW = 22687, // old spell id 7068 -> wrong SPELL_CLEAVE = 20691, SPELL_TAIL_LASH = 23364, - SPELL_BONE_CONTRUST = 23363, //23362, 23361 Missing from DBC! + // SPELL_BONE_CONTRUST = 23363, // 23362, 23361 Missing from DBC! SPELL_MAGE = 23410, // wild magic SPELL_WARRIOR = 23397, // beserk @@ -63,7 +63,7 @@ enum SPELL_ROGUE = 23414, // Paralise }; -struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI +struct boss_nefarianAI : public ScriptedAI { boss_nefarianAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -82,19 +82,19 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI bool m_bPhase3; bool m_bHasEndYell; - void Reset() + void Reset() override { - m_uiShadowFlameTimer = 12000; // These times are probably wrong + m_uiShadowFlameTimer = 12000; // These times are probably wrong m_uiBellowingRoarTimer = 30000; m_uiVeilOfShadowTimer = 15000; m_uiCleaveTimer = 7000; m_uiTailLashTimer = 10000; - m_uiClassCallTimer = 35000; // 35-40 seconds + m_uiClassCallTimer = 35000; // 35-40 seconds m_bPhase3 = false; m_bHasEndYell = false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (urand(0, 4)) return; @@ -102,7 +102,7 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI DoScriptText(SAY_SLAY, m_creature, pVictim); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -110,7 +110,7 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI m_pInstance->SetData(TYPE_NEFARIAN, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -129,7 +129,7 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -143,7 +143,7 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_SHADOWFLAME_INITIAL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -196,11 +196,11 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI // ClassCall_Timer if (m_uiClassCallTimer < uiDiff) { - //Cast a random class call - //On official it is based on what classes are currently on the hostil list - //but we can't do that yet so just randomly call one + // Cast a random class call + // On official it is based on what classes are currently on the hostil list + // but we can't do that yet so just randomly call one - switch(urand(0, 8)) + switch (urand(0, 8)) { case 0: DoScriptText(SAY_MAGE, m_creature); @@ -248,7 +248,8 @@ struct MANGOS_DLL_DECL boss_nefarianAI : public ScriptedAI // Phase3 begins when we are below X health if (!m_bPhase3 && m_creature->GetHealthPercent() < 20.0f) { - // todo revive all dead dragos as 14605 + if (m_pInstance) + m_pInstance->SetData(TYPE_NEFARIAN, SPECIAL); m_bPhase3 = true; DoScriptText(SAY_RAISE_SKELETONS, m_creature); } diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp index 58862b24b..0ba23a736 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_razorgore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Razorgore -SD%Complete: 50 -SDComment: Needs additional review. Phase 1 NYI (Grethok the Controller), Conflagration needs core support +SD%Complete: 95 +SDComment: Timers may be improved. SDCategory: Blackwing Lair EndScriptData */ @@ -31,24 +31,17 @@ enum SAY_EGGS_BROKEN_3 = -1469024, SAY_DEATH = -1469025, - EMOTE_TROOPS_FLEE = -1469033, // emote by Nefarian's Troops npc - - // phase I event spells SPELL_POSSESS = 23014, // visual effect and increase the damage taken - SPELL_EXPLODE_ORB = 20037, // used if attacked without destroying the eggs - related to 20038 + SPELL_DESTROY_EGG = 19873, + SPELL_EXPLODE_ORB = 20037, // used if attacked without destroying the eggs - triggers 20038 SPELL_CLEAVE = 19632, SPELL_WARSTOMP = 24375, SPELL_FIREBALL_VOLLEY = 22425, SPELL_CONFLAGRATION = 23023, - - // npcs used in phase I - NPC_BLACKWING_LEGIONNAIRE = 12416, - NPC_BLACKWING_MAGE = 12420, - NPC_DRAGONSPAWN = 12422, }; -struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI +struct boss_razorgoreAI : public ScriptedAI { boss_razorgoreAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -64,60 +57,103 @@ struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI uint32 m_uiFireballVolleyTimer; uint32 m_uiConflagrationTimer; - void Reset() + bool m_bEggsExploded; + + void Reset() override { m_uiIntroVisualTimer = 5000; + m_bEggsExploded = false; - m_uiCleaveTimer = 15000; // These times are probably wrong - m_uiWarStompTimer = 35000; - m_uiConflagrationTimer = 12000; - m_uiFireballVolleyTimer = 7000; + m_uiCleaveTimer = urand(4000, 8000); + m_uiWarStompTimer = 30000; + m_uiConflagrationTimer = urand(10000, 15000); + m_uiFireballVolleyTimer = urand(15000, 20000); } - void Aggro(Unit* pWho) + void JustDied(Unit* /*pKiller*/) override { - // TODO Temporarily add this InstData setting, must be started with Phase 1 which is not yet implemented if (m_pInstance) - m_pInstance->SetData(TYPE_RAZORGORE, IN_PROGRESS); - } + { + // Don't set instance data unless all eggs are destroyed + if (m_pInstance->GetData(TYPE_RAZORGORE) != SPECIAL) + return; - void JustDied(Unit* pKiller) - { - if (m_pInstance) m_pInstance->SetData(TYPE_RAZORGORE, DONE); + } DoScriptText(SAY_DEATH, m_creature); } - void JustReachedHome() + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (uiDamage < m_creature->GetHealth()) + return; + + if (!m_pInstance) + return; + + // Don't allow any accident + if (m_bEggsExploded) + { + uiDamage = 0; + return; + } + + // Boss explodes everything and resets - this happens if not all eggs are destroyed + if (m_pInstance->GetData(TYPE_RAZORGORE) == IN_PROGRESS) + { + uiDamage = 0; + m_bEggsExploded = true; + m_pInstance->SetData(TYPE_RAZORGORE, FAIL); + DoCastSpellIfCan(m_creature, SPELL_EXPLODE_ORB, CAST_TRIGGERED); + m_creature->ForcedDespawn(); + } + } + + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_RAZORGORE, FAIL); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override { - // Set visual on OOC timer - if (m_uiIntroVisualTimer) + // Defenders should attack the players and the boss + pSummoned->SetInCombatWithZone(); + pSummoned->AI()->AttackStart(m_creature); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { - if (m_uiIntroVisualTimer <= uiDiff) + // Set visual only on OOC timer + if (m_uiIntroVisualTimer) { - if (Creature* pOrbTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_BLACKWING_ORB_TRIGGER)) - pOrbTrigger->CastSpell(m_creature, SPELL_POSSESS, false); - m_uiIntroVisualTimer = 0; + if (m_uiIntroVisualTimer <= uiDiff) + { + if (!m_pInstance) + { + script_error_log("Instance Blackwing Lair: ERROR Failed to load instance data for this instace."); + return; + } + + if (Creature* pOrbTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_BLACKWING_ORB_TRIGGER)) + pOrbTrigger->CastSpell(m_creature, SPELL_POSSESS, false); + m_uiIntroVisualTimer = 0; + } + else + m_uiIntroVisualTimer -= uiDiff; } - else - m_uiIntroVisualTimer -= uiDiff; - } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + } // Cleave if (m_uiCleaveTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) - m_uiCleaveTimer = urand(7000, 10000); + m_uiCleaveTimer = urand(4000, 8000); } else m_uiCleaveTimer -= uiDiff; @@ -126,7 +162,7 @@ struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI if (m_uiWarStompTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WARSTOMP) == CAST_OK) - m_uiWarStompTimer = urand(15000, 25000); + m_uiWarStompTimer = 30000; } else m_uiWarStompTimer -= uiDiff; @@ -135,7 +171,7 @@ struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI if (m_uiFireballVolleyTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_FIREBALL_VOLLEY) == CAST_OK) - m_uiFireballVolleyTimer = urand(12000, 15000); + m_uiFireballVolleyTimer = urand(15000, 20000); } else m_uiFireballVolleyTimer -= uiDiff; @@ -144,7 +180,7 @@ struct MANGOS_DLL_DECL boss_razorgoreAI : public ScriptedAI if (m_uiConflagrationTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_CONFLAGRATION) == CAST_OK) - m_uiConflagrationTimer = 12000; + m_uiConflagrationTimer = urand(15000, 25000); } else m_uiConflagrationTimer -= uiDiff; @@ -167,6 +203,35 @@ CreatureAI* GetAI_boss_razorgore(Creature* pCreature) return new boss_razorgoreAI(pCreature); } +bool EffectDummyGameObj_go_black_dragon_egg(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, GameObject* pGOTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_DESTROY_EGG && uiEffIndex == EFFECT_INDEX_1) + { + if (!pGOTarget->isSpawned()) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGOTarget->GetInstanceData()) + { + if (urand(0, 1)) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_EGGS_BROKEN_1, pCaster); break; + case 1: DoScriptText(SAY_EGGS_BROKEN_2, pCaster); break; + case 2: DoScriptText(SAY_EGGS_BROKEN_3, pCaster); break; + } + } + + // Store the eggs which are destroyed, in order to count them for the second phase + pInstance->SetData64(DATA_DRAGON_EGG, pGOTarget->GetObjectGuid()); + } + + return true; + } + + return false; +} + void AddSC_boss_razorgore() { Script* pNewScript; @@ -175,4 +240,9 @@ void AddSC_boss_razorgore() pNewScript->Name = "boss_razorgore"; pNewScript->GetAI = &GetAI_boss_razorgore; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_black_dragon_egg"; + pNewScript->pEffectDummyGO = &EffectDummyGameObj_go_black_dragon_egg; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp index bb8581bbd..177983df4 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_vaelastrasz.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -56,7 +56,7 @@ enum AREATRIGGER_VAEL_INTRO = 3626, }; -struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI +struct boss_vaelastraszAI : public ScriptedAI { boss_vaelastraszAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -85,7 +85,7 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI uint32 m_uiTailSweepTimer; bool m_bHasYelled; - void Reset() + void Reset() override { m_playerGuid.Clear(); @@ -129,7 +129,7 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI m_uiSpeechNum = 0; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (urand(0, 4)) return; @@ -137,7 +137,7 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI DoScriptText(SAY_KILLTARGET, m_creature, pVictim); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_VAELASTRASZ, IN_PROGRESS); @@ -146,19 +146,19 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_ESSENCE_OF_THE_RED); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_VAELASTRASZ, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_VAELASTRASZ, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_LORD_VICTOR_NEFARIUS) { @@ -168,7 +168,7 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiIntroTimer) { @@ -224,7 +224,7 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI ++m_uiSpeechNum; break; case 2: - m_creature->setFaction(FACTION_HOSTILE); + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN); if (m_playerGuid) { @@ -314,7 +314,7 @@ struct MANGOS_DLL_DECL boss_vaelastraszAI : public ScriptedAI } }; -bool GossipSelect_boss_vaelastrasz(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_boss_vaelastrasz(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { switch (uiAction) { diff --git a/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp b/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp index 1f7715a1e..393cffcad 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/boss_victor_nefarius.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -55,6 +55,8 @@ enum SPELL_FEAR = 22678, SPELL_SHADOWBLINK = 22681, // triggers a random from spells (22668 - 22676) + SPELL_SUMMON_DRAKONID_BONES = 23363, + MAP_ID_BWL = 469, FACTION_BLACK_DRAGON = 103 @@ -75,26 +77,26 @@ struct SpawnLocation static const SpawnLocation aNefarianLocs[4] = { - {-7599.32f, -1191.72f, 475.545f}, // opening where red/blue/black darknid spawner appear (ori 3.05433) - {-7526.27f, -1135.04f, 473.445f}, // same as above, closest to door (ori 5.75959) - {-7498.177f, -1273.277f, 481.649f}, // nefarian spawn location (ori 1.798) - {-7502.002f, -1256.503f, 476.758f}, // nefarian fly to this position + { -7599.32f, -1191.72f, 475.545f}, // opening where red/blue/black darknid spawner appear (ori 3.05433) + { -7526.27f, -1135.04f, 473.445f}, // same as above, closest to door (ori 5.75959) + { -7498.177f, -1273.277f, 481.649f}, // nefarian spawn location (ori 1.798) + { -7502.002f, -1256.503f, 476.758f}, // nefarian fly to this position }; static const uint32 aPossibleDrake[MAX_DRAKES] = {NPC_BRONZE_DRAKANOID, NPC_BLUE_DRAKANOID, NPC_RED_DRAKANOID, NPC_GREEN_DRAKANOID, NPC_BLACK_DRAKANOID}; -//This script is complicated -//Instead of morphing Victor Nefarius we will have him control phase 1 -//And then have him spawn "Nefarian" for phase 2 -//When phase 2 starts Victor Nefarius will go invisible and stop attacking -//If Nefarian reched home because nef killed the players then nef will trigger this guy to EnterEvadeMode -//and allow players to start the event over -//If nefarian dies then he will kill himself then he will be despawned in Nefarian script -//To prevent players from doing the event twice +// This script is complicated +// Instead of morphing Victor Nefarius we will have him control phase 1 +// And then have him spawn "Nefarian" for phase 2 +// When phase 2 starts Victor Nefarius will go invisible and stop attacking +// If Nefarian reched home because nef killed the players then nef will trigger this guy to EnterEvadeMode +// and allow players to start the event over +// If nefarian dies then he will kill himself then he will be despawned in Nefarian script +// To prevent players from doing the event twice // Dev note: Lord Victor Nefarius should despawn completely, then ~5 seconds later Nefarian should appear. -struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private DialogueHelper +struct boss_victor_nefariusAI : public ScriptedAI, private DialogueHelper { boss_victor_nefariusAI(Creature* pCreature) : ScriptedAI(pCreature), DialogueHelper(aIntroDialogue) @@ -127,7 +129,7 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo uint32 m_uiShadowCommandTimer; uint32 m_uiShadowBlinkTimer; - void Reset() + void Reset() override { // Check the map id because the same creature entry is involved in other scripted event in other instance if (m_creature->GetMapId() != MAP_ID_BWL) @@ -150,19 +152,19 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo m_creature->SetVisibility(VISIBILITY_ON); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NEFARIAN, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NEFARIAN, FAIL); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, false)) { @@ -175,7 +177,7 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (m_creature->GetMapId() != MAP_ID_BWL) return; @@ -185,7 +187,7 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo pSummoned->SetWalk(false); // see boss_onyxia (also note the removal of this in boss_nefarian) - pSummoned->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + pSummoned->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); pSummoned->SetLevitate(true); // Let Nefarian fly towards combat area @@ -199,11 +201,9 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); } - - pSummoned->SetRespawnDelay(7*DAY); } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override { if (m_creature->GetMapId() != MAP_ID_BWL) return; @@ -216,7 +216,7 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (m_creature->GetMapId() != MAP_ID_BWL) return; @@ -224,9 +224,11 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo // Despawn self when Nefarian is killed if (pSummoned->GetEntry() == NPC_NEFARIAN) m_creature->ForcedDespawn(); + else + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_DRAKONID_BONES, true); } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { // Start combat after the dialogue is finished if (iEntry == SPELL_SHADOWBLINK) @@ -244,7 +246,7 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo StartNextDialogueText(SAY_GAMESBEGIN_1); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_creature->GetMapId() != MAP_ID_BWL) return; @@ -326,24 +328,24 @@ struct MANGOS_DLL_DECL boss_victor_nefariusAI : public ScriptedAI, private Dialo // Add spawning mechanism if (m_uiAddSpawnTimer < uiDiff) { - //Spawn 2 random types of creatures at the 2 locations + // Spawn 2 random types of creatures at the 2 locations uint32 uiCreatureId = 0; // 1 in 3 chance it will be a chromatic - uiCreatureId = urand(0, 2) ? m_uiDrakeTypeOne : NPC_CHROMATIC_DRAKANOID; - m_creature->SummonCreature(uiCreatureId, aNefarianLocs[0].m_fX, aNefarianLocs[0].m_fY, aNefarianLocs[0].m_fZ, 5.000f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30*MINUTE*IN_MILLISECONDS); + uiCreatureId = urand(0, 2) ? m_uiDrakeTypeOne : uint32(NPC_CHROMATIC_DRAKANOID); + m_creature->SummonCreature(uiCreatureId, aNefarianLocs[0].m_fX, aNefarianLocs[0].m_fY, aNefarianLocs[0].m_fZ, 5.000f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 30000); // 1 in 3 chance it will be a chromatic - uiCreatureId = urand(0, 2) ? m_uiDrakeTypeTwo : NPC_CHROMATIC_DRAKANOID; - m_creature->SummonCreature(uiCreatureId, aNefarianLocs[1].m_fX, aNefarianLocs[1].m_fY, aNefarianLocs[1].m_fZ, 5.000, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30*MINUTE*IN_MILLISECONDS); + uiCreatureId = urand(0, 2) ? m_uiDrakeTypeTwo : uint32(NPC_CHROMATIC_DRAKANOID); + m_creature->SummonCreature(uiCreatureId, aNefarianLocs[1].m_fX, aNefarianLocs[1].m_fY, aNefarianLocs[1].m_fZ, 5.000, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 30000); - //Begin phase 2 by spawning Nefarian + // Begin phase 2 by spawning Nefarian if (m_uiSpawnedAdds >= MAX_DRAKE_SUMMONS) { - //Inturrupt any spell casting + // Inturrupt any spell casting m_creature->InterruptNonMeleeSpells(false); - //Make super invis + // Make super invis if (m_creature->GetVisibility() != VISIBILITY_OFF) m_creature->SetVisibility(VISIBILITY_OFF); @@ -370,26 +372,26 @@ bool GossipHello_boss_victor_nefarius(Player* pPlayer, Creature* pCreature) if (pCreature->GetMapId() != MAP_ID_BWL) return true; - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEFARIUS_1 , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEFARIUS_1 , GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_NEFARIUS_1, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_boss_victor_nefarius(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_boss_victor_nefarius(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (pCreature->GetMapId() != MAP_ID_BWL) return true; - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: pCreature->HandleEmote(EMOTE_ONESHOT_TALK); - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEFARIUS_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEFARIUS_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_NEFARIUS_2, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: pCreature->HandleEmote(EMOTE_ONESHOT_TALK); - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEFARIUS_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEFARIUS_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_NEFARIUS_3, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: diff --git a/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp b/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp index b4d4debcd..3eeb011e1 100644 --- a/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp +++ b/scripts/eastern_kingdoms/blackwing_lair/instance_blackwing_lair.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Instance_Blackwing_Lair -SD%Complete: 0 +SD%Complete: 90 SDComment: SDCategory: Blackwing Lair EndScriptData */ @@ -24,7 +24,9 @@ EndScriptData */ #include "precompiled.h" #include "blackwing_lair.h" -instance_blackwing_lair::instance_blackwing_lair(Map* pMap) : ScriptedInstance(pMap) +instance_blackwing_lair::instance_blackwing_lair(Map* pMap) : ScriptedInstance(pMap), + m_uiResetTimer(0), + m_uiDefenseTimer(0) { Initialize(); } @@ -54,8 +56,15 @@ void instance_blackwing_lair::OnCreatureCreate(Creature* pCreature) m_lTechnicianGuids.push_back(pCreature->GetObjectGuid()); break; case NPC_MONSTER_GENERATOR: - m_lGeneratorGuids.push_back(pCreature->GetObjectGuid()); + m_vGeneratorGuids.push_back(pCreature->GetObjectGuid()); break; + case NPC_BLACKWING_LEGIONNAIRE: + case NPC_BLACKWING_MAGE: + case NPC_DRAGONSPAWN: + m_lDefendersGuids.push_back(pCreature->GetObjectGuid()); + break; + case NPC_RAZORGORE: + case NPC_NEFARIANS_TROOPS: case NPC_BLACKWING_ORB_TRIGGER: case NPC_VAELASTRASZ: case NPC_LORD_VICTOR_NEFARIUS: @@ -66,7 +75,7 @@ void instance_blackwing_lair::OnCreatureCreate(Creature* pCreature) void instance_blackwing_lair::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_DOOR_RAZORGORE_ENTER: case GO_ORB_OF_DOMINATION: @@ -89,7 +98,10 @@ void instance_blackwing_lair::OnObjectCreate(GameObject* pGo) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_BLACK_DRAGON_EGG: - m_lDragonEggGuids.push_back(pGo->GetObjectGuid()); + m_lDragonEggsGuids.push_back(pGo->GetObjectGuid()); + return; + case GO_DRAKONID_BONES: + m_lDrakonidBonesGuids.push_back(pGo->GetObjectGuid()); return; default: @@ -100,19 +112,30 @@ void instance_blackwing_lair::OnObjectCreate(GameObject* pGo) void instance_blackwing_lair::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_RAZORGORE: m_auiEncounter[uiType] = uiData; - DoUseDoorOrButton(GO_DOOR_RAZORGORE_ENTER); + if (uiData != SPECIAL) + DoUseDoorOrButton(GO_DOOR_RAZORGORE_ENTER); if (uiData == DONE) DoUseDoorOrButton(GO_DOOR_RAZORGORE_EXIT); else if (uiData == FAIL) { + m_uiResetTimer = 30000; + // Reset the Orb of Domination and the eggs DoToggleGameObjectFlags(GO_ORB_OF_DOMINATION, GO_FLAG_NO_INTERACT, true); - // ToDo: reset the Dragon Eggs + // Reset defenders + for (GuidList::const_iterator itr = m_lDefendersGuids.begin(); itr != m_lDefendersGuids.end(); ++itr) + { + if (Creature* pDefender = instance->GetCreature(*itr)) + pDefender->ForcedDespawn(); + } + + m_lUsedEggsGuids.clear(); + m_lDefendersGuids.clear(); } break; case TYPE_VAELASTRASZ: @@ -139,8 +162,38 @@ void instance_blackwing_lair::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_DOOR_CHROMAGGUS_EXIT); break; case TYPE_NEFARIAN: + // Don't store the same thing twice + if (m_auiEncounter[uiType] == uiData) + break; + if (uiData == SPECIAL) + { + // handle missing spell 23362 + Creature* pNefarius = GetSingleCreatureFromStorage(NPC_LORD_VICTOR_NEFARIUS); + if (!pNefarius) + break; + + for (GuidList::const_iterator itr = m_lDrakonidBonesGuids.begin(); itr != m_lDrakonidBonesGuids.end(); ++itr) + { + // The Go script will handle the missing spell 23361 + if (GameObject* pGo = instance->GetGameObject(*itr)) + pGo->Use(pNefarius); + } + // Don't store special data + break; + } m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_DOOR_NEFARIAN); + // Cleanup the drakonid bones + if (uiData == FAIL) + { + for (GuidList::const_iterator itr = m_lDrakonidBonesGuids.begin(); itr != m_lDrakonidBonesGuids.end(); ++itr) + { + if (GameObject* pGo = instance->GetGameObject(*itr)) + pGo->SetLootState(GO_JUST_DEACTIVATED); + } + + m_lDrakonidBonesGuids.clear(); + } break; } @@ -150,8 +203,8 @@ void instance_blackwing_lair::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7]; m_strInstData = saveStream.str(); @@ -172,9 +225,9 @@ void instance_blackwing_lair::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -183,7 +236,7 @@ void instance_blackwing_lair::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_blackwing_lair::GetData(uint32 uiType) +uint32 instance_blackwing_lair::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -191,10 +244,60 @@ uint32 instance_blackwing_lair::GetData(uint32 uiType) return 0; } +void instance_blackwing_lair::SetData64(uint32 uiData, uint64 uiGuid) +{ + if (uiData == DATA_DRAGON_EGG) + { + if (GameObject* pEgg = instance->GetGameObject(ObjectGuid(uiGuid))) + m_lUsedEggsGuids.push_back(pEgg->GetObjectGuid()); + + // If all eggs are destroyed, then allow Razorgore to be attacked + if (m_lUsedEggsGuids.size() == m_lDragonEggsGuids.size()) + { + SetData(TYPE_RAZORGORE, SPECIAL); + DoToggleGameObjectFlags(GO_ORB_OF_DOMINATION, GO_FLAG_NO_INTERACT, true); + + // Emote for the start of the second phase + if (Creature* pTrigger = GetSingleCreatureFromStorage(NPC_NEFARIANS_TROOPS)) + { + DoScriptText(EMOTE_ORB_SHUT_OFF, pTrigger); + DoScriptText(EMOTE_TROOPS_FLEE, pTrigger); + } + + // Break mind control and set max health + if (Creature* pRazorgore = GetSingleCreatureFromStorage(NPC_RAZORGORE)) + { + pRazorgore->RemoveAllAuras(); + pRazorgore->SetHealth(pRazorgore->GetMaxHealth()); + } + + // All defenders evade and despawn + for (GuidList::const_iterator itr = m_lDefendersGuids.begin(); itr != m_lDefendersGuids.end(); ++itr) + { + if (Creature* pDefender = instance->GetCreature(*itr)) + { + pDefender->AI()->EnterEvadeMode(); + pDefender->ForcedDespawn(10000); + } + } + } + } +} + +void instance_blackwing_lair::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_GRETHOK_CONTROLLER) + { + SetData(TYPE_RAZORGORE, IN_PROGRESS); + m_uiDefenseTimer = 40000; + } +} + void instance_blackwing_lair::OnCreatureDeath(Creature* pCreature) { if (pCreature->GetEntry() == NPC_GRETHOK_CONTROLLER) { + // Allow orb to be used DoToggleGameObjectFlags(GO_ORB_OF_DOMINATION, GO_FLAG_NO_INTERACT, false); if (Creature* pOrbTrigger = GetSingleCreatureFromStorage(NPC_BLACKWING_ORB_TRIGGER)) @@ -202,6 +305,65 @@ void instance_blackwing_lair::OnCreatureDeath(Creature* pCreature) } } +void instance_blackwing_lair::Update(uint32 uiDiff) +{ + // Reset Razorgore in case of wipe + if (m_uiResetTimer) + { + if (m_uiResetTimer <= uiDiff) + { + // Respawn Razorgore + if (Creature* pRazorgore = GetSingleCreatureFromStorage(NPC_RAZORGORE)) + { + if (!pRazorgore->isAlive()) + pRazorgore->Respawn(); + } + + // Respawn the Dragon Eggs + for (GuidList::const_iterator itr = m_lDragonEggsGuids.begin(); itr != m_lDragonEggsGuids.end(); ++itr) + { + if (GameObject* pEgg = instance->GetGameObject(*itr)) + { + if (!pEgg->isSpawned()) + pEgg->Respawn(); + } + } + + m_uiResetTimer = 0; + } + else + m_uiResetTimer -= uiDiff; + } + + if (GetData(TYPE_RAZORGORE) != IN_PROGRESS) + return; + + if (m_uiDefenseTimer < uiDiff) + { + // Allow Razorgore to spawn the defenders + Creature* pRazorgore = GetSingleCreatureFromStorage(NPC_RAZORGORE); + if (!pRazorgore) + return; + + // Randomize generators + std::random_shuffle(m_vGeneratorGuids.begin(), m_vGeneratorGuids.end()); + + // Spawn the defenders + for (uint8 i = 0; i < MAX_EGGS_DEFENDERS; ++i) + { + Creature* pGenerator = instance->GetCreature(m_vGeneratorGuids[i]); + if (!pGenerator) + return; + + pRazorgore->SummonCreature(aRazorgoreSpawns[i], pGenerator->GetPositionX(), pGenerator->GetPositionY(), pGenerator->GetPositionZ(), pGenerator->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); + } + + m_uiDefenseTimer = 20000; + } + else + m_uiDefenseTimer -= uiDiff; +} + InstanceData* GetInstanceData_instance_blackwing_lair(Map* pMap) { return new instance_blackwing_lair(pMap); diff --git a/scripts/eastern_kingdoms/blasted_lands.cpp b/scripts/eastern_kingdoms/blasted_lands.cpp index a2a77027e..ea62ea389 100644 --- a/scripts/eastern_kingdoms/blasted_lands.cpp +++ b/scripts/eastern_kingdoms/blasted_lands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -45,22 +45,22 @@ bool GossipHello_npc_fallen_hero_of_horde(Player* pPlayer, Creature* pCreature) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(2784) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); if (pPlayer->GetQuestStatus(2801) == QUEST_STATUS_INCOMPLETE && pPlayer->GetTeam() == HORDE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Continue story...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Continue story...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); if (pPlayer->GetQuestStatus(2801) == QUEST_STATUS_INCOMPLETE && pPlayer->GetTeam() == ALLIANCE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Why are you here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_fallen_hero_of_horde(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_fallen_hero_of_horde(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FALLEN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); diff --git a/scripts/eastern_kingdoms/boss_kruul.cpp b/scripts/eastern_kingdoms/boss_kruul.cpp deleted file mode 100644 index 34b385446..000000000 --- a/scripts/eastern_kingdoms/boss_kruul.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Kruul -SD%Complete: 100 -SDComment: Highlord Kruul are presumably no longer in-game on regular bases, however future events could bring him back. -SDCategory: Bosses -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_SHADOWVOLLEY 21341 -#define SPELL_CLEAVE 20677 -#define SPELL_THUNDERCLAP 23931 -#define SPELL_TWISTEDREFLECTION 21063 -#define SPELL_VOIDBOLT 21066 -#define SPELL_RAGE 21340 -#define SPELL_CAPTURESOUL 21054 - -struct MANGOS_DLL_DECL boss_kruulAI : public ScriptedAI -{ - boss_kruulAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 ShadowVolley_Timer; - uint32 Cleave_Timer; - uint32 ThunderClap_Timer; - uint32 TwistedReflection_Timer; - uint32 VoidBolt_Timer; - uint32 Rage_Timer; - uint32 Hound_Timer; - int Rand; - int RandX; - int RandY; - Creature* Summoned; - - void Reset() - { - ShadowVolley_Timer = 10000; - Cleave_Timer = 14000; - ThunderClap_Timer = 20000; - TwistedReflection_Timer = 25000; - VoidBolt_Timer = 30000; - Rage_Timer = 60000; //Cast rage after 1 minute - Hound_Timer = 8000; - } - - void KilledUnit(Unit* pVictim) - { - // When a player, pet or totem gets killed, Lord Kazzak casts this spell to instantly regenerate 70,000 health. - DoCastSpellIfCan(m_creature,SPELL_CAPTURESOUL); - - } - - void SummonHounds(Unit* victim) - { - Rand = rand()%10; - switch(urand(0, 1)) - { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; - } - Rand = 0; - Rand = rand()%10; - switch(urand(0, 1)) - { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; - } - Rand = 0; - Summoned = DoSpawnCreature(19207, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 300000); - if (Summoned) - Summoned->AI()->AttackStart(victim); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //ShadowVolley_Timer - if (ShadowVolley_Timer < diff) - { - if (rand()%100 < 46) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWVOLLEY); - } - - ShadowVolley_Timer = 5000; - }else ShadowVolley_Timer -= diff; - - //Cleave_Timer - if (Cleave_Timer < diff) - { - if (rand()%100 < 50) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - } - - Cleave_Timer = 10000; - }else Cleave_Timer -= diff; - - //ThunderClap_Timer - if (ThunderClap_Timer < diff) - { - if (rand()%100 < 20) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_THUNDERCLAP); - } - - ThunderClap_Timer = 12000; - }else ThunderClap_Timer -= diff; - - //TwistedReflection_Timer - if (TwistedReflection_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_TWISTEDREFLECTION); - TwistedReflection_Timer = 30000; - }else TwistedReflection_Timer -= diff; - - //VoidBolt_Timer - if (VoidBolt_Timer < diff) - { - if (rand()%100 < 40) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_VOIDBOLT); - } - - VoidBolt_Timer = 18000; - }else VoidBolt_Timer -= diff; - - //Rage_Timer - if (Rage_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_RAGE); - Rage_Timer = 70000; - }else Rage_Timer -= diff; - - //Hound_Timer - if (Hound_Timer < diff) - { - SummonHounds(m_creature->getVictim()); - SummonHounds(m_creature->getVictim()); - SummonHounds(m_creature->getVictim()); - - Hound_Timer = 45000; - }else Hound_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_kruul(Creature* pCreature) -{ - return new boss_kruulAI(pCreature); -} - -void AddSC_boss_kruul() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_kruul"; - pNewScript->GetAI = &GetAI_boss_kruul; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/burning_steppes.cpp b/scripts/eastern_kingdoms/burning_steppes.cpp index 6a1fff548..374872dce 100644 --- a/scripts/eastern_kingdoms/burning_steppes.cpp +++ b/scripts/eastern_kingdoms/burning_steppes.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,33 +17,35 @@ /* ScriptData SDName: Burning_Steppes SD%Complete: 100 -SDComment: Quest support: 4224, 4866 +SDComment: Quest support: 4121, 4122, 4224, 4866 SDCategory: Burning Steppes EndScriptData */ /* ContentData npc_ragged_john +npc_grark_lorkrub EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### ## npc_ragged_john ######*/ -struct MANGOS_DLL_DECL npc_ragged_johnAI : public ScriptedAI +struct npc_ragged_johnAI : public ScriptedAI { npc_ragged_johnAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* who) override { if (who->HasAura(16468, EFFECT_INDEX_0)) { if (who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 15) && who->isInAccessablePlaceFor(m_creature)) { - DoCastSpellIfCan(who,16472); + DoCastSpellIfCan(who, 16472); ((Player*)who)->AreaExploredOrEventHappens(4866); } } @@ -74,15 +76,15 @@ bool GossipHello_npc_ragged_john(Player* pPlayer, Creature* pCreature) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(4224) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Official buisness, John. I need some information about Marsha Windsor. Tell me about the last time you saw him.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Official business, John. I need some information about Marshal Windsor. Tell me about the last time you saw him.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); pPlayer->SEND_GOSSIP_MENU(2713, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_ragged_john(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_ragged_john(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "So what did you do?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); @@ -97,7 +99,7 @@ bool GossipSelect_npc_ragged_john(Player* pPlayer, Creature* pCreature, uint32 u pPlayer->SEND_GOSSIP_MENU(2716, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Interesting... continue John.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Interesting... continue, John.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); pPlayer->SEND_GOSSIP_MENU(2717, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+4: @@ -109,7 +111,7 @@ bool GossipSelect_npc_ragged_john(Player* pPlayer, Creature* pCreature, uint32 u pPlayer->SEND_GOSSIP_MENU(2719, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ok so where the hell is he? Wait a minute! Are you drunk?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ok, so where the hell is he? Wait a minute! Are you drunk?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); pPlayer->SEND_GOSSIP_MENU(2720, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+7: @@ -121,11 +123,11 @@ bool GossipSelect_npc_ragged_john(Player* pPlayer, Creature* pCreature, uint32 u pPlayer->SEND_GOSSIP_MENU(2722, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+9: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ahh... Ironfoe", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ahh... Ironfoe.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); pPlayer->SEND_GOSSIP_MENU(2723, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+10: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks, Ragged John. Your story was very uplifting and informative", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks, Ragged John. Your story was very uplifting and informative.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); pPlayer->SEND_GOSSIP_MENU(2725, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+11: @@ -136,6 +138,315 @@ bool GossipSelect_npc_ragged_john(Player* pPlayer, Creature* pCreature, uint32 u return true; } +/*###### +## npc_grark_lorkrub +######*/ + +enum +{ + SAY_START = -1000873, + SAY_PAY = -1000874, + SAY_FIRST_AMBUSH_START = -1000875, + SAY_FIRST_AMBUSH_END = -1000876, + SAY_SEC_AMBUSH_START = -1000877, + SAY_SEC_AMBUSH_END = -1000878, + SAY_THIRD_AMBUSH_START = -1000879, + SAY_THIRD_AMBUSH_END = -1000880, + EMOTE_LAUGH = -1000881, + SAY_LAST_STAND = -1000882, + SAY_LEXLORT_1 = -1000883, + SAY_LEXLORT_2 = -1000884, + EMOTE_RAISE_AXE = -1000885, + EMOTE_LOWER_HAND = -1000886, + SAY_LEXLORT_3 = -1000887, + SAY_LEXLORT_4 = -1000888, + + EMOTE_SUBMIT = -1000889, + SAY_AGGRO = -1000890, + + SPELL_CAPTURE_GRARK = 14250, + + NPC_BLACKROCK_AMBUSHER = 9522, + NPC_BLACKROCK_RAIDER = 9605, + NPC_FLAMESCALE_DRAGONSPAWN = 7042, + NPC_SEARSCALE_DRAKE = 7046, + + NPC_GRARK_LORKRUB = 9520, + NPC_HIGH_EXECUTIONER_NUZARK = 9538, + NPC_SHADOW_OF_LEXLORT = 9539, + + FACTION_FRIENDLY = 35, + + QUEST_ID_PRECARIOUS_PREDICAMENT = 4121 +}; + +static const DialogueEntry aOutroDialogue[] = +{ + {SAY_LAST_STAND, NPC_GRARK_LORKRUB, 5000}, + {SAY_LEXLORT_1, NPC_SHADOW_OF_LEXLORT, 3000}, + {SAY_LEXLORT_2, NPC_SHADOW_OF_LEXLORT, 5000}, + {EMOTE_RAISE_AXE, NPC_HIGH_EXECUTIONER_NUZARK, 4000}, + {EMOTE_LOWER_HAND, NPC_SHADOW_OF_LEXLORT, 3000}, + {SAY_LEXLORT_3, NPC_SHADOW_OF_LEXLORT, 3000}, + {NPC_GRARK_LORKRUB, 0, 5000}, + {SAY_LEXLORT_4, NPC_SHADOW_OF_LEXLORT, 0}, + {0, 0, 0}, +}; + +struct npc_grark_lorkrubAI : public npc_escortAI, private DialogueHelper +{ + npc_grark_lorkrubAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aOutroDialogue) + { + Reset(); + } + + ObjectGuid m_nuzarkGuid; + ObjectGuid m_lexlortGuid; + + GuidList m_lSearscaleGuidList; + + uint8 m_uiKilledCreatures; + bool m_bIsFirstSearScale; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiKilledCreatures = 0; + m_bIsFirstSearScale = true; + + m_lSearscaleGuidList.clear(); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + + void Aggro(Unit* /*pWho*/) override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + DoScriptText(SAY_AGGRO, m_creature); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // No combat during escort + if (HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + npc_escortAI::MoveInLineOfSight(pWho); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 1: + DoScriptText(SAY_START, m_creature); + break; + case 7: + DoScriptText(SAY_PAY, m_creature); + break; + case 12: + DoScriptText(SAY_FIRST_AMBUSH_START, m_creature); + SetEscortPaused(true); + + m_creature->SummonCreature(NPC_BLACKROCK_AMBUSHER, -7844.3f, -1521.6f, 139.2f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKROCK_AMBUSHER, -7860.4f, -1507.8f, 141.0f, 6.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKROCK_RAIDER, -7845.6f, -1508.1f, 138.8f, 6.1f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKROCK_RAIDER, -7859.8f, -1521.8f, 139.2f, 6.2f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + break; + case 24: + DoScriptText(SAY_SEC_AMBUSH_START, m_creature); + SetEscortPaused(true); + + m_creature->SummonCreature(NPC_BLACKROCK_AMBUSHER, -8035.3f, -1222.2f, 135.5f, 5.1f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_FLAMESCALE_DRAGONSPAWN, -8037.5f, -1216.9f, 135.8f, 5.1f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKROCK_AMBUSHER, -8009.5f, -1222.1f, 139.2f, 3.9f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_FLAMESCALE_DRAGONSPAWN, -8007.1f, -1219.4f, 140.1f, 3.9f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + break; + case 28: + m_creature->SummonCreature(NPC_SEARSCALE_DRAKE, -7897.8f, -1123.1f, 233.4f, 3.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + m_creature->SummonCreature(NPC_SEARSCALE_DRAKE, -7898.8f, -1125.1f, 193.9f, 3.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + m_creature->SummonCreature(NPC_SEARSCALE_DRAKE, -7895.6f, -1119.5f, 194.5f, 3.1f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + break; + case 30: + { + SetEscortPaused(true); + DoScriptText(SAY_THIRD_AMBUSH_START, m_creature); + + Player* pPlayer = GetPlayerForEscort(); + if (!pPlayer) + return; + + // Set all the dragons in combat + for (GuidList::const_iterator itr = m_lSearscaleGuidList.begin(); itr != m_lSearscaleGuidList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->AI()->AttackStart(pPlayer); + } + break; + } + case 36: + DoScriptText(EMOTE_LAUGH, m_creature); + break; + case 45: + StartNextDialogueText(SAY_LAST_STAND); + SetEscortPaused(true); + + m_creature->SummonCreature(NPC_HIGH_EXECUTIONER_NUZARK, -7532.3f, -1029.4f, 258.0f, 2.7f, TEMPSUMMON_TIMED_DESPAWN, 40000); + m_creature->SummonCreature(NPC_SHADOW_OF_LEXLORT, -7532.8f, -1032.9f, 258.2f, 2.5f, TEMPSUMMON_TIMED_DESPAWN, 40000); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case SAY_LEXLORT_1: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case SAY_LEXLORT_3: + // Note: this part isn't very clear. Should he just simply attack him, or charge him? + if (Creature* pNuzark = m_creature->GetMap()->GetCreature(m_nuzarkGuid)) + pNuzark->HandleEmote(EMOTE_ONESHOT_ATTACK2HTIGHT); + break; + case NPC_GRARK_LORKRUB: + // Fake death creature when the axe is lowered. This will allow us to finish the event + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + break; + case SAY_LEXLORT_4: + // Finish the quest + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_PRECARIOUS_PREDICAMENT, m_creature); + // Kill self + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_HIGH_EXECUTIONER_NUZARK: m_nuzarkGuid = pSummoned->GetObjectGuid(); break; + case NPC_SHADOW_OF_LEXLORT: m_lexlortGuid = pSummoned->GetObjectGuid(); break; + case NPC_SEARSCALE_DRAKE: + // If it's the flying drake allow him to move in circles + if (m_bIsFirstSearScale) + { + m_bIsFirstSearScale = false; + + pSummoned->SetLevitate(true); + // ToDo: this guy should fly in circles above the creature + } + m_lSearscaleGuidList.push_back(pSummoned->GetObjectGuid()); + break; + + default: + // The hostile mobs should attack the player only + if (Player* pPlayer = GetPlayerForEscort()) + pSummoned->AI()->AttackStart(pPlayer); + break; + } + } + + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override + { + ++m_uiKilledCreatures; + + switch (m_uiKilledCreatures) + { + case 4: + DoScriptText(SAY_FIRST_AMBUSH_END, m_creature); + SetEscortPaused(false); + break; + case 8: + DoScriptText(SAY_SEC_AMBUSH_END, m_creature); + SetEscortPaused(false); + break; + case 11: + DoScriptText(SAY_THIRD_AMBUSH_END, m_creature); + SetEscortPaused(false); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_GRARK_LORKRUB: return m_creature; + case NPC_HIGH_EXECUTIONER_NUZARK: return m_creature->GetMap()->GetCreature(m_nuzarkGuid); + case NPC_SHADOW_OF_LEXLORT: return m_creature->GetMap()->GetCreature(m_lexlortGuid); + + default: + return NULL; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_grark_lorkrub(Creature* pCreature) +{ + return new npc_grark_lorkrubAI(pCreature); +} + +bool QuestAccept_npc_grark_lorkrub(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_PRECARIOUS_PREDICAMENT) + { + if (npc_grark_lorkrubAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest); + + return true; + } + + return false; +} + +bool EffectDummyCreature_spell_capture_grark(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_CAPTURE_GRARK && uiEffIndex == EFFECT_INDEX_0) + { + // Note: this implementation needs additional research! There is a lot of guesswork involved in this! + if (pCreatureTarget->GetHealthPercent() > 25.0f) + return false; + + // The faction is guesswork - needs more research + DoScriptText(EMOTE_SUBMIT, pCreatureTarget); + pCreatureTarget->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + pCreatureTarget->AI()->EnterEvadeMode(); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + void AddSC_burning_steppes() { Script* pNewScript; @@ -146,4 +457,11 @@ void AddSC_burning_steppes() pNewScript->pGossipHello = &GossipHello_npc_ragged_john; pNewScript->pGossipSelect = &GossipSelect_npc_ragged_john; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_grark_lorkrub"; + pNewScript->GetAI = &GetAI_npc_grark_lorkrub; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_grark_lorkrub; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_capture_grark; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp b/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp index a9b477c52..91064adae 100644 --- a/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp +++ b/scripts/eastern_kingdoms/deadmines/boss_mr_smite.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -34,10 +34,10 @@ enum EQUIP_ID_HAMMER = 10756, SPELL_NIBLE_REFLEXES = 6433, // removed after phase 1 - SPELL_SMITE_SLAM = 6435, + SPELL_SMITE_SLAM = 6435, // only casted in phase 3 SPELL_SMITE_STOMP = 6432, - SPELL_SMITE_HAMMER = 6436, - SPELL_THRASH = 12787, // unclear, possible 3417 (only 10% proc chance) + SPELL_SMITE_HAMMER = 6436, // unclear, not casted in sniff + SPELL_THRASH = 12787, // only casted in phase 2; unclear, 3391 directly casted in sniff PHASE_1 = 1, PHASE_2 = 2, @@ -48,7 +48,7 @@ enum PHASE_EQUIP_END = 7, }; -struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI +struct boss_mr_smiteAI : public ScriptedAI { boss_mr_smiteAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -56,7 +56,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI uint32 m_uiEquipTimer; uint32 m_uiSlamTimer; - void Reset() + void Reset() override { m_uiPhase = PHASE_1; m_uiEquipTimer = 0; @@ -68,7 +68,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI SetEquipmentSlots(true); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -79,7 +79,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI AttackStart(pAttacker); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_uiPhase > PHASE_3) return; @@ -94,7 +94,12 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI } } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void JustReachedHome() override + { + DoCastSpellIfCan(m_creature, SPELL_NIBLE_REFLEXES, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + + void MovementInform(uint32 uiMotionType, uint32 /*uiPointId*/) override { if (uiMotionType != POINT_MOTION_TYPE) return; @@ -165,7 +170,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI AttackStart(pVictim); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -181,7 +186,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI m_uiEquipTimer = 0; } - switch(m_uiPhase) + switch (m_uiPhase) { case PHASE_EQUIP_START: PhaseEquipStart(); @@ -198,7 +203,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI } // the normal combat phases - switch(m_uiPhase) + switch (m_uiPhase) { case PHASE_1: { @@ -206,7 +211,7 @@ struct MANGOS_DLL_DECL boss_mr_smiteAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_SMITE_STOMP) == CAST_OK) { - DoScriptText(SAY_PHASE_2, m_creature); + DoScriptText(m_creature->GetHealthPercent() < 33.0f ? SAY_PHASE_3 : SAY_PHASE_2, m_creature); m_uiPhase = PHASE_EQUIP_START; m_uiEquipTimer = 2500; diff --git a/scripts/eastern_kingdoms/deadmines/deadmines.cpp b/scripts/eastern_kingdoms/deadmines/deadmines.cpp index fbc959c81..63beaa94b 100644 --- a/scripts/eastern_kingdoms/deadmines/deadmines.cpp +++ b/scripts/eastern_kingdoms/deadmines/deadmines.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,7 +24,7 @@ EndScriptData */ #include "precompiled.h" #include "deadmines.h" -bool GOUse_go_defias_cannon(Player* pPlayer, GameObject* pGo) +bool GOUse_go_defias_cannon(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); diff --git a/scripts/eastern_kingdoms/deadmines/deadmines.h b/scripts/eastern_kingdoms/deadmines/deadmines.h index 96215e59f..1e1e139b1 100644 --- a/scripts/eastern_kingdoms/deadmines/deadmines.h +++ b/scripts/eastern_kingdoms/deadmines/deadmines.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -37,33 +37,34 @@ enum QUEST_FORTUNE_AWAITS = 7938, }; -class MANGOS_DLL_DECL instance_deadmines : public ScriptedInstance +class instance_deadmines : public ScriptedInstance { public: instance_deadmines(Map* pMap); - void Initialize(); + void Initialize() override; - void OnPlayerEnter(Player* pPlayer); + void OnPlayerEnter(Player* pPlayer) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; uint32 m_uiIronDoorTimer; + uint32 m_uiDoorStep; }; #endif diff --git a/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp b/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp index 4dded539a..279a463a6 100644 --- a/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp +++ b/scripts/eastern_kingdoms/deadmines/instance_deadmines.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,7 +25,8 @@ EndScriptData */ #include "deadmines.h" instance_deadmines::instance_deadmines(Map* pMap) : ScriptedInstance(pMap), - m_uiIronDoorTimer(0) + m_uiIronDoorTimer(0), + m_uiDoorStep(0) { Initialize(); } @@ -39,7 +40,7 @@ void instance_deadmines::OnPlayerEnter(Player* pPlayer) { // Respawn the Mysterious chest if one of the players who enter the instance has the quest in his log if (pPlayer->GetQuestStatus(QUEST_FORTUNE_AWAITS) == QUEST_STATUS_COMPLETE && - !pPlayer->GetQuestRewardStatus(QUEST_FORTUNE_AWAITS)) + !pPlayer->GetQuestRewardStatus(QUEST_FORTUNE_AWAITS)) DoRespawnGameObject(GO_MYSTERIOUS_CHEST, HOUR); } @@ -51,7 +52,7 @@ void instance_deadmines::OnCreatureCreate(Creature* pCreature) void instance_deadmines::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_FACTORY_DOOR: if (m_auiEncounter[TYPE_RHAHKZOR] == DONE) @@ -87,7 +88,7 @@ void instance_deadmines::OnObjectCreate(GameObject* pGo) void instance_deadmines::OnCreatureDeath(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_RHAHKZOR: SetData(TYPE_RHAHKZOR, DONE); break; case NPC_SNEED: SetData(TYPE_SNEED, DONE); break; @@ -97,7 +98,7 @@ void instance_deadmines::OnCreatureDeath(Creature* pCreature) void instance_deadmines::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_RHAHKZOR: { @@ -125,30 +126,9 @@ void instance_deadmines::SetData(uint32 uiType, uint32 uiData) } case TYPE_IRON_CLAD_DOOR: { + // delayed door animation to sync with Defias Cannon animation if (uiData == DONE) - { - DoUseDoorOrButton(GO_IRON_CLAD_DOOR, 0, true); - m_uiIronDoorTimer = 15000; - - if (Creature* pMrSmite = GetSingleCreatureFromStorage(NPC_MR_SMITE)) - DoScriptText(INST_SAY_ALARM1, pMrSmite); - - if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_IRON_CLAD_DOOR)) - { - // should be static spawns, fetch the closest ones at the pier - if (Creature* pi1 = GetClosestCreatureWithEntry(pDoor, NPC_PIRATE, 40.0f)) - { - pi1->SetWalk(false); - pi1->GetMotionMaster()->MovePoint(0, pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ()); - } - - if (Creature* pi2 = GetClosestCreatureWithEntry(pDoor, NPC_SQUALLSHAPER, 40.0f)) - { - pi2->SetWalk(false); - pi2->GetMotionMaster()->MovePoint(0, pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ()); - } - } - } + m_uiIronDoorTimer = 500; m_auiEncounter[uiType] = uiData; break; @@ -169,7 +149,7 @@ void instance_deadmines::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_deadmines::GetData(uint32 uiType) +uint32 instance_deadmines::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -205,10 +185,41 @@ void instance_deadmines::Update(uint32 uiDiff) { if (m_uiIronDoorTimer <= uiDiff) { - if (Creature* pMrSmite = GetSingleCreatureFromStorage(NPC_MR_SMITE)) - DoScriptText(INST_SAY_ALARM2, pMrSmite); + switch (m_uiDoorStep) + { + case 0: + DoUseDoorOrButton(GO_IRON_CLAD_DOOR, 0, true); + + if (Creature* pMrSmite = GetSingleCreatureFromStorage(NPC_MR_SMITE)) + DoScriptText(INST_SAY_ALARM1, pMrSmite); + + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_IRON_CLAD_DOOR)) + { + // should be static spawns, fetch the closest ones at the pier + if (Creature* pi1 = GetClosestCreatureWithEntry(pDoor, NPC_PIRATE, 40.0f)) + { + pi1->SetWalk(false); + pi1->GetMotionMaster()->MovePoint(0, pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ()); + } + + if (Creature* pi2 = GetClosestCreatureWithEntry(pDoor, NPC_SQUALLSHAPER, 40.0f)) + { + pi2->SetWalk(false); + pi2->GetMotionMaster()->MovePoint(0, pDoor->GetPositionX(), pDoor->GetPositionY(), pDoor->GetPositionZ()); + } + } - m_uiIronDoorTimer = 0; + ++m_uiDoorStep; + m_uiIronDoorTimer = 15000; + break; + case 1: + if (Creature* pMrSmite = GetSingleCreatureFromStorage(NPC_MR_SMITE)) + DoScriptText(INST_SAY_ALARM2, pMrSmite); + + m_uiDoorStep = 0; + m_uiIronDoorTimer = 0; + break; + } } else m_uiIronDoorTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/dun_morogh.cpp b/scripts/eastern_kingdoms/dun_morogh.cpp index af9864446..effd255b2 100644 --- a/scripts/eastern_kingdoms/dun_morogh.cpp +++ b/scripts/eastern_kingdoms/dun_morogh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,76 +16,16 @@ /* ScriptData SDName: Dun_Morogh -SD%Complete: 50 -SDComment: Quest support: 1783 +SD%Complete: 0 +SDComment: Placeholder SDCategory: Dun Morogh EndScriptData */ /* ContentData -npc_narm_faulk EndContentData */ #include "precompiled.h" -/*###### -## npc_narm_faulk -######*/ - -#define SAY_HEAL -1000187 - -struct MANGOS_DLL_DECL npc_narm_faulkAI : public ScriptedAI -{ - uint32 lifeTimer; - bool spellHit; - - npc_narm_faulkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - spellHit = false; - } - - void MoveInLineOfSight(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (m_creature->IsStandState()) - { - if (lifeTimer < diff) - m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; - } - } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - if (Spellkind->Id == 8593 && !spellHit) - { - DoCastSpellIfCan(m_creature,32343); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - //m_creature->RemoveAllAuras(); - DoScriptText(SAY_HEAL, m_creature, Hitter); - spellHit = true; - } - } - -}; -CreatureAI* GetAI_npc_narm_faulk(Creature* pCreature) -{ - return new npc_narm_faulkAI(pCreature); -} - void AddSC_dun_morogh() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "npc_narm_faulk"; - pNewScript->GetAI = &GetAI_npc_narm_faulk; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/eastern_plaguelands.cpp b/scripts/eastern_kingdoms/eastern_plaguelands.cpp index 7829c79d1..162762ab6 100644 --- a/scripts/eastern_kingdoms/eastern_plaguelands.cpp +++ b/scripts/eastern_kingdoms/eastern_plaguelands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,109 +17,295 @@ /* ScriptData SDName: Eastern_Plaguelands SD%Complete: 100 -SDComment: Quest support: 5211, 5742. +SDComment: Quest support: 7622. SDCategory: Eastern Plaguelands EndScriptData */ /* ContentData -mobs_ghoul_flayer -npc_darrowshire_spirit -npc_tirion_fordring +npc_eris_havenfire EndContentData */ #include "precompiled.h" -//id8530 - cannibal ghoul -//id8531 - gibbering ghoul -//id8532 - diseased flayer +/*###### +## npc_eris_havenfire +######*/ -struct MANGOS_DLL_DECL mobs_ghoul_flayerAI : public ScriptedAI +enum { - mobs_ghoul_flayerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + SAY_PHASE_HEAL = -1000815, + SAY_EVENT_END = -1000816, + SAY_EVENT_FAIL_1 = -1000817, + SAY_EVENT_FAIL_2 = -1000818, + SAY_PEASANT_APPEAR_1 = -1000819, + SAY_PEASANT_APPEAR_2 = -1000820, + SAY_PEASANT_APPEAR_3 = -1000821, - void Reset() { } + // SPELL_DEATHS_DOOR = 23127, // damage spells cast on the peasants + // SPELL_SEETHING_PLAGUE = 23072, + SPELL_ENTER_THE_LIGHT_DND = 23107, + SPELL_BLESSING_OF_NORDRASSIL = 23108, - void JustDied(Unit* Killer) - { - if (Killer->GetTypeId() == TYPEID_PLAYER) - m_creature->SummonCreature(11064, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000); - } + NPC_INJURED_PEASANT = 14484, + NPC_PLAGUED_PEASANT = 14485, + NPC_SCOURGE_ARCHER = 14489, + NPC_SCOURGE_FOOTSOLDIER = 14486, + NPC_THE_CLEANER = 14503, // can be summoned if the priest has more players in the party for help. requires further research + + QUEST_BALANCE_OF_LIGHT_AND_SHADOW = 7622, + MAX_PEASANTS = 12, + MAX_ARCHERS = 8, }; -CreatureAI* GetAI_mobs_ghoul_flayer(Creature* pCreature) +static const float aArcherSpawn[8][4] = { - return new mobs_ghoul_flayerAI(pCreature); -} + {3327.42f, -3021.11f, 170.57f, 6.01f}, + {3335.4f, -3054.3f, 173.63f, 0.49f}, + {3351.3f, -3079.08f, 178.67f, 1.15f}, + {3358.93f, -3076.1f, 174.87f, 1.57f}, + {3371.58f, -3069.24f, 175.20f, 1.99f}, + {3369.46f, -3023.11f, 171.83f, 3.69f}, + {3383.25f, -3057.01f, 181.53f, 2.21f}, + {3380.03f, -3062.73f, 181.90f, 2.31f}, +}; -/*###### -## npc_darrowshire_spirit -######*/ +static const float aPeasantSpawnLoc[3] = {3360.12f, -3047.79f, 165.26f}; +static const float aPeasantMoveLoc[3] = {3335.0f, -2994.04f, 161.14f}; -#define SPELL_SPIRIT_SPAWNIN 17321 +static const int32 aPeasantSpawnYells[3] = {SAY_PEASANT_APPEAR_1, SAY_PEASANT_APPEAR_2, SAY_PEASANT_APPEAR_3}; -struct MANGOS_DLL_DECL npc_darrowshire_spiritAI : public ScriptedAI +struct npc_eris_havenfireAI : public ScriptedAI { - npc_darrowshire_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_eris_havenfireAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() + uint32 m_uiEventTimer; + uint32 m_uiSadEndTimer; + uint8 m_uiPhase; + uint8 m_uiCurrentWave; + uint8 m_uiKillCounter; + uint8 m_uiSaveCounter; + + ObjectGuid m_playerGuid; + GuidList m_lSummonedGuidList; + + void Reset() override { - DoCastSpellIfCan(m_creature,SPELL_SPIRIT_SPAWNIN); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiEventTimer = 0; + m_uiSadEndTimer = 0; + m_uiPhase = 0; + m_uiCurrentWave = 0; + m_uiKillCounter = 0; + m_uiSaveCounter = 0; + + m_playerGuid.Clear(); + m_lSummonedGuidList.clear(); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } -}; -CreatureAI* GetAI_npc_darrowshire_spirit(Creature* pCreature) -{ - return new npc_darrowshire_spiritAI(pCreature); -} + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_INJURED_PEASANT: + case NPC_PLAGUED_PEASANT: + float fX, fY, fZ; + pSummoned->GetRandomPoint(aPeasantMoveLoc[0], aPeasantMoveLoc[1], aPeasantMoveLoc[2], 10.0f, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_lSummonedGuidList.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_SCOURGE_FOOTSOLDIER: + case NPC_THE_CLEANER: + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pSummoned->AI()->AttackStart(pPlayer); + break; + case NPC_SCOURGE_ARCHER: + // ToDo: make these ones attack the peasants + break; + } -bool GossipHello_npc_darrowshire_spirit(Player* pPlayer, Creature* pCreature) -{ - pPlayer->SEND_GOSSIP_MENU(3873, pCreature->GetObjectGuid()); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - return true; -} + m_lSummonedGuidList.push_back(pSummoned->GetObjectGuid()); + } -/*###### -## npc_tirion_fordring -######*/ + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; -bool GossipHello_npc_tirion_fordring(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + if (uiPointId) + { + ++m_uiSaveCounter; + pSummoned->GetMotionMaster()->Clear(); + + pSummoned->RemoveAllAuras(); + pSummoned->CastSpell(pSummoned, SPELL_ENTER_THE_LIGHT_DND, false); + pSummoned->ForcedDespawn(10000); - if (pPlayer->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && pPlayer->getStandState() == UNIT_STAND_STATE_SIT) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I am ready to hear your tale, Tirion.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + // Event ended + if (m_uiSaveCounter >= 50 && m_uiCurrentWave == 5) + DoBalanceEventEnd(); + // Phase ended + else if (m_uiSaveCounter + m_uiKillCounter == m_uiCurrentWave * MAX_PEASANTS) + DoHandlePhaseEnd(); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_INJURED_PEASANT || pSummoned->GetEntry() == NPC_PLAGUED_PEASANT) + { + ++m_uiKillCounter; - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + // If more than 15 peasants have died, then fail the quest + if (m_uiKillCounter == MAX_PEASANTS) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->FailQuest(QUEST_BALANCE_OF_LIGHT_AND_SHADOW); - return true; + DoScriptText(SAY_EVENT_FAIL_1, m_creature); + m_uiSadEndTimer = 4000; + } + else if (m_uiSaveCounter + m_uiKillCounter == m_uiCurrentWave * MAX_PEASANTS) + DoHandlePhaseEnd(); + } + } + + void DoSummonWave(uint32 uiSummonId = 0) + { + float fX, fY, fZ; + + if (!uiSummonId) + { + for (uint8 i = 0; i < MAX_PEASANTS; ++i) + { + uint32 uiSummonEntry = roll_chance_i(70) ? NPC_INJURED_PEASANT : NPC_PLAGUED_PEASANT; + m_creature->GetRandomPoint(aPeasantSpawnLoc[0], aPeasantSpawnLoc[1], aPeasantSpawnLoc[2], 10.0f, fX, fY, fZ); + if (Creature* pTemp = m_creature->SummonCreature(uiSummonEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + // Only the first mob needs to yell + if (!i) + DoScriptText(aPeasantSpawnYells[urand(0, 2)], pTemp); + } + } + + ++m_uiCurrentWave; + } + else if (uiSummonId == NPC_SCOURGE_FOOTSOLDIER) + { + uint8 uiRand = urand(2, 3); + for (uint8 i = 0; i < uiRand; ++i) + { + m_creature->GetRandomPoint(aPeasantSpawnLoc[0], aPeasantSpawnLoc[1], aPeasantSpawnLoc[2], 15.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_SCOURGE_FOOTSOLDIER, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + else if (uiSummonId == NPC_SCOURGE_ARCHER) + { + for (uint8 i = 0; i < MAX_ARCHERS; ++i) + m_creature->SummonCreature(NPC_SCOURGE_ARCHER, aArcherSpawn[i][0], aArcherSpawn[i][1], aArcherSpawn[i][2], aArcherSpawn[i][3], TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void DoHandlePhaseEnd() + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->CastSpell(pPlayer, SPELL_BLESSING_OF_NORDRASSIL, true); + + DoScriptText(SAY_PHASE_HEAL, m_creature); + + // Send next wave + if (m_uiCurrentWave < 5) + DoSummonWave(); + } + + void DoStartBalanceEvent(Player* pPlayer) + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_playerGuid = pPlayer->GetObjectGuid(); + m_uiEventTimer = 5000; + } + + void DoBalanceEventEnd() + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->AreaExploredOrEventHappens(QUEST_BALANCE_OF_LIGHT_AND_SHADOW); + + DoScriptText(SAY_EVENT_END, m_creature); + DoDespawnSummons(true); + EnterEvadeMode(); + } + + void DoDespawnSummons(bool bIsEventEnd = false) + { + for (GuidList::const_iterator itr = m_lSummonedGuidList.begin(); itr != m_lSummonedGuidList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + if (bIsEventEnd && (pTemp->GetEntry() == NPC_INJURED_PEASANT || pTemp->GetEntry() == NPC_PLAGUED_PEASANT)) + continue; + + pTemp->ForcedDespawn(); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiPhase) + { + case 0: + DoSummonWave(NPC_SCOURGE_ARCHER); + m_uiEventTimer = 5000; + break; + case 1: + DoSummonWave(); + m_uiEventTimer = urand(60000, 80000); + break; + default: + // The summoning timer of the soldiers isn't very clear + DoSummonWave(NPC_SCOURGE_FOOTSOLDIER); + m_uiEventTimer = urand(5000, 30000); + break; + } + ++m_uiPhase; + } + else + m_uiEventTimer -= uiDiff; + } + + // Handle event end in case of fail + if (m_uiSadEndTimer) + { + if (m_uiSadEndTimer <= uiDiff) + { + DoScriptText(SAY_EVENT_FAIL_2, m_creature); + m_creature->ForcedDespawn(5000); + DoDespawnSummons(); + m_uiSadEndTimer = 0; + } + else + m_uiSadEndTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_eris_havenfire(Creature* pCreature) +{ + return new npc_eris_havenfireAI(pCreature); } -bool GossipSelect_npc_tirion_fordring(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool QuestAccept_npc_eris_havenfire(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - switch(uiAction) + if (pQuest->GetQuestId() == QUEST_BALANCE_OF_LIGHT_AND_SHADOW) { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thank you, Tirion. What of your identity?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(4493, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "That is terrible.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(4494, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I will, Tirion.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(4495, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(5742); - break; + if (npc_eris_havenfireAI* pErisAI = dynamic_cast(pCreature->AI())) + pErisAI->DoStartBalanceEvent(pPlayer); } + return true; } @@ -128,19 +314,8 @@ void AddSC_eastern_plaguelands() Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "mobs_ghoul_flayer"; - pNewScript->GetAI = &GetAI_mobs_ghoul_flayer; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_darrowshire_spirit"; - pNewScript->GetAI = &GetAI_npc_darrowshire_spirit; - pNewScript->pGossipHello = &GossipHello_npc_darrowshire_spirit; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_tirion_fordring"; - pNewScript->pGossipHello = &GossipHello_npc_tirion_fordring; - pNewScript->pGossipSelect = &GossipSelect_npc_tirion_fordring; + pNewScript->Name = "npc_eris_havenfire"; + pNewScript->GetAI = &GetAI_npc_eris_havenfire; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_eris_havenfire; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/elwynn_forest.cpp b/scripts/eastern_kingdoms/elwynn_forest.cpp index 887c6eceb..aecaa7bf0 100644 --- a/scripts/eastern_kingdoms/elwynn_forest.cpp +++ b/scripts/eastern_kingdoms/elwynn_forest.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,76 +16,16 @@ /* ScriptData SDName: Elwynn_Forest -SD%Complete: 50 -SDComment: Quest support: 1786 +SD%Complete: 0 +SDComment: Placeholder SDCategory: Elwynn Forest EndScriptData */ /* ContentData -npc_henze_faulk EndContentData */ #include "precompiled.h" -/*###### -## npc_henze_faulk -######*/ - -#define SAY_HEAL -1000187 - -struct MANGOS_DLL_DECL npc_henze_faulkAI : public ScriptedAI -{ - uint32 lifeTimer; - bool spellHit; - - npc_henze_faulkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - lifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); // lay down - spellHit = false; - } - - void MoveInLineOfSight(Unit *who) { } - - void UpdateAI(const uint32 diff) - { - if (m_creature->IsStandState()) - { - if (lifeTimer < diff) - m_creature->AI()->EnterEvadeMode(); - else - lifeTimer -= diff; - } - } - - void SpellHit(Unit *Hitter, const SpellEntry *Spellkind) - { - if (Spellkind->Id == 8593 && !spellHit) - { - DoCastSpellIfCan(m_creature,32343); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - //m_creature->RemoveAllAuras(); - DoScriptText(SAY_HEAL, m_creature, Hitter); - spellHit = true; - } - } - -}; -CreatureAI* GetAI_npc_henze_faulk(Creature* pCreature) -{ - return new npc_henze_faulkAI(pCreature); -} - void AddSC_elwynn_forest() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "npc_henze_faulk"; - pNewScript->GetAI = &GetAI_npc_henze_faulk; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/eversong_woods.cpp b/scripts/eastern_kingdoms/eversong_woods.cpp index a96a06e74..75506eda4 100644 --- a/scripts/eastern_kingdoms/eversong_woods.cpp +++ b/scripts/eastern_kingdoms/eversong_woods.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -60,7 +60,7 @@ const int32 uiSayId[4] = -1000322 }; -float fChallengerLoc[4][4]= +float fChallengerLoc[4][4] = { {10110.667f, -6628.059f, 4.100f, 2.708f}, {10093.919f, -6634.340f, 4.098f, 1.106f}, @@ -68,7 +68,7 @@ float fChallengerLoc[4][4]= {10104.807f, -6611.145f, 4.101f, 4.265f} }; -struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI +struct npc_kelerun_bloodmournAI : public ScriptedAI { npc_kelerun_bloodmournAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -88,15 +88,12 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI bool m_bIsEventInProgress; - void Reset() + void Reset() override { m_creature->SetUInt32Value(UNIT_NPC_FLAGS, m_uiNpcFlags); m_playerGuid.Clear(); - for (uint8 i = 0; i < MAX_CHALLENGER; ++i) - m_aChallengerGuids[i].Clear(); - m_uiChallengerCount = 0; m_uiTimeOutTimer = 60000; @@ -104,6 +101,12 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI m_uiEngageTimer = 0; m_bIsEventInProgress = false; + for (uint8 i = 0; i < MAX_CHALLENGER; ++i) // Despawn challengers + { + if (Creature* pChallenger = m_creature->GetMap()->GetCreature(m_aChallengerGuids[i])) + pChallenger->ForcedDespawn(1000); + m_aChallengerGuids[i].Clear(); + } } void StartEvent() @@ -128,12 +131,12 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI void DoSpawnChallengers() { - for(uint8 i = 0; i < MAX_CHALLENGER; ++i) + for (uint8 i = 0; i < MAX_CHALLENGER; ++i) { if (Creature* pCreature = m_creature->SummonCreature(uiChallengerId[i], - fChallengerLoc[i][0], fChallengerLoc[i][1], - fChallengerLoc[i][2], fChallengerLoc[i][3], - TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000)) + fChallengerLoc[i][0], fChallengerLoc[i][1], + fChallengerLoc[i][2], fChallengerLoc[i][3], + TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000)) { m_aChallengerGuids[i] = pCreature->GetObjectGuid(); pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -141,76 +144,77 @@ struct MANGOS_DLL_DECL npc_kelerun_bloodmournAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bIsEventInProgress) { - if (m_uiTimeOutTimer && m_uiTimeOutTimer < uiDiff) + if (m_uiTimeOutTimer) { - if (!m_playerGuid) + if (m_uiTimeOutTimer <= uiDiff) { - //player are expected to use GO within a minute, if not, event will fail. - Reset(); - return; + if (!m_playerGuid) // player are expected to use GO within a minute, if not, event will fail. + { + Reset(); + return; + } + m_uiTimeOutTimer = 0; } - - m_uiTimeOutTimer = 0; + else + m_uiTimeOutTimer -= uiDiff; } - else - m_uiTimeOutTimer -= uiDiff; if (m_uiCheckAliveStateTimer < uiDiff) { - if (Creature* pChallenger = m_creature->GetMap()->GetCreature(m_aChallengerGuids[m_uiChallengerCount])) + Creature* pChallenger = m_creature->GetMap()->GetCreature(m_aChallengerGuids[m_uiChallengerCount]); + if (pChallenger && !pChallenger->isAlive()) { - if (!pChallenger->isAlive()) + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); + if (!pPlayer || !pPlayer->isAlive()) + { + Reset(); + return; + } + + ++m_uiChallengerCount; + + // count starts at 0 + if (m_uiChallengerCount == MAX_CHALLENGER) { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); - - if (pPlayer && !pPlayer->isAlive()) - { - Reset(); - return; - } - - ++m_uiChallengerCount; - - //count starts at 0 - if (m_uiChallengerCount == MAX_CHALLENGER) - { - if (pPlayer && pPlayer->isAlive()) - pPlayer->GroupEventHappens(QUEST_SECOND_TRIAL, m_creature); - - Reset(); - return; - } - else - m_uiEngageTimer = 15000; + pPlayer->GroupEventHappens(QUEST_SECOND_TRIAL, m_creature); + Reset(); + return; } + else + m_uiEngageTimer = 15000; } m_uiCheckAliveStateTimer = 2500; } else m_uiCheckAliveStateTimer -= uiDiff; - if (m_uiEngageTimer && m_uiEngageTimer < uiDiff) + if (m_uiEngageTimer) { - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); - - if (pPlayer && pPlayer->isAlive()) + if (m_uiEngageTimer <= uiDiff) { + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); + if (!pPlayer || !pPlayer->isAlive()) + { + Reset(); + return; + } + if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_aChallengerGuids[m_uiChallengerCount])) { DoScriptText(uiSayId[m_uiChallengerCount], m_creature, pPlayer); pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); pCreature->AI()->AttackStart(pPlayer); } - } - m_uiEngageTimer = 0; + m_uiEngageTimer = 0; + } + else + m_uiEngageTimer -= uiDiff; } - else - m_uiEngageTimer -= uiDiff; } } }; @@ -220,8 +224,8 @@ CreatureAI* GetAI_npc_kelerun_bloodmourn(Creature* pCreature) return new npc_kelerun_bloodmournAI(pCreature); } -//easiest way is to expect database to respawn GO at quest accept (quest_start_script) -bool QuestAccept_npc_kelerun_bloodmourn(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +// easiest way is to expect database to respawn GO at quest accept (quest_start_script) +bool QuestAccept_npc_kelerun_bloodmourn(Player* /*pPlayer*/, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_SECOND_TRIAL) { @@ -254,19 +258,26 @@ enum SAY_ANVIL1 = -1000209, SAY_ANVIL2 = -1000210, - FACTION_DEFAULT = 35, + GOSSIP_ITEM_MOMENT = -3000108, + GOSSIP_ITEM_SHOW = -3000110, + + GOSSIP_TEXT_ID_MOMENT = 8239, + GOSSIP_TEXT_ID_SHOW = 8240, + FACTION_HOSTILE = 24, QUEST_THE_DWARVEN_SPY = 8483 }; -struct MANGOS_DLL_DECL npc_prospector_anvilwardAI : public npc_escortAI +struct npc_prospector_anvilwardAI : public npc_escortAI { // CreatureAI functions npc_prospector_anvilwardAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} + void Reset() override { } + // Pure Virtual Functions - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); @@ -282,22 +293,11 @@ struct MANGOS_DLL_DECL npc_prospector_anvilwardAI : public npc_escortAI DoScriptText(SAY_ANVIL2, m_creature, pPlayer); break; case 6: - m_creature->setFaction(FACTION_HOSTILE); + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + AttackStart(pPlayer); break; } } - - void Reset() - { - //Default npc faction - m_creature->setFaction(FACTION_DEFAULT); - } - - void JustDied(Unit* pKiller) - { - //Default npc faction - m_creature->setFaction(FACTION_DEFAULT); - } }; CreatureAI* GetAI_npc_prospector_anvilward(Creature* pCreature) @@ -305,25 +305,22 @@ CreatureAI* GetAI_npc_prospector_anvilward(Creature* pCreature) return new npc_prospector_anvilwardAI(pCreature); } -#define GOSSIP_ITEM_MOMENT "I need a moment of your time, sir." -#define GOSSIP_ITEM_SHOW "Why... yes, of course. I've something to show you right inside this building, Mr. Anvilward." - bool GossipHello_npc_prospector_anvilward(Player* pPlayer, Creature* pCreature) { if (pPlayer->GetQuestStatus(QUEST_THE_DWARVEN_SPY) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MOMENT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MOMENT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(8239, pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_MOMENT, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_prospector_anvilward(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_prospector_anvilward(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SHOW, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(8240, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SHOW, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_SHOW, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->CLOSE_GOSSIP_MENU(); @@ -350,7 +347,7 @@ enum NPC_ANGERSHADE = 15656 }; -struct MANGOS_DLL_DECL npc_apprentice_mirvedaAI : public ScriptedAI +struct npc_apprentice_mirvedaAI : public ScriptedAI { npc_apprentice_mirvedaAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -358,14 +355,14 @@ struct MANGOS_DLL_DECL npc_apprentice_mirvedaAI : public ScriptedAI uint32 m_uiFireballTimer; ObjectGuid m_playerGuid; - void Reset() + void Reset() override { m_uiMobCount = 0; m_playerGuid.Clear(); m_uiFireballTimer = 0; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); @@ -373,13 +370,13 @@ struct MANGOS_DLL_DECL npc_apprentice_mirvedaAI : public ScriptedAI pPlayer->SendQuestFailed(QUEST_UNEXPECTED_RESULT); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); ++m_uiMobCount; } - void SummonedCreatureJustDied(Creature* pKilled) + void SummonedCreatureJustDied(Creature* /*pKilled*/) override { --m_uiMobCount; @@ -405,9 +402,9 @@ struct MANGOS_DLL_DECL npc_apprentice_mirvedaAI : public ScriptedAI m_creature->SummonCreature(NPC_ANGERSHADE, 8745.0f, -7134.32f, 35.22f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 4000); } - void UpdateAI (const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -433,7 +430,7 @@ bool QuestAccept_unexpected_results(Player* pPlayer, Creature* pCreature, const CreatureAI* GetAI_npc_apprentice_mirvedaAI(Creature* pCreature) { - return new npc_apprentice_mirvedaAI (pCreature); + return new npc_apprentice_mirvedaAI(pCreature); } /*###### @@ -457,14 +454,14 @@ static const float aSummonPos[6][4] = {8301.548f, -7247.548f, 139.974f, 1.828518f} }; -struct MANGOS_DLL_DECL npc_infused_crystalAI : public Scripted_NoMovementAI +struct npc_infused_crystalAI : public Scripted_NoMovementAI { npc_infused_crystalAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { m_bFirstWave = true; m_uiWaveTimer = 1000; m_uiKilledCount = 0; - m_uiFinishTimer = 60*IN_MILLISECONDS; + m_uiFinishTimer = 60 * IN_MILLISECONDS; Reset(); } @@ -473,14 +470,14 @@ struct MANGOS_DLL_DECL npc_infused_crystalAI : public Scripted_NoMovementAI uint8 m_uiKilledCount; uint32 m_uiFinishTimer; - void Reset() {} + void Reset() override {} - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override { ++m_uiKilledCount; @@ -488,7 +485,7 @@ struct MANGOS_DLL_DECL npc_infused_crystalAI : public Scripted_NoMovementAI m_uiWaveTimer = std::min(m_uiWaveTimer, (uint32)10000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiWaveTimer) { @@ -497,14 +494,14 @@ struct MANGOS_DLL_DECL npc_infused_crystalAI : public Scripted_NoMovementAI if (m_bFirstWave) { for (uint8 i = 0; i < 3; ++i) - m_creature->SummonCreature(NPC_ENRAGED_WRAITH, aSummonPos[i][0], aSummonPos[i][1], aSummonPos[i][2], aSummonPos[i][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5*MINUTE); + m_creature->SummonCreature(NPC_ENRAGED_WRAITH, aSummonPos[i][0], aSummonPos[i][1], aSummonPos[i][2], aSummonPos[i][3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 5 * MINUTE); m_uiWaveTimer = 29000; m_bFirstWave = false; } else { for (uint8 i = 3; i < 6; ++i) - m_creature->SummonCreature(NPC_ENRAGED_WRAITH, aSummonPos[i][0], aSummonPos[i][1], aSummonPos[i][2], aSummonPos[i][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5*MINUTE); + m_creature->SummonCreature(NPC_ENRAGED_WRAITH, aSummonPos[i][0], aSummonPos[i][1], aSummonPos[i][2], aSummonPos[i][3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 5 * MINUTE); m_uiWaveTimer = 0; } } @@ -535,7 +532,7 @@ struct MANGOS_DLL_DECL npc_infused_crystalAI : public Scripted_NoMovementAI CreatureAI* GetAI_npc_infused_crystalAI(Creature* pCreature) { - return new npc_infused_crystalAI (pCreature); + return new npc_infused_crystalAI(pCreature); } void AddSC_eversong_woods() diff --git a/scripts/eastern_kingdoms/ghostlands.cpp b/scripts/eastern_kingdoms/ghostlands.cpp index 3bc51bc1b..d6cc15ee9 100644 --- a/scripts/eastern_kingdoms/ghostlands.cpp +++ b/scripts/eastern_kingdoms/ghostlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -48,14 +48,14 @@ enum FACTION_SMOON_E = 1603, }; -struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI +struct npc_ranger_lilathaAI : public npc_escortAI { npc_ranger_lilathaAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } ObjectGuid m_goCageGuid; ObjectGuid m_heliosGuid; - void MoveInLineOfSight(Unit* pUnit) + void MoveInLineOfSight(Unit* pUnit) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -69,14 +69,14 @@ struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI npc_escortAI::MoveInLineOfSight(pUnit); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 i) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(i) + switch (i) { case 0: if (GameObject* pGoTemp = GetClosestGameObjectWithEntry(m_creature, GO_CAGE, 10.0f)) @@ -126,7 +126,7 @@ struct MANGOS_DLL_DECL npc_ranger_lilathaAI : public npc_escortAI } } - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -145,7 +145,7 @@ bool QuestAccept_npc_ranger_lilatha(Player* pPlayer, Creature* pCreature, const { if (pQuest->GetQuestId() == QUEST_CATACOMBS) { - pCreature->setFaction(FACTION_SMOON_E); + pCreature->SetFactionTemporary(FACTION_SMOON_E, TEMPFACTION_RESTORE_RESPAWN); if (npc_ranger_lilathaAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); diff --git a/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp b/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp index 30febcc13..b334ecf13 100644 --- a/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp +++ b/scripts/eastern_kingdoms/gnomeregan/boss_thermaplugg.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -42,7 +42,7 @@ enum static const float fBombSpawnZ = -316.2625f; -struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI +struct boss_thermapluggAI : public ScriptedAI { boss_thermapluggAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -59,21 +59,21 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI sBombFace* m_asBombFaces; float m_afSpawnPos[3]; - GUIDList m_lSummonedBombGUIDs; - GUIDList m_lLandedBombGUIDs; + GuidList m_lSummonedBombGUIDs; + GuidList m_lLandedBombGUIDs; - void Reset() + void Reset() override { m_uiKnockAwayTimer = urand(17000, 20000); m_uiActivateBombTimer = urand(10000, 15000); m_bIsPhaseTwo = false; m_asBombFaces = NULL; - memset(&m_afSpawnPos, 0.0f, sizeof(m_afSpawnPos)); + memset(&m_afSpawnPos, 0, sizeof(m_afSpawnPos)); m_lLandedBombGUIDs.clear(); } - void GetAIInformation(ChatHandler& reader) + void GetAIInformation(ChatHandler& reader) override { reader.PSendSysMessage("Thermaplugg, currently phase %s", m_bIsPhaseTwo ? "two" : "one"); @@ -84,12 +84,12 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_THERMAPLUGG, DONE); @@ -97,7 +97,7 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI m_lSummonedBombGUIDs.clear(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -112,13 +112,13 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI m_afSpawnPos[2] = m_creature->GetPositionZ(); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_THERMAPLUGG, FAIL); // Remove remaining bombs - for (GUIDList::const_iterator itr = m_lSummonedBombGUIDs.begin(); itr != m_lSummonedBombGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lSummonedBombGUIDs.begin(); itr != m_lSummonedBombGUIDs.end(); ++itr) { if (Creature* pBomb = m_creature->GetMap()->GetCreature(*itr)) pBomb->ForcedDespawn(); @@ -126,31 +126,31 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI m_lSummonedBombGUIDs.clear(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_WALKING_BOMB) { m_lSummonedBombGUIDs.push_back(pSummoned->GetObjectGuid()); // calculate point for falling down float fX, fY; - fX = 0.2*m_afSpawnPos[0] + 0.8*pSummoned->GetPositionX(); - fY = 0.2*m_afSpawnPos[1] + 0.8*pSummoned->GetPositionY(); + fX = 0.2 * m_afSpawnPos[0] + 0.8 * pSummoned->GetPositionX(); + fY = 0.2 * m_afSpawnPos[1] + 0.8 * pSummoned->GetPositionY(); pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, m_afSpawnPos[2] - 2.0f); } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override { if (pSummoned->GetEntry() == NPC_WALKING_BOMB && uiMotionType == POINT_MOTION_TYPE && uiPointId == 1) m_lLandedBombGUIDs.push_back(pSummoned->GetObjectGuid()); } - void SummonedCreatureDespawn(Creature* pSummoned) + void SummonedCreatureDespawn(Creature* pSummoned) override { m_lSummonedBombGUIDs.remove(pSummoned->GetObjectGuid()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -158,7 +158,7 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI // Movement of Summoned mobs if (!m_lLandedBombGUIDs.empty()) { - for (GUIDList::const_iterator itr = m_lLandedBombGUIDs.begin(); itr != m_lLandedBombGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lLandedBombGUIDs.begin(); itr != m_lLandedBombGUIDs.end(); ++itr) { if (Creature* pBomb = m_creature->GetMap()->GetCreature(*itr)) pBomb->GetMotionMaster()->MoveFollow(m_creature, 0.0f, 0.0f); @@ -192,7 +192,7 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, m_bIsPhaseTwo ? SPELL_ACTIVATE_BOMB_B : SPELL_ACTIVATE_BOMB_A) == CAST_OK) { - m_uiActivateBombTimer = (m_bIsPhaseTwo ? urand(6, 12) : urand(12, 17))*IN_MILLISECONDS; + m_uiActivateBombTimer = (m_bIsPhaseTwo ? urand(6, 12) : urand(12, 17)) * IN_MILLISECONDS; if (!urand(0, 5)) // TODO, chance/ place for this correct? DoScriptText(SAY_BOMB, m_creature); } @@ -213,8 +213,8 @@ struct MANGOS_DLL_DECL boss_thermapluggAI : public ScriptedAI float fX = 0.0f, fY = 0.0f; if (GameObject* pFace = m_creature->GetMap()->GetGameObject(m_asBombFaces[i].m_gnomeFaceGuid)) { - fX = 0.35*m_afSpawnPos[0] + 0.65*pFace->GetPositionX(); - fY = 0.35*m_afSpawnPos[1] + 0.65*pFace->GetPositionY(); + fX = 0.35 * m_afSpawnPos[0] + 0.65 * pFace->GetPositionX(); + fY = 0.35 * m_afSpawnPos[1] + 0.65 * pFace->GetPositionY(); } m_creature->SummonCreature(NPC_WALKING_BOMB, fX, fY, fBombSpawnZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); m_asBombFaces[i].m_uiBombTimer = urand(10000, 25000); // TODO @@ -234,7 +234,7 @@ CreatureAI* GetAI_boss_thermaplugg(Creature* pCreature) return new boss_thermapluggAI(pCreature); } -bool EffectDummyCreature_spell_boss_thermaplugg(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_spell_boss_thermaplugg(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if ((uiSpellId != SPELL_ACTIVATE_BOMB_A && uiSpellId != SPELL_ACTIVATE_BOMB_B) || uiEffIndex != EFFECT_INDEX_0) return false; diff --git a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp index 82e209f04..221c4da32 100644 --- a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp +++ b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,18 +16,20 @@ /* ScriptData SDName: gnomeregan -SD%Complete: 100 -SDComment: Grubbis Encounter +SD%Complete: 90 +SDComment: Grubbis Encounter, quest 2904 (A fine mess) SDCategory: Gnomeregan EndScriptData */ /* ContentData npc_blastmaster_emi_shortfuse +npc_kernobee EndContentData */ #include "precompiled.h" #include "gnomeregan.h" #include "escort_ai.h" +#include "follower_ai.h" /*###### ## npc_blastmaster_emi_shortfuse @@ -126,7 +128,7 @@ static const sSummonInformation asSummonInfo[MAX_SUMMON_POSITIONS] = {7, NPC_CHOMPER, -473.1326f, -103.0901f, -146.1155f, 2.042035f} }; -struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI +struct npc_blastmaster_emi_shortfuseAI : public npc_escortAI { npc_blastmaster_emi_shortfuseAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -143,11 +145,11 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI uint32 m_uiPhaseTimer; ObjectGuid m_playerGuid; bool m_bDidAggroText, m_bSouthernCaveInOpened, m_bNorthernCaveInOpened; - GUIDList m_luiSummonedMobGUIDs; + GuidList m_luiSummonedMobGUIDs; - void Reset() + void Reset() override { - m_bDidAggroText = false; // Used for 'defend' text, is triggered when the npc is attacked + m_bDidAggroText = false; // Used for 'defend' text, is triggered when the npc is attacked if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -170,7 +172,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -180,7 +182,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(m_uiPhase > 20 ? GO_CAVE_IN_NORTH : GO_CAVE_IN_SOUTH)) { float fX, fY, fZ; - pDoor->GetNearPoint(pDoor, fX, fY, fZ, 0.0f, 2.0f, frand(0.0f, 2*M_PI_F)); + pDoor->GetNearPoint(pDoor, fX, fY, fZ, 0.0f, 2.0f, frand(0.0f, 2 * M_PI_F)); pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } break; @@ -193,7 +195,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI m_luiSummonedMobGUIDs.push_back(pSummoned->GetObjectGuid()); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_GRUBBIS) { @@ -209,7 +211,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI return m_uiPhase == 11 || m_uiPhase == 13 || m_uiPhase == 26 || m_uiPhase == 28; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // In case we are preparing the explosive charges, we won't start attacking mobs if (IsPreparingExplosiveCharge()) @@ -218,7 +220,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI npc_escortAI::MoveInLineOfSight(pWho); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { // In case we are preparing the explosive charges, we won't start attacking mobs if (IsPreparingExplosiveCharge()) @@ -227,7 +229,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI npc_escortAI::AttackStart(pWho); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { // Possibility for Aggro-Text only once per combat if (m_bDidAggroText) @@ -239,7 +241,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature, pAttacker); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (!m_pInstance) return; @@ -251,7 +253,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI if (m_bNorthernCaveInOpened) // close northern cave-in door m_pInstance->DoUseDoorOrButton(GO_CAVE_IN_NORTH); - for (GUIDList::const_iterator itr = m_luiSummonedMobGUIDs.begin(); itr != m_luiSummonedMobGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiSummonedMobGUIDs.begin(); itr != m_luiSummonedMobGUIDs.end(); ++itr) { if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) pSummoned->ForcedDespawn(); @@ -270,7 +272,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI m_playerGuid = pPlayer->GetObjectGuid(); } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { switch (uiPointId) { @@ -293,9 +295,9 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 4: m_uiPhaseTimer = 1000; @@ -336,7 +338,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI } } - void UpdateEscortAI(uint32 const uiDiff) + void UpdateEscortAI(uint32 const uiDiff) override { // the phases are handled OOC (keeps them in sync with the waypoints) if (m_uiPhaseTimer && !m_creature->getVictim()) @@ -347,7 +349,7 @@ struct MANGOS_DLL_DECL npc_blastmaster_emi_shortfuseAI : public npc_escortAI { case 1: DoScriptText(SAY_START, m_creature); - m_creature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); m_uiPhaseTimer = 5000; @@ -600,16 +602,16 @@ bool GossipHello_npc_blastmaster_emi_shortfuse(Player* pPlayer, Creature* pCreat { if (pInstance->GetData(TYPE_GRUBBIS) == NOT_STARTED || pInstance->GetData(TYPE_GRUBBIS) == FAIL) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); } } return true; } -bool GossipSelect_npc_blastmaster_emi_shortfuse(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_blastmaster_emi_shortfuse(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { if (instance_gnomeregan* pInstance = (instance_gnomeregan*)pCreature->GetInstanceData()) { @@ -625,6 +627,82 @@ bool GossipSelect_npc_blastmaster_emi_shortfuse(Player* pPlayer, Creature* pCrea return true; } +/*###### +## npc_kernobee +## TODO: It appears there are some things missing, including his? alarm-bot +######*/ + +enum +{ + QUEST_A_FINE_MESS = 2904, + TRIGGER_GNOME_EXIT = 324, // Add scriptlib support for it, atm simply use hardcoded values +}; + +static const float aKernobeePositions[2][3] = +{ + { -330.92f, -3.03f, -152.85f}, // End position + { -297.32f, -7.32f, -152.85f} // Walk out of the door +}; + +struct npc_kernobeeAI : public FollowerAI +{ + npc_kernobeeAI(Creature* pCreature) : FollowerAI(pCreature) + { + m_uiCheckEndposTimer = 10000; + Reset(); + } + + uint32 m_uiCheckEndposTimer; + + void Reset() override {} + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + // No idea why he has UNIT_STAND_STATE_DEAD in UDB .. + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + StartFollow((Player*)pInvoker, 0, GetQuestTemplateStore(uiMiscValue)); + } + } + + void UpdateFollowerAI(const uint32 uiDiff) + { + FollowerAI::UpdateFollowerAI(uiDiff); // Do combat handling + + if (m_creature->isInCombat() || !HasFollowState(STATE_FOLLOW_INPROGRESS) || HasFollowState(STATE_FOLLOW_COMPLETE)) + return; + + if (m_uiCheckEndposTimer < uiDiff) + { + m_uiCheckEndposTimer = 500; + if (m_creature->IsWithinDist3d(aKernobeePositions[0][0], aKernobeePositions[0][1], aKernobeePositions[0][2], 2 * INTERACTION_DISTANCE)) + { + SetFollowComplete(true); + if (Player* pPlayer = GetLeaderForFollower()) + pPlayer->GroupEventHappens(QUEST_A_FINE_MESS, m_creature); + m_creature->GetMotionMaster()->MovePoint(1, aKernobeePositions[1][0], aKernobeePositions[1][1], aKernobeePositions[1][2], false); + m_creature->ForcedDespawn(2000); + } + } + else + m_uiCheckEndposTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_kernobee(Creature* pCreature) +{ + return new npc_kernobeeAI(pCreature); +} + +bool QuestAccept_npc_kernobee(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_A_FINE_MESS) + pCreature->AI()->SendAIEvent(AI_EVENT_START_EVENT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + void AddSC_gnomeregan() { Script* pNewScript; @@ -635,4 +713,10 @@ void AddSC_gnomeregan() pNewScript->pGossipHello = &GossipHello_npc_blastmaster_emi_shortfuse; pNewScript->pGossipSelect = &GossipSelect_npc_blastmaster_emi_shortfuse; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_kernobee"; + pNewScript->GetAI = &GetAI_npc_kernobee; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_kernobee; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h index cb5e5c781..63b2bddd9 100644 --- a/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h +++ b/scripts/eastern_kingdoms/gnomeregan/gnomeregan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -51,26 +51,26 @@ struct sBombFace uint32 m_uiBombTimer; }; -class MANGOS_DLL_DECL instance_gnomeregan : public ScriptedInstance +class instance_gnomeregan : public ScriptedInstance { public: instance_gnomeregan(Map* pMap); ~instance_gnomeregan() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; sBombFace* GetBombFaces(); void DoActivateBombFace(uint8 uiIndex); void DoDeactivateBombFace(uint8 uiIndex); - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; @@ -79,9 +79,9 @@ class MANGOS_DLL_DECL instance_gnomeregan : public ScriptedInstance sBombFace m_asBombFaces[MAX_GNOME_FACES]; ObjectGuid m_aExplosiveSortedGuids[2][MAX_EXPLOSIVES_PER_SIDE]; - GUIDList m_luiExplosiveChargeGUIDs; - GUIDList m_luiSpawnedExplosiveChargeGUIDs; - GUIDList m_lRedRocketGUIDs; + GuidList m_luiExplosiveChargeGUIDs; + GuidList m_luiSpawnedExplosiveChargeGUIDs; + GuidList m_lRedRocketGUIDs; }; #endif diff --git a/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp b/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp index 639eeb37d..d254fde2a 100644 --- a/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp +++ b/scripts/eastern_kingdoms/gnomeregan/instance_gnomeregan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -48,7 +48,7 @@ void instance_gnomeregan::OnCreatureCreate(Creature* pCreature) void instance_gnomeregan::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_CAVE_IN_NORTH: case GO_CAVE_IN_SOUTH: @@ -75,7 +75,7 @@ static bool sortFromEastToWest(GameObject* pFirst, GameObject* pSecond) void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_GRUBBIS: m_auiEncounter[0] = uiData; @@ -85,7 +85,7 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) if (!m_luiExplosiveChargeGUIDs.empty()) { std::list lExplosiveCharges; - for (GUIDList::const_iterator itr = m_luiExplosiveChargeGUIDs.begin(); itr != m_luiExplosiveChargeGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiExplosiveChargeGUIDs.begin(); itr != m_luiExplosiveChargeGUIDs.end(); ++itr) { if (GameObject* pCharge = instance->GetGameObject(*itr)) lExplosiveCharges.push_back(pCharge); @@ -125,7 +125,7 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) } if (uiData == DONE) { - for (GUIDList::const_iterator itr = m_lRedRocketGUIDs.begin(); itr != m_lRedRocketGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lRedRocketGUIDs.begin(); itr != m_lRedRocketGUIDs.end(); ++itr) DoRespawnGameObject(*itr, HOUR); } break; @@ -152,7 +152,7 @@ void instance_gnomeregan::SetData(uint32 uiType, uint32 uiData) Creature* pBlastmaster = GetSingleCreatureFromStorage(NPC_BLASTMASTER_SHORTFUSE); if (!pBlastmaster) break; - for (GUIDList::const_iterator itr = m_luiSpawnedExplosiveChargeGUIDs.begin(); itr != m_luiSpawnedExplosiveChargeGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiSpawnedExplosiveChargeGUIDs.begin(); itr != m_luiSpawnedExplosiveChargeGUIDs.end(); ++itr) { if (GameObject* pExplosive = instance->GetGameObject(*itr)) pExplosive->Use(pBlastmaster); @@ -220,7 +220,7 @@ void instance_gnomeregan::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -229,9 +229,9 @@ void instance_gnomeregan::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_gnomeregan::GetData(uint32 uiType) +uint32 instance_gnomeregan::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_GRUBBIS: return m_auiEncounter[0]; case TYPE_THERMAPLUGG: return m_auiEncounter[1]; diff --git a/scripts/eastern_kingdoms/hinterlands.cpp b/scripts/eastern_kingdoms/hinterlands.cpp index 129b9f75d..ce9560ea5 100644 --- a/scripts/eastern_kingdoms/hinterlands.cpp +++ b/scripts/eastern_kingdoms/hinterlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,7 +29,7 @@ EndContentData */ #include "precompiled.h" #include "escort_ai.h" - /*###### +/*###### ## npc_00x09hl ######*/ @@ -47,15 +47,21 @@ enum NPC_VILE_AMBUSHER = 7809 }; -struct MANGOS_DLL_DECL npc_00x09hlAI : public npc_escortAI +struct npc_00x09hlAI : public npc_escortAI { npc_00x09hlAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + uint8 m_uiSummonCount; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_uiSummonCount = 0; + } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 26: DoScriptText(SAY_OOX_AMBUSH, m_creature); @@ -71,32 +77,43 @@ struct MANGOS_DLL_DECL npc_00x09hlAI : public npc_escortAI } } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 27: - for(uint8 i = 0; i < 3; ++i) + if (m_uiSummonCount >= 3) + break; + + for (uint8 i = 0; i < 3; ++i) { float fX, fY, fZ; m_creature->GetRandomPoint(147.927444f, -3851.513428f, 130.893f, 7.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_MARAUDING_OWL, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000); + ++m_uiSummonCount; } break; case 44: - for(uint8 i = 0; i < 3; ++i) + if (m_uiSummonCount >= 6) + break; + + for (uint8 i = 0; i < 3; ++i) { float fX, fY, fZ; m_creature->GetRandomPoint(-141.151581f, -4291.213867f, 120.130f, 7.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_VILE_AMBUSHER, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000); + ++m_uiSummonCount; } break; } + + // make sure we always have the right stand state + m_creature->SetStandState(UNIT_STAND_STATE_STAND); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->GetEntry() == NPC_MARAUDING_OWL || pWho->GetEntry() == NPC_VILE_AMBUSHER) return; @@ -104,7 +121,7 @@ struct MANGOS_DLL_DECL npc_00x09hlAI : public npc_escortAI DoScriptText(urand(0, 1) ? SAY_OOX_AGGRO1 : SAY_OOX_AGGRO2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); } @@ -115,7 +132,7 @@ bool QuestAccept_npc_00x09hl(Player* pPlayer, Creature* pCreature, const Quest* if (pQuest->GetQuestId() == QUEST_RESQUE_OOX_09) { pCreature->SetStandState(UNIT_STAND_STATE_STAND); - pCreature->setFaction((pPlayer->GetTeam() == ALLIANCE) ? FACTION_ESCORT_A_PASSIVE : FACTION_ESCORT_H_PASSIVE); + pCreature->SetFactionTemporary(pPlayer->GetTeam() == ALLIANCE ? FACTION_ESCORT_A_PASSIVE : FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_OOX_START, pCreature, pPlayer); @@ -167,7 +184,7 @@ Location m_afAmbushMoveTo[] = {70.886589f, -2874.335449f, 116.675f} }; -struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI +struct npc_rinjiAI : public npc_escortAI { npc_rinjiAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -181,13 +198,13 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI uint32 m_uiPostEventTimer; int m_iSpawnId; - void Reset() + void Reset() override { m_uiPostEventCount = 0; m_uiPostEventTimer = 3000; } - void JustRespawned() + void JustRespawned() override { m_bIsByOutrunner = false; m_iSpawnId = 0; @@ -195,7 +212,7 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI npc_escortAI::JustRespawned(); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -208,7 +225,7 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI if (urand(0, 3)) return; - //only if attacked and escorter is not in combat? + // only if attacked and escorter is not in combat? DoScriptText(urand(0, 1) ? SAY_RIN_HELP_1 : SAY_RIN_HELP_2, m_creature); } } @@ -219,31 +236,31 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI m_iSpawnId = 1; m_creature->SummonCreature(NPC_RANGER, - m_afAmbushSpawn[m_iSpawnId].m_fX, m_afAmbushSpawn[m_iSpawnId].m_fY, m_afAmbushSpawn[m_iSpawnId].m_fZ, 0.0f, - TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + m_afAmbushSpawn[m_iSpawnId].m_fX, m_afAmbushSpawn[m_iSpawnId].m_fY, m_afAmbushSpawn[m_iSpawnId].m_fZ, 0.0f, + TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 60000); - for(int i = 0; i < 2; ++i) + for (int i = 0; i < 2; ++i) { m_creature->SummonCreature(NPC_OUTRUNNER, - m_afAmbushSpawn[m_iSpawnId].m_fX, m_afAmbushSpawn[m_iSpawnId].m_fY, m_afAmbushSpawn[m_iSpawnId].m_fZ, 0.0f, - TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); + m_afAmbushSpawn[m_iSpawnId].m_fX, m_afAmbushSpawn[m_iSpawnId].m_fY, m_afAmbushSpawn[m_iSpawnId].m_fZ, 0.0f, + TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 60000); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { m_creature->SetWalk(false); pSummoned->GetMotionMaster()->MovePoint(0, m_afAmbushMoveTo[m_iSpawnId].m_fX, m_afAmbushMoveTo[m_iSpawnId].m_fY, m_afAmbushMoveTo[m_iSpawnId].m_fZ); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(uiPointId) + switch (uiPointId) { case 1: DoScriptText(SAY_RIN_FREE, m_creature, pPlayer); @@ -263,9 +280,9 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { - //Check if we have a current target + // Check if we have a current target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { if (HasEscortState(STATE_ESCORT_ESCORTING) && m_uiPostEventCount) @@ -276,7 +293,7 @@ struct MANGOS_DLL_DECL npc_rinjiAI : public npc_escortAI if (Player* pPlayer = GetPlayerForEscort()) { - switch(m_uiPostEventCount) + switch (m_uiPostEventCount) { case 1: DoScriptText(SAY_RIN_PROGRESS_1, m_creature, pPlayer); diff --git a/scripts/eastern_kingdoms/ironforge.cpp b/scripts/eastern_kingdoms/ironforge.cpp index 1a2e836b3..b0866fa4e 100644 --- a/scripts/eastern_kingdoms/ironforge.cpp +++ b/scripts/eastern_kingdoms/ironforge.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,78 +16,16 @@ /* ScriptData SDName: Ironforge -SD%Complete: 100 -SDComment: Quest support: 3702 +SD%Complete: 0 +SDComment: Placeholder SDCategory: Ironforge EndScriptData */ /* ContentData -npc_royal_historian_archesonus EndContentData */ #include "precompiled.h" -/*###### -## npc_royal_historian_archesonus -######*/ - -#define GOSSIP_ITEM_ROYAL "I am ready to listen" -#define GOSSIP_ITEM_ROYAL_1 "That is tragic. How did this happen?" -#define GOSSIP_ITEM_ROYAL_2 "Interesting, continue please." -#define GOSSIP_ITEM_ROYAL_3 "Unbelievable! How dare they??" -#define GOSSIP_ITEM_ROYAL_4 "Of course I will help!" - -bool GossipHello_npc_royal_historian_archesonus(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(3702) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ROYAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(2235, pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_royal_historian_archesonus(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ROYAL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(2236, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ROYAL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(2237, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ROYAL_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(2238, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ROYAL_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(2239, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(3702); - break; - } - return true; -} - void AddSC_ironforge() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "npc_royal_historian_archesonus"; - pNewScript->pGossipHello = &GossipHello_npc_royal_historian_archesonus; - pNewScript->pGossipSelect = &GossipSelect_npc_royal_historian_archesonus; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/isle_of_queldanas.cpp b/scripts/eastern_kingdoms/isle_of_queldanas.cpp index 805ec970e..abc812dc2 100644 --- a/scripts/eastern_kingdoms/isle_of_queldanas.cpp +++ b/scripts/eastern_kingdoms/isle_of_queldanas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -40,20 +40,20 @@ enum TIME_PET_DURATION = 7500 }; -struct MANGOS_DLL_DECL npc_converted_sentryAI : public ScriptedAI +struct npc_converted_sentryAI : public ScriptedAI { npc_converted_sentryAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiCreditTimer; - void Reset() + void Reset() override { m_uiCreditTimer = 2500; } - void MoveInLineOfSight(Unit* pWho) {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiCreditTimer) { diff --git a/scripts/eastern_kingdoms/karazhan/boss_curator.cpp b/scripts/eastern_kingdoms/karazhan/boss_curator.cpp index 90f39a888..9b7df8776 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_curator.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_curator.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss_Curator -SD%Complete: 80% +SD%Complete: 90% SDComment: SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" enum { @@ -37,81 +38,94 @@ enum // Flare NPC_ASTRAL_FLARE = 17096, SPELL_ASTRAL_FLARE_PASSIVE = 30234, + SPELL_ASTRAL_FLARE_VISUAL = 30237, // The Curator SPELL_HATEFUL_BOLT = 30383, SPELL_EVOCATION = 30254, - SPELL_ENRAGE = 30403, + SPELL_ARCANE_INFUSION = 30403, SPELL_BERSERK = 26662 }; -struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI +struct boss_curatorAI : public ScriptedAI { - boss_curatorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_curatorAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; uint32 m_uiFlareTimer; uint32 m_uiHatefulBoltTimer; uint32 m_uiBerserkTimer; - bool m_bIsBerserk; bool m_bIsEnraged; - void Reset() + void Reset() override { - m_uiFlareTimer = 10000; + m_uiFlareTimer = 10000; m_uiHatefulBoltTimer = 15000; // This time may be wrong - m_uiBerserkTimer = 12*MINUTE*IN_MILLISECONDS; - m_bIsBerserk = false; - m_bIsEnraged = false; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_bIsEnraged = false; m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, true); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_CURATOR, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_CURATOR, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CURATOR, FAIL); + } + + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_ASTRAL_FLARE) { - // Flare start with agro on it's target, should be immune to arcane - pSummoned->CastSpell(pSummoned, SPELL_ASTRAL_FLARE_PASSIVE, false); + // Flare start with aggro on it's target, should be immune to arcane + pSummoned->CastSpell(pSummoned, SPELL_ASTRAL_FLARE_PASSIVE, true); + pSummoned->CastSpell(pSummoned, SPELL_ASTRAL_FLARE_VISUAL, true); pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, true); - if (m_creature->getVictim()) - { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - - pSummoned->AddThreat(pTarget ? pTarget : m_creature->getVictim(), 1000.0f); - } + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // always decrease BerserkTimer - if (!m_bIsBerserk) + if (m_uiBerserkTimer) { - if (m_uiBerserkTimer < uiDiff) + if (m_uiBerserkTimer <= uiDiff) { - // break evocation if we are under it's effect - if (m_creature->HasAura(SPELL_EVOCATION)) - m_creature->RemoveAurasDueToSpell(SPELL_EVOCATION); + // Also interrupt evocation + m_creature->RemoveAurasDueToSpell(SPELL_EVOCATION); if (DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { @@ -119,7 +133,7 @@ struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI DoScriptText(SAY_ENRAGE, m_creature); // don't know if he's supposed to do summon/evocate after hard enrage (probably not) - m_bIsBerserk = true; + m_uiBerserkTimer = 0; } } else @@ -130,37 +144,36 @@ struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI if (m_creature->HasAura(SPELL_EVOCATION)) return; - if (!m_bIsEnraged && !m_bIsBerserk) + if (!m_bIsEnraged) { if (m_uiFlareTimer < uiDiff) { m_uiFlareTimer = 10000; // summon Astral Flare - DoSpawnCreature(NPC_ASTRAL_FLARE, rand()%37, rand()%37, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_ASTRAL_FLARE, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); // reduce mana by 10% of maximum if (int32 iMana = m_creature->GetMaxPower(POWER_MANA)) { - m_creature->ModifyPower(POWER_MANA, -(iMana/10)); + m_creature->ModifyPower(POWER_MANA, -(iMana / 10)); - //if this get's us below 10%, then we evocate (the 10th should be summoned now - if (m_creature->GetPower(POWER_MANA)*10 < m_creature->GetMaxPower(POWER_MANA)) + // if this get's us below 10%, then we evocate (the 10th should be summoned now + if (m_creature->GetPower(POWER_MANA) * 10 < m_creature->GetMaxPower(POWER_MANA)) { - DoScriptText(SAY_EVOCATE, m_creature); - - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - m_creature->CastSpell(m_creature, SPELL_EVOCATION, false); - - //this small delay should make first flare appear fast after evocate, and also prevent possible spawn flood - m_uiFlareTimer = 1000; + if (DoCastSpellIfCan(m_creature, SPELL_EVOCATION, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_EVOCATE, m_creature); + // this small delay should make first flare appear fast after evocate, and also prevent possible spawn flood + m_uiFlareTimer = 1000; + } return; } else { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_SUMMON1, m_creature); break; case 1: DoScriptText(SAY_SUMMON2, m_creature); break; @@ -173,11 +186,13 @@ struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI if (m_creature->GetHealthPercent() < 15.0f) { - if (!m_creature->IsNonMeleeSpellCasted(false)) + // Also stop evocation + m_creature->RemoveAurasDueToSpell(SPELL_EVOCATION); + + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_INFUSION, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - m_bIsEnraged = true; DoScriptText(SAY_ENRAGE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); + m_bIsEnraged = true; } } } @@ -185,9 +200,10 @@ struct MANGOS_DLL_DECL boss_curatorAI : public ScriptedAI if (m_uiHatefulBoltTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1)) - m_creature->CastSpell(pTarget, SPELL_HATEFUL_BOLT, false); - - m_uiHatefulBoltTimer = m_bIsEnraged ? 7000 : 15000; + { + if (DoCastSpellIfCan(pTarget, SPELL_HATEFUL_BOLT) == CAST_OK) + m_uiHatefulBoltTimer = m_bIsEnraged ? 7000 : 15000; + } } else m_uiHatefulBoltTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp b/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp index aaf9e5e33..44ac97350 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_maiden_of_virtue.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,6 +22,7 @@ SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" enum { @@ -39,26 +40,32 @@ enum SPELL_HOLYGROUND = 29512 }; -struct MANGOS_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI +struct boss_maiden_of_virtueAI : public ScriptedAI { - boss_maiden_of_virtueAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_maiden_of_virtueAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } - uint32 m_uiRepentance_Timer; - uint32 m_uiHolyfire_Timer; - uint32 m_uiHolywrath_Timer; - uint32 m_uiHolyground_Timer; + ScriptedInstance* m_pInstance; - void Reset() + uint32 m_uiRepentanceTimer; + uint32 m_uiHolyfireTimer; + uint32 m_uiHolywrathTimer; + uint32 m_uiHolygroundTimer; + + void Reset() override { - m_uiRepentance_Timer = urand(25000, 40000); - m_uiHolyfire_Timer = urand(8000, 25000); - m_uiHolywrath_Timer = urand(15000, 25000); - m_uiHolyground_Timer = 3000; + m_uiRepentanceTimer = urand(25000, 40000); + m_uiHolyfireTimer = urand(8000, 25000); + m_uiHolywrathTimer = urand(15000, 25000); + m_uiHolygroundTimer = 3000; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 5)) // 50% chance to say something out of 3 texts + switch (urand(0, 5)) // 50% chance to say something out of 3 texts { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -66,79 +73,72 @@ struct MANGOS_DLL_DECL boss_maiden_of_virtueAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MAIDEN, DONE); } - void Aggro(Unit *pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MAIDEN, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MAIDEN, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiHolyground_Timer < uiDiff) + if (m_uiHolygroundTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_HOLYGROUND, CAST_TRIGGERED); //Triggered so it doesn't interrupt her at all - m_uiHolyground_Timer = 3000; + if (DoCastSpellIfCan(m_creature, SPELL_HOLYGROUND, CAST_TRIGGERED) == CAST_OK) + m_uiHolygroundTimer = 3000; } else - m_uiHolyground_Timer -= uiDiff; + m_uiHolygroundTimer -= uiDiff; - if (m_uiRepentance_Timer < uiDiff) + if (m_uiRepentanceTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_REPENTANCE) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_REPENTANCE) == CAST_OK) { DoScriptText(urand(0, 1) ? SAY_REPENTANCE1 : SAY_REPENTANCE2, m_creature); - - //A little randomness on that spell - m_uiRepentance_Timer = urand(25000, 35000); + m_uiRepentanceTimer = urand(25000, 35000); } } else - m_uiRepentance_Timer -= uiDiff; + m_uiRepentanceTimer -= uiDiff; - if (m_uiHolyfire_Timer < uiDiff) + if (m_uiHolyfireTimer < uiDiff) { - //Time for an omgwtfpwn code to make maiden cast holy fire only on units outside the holy ground's 18 yard range - Unit* pTarget = NULL; - std::vector target_list; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (pTarget && !pTarget->IsWithinDist(m_creature, 12.0f, false)) - target_list.push_back(pTarget); - - pTarget = NULL; - } - - if (target_list.size()) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_HOLYFIRE, SELECT_FLAG_NOT_IN_MELEE_RANGE)) { - if (pTarget = *(target_list.begin()+rand()%target_list.size())) - DoCastSpellIfCan(pTarget,SPELL_HOLYFIRE); + if (DoCastSpellIfCan(pTarget, SPELL_HOLYFIRE) == CAST_OK) + m_uiHolyfireTimer = urand(8000, 23000); } - - m_uiHolyfire_Timer = urand(8000, 23000); //Anywhere from 8 to 23 seconds, good luck having several of those in a row! } else - m_uiHolyfire_Timer -= uiDiff; + m_uiHolyfireTimer -= uiDiff; - if (m_uiHolywrath_Timer < uiDiff) + if (m_uiHolywrathTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) DoCastSpellIfCan(pTarget, SPELL_HOLYWRATH); - m_uiHolywrath_Timer = urand(20000, 25000); //20-25 secs sounds nice + m_uiHolywrathTimer = urand(20000, 25000); } else - m_uiHolywrath_Timer -= uiDiff; + m_uiHolywrathTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp b/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp index 6cd022c52..98d5e24df 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_midnight.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss_Midnight -SD%Complete: 90 -SDComment: Use SPELL_SUMMON_ATTUMEN and SPELL_SUMMON_ATTUMEN_MOUNTED instead of SummonCreature. +SD%Complete: 100 +SDComment: SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" enum { @@ -37,137 +38,150 @@ enum SAY_RANDOM1 = -1532009, SAY_RANDOM2 = -1532010, - SPELL_SHADOWCLEAVE = 29832, - SPELL_INTANGIBLE_PRESENCE = 29833, - SPELL_BERSERKER_CHARGE = 26561, //Only when mounted + // Midnight + SPELL_MOUNT = 29770, + SPELL_KNOCKDOWN = 29711, SPELL_SUMMON_ATTUMEN = 29714, - SPELL_SUMMON_ATTUMEN_MOUNTED= 29799, + SPELL_SUMMON_ATTUMEN_MOUNTED = 29799, - MOUNTED_DISPLAYID = 16040, // should use creature 16152 instead of changing displayid + // Attumen + SPELL_SHADOWCLEAVE = 29832, + SPELL_INTANGIBLE_PRESENCE = 29833, + SPELL_UPPERCUT = 29850, + SPELL_BERSERKER_CHARGE = 26561, // Only when mounted - //Attumen (TODO: Use the summoning spell instead of creature id. It works , but is not convenient for us) - SUMMON_ATTUMEN = 15550 + NPC_ATTUMEN_MOUNTED = 16152, }; -struct MANGOS_DLL_DECL boss_midnightAI : public ScriptedAI +struct boss_midnightAI : public ScriptedAI { - boss_midnightAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_midnightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + Reset(); + } + + instance_karazhan* m_pInstance; - ObjectGuid m_attumenGuid; - uint8 m_uiPhase; - uint32 m_uiMount_Timer; + uint8 m_uiPhase; + uint32 m_uiKnockDown; - void Reset() + void Reset() override { - m_uiPhase = 1; - m_uiMount_Timer = 0; + m_uiPhase = 0; + m_uiKnockDown = urand(6000, 9000); - m_creature->SetVisibility(VISIBILITY_ON); + SetCombatMovement(true); } - void KilledUnit(Unit* pVictim) + void Aggro(Unit* /*pWho*/) override { - if (m_uiPhase == 2) + if (m_pInstance) + m_pInstance->SetData(TYPE_ATTUMEN, IN_PROGRESS); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + if (m_uiPhase == 1 && m_pInstance) { - if (Creature* pAttumen = m_creature->GetMap()->GetCreature(m_attumenGuid)) + if (Creature* pAttumen = m_pInstance->GetSingleCreatureFromStorage(NPC_ATTUMEN)) DoScriptText(SAY_MIDNIGHT_KILL, pAttumen); } } - void Mount(Creature* pAttumen) + void JustReachedHome() override { - DoScriptText(SAY_MOUNT, pAttumen); - m_uiPhase = 3; + if (m_pInstance) + m_pInstance->SetData(TYPE_ATTUMEN, FAIL); + } - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pAttumen->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + void JustSummoned(Creature* pSummoned) override + { + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); - float fAngle = m_creature->GetAngle(pAttumen); - float fDistance = m_creature->GetDistance2d(pAttumen); + if (pSummoned->GetEntry() == NPC_ATTUMEN) + { + // Attumen yells when spawned + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_APPEAR1, pSummoned); break; + case 1: DoScriptText(SAY_APPEAR2, pSummoned); break; + case 2: DoScriptText(SAY_APPEAR3, pSummoned); break; + } + } + else if (pSummoned->GetEntry() == NPC_ATTUMEN_MOUNTED) + { + DoScriptText(SAY_MOUNT, pSummoned); - float fNewX = m_creature->GetPositionX() + cos(fAngle)*(fDistance/2) ; - float fNewY = m_creature->GetPositionY() + sin(fAngle)*(fDistance/2) ; - float fNewZ = 50.0f; + if (!m_pInstance) + return; - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MovePoint(0, fNewX, fNewY, fNewZ); + // The summoned has the health equal to the one which has the higher HP percentage of both + if (Creature* pAttumen = m_pInstance->GetSingleCreatureFromStorage(NPC_ATTUMEN)) + pSummoned->SetHealth(pAttumen->GetHealth() > m_creature->GetHealth() ? pAttumen->GetHealth() : m_creature->GetHealth()); + } + } - fDistance += 10.0f; - fNewX = m_creature->GetPositionX() + cos(fAngle)*(fDistance/2); - fNewY = m_creature->GetPositionY() + sin(fAngle)*(fDistance/2); + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId || !m_pInstance) + return; - pAttumen->GetMotionMaster()->Clear(); - pAttumen->GetMotionMaster()->MovePoint(0, fNewX, fNewY, fNewZ); + // Spawn the mounted Attumen and despawn + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ATTUMEN_MOUNTED, CAST_TRIGGERED) == CAST_OK) + { + if (Creature* pAttumen = m_pInstance->GetSingleCreatureFromStorage(NPC_ATTUMEN)) + pAttumen->ForcedDespawn(); - m_uiMount_Timer = 1000; + m_creature->ForcedDespawn(); + } } - void SetMidnight(Creature*, ObjectGuid); // Below .. + // Wrapper to prepare phase 3 + void DoPrepareMount(Creature* pTarget) + { + if (pTarget) + { + m_uiPhase = 2; + + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(1, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + } + } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - switch(m_uiPhase) + // Stop attacking during the mount phase + if (m_uiPhase == 2) + return; + + // Spawn Attumen on 95% hp + if (m_uiPhase == 0 && m_creature->GetHealthPercent() < 95.0f) { - case 1: - if (m_creature->GetHealthPercent() < 95.0f) - { - m_uiPhase = 2; - - if (Creature* pAttumen = m_creature->SummonCreature(SUMMON_ATTUMEN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000)) - { - m_attumenGuid = pAttumen->GetObjectGuid(); - pAttumen->AI()->AttackStart(m_creature->getVictim()); - SetMidnight(pAttumen, m_creature->GetObjectGuid()); - - switch(urand(0, 2)) - { - case 0: DoScriptText(SAY_APPEAR1, pAttumen); break; - case 1: DoScriptText(SAY_APPEAR2, pAttumen); break; - case 2: DoScriptText(SAY_APPEAR3, pAttumen); break; - } - } - } - break; - case 2: - if (m_creature->GetHealthPercent() < 25.0f) - { - if (Creature* pAttumen = m_creature->GetMap()->GetCreature(m_attumenGuid)) - Mount(pAttumen); - } - break; - case 3: - if (m_uiMount_Timer) - { - if (m_uiMount_Timer <= uiDiff) - { - m_uiMount_Timer = 0; - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->GetMotionMaster()->MoveIdle(); - - if (Creature *pAttumen = m_creature->GetMap()->GetCreature(m_attumenGuid)) - { - pAttumen->SetDisplayId(MOUNTED_DISPLAYID); - pAttumen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (pAttumen->getVictim()) - { - pAttumen->GetMotionMaster()->MoveChase(pAttumen->getVictim()); - pAttumen->SetTargetGuid(pAttumen->getVictim()->GetObjectGuid()); - } - pAttumen->SetFloatValue(OBJECT_FIELD_SCALE_X,1); - } - } - else - m_uiMount_Timer -= uiDiff; - } - break; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ATTUMEN) == CAST_OK) + m_uiPhase = 1; } - if (m_uiPhase != 3) - DoMeleeAttackIfReady(); + // Spawn Attumen mounted at 25% + if (m_uiPhase == 1 && m_creature->GetHealthPercent() < 25.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_MOUNT, CAST_TRIGGERED) == CAST_OK) + m_uiPhase = 2; + } + + if (m_uiKnockDown < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KNOCKDOWN) == CAST_OK) + m_uiKnockDown = urand(6000, 9000); + } + else + m_uiKnockDown -= uiDiff; + + DoMeleeAttackIfReady(); } }; @@ -176,93 +190,80 @@ CreatureAI* GetAI_boss_midnight(Creature* pCreature) return new boss_midnightAI(pCreature); } -struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI +struct boss_attumenAI : public ScriptedAI { boss_attumenAI(Creature* pCreature) : ScriptedAI(pCreature) { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); Reset(); - m_uiPhase = 1; - - m_uiCleaveTimer = urand(10000, 16000); - m_uiCurseTimer = 30000; - m_uiRandomYellTimer = urand(30000, 60000); //Occasionally yell - m_uiChargeTimer = 20000; - m_uiResetTimer = 0; } - ObjectGuid m_midnightGuid; - uint8 m_uiPhase; + instance_karazhan* m_pInstance; + uint32 m_uiCleaveTimer; uint32 m_uiCurseTimer; uint32 m_uiRandomYellTimer; - uint32 m_uiChargeTimer; //only when mounted - uint32 m_uiResetTimer; + uint32 m_uiKnockDown; + uint32 m_uiChargeTimer; // only when mounted - void Reset() + bool m_bHasSummonRider; + + void Reset() override { - m_uiResetTimer = 2000; + m_uiCleaveTimer = urand(10000, 16000); + m_uiCurseTimer = 30000; + m_uiRandomYellTimer = urand(30000, 60000); // Occasionally yell + m_uiChargeTimer = 20000; + m_uiKnockDown = urand(6000, 9000); + + m_bHasSummonRider = false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void SpellHit(Unit* pSource, const SpellEntry* pSpell) + void SpellHit(Unit* /*pSource*/, const SpellEntry* pSpell) override { if (pSpell->Mechanic == MECHANIC_DISARM) DoScriptText(SAY_DISARMED, m_creature); } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); - if (Creature* pMidnight = m_creature->GetMap()->GetCreature(m_midnightGuid)) - pMidnight->DealDamage(pMidnight, pMidnight->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (m_pInstance) + m_pInstance->SetData(TYPE_ATTUMEN, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override { - if (m_uiResetTimer) - { - if (m_uiResetTimer <= uiDiff) - { - m_uiResetTimer = 0; - - if (Creature *pMidnight = m_creature->GetMap()->GetCreature(m_midnightGuid)) - { - pMidnight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pMidnight->SetVisibility(VISIBILITY_ON); - } - m_midnightGuid.Clear(); + if (m_pInstance) + m_pInstance->SetData(TYPE_ATTUMEN, FAIL); - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else - m_uiResetTimer -= uiDiff; - } + // Despawn Attumen on fail + m_creature->ForcedDespawn(); + } - //Return since we have no target + void UpdateAI(const uint32 uiDiff) override + { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) - return; - if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWCLEAVE); - m_uiCleaveTimer = urand(10000, 16000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWCLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 16000); } else m_uiCleaveTimer -= uiDiff; if (m_uiCurseTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_INTANGIBLE_PRESENCE); - m_uiCurseTimer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_INTANGIBLE_PRESENCE) == CAST_OK) + m_uiCurseTimer = 30000; } else m_uiCurseTimer -= uiDiff; @@ -275,7 +276,17 @@ struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI else m_uiRandomYellTimer -= uiDiff; - if (m_creature->GetDisplayId() == MOUNTED_DISPLAYID) + if (m_uiKnockDown < uiDiff) + { + // Cast knockdown when mounted, otherwise uppercut + if (DoCastSpellIfCan(m_creature->getVictim(), m_creature->GetEntry() == NPC_ATTUMEN_MOUNTED ? SPELL_KNOCKDOWN : SPELL_UPPERCUT) == CAST_OK) + m_uiKnockDown = urand(6000, 9000); + } + else + m_uiKnockDown -= uiDiff; + + // If creature is mounted then cast charge + if (m_creature->GetEntry() == NPC_ATTUMEN_MOUNTED) { if (m_uiChargeTimer < uiDiff) { @@ -290,18 +301,13 @@ struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI else m_uiChargeTimer -= uiDiff; } - else + // Else, mount if below 25% + else if (!m_bHasSummonRider && m_creature->GetHealthPercent() < 25.0f) { - if (m_creature->GetHealthPercent() < 25.0f) + if (Creature* pMidnight = m_pInstance->GetSingleCreatureFromStorage(NPC_MIDNIGHT)) { - if (Creature *pMidnight = m_creature->GetMap()->GetCreature(m_midnightGuid)) - { - if (boss_midnightAI* pMidnightAI = dynamic_cast(pMidnight->AI())) - pMidnightAI->Mount(m_creature); - - m_creature->SetHealth(pMidnight->GetHealth()); - DoResetThreat(); - } + pMidnight->CastSpell(m_creature, SPELL_MOUNT, true); + m_bHasSummonRider = true; } } @@ -309,15 +315,29 @@ struct MANGOS_DLL_DECL boss_attumenAI : public ScriptedAI } }; -void boss_midnightAI::SetMidnight(Creature* pAttumen, ObjectGuid midnightGuid) +CreatureAI* GetAI_boss_attumen(Creature* pCreature) { - if (boss_attumenAI* pAttumenAI = dynamic_cast(pAttumen->AI())) - pAttumenAI->m_midnightGuid = midnightGuid; + return new boss_attumenAI(pCreature); } -CreatureAI* GetAI_boss_attumen(Creature* pCreature) +bool EffectDummyCreature_spell_mount_attumen(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - return new boss_attumenAI(pCreature); + // always check spellid and effectindex + if (uiSpellId == SPELL_MOUNT && uiEffIndex == EFFECT_INDEX_0) + { + // Avoid possible DB errors + if (pCaster->GetEntry() == NPC_MIDNIGHT && pCreatureTarget->GetEntry() == NPC_ATTUMEN) + { + // Prepare for mount + if (boss_midnightAI* pMidnightAI = dynamic_cast(((Creature*)pCaster)->AI())) + pMidnightAI->DoPrepareMount(pCreatureTarget); + } + + // always return true when we are handling this spell and effect + return true; + } + + return false; } void AddSC_boss_attumen() @@ -327,6 +347,7 @@ void AddSC_boss_attumen() pNewScript = new Script; pNewScript->Name = "boss_attumen"; pNewScript->GetAI = &GetAI_boss_attumen; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_mount_attumen; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp b/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp index 8b1de57f8..7a36f6d5e 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_moroes.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Moroes SD%Complete: 95 -SDComment: +SDComment: Timers. SDCategory: Karazhan EndScriptData */ @@ -26,7 +26,8 @@ EndScriptData */ enum { - MAX_GUESTS = 4, + MAX_ACTIVE_GUESTS = 4, + MAX_GUESTS = 6, SAY_AGGRO = -1532011, SAY_SPECIAL_1 = -1532012, @@ -43,85 +44,66 @@ enum SPELL_FRENZY = 37023 }; -static const float afLocations[4][MAX_GUESTS]= +static const float afLocations[MAX_ACTIVE_GUESTS][4] = { - {-10991.0f, -1884.33f, 81.73f, 0.614315f}, - {-10989.4f, -1885.88f, 81.73f, 0.904913f}, - {-10978.1f, -1887.07f, 81.73f, 2.035550f}, - {-10975.9f, -1885.81f, 81.73f, 2.253890f} + { -10991.0f, -1884.33f, 81.73f, 0.614315f}, + { -10989.4f, -1885.88f, 81.73f, 0.904913f}, + { -10978.1f, -1887.07f, 81.73f, 2.035550f}, + { -10975.9f, -1885.81f, 81.73f, 2.253890f} }; -static const uint32 auiAdds[6]= +static const uint32 auiGuests[MAX_GUESTS] = { - 17007, - 19872, - 19873, - 19874, - 19875, - 19876 + NPC_LADY_KEIRA_BERRYBUCK, + NPC_LADY_CATRIONA_VON_INDI, + NPC_LORD_CRISPIN_FERENCE, + NPC_BARON_RAFE_DREUGER, + NPC_BARONESS_DOROTHEA_MILLSTIPE, + NPC_LORD_ROBIN_DARIS }; -struct MANGOS_DLL_DECL boss_moroesAI : public ScriptedAI +struct boss_moroesAI : public ScriptedAI { boss_moroesAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_bFirstTime = true; m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } ScriptedInstance* m_pInstance; - ObjectGuid m_aAddGuid[MAX_GUESTS]; - uint32 m_auiAddId[MAX_GUESTS]; + std::vector m_vGuestsEntryList; - uint32 m_uiVanish_Timer; - uint32 m_uiBlind_Timer; - uint32 m_uiGouge_Timer; - uint32 m_uiWait_Timer; - uint32 m_uiCheckAdds_Timer; + uint32 m_uiVanishTimer; + uint32 m_uiBlindTimer; + uint32 m_uiGougeTimer; + uint32 m_uiWaitTimer; - bool m_bFirstTime; - bool m_bInVanish; bool m_bEnrage; - void Reset() + void Reset() override { - m_uiVanish_Timer = 30000; - m_uiBlind_Timer = 35000; - m_uiGouge_Timer = 23000; - m_uiWait_Timer = 0; - m_uiCheckAdds_Timer = 5000; + m_uiVanishTimer = 30000; + m_uiBlindTimer = 35000; + m_uiGougeTimer = 23000; + m_uiWaitTimer = 0; m_bEnrage = false; - m_bInVanish = false; - SpawnAdds(); - - m_creature->setFaction(16); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (m_pInstance) - m_pInstance->SetData(TYPE_MOROES, NOT_STARTED); + DoSpawnGuests(); } - void StartEvent() + void Aggro(Unit* /*pWho*/) override { + DoScriptText(SAY_AGGRO, m_creature); + if (m_pInstance) m_pInstance->SetData(TYPE_MOROES, IN_PROGRESS); } - void Aggro(Unit* pWho) + void KilledUnit(Unit* /*pVictim*/) override { - StartEvent(); - DoScriptText(SAY_AGGRO, m_creature); - AddsAttack(); - } - - void KilledUnit(Unit* pVictim) - { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -129,660 +111,168 @@ struct MANGOS_DLL_DECL boss_moroesAI : public ScriptedAI } } - void JustDied(Unit* pVictim) + void JustReachedHome() override + { + DoRemoveGarroteAura(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MOROES, FAIL); + } + + void JustDied(Unit* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); + DoRemoveGarroteAura(); if (m_pInstance) m_pInstance->SetData(TYPE_MOROES, DONE); + } - //remove aura from spell Garrote when Moroes dies - Map* pMap = m_creature->GetMap(); - if (pMap->IsDungeon()) - { - Map::PlayerList const &PlayerList = pMap->GetPlayers(); - - if (PlayerList.isEmpty()) - return; + void EnterEvadeMode() override + { + // Don't evade during vanish phase + if (m_uiWaitTimer) + return; - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (i->getSource()->isAlive() && i->getSource()->HasAura(SPELL_GARROTE, EFFECT_INDEX_0)) - i->getSource()->RemoveAurasDueToSpell(SPELL_GARROTE); - } - } + ScriptedAI::EnterEvadeMode(); } - void SpawnAdds() + void DoSpawnGuests() { - if (m_bFirstTime) + // not if m_creature are dead, so avoid + if (!m_creature->isAlive()) + return; + + // it's empty, so first time + if (m_vGuestsEntryList.empty()) { - std::vector vAddList; + // pre-allocate size for speed + m_vGuestsEntryList.resize(MAX_GUESTS); - for (uint8 i = 0; i < 6; ++i) - vAddList.push_back(auiAdds[i]); + // fill vector array with entries from creature array + for (uint8 i = 0; i < MAX_GUESTS; ++i) + m_vGuestsEntryList[i] = auiGuests[i]; - while (vAddList.size() > MAX_GUESTS) - vAddList.erase((vAddList.begin())+(rand()%vAddList.size())); + std::random_shuffle(m_vGuestsEntryList.begin(), m_vGuestsEntryList.end()); - uint8 i = 0; - for (std::vector::iterator itr = vAddList.begin(); itr != vAddList.end(); ++itr, ++i) - { - if (Creature* pCreature = m_creature->SummonCreature(*itr, afLocations[i][0], afLocations[i][1], afLocations[i][2], afLocations[i][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) - { - m_aAddGuid[i] = pCreature->GetObjectGuid(); - m_auiAddId[i] = *itr; - } - } - - m_bFirstTime = false; + // Summon the 4 entries + for (uint8 i = 0; i < MAX_ACTIVE_GUESTS; ++i) + m_creature->SummonCreature(m_vGuestsEntryList[i], afLocations[i][0], afLocations[i][1], afLocations[i][2], afLocations[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); } + // Resummon the killed adds else { - for (uint8 i = 0; i < MAX_GUESTS; ++i) + if (!m_pInstance) + return; + + for (uint8 i = 0; i < MAX_ACTIVE_GUESTS; ++i) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_aAddGuid[i])) - { - if (!pCreature->isAlive()) // Exists but is dead - { - pCreature->Respawn(); - pCreature->AI()->EnterEvadeMode(); - } - else if (!pCreature->IsInEvadeMode()) // Exists and is alive - { - pCreature->AI()->EnterEvadeMode(); - } - } - else - { // Does not exist - if (Creature* pCreature = m_creature->SummonCreature(m_auiAddId[i], afLocations[i][0], afLocations[i][1], afLocations[i][2], afLocations[i][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) - m_aAddGuid[i] = pCreature->GetObjectGuid(); - } + // If we already have the creature on the map, then don't summon it + if (m_pInstance->GetSingleCreatureFromStorage(m_vGuestsEntryList[i], true)) + continue; + + m_creature->SummonCreature(m_vGuestsEntryList[i], afLocations[i][0], afLocations[i][1], afLocations[i][2], afLocations[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); } } } - void AddsAttack() + // Wrapper to remove the Garrote aura on death and on evade - ToDo: maybe find a better way for this! + void DoRemoveGarroteAura() { - for(uint8 i = 0; i < MAX_GUESTS; ++i) + // remove aura from spell Garrote when Moroes dies + Map* pMap = m_creature->GetMap(); + if (pMap->IsDungeon()) { - if (m_aAddGuid[i]) + Map::PlayerList const& PlayerList = pMap->GetPlayers(); + + if (PlayerList.isEmpty()) + return; + + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { - Creature* pTemp = m_creature->GetMap()->GetCreature(m_aAddGuid[i]); - if (pTemp && pTemp->isAlive()) - pTemp->AI()->AttackStart(m_creature->getVictim()); - else - EnterEvadeMode(); + if (i->getSource()->isAlive() && i->getSource()->HasAura(SPELL_GARROTE)) + i->getSource()->RemoveAurasDueToSpell(SPELL_GARROTE); } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_pInstance && !m_pInstance->GetData(TYPE_MOROES)) - EnterEvadeMode(); - - if (!m_bEnrage && m_creature->GetHealthPercent() < 30.0f) + // Note: because the Vanish spell adds invisibility effect on the target, the timers won't be decreased during the vanish phase + if (m_uiWaitTimer) { - DoCastSpellIfCan(m_creature, SPELL_FRENZY); - m_bEnrage = true; - } - - if (m_uiCheckAdds_Timer < uiDiff) - { - for (uint8 i = 0; i < MAX_GUESTS; ++i) + if (m_uiWaitTimer <= uiDiff) { - if (m_aAddGuid[i]) + // It's not very clear how to handle this spell + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - Creature* pTemp = m_creature->GetMap()->GetCreature(m_aAddGuid[i]); - if (pTemp && pTemp->isAlive() && (!pTemp->SelectHostileTarget() || !pTemp->getVictim())) - pTemp->AI()->AttackStart(m_creature->getVictim()); + DoScriptText(urand(0, 1) ? SAY_SPECIAL_1 : SAY_SPECIAL_2, m_creature); + DoResetThreat(); + AttackStart(pTarget); + pTarget->CastSpell(pTarget, SPELL_GARROTE, true); } + m_uiWaitTimer = 0; } - m_uiCheckAdds_Timer = 5000; + else + m_uiWaitTimer -= uiDiff; + + // Don't user other abilities in vanish + return; } - else - m_uiCheckAdds_Timer -= uiDiff; - if (!m_bEnrage) + if (!m_bEnrage && m_creature->GetHealthPercent() < 30.0f) { - // Cast Vanish, then Garrote random victim - if (m_uiVanish_Timer < uiDiff) - { - m_creature->setFaction(35); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCastSpellIfCan(m_creature, SPELL_VANISH); - m_bInVanish = true; - m_uiVanish_Timer = 30000; - m_uiWait_Timer = 5000; - } - else - m_uiVanish_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + m_bEnrage = true; + } - if (m_bInVanish) + // No other spells are cast after enrage + if (!m_bEnrage) + { + if (m_uiVanishTimer < uiDiff) { - if (m_uiWait_Timer < uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_VANISH) == CAST_OK) { - DoScriptText(urand(0, 1) ? SAY_SPECIAL_1 : SAY_SPECIAL_2, m_creature); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pTarget->CastSpell(pTarget, SPELL_GARROTE, true); - - m_creature->setFaction(16); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->AI()->AttackStart(m_creature->getVictim()); - m_bInVanish = false; + m_uiVanishTimer = 30000; + m_uiWaitTimer = 1000; } - else - m_uiWait_Timer -= uiDiff; } + else + m_uiVanishTimer -= uiDiff; - //Gouge highest aggro, and attack second highest - if (m_uiGouge_Timer < uiDiff) + // Gouge highest aggro, and attack second highest + if (m_uiGougeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE); - m_uiGouge_Timer = 40000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE) == CAST_OK) + m_uiGougeTimer = 40000; } else - m_uiGouge_Timer -= uiDiff; + m_uiGougeTimer -= uiDiff; - if (m_uiBlind_Timer < uiDiff) + if (m_uiBlindTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BLIND, SELECT_FLAG_PLAYER)) - DoCastSpellIfCan(pTarget, SPELL_BLIND); - - m_uiBlind_Timer = 40000; + { + if (DoCastSpellIfCan(pTarget, SPELL_BLIND) == CAST_OK) + m_uiBlindTimer = 40000; + } } else - m_uiBlind_Timer -= uiDiff; + m_uiBlindTimer -= uiDiff; } - if (!m_bInVanish) - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL boss_moroes_guestAI : public ScriptedAI -{ - ScriptedInstance* m_pInstance; - - ObjectGuid m_aGuestGuid[MAX_GUESTS]; - - boss_moroes_guestAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - AcquireGUID(); - Reset(); - } - - void Reset() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_MOROES, NOT_STARTED); - } - - void AcquireGUID() - { - if (!m_pInstance) - return; - - if (Creature* pMoroes = m_pInstance->GetSingleCreatureFromStorage(NPC_MOROES)) - { - m_aGuestGuid[0] = pMoroes->GetObjectGuid(); - - for(uint8 i = 0; i < 3; ++i) - { - ObjectGuid addGuid; - - if (boss_moroesAI* pMoroesAI = dynamic_cast(pMoroes->AI())) - addGuid = pMoroesAI->m_aAddGuid[i]; - - if (addGuid && addGuid != m_creature->GetObjectGuid()) - m_aGuestGuid[i+1] = addGuid; - } - } - } - - Unit* SelectTarget() - { - if (ObjectGuid tempGuid = m_aGuestGuid[urand(0, MAX_GUESTS-1)]) - { - Creature* pTemp = m_creature->GetMap()->GetCreature(tempGuid); - if (pTemp && pTemp->isAlive()) - return pTemp; - } - - return m_creature; - } - - // TODO double check this design! - with momentarily system DoMeleeAttackIfReady is called before the spells are handled - void UpdateAI(const uint32 uiDiff) - { - if (m_pInstance && !m_pInstance->GetData(TYPE_MOROES)) - EnterEvadeMode(); - DoMeleeAttackIfReady(); } }; -enum -{ - SPELL_MANABURN = 29405, - SPELL_MINDFLY = 29570, - SPELL_SWPAIN = 34441, - SPELL_SHADOWFORM = 29406 -}; - -struct MANGOS_DLL_DECL boss_baroness_dorothea_millstipeAI : public boss_moroes_guestAI -{ - //Shadow Priest - boss_baroness_dorothea_millstipeAI(Creature* pCreature) : boss_moroes_guestAI(pCreature) { Reset(); } - - uint32 m_uiManaBurn_Timer; - uint32 m_uiMindFlay_Timer; - uint32 m_uiShadowWordPain_Timer; - - void Reset() - { - m_uiManaBurn_Timer = 7000; - m_uiMindFlay_Timer = 1000; - m_uiShadowWordPain_Timer = 6000; - - DoCastSpellIfCan(m_creature, SPELL_SHADOWFORM, CAST_TRIGGERED); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_moroes_guestAI::UpdateAI(uiDiff); - - if (m_uiMindFlay_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MINDFLY); - m_uiMindFlay_Timer = 12000; //3sec channeled - } - else - m_uiMindFlay_Timer -= uiDiff; - - if (m_uiManaBurn_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANABURN, SELECT_FLAG_POWER_MANA)) - DoCastSpellIfCan(pTarget, SPELL_MANABURN); - - m_uiManaBurn_Timer = 5000; //3 sec cast - } - else - m_uiManaBurn_Timer -= uiDiff; - - if (m_uiShadowWordPain_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - DoCastSpellIfCan(pTarget, SPELL_SWPAIN); - m_uiShadowWordPain_Timer = 7000; - } - } - else - m_uiShadowWordPain_Timer -= uiDiff; - } -}; - -enum -{ - SPELL_HAMMEROFJUSTICE = 13005, - SPELL_JUDGEMENTOFCOMMAND = 29386, - SPELL_SEALOFCOMMAND = 29385 -}; - -struct MANGOS_DLL_DECL boss_baron_rafe_dreugerAI : public boss_moroes_guestAI -{ - //Retr Pally - boss_baron_rafe_dreugerAI(Creature* pCreature) : boss_moroes_guestAI(pCreature) { Reset(); } - - uint32 m_uiHammerOfJustice_Timer; - uint32 m_uiSealOfCommand_Timer; - uint32 m_uiJudgementOfCommand_Timer; - - void Reset() - { - m_uiHammerOfJustice_Timer = 1000; - m_uiSealOfCommand_Timer = 7000; - m_uiJudgementOfCommand_Timer = m_uiSealOfCommand_Timer + 29000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_moroes_guestAI::UpdateAI(uiDiff); - - if (m_uiSealOfCommand_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_SEALOFCOMMAND); - m_uiSealOfCommand_Timer = 32000; - m_uiJudgementOfCommand_Timer = 29000; - } - else - m_uiSealOfCommand_Timer -= uiDiff; - - if (m_uiJudgementOfCommand_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_JUDGEMENTOFCOMMAND); - m_uiJudgementOfCommand_Timer = m_uiSealOfCommand_Timer + 29000; - } - else - m_uiJudgementOfCommand_Timer -= uiDiff; - - if (m_uiHammerOfJustice_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMEROFJUSTICE); - m_uiHammerOfJustice_Timer = 12000; - } - else - m_uiHammerOfJustice_Timer -= uiDiff; - } -}; - -enum -{ - SPELL_DISPELMAGIC = 15090, // Self or other guest+Moroes - SPELL_GREATERHEAL = 29564, // Self or other guest+Moroes - SPELL_HOLYFIRE = 29563, - SPELL_PWSHIELD = 29408 -}; - -struct MANGOS_DLL_DECL boss_lady_catriona_von_indiAI : public boss_moroes_guestAI -{ - //Holy Priest - boss_lady_catriona_von_indiAI(Creature* pCreature) : boss_moroes_guestAI(pCreature) { Reset(); } - - uint32 m_uiDispelMagic_Timer; - uint32 m_uiGreaterHeal_Timer; - uint32 m_uiHolyFire_Timer; - uint32 m_uiPowerWordShield_Timer; - - void Reset() - { - m_uiDispelMagic_Timer = 11000; - m_uiGreaterHeal_Timer = 1500; - m_uiHolyFire_Timer = 5000; - m_uiPowerWordShield_Timer = 1000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_moroes_guestAI::UpdateAI(uiDiff); - - if (m_uiPowerWordShield_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_PWSHIELD); - m_uiPowerWordShield_Timer = 15000; - } - else - m_uiPowerWordShield_Timer -= uiDiff; - - if (m_uiGreaterHeal_Timer < uiDiff) - { - DoCastSpellIfCan(SelectTarget(), SPELL_GREATERHEAL); - m_uiGreaterHeal_Timer = 17000; - } - else - m_uiGreaterHeal_Timer -= uiDiff; - - if (m_uiHolyFire_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLYFIRE); - m_uiHolyFire_Timer = 22000; - } - else - m_uiHolyFire_Timer -= uiDiff; - - if (m_uiDispelMagic_Timer < uiDiff) - { - if (Unit* pTarget = urand(0, 1) ? SelectTarget() : m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_DISPELMAGIC); - - m_uiDispelMagic_Timer = 25000; - } - else - m_uiDispelMagic_Timer -= uiDiff; - } -}; - -enum -{ - SPELL_CLEANSE = 29380, //Self or other guest+Moroes - SPELL_GREATERBLESSOFMIGHT = 29381, //Self or other guest+Moroes - SPELL_HOLYLIGHT = 29562, //Self or other guest+Moroes - SPELL_DIVINESHIELD = 41367 -}; - -struct MANGOS_DLL_DECL boss_lady_keira_berrybuckAI : public boss_moroes_guestAI -{ - //Holy Pally - boss_lady_keira_berrybuckAI(Creature* pCreature) : boss_moroes_guestAI(pCreature) { Reset(); } - - uint32 m_uiCleanse_Timer; - uint32 m_uiGreaterBless_Timer; - uint32 m_uiHolyLight_Timer; - uint32 m_uiDivineShield_Timer; - - void Reset() - { - m_uiCleanse_Timer = 13000; - m_uiGreaterBless_Timer = 1000; - m_uiHolyLight_Timer = 7000; - m_uiDivineShield_Timer = 31000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_moroes_guestAI::UpdateAI(uiDiff); - - if (m_uiDivineShield_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_DIVINESHIELD); - m_uiDivineShield_Timer = 31000; - } - else - m_uiDivineShield_Timer -= uiDiff; - - if (m_uiHolyLight_Timer < uiDiff) - { - DoCast(SelectTarget(), SPELL_HOLYLIGHT); - m_uiHolyLight_Timer = 10000; - } - else - m_uiHolyLight_Timer -= uiDiff; - - if (m_uiGreaterBless_Timer < uiDiff) - { - DoCastSpellIfCan(SelectTarget(), SPELL_GREATERBLESSOFMIGHT); - m_uiGreaterBless_Timer = 50000; - } - else - m_uiGreaterBless_Timer -= uiDiff; - - if (m_uiCleanse_Timer < uiDiff) - { - DoCastSpellIfCan(SelectTarget(), SPELL_CLEANSE); - m_uiCleanse_Timer = 10000; - } - else - m_uiCleanse_Timer -= uiDiff; - } -}; - -enum -{ - SPELL_HAMSTRING = 9080, - SPELL_MORTALSTRIKE = 29572, - SPELL_WHIRLWIND = 29573 -}; - -struct MANGOS_DLL_DECL boss_lord_robin_darisAI : public boss_moroes_guestAI -{ - //Arms Warr - boss_lord_robin_darisAI(Creature* pCreature) : boss_moroes_guestAI(pCreature) { Reset(); } - - uint32 m_uiHamstring_Timer; - uint32 m_uiMortalStrike_Timer; - uint32 m_uiWhirlWind_Timer; - - void Reset() - { - m_uiHamstring_Timer = 7000; - m_uiMortalStrike_Timer = 10000; - m_uiWhirlWind_Timer = 21000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_moroes_guestAI::UpdateAI(uiDiff); - - if (m_uiHamstring_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING); - m_uiHamstring_Timer = 12000; - } - else - m_uiHamstring_Timer -= uiDiff; - - if (m_uiMortalStrike_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTALSTRIKE); - m_uiMortalStrike_Timer = 18000; - } - else - m_uiMortalStrike_Timer -= uiDiff; - - if (m_uiWhirlWind_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlWind_Timer = 21000; - } - else - m_uiWhirlWind_Timer -= uiDiff; - } -}; - -enum -{ - SPELL_DISARM = 8379, - SPELL_HEROICSTRIKE = 29567, - SPELL_SHIELDBASH = 11972, - SPELL_SHIELDWALL = 29390 -}; - -struct MANGOS_DLL_DECL boss_lord_crispin_ferenceAI : public boss_moroes_guestAI -{ - //Arms Warr - boss_lord_crispin_ferenceAI(Creature* pCreature) : boss_moroes_guestAI(pCreature) { Reset(); } - - uint32 m_uiDisarm_Timer; - uint32 m_uiHeroicStrike_Timer; - uint32 m_uiShieldBash_Timer; - uint32 m_uiShieldWall_Timer; - - void Reset() - { - m_uiDisarm_Timer = 6000; - m_uiHeroicStrike_Timer = 10000; - m_uiShieldBash_Timer = 8000; - m_uiShieldWall_Timer = 4000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_moroes_guestAI::UpdateAI(uiDiff); - - if (m_uiDisarm_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISARM); - m_uiDisarm_Timer = 12000; - } - else - m_uiDisarm_Timer -= uiDiff; - - if (m_uiHeroicStrike_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEROICSTRIKE); - m_uiHeroicStrike_Timer = 10000; - }else m_uiHeroicStrike_Timer -= uiDiff; - - if (m_uiShieldBash_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHIELDBASH); - m_uiShieldBash_Timer = 13000; - } - else - m_uiShieldBash_Timer -= uiDiff; - - if (m_uiShieldWall_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_SHIELDWALL); - m_uiShieldWall_Timer = 21000; - } - else - m_uiShieldWall_Timer -= uiDiff; - } -}; - CreatureAI* GetAI_boss_moroes(Creature* pCreature) { return new boss_moroesAI(pCreature); } -CreatureAI* GetAI_baroness_dorothea_millstipe(Creature* pCreature) -{ - return new boss_baroness_dorothea_millstipeAI(pCreature); -} - -CreatureAI* GetAI_baron_rafe_dreuger(Creature* pCreature) -{ - return new boss_baron_rafe_dreugerAI(pCreature); -} - -CreatureAI* GetAI_lady_catriona_von_indi(Creature* pCreature) -{ - return new boss_lady_catriona_von_indiAI(pCreature); -} - -CreatureAI* GetAI_lady_keira_berrybuck(Creature* pCreature) -{ - return new boss_lady_keira_berrybuckAI(pCreature); -} - -CreatureAI* GetAI_lord_robin_daris(Creature* pCreature) -{ - return new boss_lord_robin_darisAI(pCreature); -} - -CreatureAI* GetAI_lord_crispin_ference(Creature* pCreature) -{ - return new boss_lord_crispin_ferenceAI(pCreature); -} - void AddSC_boss_moroes() { Script* pNewScript; @@ -791,34 +281,4 @@ void AddSC_boss_moroes() pNewScript->Name = "boss_moroes"; pNewScript->GetAI = &GetAI_boss_moroes; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_baroness_dorothea_millstipe"; - pNewScript->GetAI = &GetAI_baroness_dorothea_millstipe; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_baron_rafe_dreuger"; - pNewScript->GetAI = &GetAI_baron_rafe_dreuger; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_lady_catriona_von_indi"; - pNewScript->GetAI = &GetAI_lady_catriona_von_indi; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_lady_keira_berrybuck"; - pNewScript->GetAI = &GetAI_lady_keira_berrybuck; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_lord_robin_daris"; - pNewScript->GetAI = &GetAI_lord_robin_daris; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_lord_crispin_ference"; - pNewScript->GetAI = &GetAI_lord_crispin_ference; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp b/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp index b0271fe9b..4aa16bb41 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_netherspite.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Netherspite -SD%Complete: 30% -SDComment: find spell ID for tail swipe added in patch 3.0.2 +SD%Complete: 75 +SDComment: Nether portals partially implemented. Find spell ID for tail swipe added in patch 3.0.2 SDCategory: Karazhan EndScriptData */ @@ -26,69 +26,100 @@ EndScriptData */ enum { - //netherspite spells + // netherspite spells SPELL_NETHERBURN = 30522, SPELL_VOID_ZONE = 37063, SPELL_NETHERBREATH = 38523, SPELL_EMPOWERMENT = 38549, - SPELL_NETHER_INFUSION = 38688, - SPELL_NETHERSPITE_ROAR = 38684, - SPELL_BANISH_VISUAL = 39833, - SPELL_ROOT = 42716, + SPELL_NETHER_INFUSION = 38688, // hard enrage spell + SPELL_NETHERSPITE_ROAR = 38684, // on banish phase begin + SPELL_SHADOWFORM = 38542, // banish visual spell + SPELL_FACE_RANDOM_TARGET = 38546, // triggered by spell 38684 - currently not used + SPELL_PORTAL_ATTUNEMENT = 30425, - //void zone spells - SPELL_CONSUMPTION = 30497, + // void zone spells + SPELL_CONSUMPTION = 28865, - //beam buffs - SPELL_PERSEVERENCE_NS = 30466, - SPELL_PERSEVERENCE_PLR = 30421, + // ***** Netherspite portals spells ***** // + // beam buffs SPELL_SERENITY_NS = 30467, SPELL_SERENITY_PLR = 30422, SPELL_DOMINANCE_NS = 30468, SPELL_DOMINANCE_PLR = 30423, + SPELL_PERSEVERENCE_NS = 30466, + SPELL_PERSEVERENCE_PLR = 30421, - //beam debuffs - SPELL_EXHAUSTION_DOM = 38639, + // beam debuffs (player with this aura cannot gain the same color buff) SPELL_EXHAUSTION_SER = 38638, + SPELL_EXHAUSTION_DOM = 38639, SPELL_EXHAUSTION_PER = 38637, - //beam spells - SPELL_BEAM_DOM = 30402, + // spells which hit players (used only for visual - as seen from spell description) SPELL_BEAM_SER = 30401, + SPELL_BEAM_DOM = 30402, SPELL_BEAM_PER = 30400, - SPELL_BLUE_PORTAL = 30491, + + // spells which hit Netherspite + SPELL_BEAM_GREEN = 30464, + SPELL_BEAM_BLUE = 30463, + SPELL_BEAM_RED = 30465, + + // portal visual spells SPELL_GREEN_PORTAL = 30490, + SPELL_BLUE_PORTAL = 30491, SPELL_RED_PORTAL = 30487, - //emotes + // passive auras + SPELL_SERENITY_PASSIVE = 30397, + SPELL_DOMINANCE_PASSIVE = 30398, + // note: for Perseverence, there isn't any passive spell - currently we use script timer + SPELL_NETHER_BEAM = 30469, // spell triggered by the passive auras + // SPELL_CLEAR_NETHER_BEAM = 37072, // not clear how to use this + + // emotes EMOTE_PHASE_BEAM = -1532089, EMOTE_PHASE_BANISH = -1532090, - //npcs - NPC_PORTAL_CREATURE = 17369, - NPC_VOID_ZONE = 16697 + // npcs + NPC_PORTAL_GREEN = 17367, + NPC_PORTAL_BLUE = 17368, + NPC_PORTAL_RED = 17369, + NPC_VOID_ZONE = 16697, + + MAX_PORTALS = 3, }; struct SpawnLocation { - float x, y, z; + float fX, fY, fZ, fO; }; // at first spawn portals got fixed coords, should be shuffled in subsequent beam phases -static SpawnLocation PortalCoordinates[] = +static const SpawnLocation aPortalCoordinates[MAX_PORTALS] = { - {-11105.508789f, -1600.851685f, 279.950256f}, - {-11195.353516f, -1613.237183f, 278.237258f}, - {-11137.846680f, -1685.607422f, 278.239258f} + { -11195.14f, -1616.375f, 278.3217f, 6.230825f}, + { -11108.13f, -1602.839f, 280.0323f, 3.717551f}, + { -11139.78f, -1681.278f, 278.3217f, 1.396263f}, }; -enum Phases +enum NetherspitePhases { BEAM_PHASE = 0, BANISH_PHASE = 1, }; -struct MANGOS_DLL_DECL boss_netherspiteAI : public ScriptedAI +static const uint32 auiPortals[MAX_PORTALS] = +{ + NPC_PORTAL_GREEN, + NPC_PORTAL_BLUE, + NPC_PORTAL_RED, +}; + +/*###### +## boss_netherspite +######*/ + +struct boss_netherspiteAI : public ScriptedAI { boss_netherspiteAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -98,68 +129,122 @@ struct MANGOS_DLL_DECL boss_netherspiteAI : public ScriptedAI ScriptedInstance* m_pInstance; - bool m_bIsEnraged; - uint8 m_uiActivePhase; + NetherspitePhases m_uiActivePhase; uint32 m_uiEnrageTimer; uint32 m_uiVoidZoneTimer; uint32 m_uiPhaseSwitchTimer; uint32 m_uiNetherbreathTimer; + uint32 m_uiEmpowermentTimer; - void Reset() + std::vector m_vPortalEntryList; + + void Reset() override { - m_bIsEnraged = false; - m_uiActivePhase = BEAM_PHASE; + m_uiActivePhase = BEAM_PHASE; - m_uiEnrageTimer = MINUTE*9*IN_MILLISECONDS; + m_uiEmpowermentTimer = 10000; + m_uiEnrageTimer = 9 * MINUTE * IN_MILLISECONDS; m_uiVoidZoneTimer = 15000; - m_uiPhaseSwitchTimer = MINUTE*IN_MILLISECONDS; + m_uiPhaseSwitchTimer = MINUTE * IN_MILLISECONDS; + + SetCombatMovement(true); + + // initialize the portal list + m_vPortalEntryList.clear(); + m_vPortalEntryList.resize(MAX_PORTALS); + + for (uint8 i = 0; i < MAX_PORTALS; ++i) + m_vPortalEntryList[i] = auiPortals[i]; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NETHERSPITE, IN_PROGRESS); + DoSummonPortals(); DoCastSpellIfCan(m_creature, SPELL_NETHERBURN); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NETHERSPITE, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_NETHERSPITE, NOT_STARTED); + m_pInstance->SetData(TYPE_NETHERSPITE, FAIL); } void SwitchPhases() { if (m_uiActivePhase == BEAM_PHASE) { - m_uiActivePhase = BANISH_PHASE; - DoScriptText(EMOTE_PHASE_BANISH, m_creature); + if (DoCastSpellIfCan(m_creature, SPELL_NETHERSPITE_ROAR) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_SHADOWFORM, CAST_TRIGGERED); + m_creature->RemoveAurasDueToSpell(SPELL_EMPOWERMENT); + + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); - m_uiNetherbreathTimer = 500; - m_uiPhaseSwitchTimer = (MINUTE/2)*IN_MILLISECONDS; + m_uiActivePhase = BANISH_PHASE; + DoScriptText(EMOTE_PHASE_BANISH, m_creature); + + m_uiNetherbreathTimer = 2000; + m_uiPhaseSwitchTimer = 30000; + } } else { + m_creature->RemoveAurasDueToSpell(SPELL_SHADOWFORM); + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_uiActivePhase = BEAM_PHASE; DoScriptText(EMOTE_PHASE_BEAM, m_creature); - DoCastSpellIfCan(m_creature, SPELL_NETHERSPITE_ROAR); - m_uiPhaseSwitchTimer = MINUTE*IN_MILLISECONDS; + DoSummonPortals(); + m_uiEmpowermentTimer = 10000; + m_uiPhaseSwitchTimer = MINUTE * IN_MILLISECONDS; } - //reset threat every phase switch + // reset threat every phase switch DoResetThreat(); } - void UpdateAI(const uint32 uiDiff) + void DoSummonPortals() + { + for (uint8 i = 0; i < MAX_PORTALS; ++i) + m_creature->SummonCreature(m_vPortalEntryList[i], aPortalCoordinates[i].fX, aPortalCoordinates[i].fY, aPortalCoordinates[i].fZ, aPortalCoordinates[i].fO, TEMPSUMMON_TIMED_DESPAWN, 60000); + + // randomize the portals after the first summon + std::random_shuffle(m_vPortalEntryList.begin(), m_vPortalEntryList.end()); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_VOID_ZONE: + pSummoned->CastSpell(pSummoned, SPELL_CONSUMPTION, false); + break; + case NPC_PORTAL_RED: + pSummoned->CastSpell(pSummoned, SPELL_RED_PORTAL, false); + break; + case NPC_PORTAL_GREEN: + pSummoned->CastSpell(pSummoned, SPELL_GREEN_PORTAL, false); + break; + case NPC_PORTAL_BLUE: + pSummoned->CastSpell(pSummoned, SPELL_BLUE_PORTAL, false); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -169,12 +254,12 @@ struct MANGOS_DLL_DECL boss_netherspiteAI : public ScriptedAI else m_uiPhaseSwitchTimer -= uiDiff; - if (!m_bIsEnraged) + if (m_uiEnrageTimer) { - if (m_uiEnrageTimer < uiDiff) + if (m_uiEnrageTimer <= uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_NETHER_INFUSION, CAST_FORCE_CAST); - m_bIsEnraged = true; + if (DoCastSpellIfCan(m_creature, SPELL_NETHER_INFUSION) == CAST_OK) + m_uiEnrageTimer = 0; } else m_uiEnrageTimer -= uiDiff; @@ -185,28 +270,40 @@ struct MANGOS_DLL_DECL boss_netherspiteAI : public ScriptedAI if (m_uiVoidZoneTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_VOID_ZONE, true); - - m_uiVoidZoneTimer = 15000; + { + if (DoCastSpellIfCan(pTarget, SPELL_VOID_ZONE) == CAST_OK) + m_uiVoidZoneTimer = 15000; + } } else m_uiVoidZoneTimer -= uiDiff; + if (m_uiEmpowermentTimer) + { + if (m_uiEmpowermentTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EMPOWERMENT) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_PORTAL_ATTUNEMENT, CAST_TRIGGERED); + m_uiEmpowermentTimer = 0; + } + } + else + m_uiEmpowermentTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); } else { if (m_uiNetherbreathTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_NETHERBREATH); - - m_uiNetherbreathTimer = urand(4000, 5000); + if (DoCastSpellIfCan(m_creature, SPELL_NETHERBREATH) == CAST_OK) + m_uiNetherbreathTimer = urand(4000, 5000); } else m_uiNetherbreathTimer -= uiDiff; } - - DoMeleeAttackIfReady(); } }; @@ -215,6 +312,110 @@ CreatureAI* GetAI_boss_netherspite(Creature* pCreature) return new boss_netherspiteAI(pCreature); } +/*###### +## npc_netherspite_portal +######*/ + +struct npc_netherspite_portalAI : public Scripted_NoMovementAI +{ + npc_netherspite_portalAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiPassiveSpellTimer; + uint32 m_uiOrientationTimer; + + void Reset() + { + m_uiPassiveSpellTimer = 0; + m_uiOrientationTimer = 0; + } + + void MoveInLineOfSight(Unit* pWho) { } + void AttackStart(Unit* pWho) { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A) + { + if (pInvoker->GetEntry() != NPC_NETHERSPITE) + return; + + // update orientation every second to focus on Netherspite + m_uiOrientationTimer = 1000; + m_creature->SetFacingToObject(pInvoker); + + switch (m_creature->GetEntry()) + { + case NPC_PORTAL_GREEN: + if (!m_creature->HasAura(SPELL_SERENITY_PASSIVE)) + DoCastSpellIfCan(m_creature, SPELL_SERENITY_PASSIVE, CAST_TRIGGERED); + break; + case NPC_PORTAL_BLUE: + if (!m_creature->HasAura(SPELL_DOMINANCE_PASSIVE)) + DoCastSpellIfCan(m_creature, SPELL_DOMINANCE_PASSIVE, CAST_TRIGGERED); + break; + case NPC_PORTAL_RED: + // Red portal spell is missing - handled in script + if (!m_uiPassiveSpellTimer) + m_uiPassiveSpellTimer = 1000; + break; + } + } + } + + void UpdateAI(const uint32 uiDiff) + { + if (m_uiPassiveSpellTimer) + { + if (m_uiPassiveSpellTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NETHER_BEAM, CAST_TRIGGERED) == CAST_OK) + m_uiPassiveSpellTimer = 1000; + } + else + m_uiPassiveSpellTimer -= uiDiff; + } + + if (m_uiOrientationTimer) + { + if (m_uiOrientationTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pNetherspite = m_pInstance->GetSingleCreatureFromStorage(NPC_NETHERSPITE)) + m_creature->SetFacingToObject(pNetherspite); + } + m_uiOrientationTimer = 1000; + } + else + m_uiOrientationTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_netherspite_portal(Creature* pCreature) +{ + return new npc_netherspite_portalAI(pCreature); +} + +bool EffectScriptEffectCreature_spell_portal_attunement(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_PORTAL_ATTUNEMENT && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_PORTAL_RED || pCreatureTarget->GetEntry() == NPC_PORTAL_GREEN || pCreatureTarget->GetEntry() == NPC_PORTAL_BLUE) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + + return true; + } + + return false; +} + void AddSC_boss_netherspite() { Script* pNewScript; @@ -223,4 +424,10 @@ void AddSC_boss_netherspite() pNewScript->Name = "boss_netherspite"; pNewScript->GetAI = &GetAI_boss_netherspite; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_netherspite_portal"; + pNewScript->GetAI = &GetAI_npc_netherspite_portal; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_spell_portal_attunement; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp b/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp index bd9117ee1..f425b59e4 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_nightbane.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,25 +16,384 @@ /* ScriptData SDName: Boss_Nightbane -SD%Complete: 0 -SDComment: Place holder +SD%Complete: 80 +SDComment: Intro movement is a little choppy because of the lack of waypoint movement support. Air phase movement requires improvement. Timers need adjustment. SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" +#include "escort_ai.h" enum { + EMOTE_AWAKEN = -1532125, + SAY_AGGRO = -1532126, + SAY_AIR_PHASE = -1532127, + SAY_LAND_PHASE_1 = -1532128, + SAY_LAND_PHASE_2 = -1532129, + EMOTE_DEEP_BREATH = -1532130, + + // ground phase spells SPELL_BELLOWING_ROAR = 39427, - SPELL_CHARRED_EARTH = 30129, //Also 30209 (Target Charred Earth) triggers this - SPELL_DISTRACTING_ASH = 30130, + SPELL_CHARRED_EARTH = 30129, // Also 30209 (Target Charred Earth) triggers this SPELL_SMOLDERING_BREATH = 30210, SPELL_TAIL_SWEEP = 25653, - SPELL_RAIN_OF_BONES = 37098, + SPELL_CLEAVE = 30131, + + // air phase spells + SPELL_DISTRACTING_ASH = 30130, + SPELL_RAIN_OF_BONES = 37098, // should trigger 30170 SPELL_SMOKING_BLAST = 37057, - SPELL_FIREBALL_BARRAGE = 30282 + SPELL_FIREBALL_BARRAGE = 30282, + + PHASE_GROUND = 1, + PHASE_AIR = 2, + PHASE_TRANSITION = 3, + + // These points are a placeholder for the air phase movement. The dragon should do some circles around the area before landing again + POINT_ID_AIR = 1, + POINT_ID_GROUND = 2, }; +struct boss_nightbaneAI : public npc_escortAI +{ + boss_nightbaneAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + Reset(); + } + + instance_karazhan* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiFlightPhase; + uint32 m_uiPhaseResetTimer; + + uint32 m_uiBellowingRoarTimer; + uint32 m_uiCharredEarthTimer; + uint32 m_uiSmolderingBreathTimer; + uint32 m_uiTailSweepTimer; + uint32 m_uiCleavetimer; + + uint32 m_uiDistractingAshTimer; + uint32 m_uiRainBonesTimer; + uint32 m_uiSmokingBlastTimer; + uint32 m_uiFireballBarrageTimer; + + bool m_bCombatStarted; + + void Reset() override + { + m_uiPhase = PHASE_GROUND; + m_uiFlightPhase = 1; + m_bCombatStarted = false; + + m_uiBellowingRoarTimer = urand(20000, 30000); + m_uiCharredEarthTimer = urand(10000, 15000); + m_uiSmolderingBreathTimer = urand(9000, 13000); + m_uiTailSweepTimer = urand(12000, 15000); + m_uiCleavetimer = urand(4000, 8000); + + SetCombatMovement(true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void DoResetAirTimers() + { + m_uiPhaseResetTimer = urand(20000, 40000); + m_uiRainBonesTimer = 3000; + m_uiDistractingAshTimer = urand(10000, 12000); + m_uiSmokingBlastTimer = urand(10000, 12000); + m_uiFireballBarrageTimer = 10000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NIGHTBANE, DONE); + } + + void EnterEvadeMode() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_NIGHTBANE, FAIL); + + // reset boss on evade + m_creature->ForcedDespawn(); + } + + void WaypointReached(uint32 uiPointId) override + { + // Set in combat after the intro is done + if (uiPointId == 31) + { + SetEscortPaused(true); + m_creature->SetLevitate(false); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_bCombatStarted = true; + m_creature->SetInCombatWithZone(); + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + // avoid overlapping of escort and combat movement + if (!m_bCombatStarted) + npc_escortAI::MovementInform(uiMotionType, uiPointId); + else + { + if (uiMotionType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case POINT_ID_AIR: + m_uiPhase = PHASE_AIR; + break; + case POINT_ID_GROUND: + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_uiPhase = PHASE_GROUND; + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + break; + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + + // Wrapper to handle movement to the closest trigger + void DoMoveToClosestTrigger(bool bGround) + { + if (!m_pInstance) + return; + + Unit* pChosenTrigger = NULL; + GuidList lTriggersList; + float fX, fY, fZ; + + // get the list of wanted triggers + m_pInstance->GetNightbaneTriggers(lTriggersList, bGround); + + // calculate the closest trigger from the list + for (GuidList::const_iterator itr = lTriggersList.begin(); itr != lTriggersList.end(); ++itr) + { + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(*itr)) + { + if (!pChosenTrigger || m_creature->GetDistanceOrder(pTrigger, pChosenTrigger, false)) + pChosenTrigger = pTrigger; + } + } + + // Move to trigger position + if (pChosenTrigger) + { + pChosenTrigger->GetPosition(fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(bGround ? POINT_ID_GROUND : POINT_ID_AIR, fX, fY, fZ); + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_GROUND: + + if (m_uiBellowingRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BELLOWING_ROAR) == CAST_OK) + m_uiBellowingRoarTimer = urand(20000, 30000); + } + else + m_uiBellowingRoarTimer -= uiDiff; + + if (m_uiSmolderingBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SMOLDERING_BREATH) == CAST_OK) + m_uiSmolderingBreathTimer = urand(14000, 20000); + } + else + m_uiSmolderingBreathTimer -= uiDiff; + + if (m_uiCharredEarthTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARRED_EARTH) == CAST_OK) + m_uiCharredEarthTimer = urand(25000, 35000); + } + } + else + m_uiCharredEarthTimer -= uiDiff; + + if (m_uiTailSweepTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_SWEEP) == CAST_OK) + m_uiTailSweepTimer = urand(14000, 20000); + } + else + m_uiTailSweepTimer -= uiDiff; + + if (m_uiCleavetimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleavetimer = urand(6000, 12000); + } + else + m_uiCleavetimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 100 - 25 * m_uiFlightPhase) + { + // Start air phase movement (handled by creature_movement_template) + SetCombatMovement(false); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + m_creature->SetLevitate(true); + DoMoveToClosestTrigger(false); + + DoScriptText(SAY_AIR_PHASE, m_creature); + m_uiPhase = PHASE_TRANSITION; + DoResetAirTimers(); + ++m_uiFlightPhase; + } + + DoMeleeAttackIfReady(); + + break; + case PHASE_AIR: + + if (m_uiRainBonesTimer) + { + if (m_uiRainBonesTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_RAIN_OF_BONES) == CAST_OK) + { + DoScriptText(EMOTE_DEEP_BREATH, m_creature); + m_uiRainBonesTimer = 0; + } + } + } + else + m_uiRainBonesTimer -= uiDiff; + } + + if (m_uiDistractingAshTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DISTRACTING_ASH) == CAST_OK) + m_uiDistractingAshTimer = urand(7000, 13000); + } + } + else + m_uiDistractingAshTimer -= uiDiff; + + if (m_uiSmokingBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SMOKING_BLAST) == CAST_OK) + m_uiSmokingBlastTimer = urand(1000, 3000); + } + } + else + m_uiSmokingBlastTimer -= uiDiff; + + if (m_uiFireballBarrageTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_FIREBALL_BARRAGE, SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIREBALL_BARRAGE) == CAST_OK) + m_uiFireballBarrageTimer = urand(3000, 6000); + } + } + else + m_uiFireballBarrageTimer -= uiDiff; + + if (m_uiPhaseResetTimer < uiDiff) + { + // ToDo: more circle movement should be done here! + DoScriptText(urand(0, 1) ? SAY_LAND_PHASE_1 : SAY_LAND_PHASE_2, m_creature); + DoMoveToClosestTrigger(true); + + m_uiPhase = PHASE_TRANSITION; + m_uiPhaseResetTimer = 20000; + } + else + m_uiPhaseResetTimer -= uiDiff; + + break; + case PHASE_TRANSITION: + // nothing here + break; + } + } +}; + +CreatureAI* GetAI_boss_nightbane(Creature* pCreature) +{ + return new boss_nightbaneAI(pCreature); +} + +bool ProcessEventId_event_spell_summon_nightbane(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + { + ScriptedInstance* pInstance = (ScriptedInstance*)((Player*)pSource)->GetInstanceData(); + if (!pInstance) + return false; + + if (pInstance->GetData(TYPE_NIGHTBANE) == NOT_STARTED || pInstance->GetData(TYPE_NIGHTBANE) == FAIL) + { + if (Creature* pNightbane = pInstance->GetSingleCreatureFromStorage(NPC_NIGHTBANE)) + { + DoScriptText(EMOTE_AWAKEN, ((Player*)pSource)); + pInstance->SetData(TYPE_NIGHTBANE, IN_PROGRESS); + + // Sort of a hack, it is unclear how this really work but the values appear to be valid (see Onyxia, too) + pNightbane->SetStandState(UNIT_STAND_STATE_STAND); + pNightbane->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + pNightbane->SetLevitate(true); + + // Switch to waypoint movement + if (boss_nightbaneAI* pNightbaneAI = dynamic_cast(pNightbane->AI())) + pNightbaneAI->Start(true); + } + } + } + + return true; +} + void AddSC_boss_nightbane() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_nightbane"; + pNewScript->GetAI = &GetAI_boss_nightbane; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_summon_nightbane"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_summon_nightbane; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp b/scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp index 89fb1e1c3..bc06a0898 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_prince_malchezaar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,211 +22,102 @@ SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" enum { - SAY_AGGRO = -1532091, - SAY_AXE_TOSS1 = -1532092, - SAY_AXE_TOSS2 = -1532093, - SAY_SPECIAL1 = -1532094, - SAY_SPECIAL2 = -1532095, - SAY_SPECIAL3 = -1532096, - SAY_SLAY1 = -1532097, - SAY_SLAY2 = -1532098, - SAY_SLAY3 = -1532099, - SAY_SUMMON1 = -1532100, - SAY_SUMMON2 = -1532101, - SAY_DEATH = -1532102, -}; - -// 18 Coordinates for Infernal spawns -struct InfernalPoint -{ - float x,y; -}; - -#define INFERNAL_Z 275.5 - -static InfernalPoint InfernalPoints[] = -{ - {-10922.8f, -1985.2f}, - {-10916.2f, -1996.2f}, - {-10932.2f, -2008.1f}, - {-10948.8f, -2022.1f}, - {-10958.7f, -1997.7f}, - {-10971.5f, -1997.5f}, - {-10990.8f, -1995.1f}, - {-10989.8f, -1976.5f}, - {-10971.6f, -1973.0f}, - {-10955.5f, -1974.0f}, - {-10939.6f, -1969.8f}, - {-10958.0f, -1952.2f}, - {-10941.7f, -1954.8f}, - {-10943.1f, -1988.5f}, - {-10948.8f, -2005.1f}, - {-10984.0f, -2019.3f}, - {-10932.8f, -1979.6f}, - {-10935.7f, -1996.0f} -}; - -enum -{ - TOTAL_INFERNAL_POINTS = 18, - -//Enfeeble is supposed to reduce hp to 1 and then heal player back to full when it ends -//Along with reducing healing and regen while enfeebled to 0% -//This spell effect will only reduce healing - - SPELL_ENFEEBLE = 30843, // Enfeeble during m_uiPhase 1 and 2 - SPELL_ENFEEBLE_EFFECT = 41624, - - SPELL_SHADOWNOVA = 30852, // Shadownova used during all phases - SPELL_SW_PAIN = 30854, // Shadow word pain during m_uiPhase 1 and 3 (different targeting rules though) - SPELL_THRASH_PASSIVE = 12787, // Extra attack chance during m_uiPhase 2 - SPELL_SUNDER_ARMOR = 30901, // Sunder armor during m_uiPhase 2 + SAY_AGGRO = -1532091, + SAY_AXE_TOSS1 = -1532092, + SAY_AXE_TOSS2 = -1532093, + SAY_SPECIAL1 = -1532094, + SAY_SPECIAL2 = -1532095, + SAY_SPECIAL3 = -1532096, + SAY_SLAY1 = -1532097, + SAY_SLAY2 = -1532098, + SAY_SLAY3 = -1532099, + SAY_SUMMON1 = -1532100, + SAY_SUMMON2 = -1532101, + SAY_DEATH = -1532102, + + // Enfeeble is supposed to reduce hp to 1 and then heal player back to full when it ends + SPELL_ENFEEBLE = 30843, // Enfeeble during phases 1 and 2 + SPELL_ENFEEBLE_EFFECT = 41624, // purpose unk - cast during the transition from phase 2 to 3 + SPELL_SHADOW_NOVA = 30852, // Shadownova used during all phases + SPELL_SW_PAIN_PHASE1 = 30854, // Shadow word pain during phase 1 + SPELL_SW_PAIN_PHASE3 = 30898, // Shadow word pain during phase 3 + SPELL_SUNDER_ARMOR = 30901, // Sunder armor during phase 2 SPELL_THRASH_AURA = 12787, // Passive proc chance for thrash - SPELL_EQUIP_AXES = 30857, // Visual for axe equiping - SPELL_AMPLIFY_DAMAGE = 39095, // Amplifiy during m_uiPhase 3 - SPELL_CLEAVE = 30131, // Same as Nightbane. - SPELL_HELLFIRE = 30859, // Infenals' hellfire aura - NETHERSPITE_INFERNAL = 17646, // The netherspite infernal creature - MALCHEZARS_AXE = 17650, // Malchezar's m_aAxeGuid (creatures), summoned during m_uiPhase 3 - - INFERNAL_MODEL_INVISIBLE = 11686, // Infernal Effects - SPELL_INFERNAL_RELAY = 30834, - - EQUIP_ID_AXE = 33542, // Axes info -}; - -//---------Infernal code first -struct MANGOS_DLL_DECL netherspite_infernalAI : public ScriptedAI -{ - netherspite_infernalAI(Creature* pCreature) : ScriptedAI(pCreature), - m_uiHellfireTimer(0), - m_uiCleanupTimer(0), - pPoint(NULL) - { - Reset(); - } + SPELL_SUMMON_AXES = 30891, // Summon 17650 + SPELL_EQUIP_AXES = 30857, // Visual for axe equiping - transition to phase 2 + SPELL_AMPLIFY_DAMAGE = 39095, // Amplifiy during phase 3 3 + // SPELL_CLEAVE = 30131, // spell not confirmed + // SPELL_INFERNAL_RELAY = 30834, // purpose unk + SPELL_INFERNAL_RELAY_SUMMON = 30835, // triggers 30836, which summons an infernal - uint32 m_uiHellfireTimer; - uint32 m_uiCleanupTimer; - ObjectGuid m_malchezaarGuid; - InfernalPoint* pPoint; + SPELL_HELLFIRE = 30859, // Infernal damage aura - void Reset() {} - void MoveInLineOfSight(Unit* pWho) {} + NPC_NETHERSPITE_INFERNAL = 17646, // The netherspite infernal creature + NPC_MALCHEZARS_AXE = 17650, // Malchezar's axes summoned during phase 3 - void UpdateAI(const uint32 uiDiff) - { - if (m_uiHellfireTimer) - { - if (m_uiHellfireTimer <= uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_HELLFIRE) == CAST_OK) - m_uiHellfireTimer = 0; - } - else - m_uiHellfireTimer -= uiDiff; - } - - if (m_uiCleanupTimer) - { - if (m_uiCleanupTimer <= uiDiff) - { - Cleanup(); - m_uiCleanupTimer = 0; - } - else - m_uiCleanupTimer -= uiDiff; - } - } - - void KilledUnit(Unit *who) - { - if (Creature* pMalchezaar = m_creature->GetMap()->GetCreature(m_malchezaarGuid)) - pMalchezaar->AI()->KilledUnit(who); - } - - void SpellHit(Unit* pWho, const SpellEntry* pSpell) - { - if (pSpell->Id == SPELL_INFERNAL_RELAY) - { - m_creature->SetDisplayId(m_creature->GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID)); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_uiHellfireTimer = 4000; - m_uiCleanupTimer = 170000; - } - } + EQUIP_ID_AXE = 23996, // Axes info - void DamageTaken(Unit* pDealer, uint32& uiDamage) - { - if (pDealer->GetObjectGuid() != m_malchezaarGuid) - uiDamage = 0; - } + ATTACK_TIMER_DEFAULT = 2000, // note: for TBC it was 2400 + ATTACK_TIMER_AXES = 1333, // note: for TBC it was 1600 - void Cleanup(); // below ... + MAX_ENFEEBLE_TARGETS = 5, }; -struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI +struct boss_malchezaarAI : public ScriptedAI { boss_malchezaarAI(Creature* pCreature) : ScriptedAI(pCreature) { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } + ScriptedInstance* m_pInstance; + + uint8 m_uiEnfeebleIndex; uint32 m_uiEnfeebleTimer; uint32 m_uiEnfeebleResetTimer; uint32 m_uiShadowNovaTimer; uint32 m_uiSWPainTimer; - uint32 SunderArmorTimer; + uint32 m_uiSunderArmorTimer; uint32 m_uiAmplifyDamageTimer; - uint32 m_uiCleave_Timer; - uint32 InfernalTimer; - uint32 m_uiAxesTargetSwitchTimer; - uint32 m_uiInfernalCleanupTimer; + uint32 m_uiInfernalTimer; - GUIDVector m_vInfernalGuids; - std::vector m_positions; + ObjectGuid m_aEnfeebleTargetGuid[MAX_ENFEEBLE_TARGETS]; + uint32 m_auiEnfeebleHealth[MAX_ENFEEBLE_TARGETS]; - ObjectGuid m_aAxeGuid[2]; - ObjectGuid m_aEnfeebleTargetGuid[5]; - uint32 m_auiEnfeebleHealth[5]; + uint8 m_uiPhase; - uint32 m_uiPhase; - - void Reset() + void Reset() override { - AxesCleanup(); - ClearWeapons(); - InfernalCleanup(); - m_positions.clear(); - - for (uint8 i = 0; i < 5; ++i) + for (uint8 i = 0; i < MAX_ENFEEBLE_TARGETS; ++i) { m_aEnfeebleTargetGuid[i].Clear(); m_auiEnfeebleHealth[i] = 0; } - for(int i = 0; i < TOTAL_INFERNAL_POINTS; ++i) - m_positions.push_back(&InfernalPoints[i]); - - m_uiEnfeebleTimer = 30000; - m_uiEnfeebleResetTimer = 38000; - m_uiShadowNovaTimer = 35500; - m_uiSWPainTimer = 20000; - m_uiAmplifyDamageTimer = 5000; - m_uiCleave_Timer = 8000; - InfernalTimer = 45000; - m_uiInfernalCleanupTimer = 47000; - m_uiAxesTargetSwitchTimer = urand(7500, 20000); - SunderArmorTimer = urand(5000, 10000); - m_uiPhase = 1; + m_uiEnfeebleIndex = 0; + m_uiEnfeebleTimer = 30000; + m_uiEnfeebleResetTimer = 0; + m_uiShadowNovaTimer = 35500; + m_uiSWPainTimer = 20000; + m_uiAmplifyDamageTimer = 5000; + m_uiInfernalTimer = 40000; + m_uiSunderArmorTimer = urand(5000, 10000); + + m_uiPhase = 1; + + // Reset equipment and attack + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + m_creature->SetAttackTime(BASE_ATTACK, ATTACK_TIMER_DEFAULT); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -234,107 +125,59 @@ struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - AxesCleanup(); - ClearWeapons(); - InfernalCleanup(); - m_positions.clear(); + // Remove the summoned axe - which is considered a guardian + m_creature->RemoveGuardians(); - for (uint8 i = 0; i < TOTAL_INFERNAL_POINTS; ++i) - m_positions.push_back(&InfernalPoints[i]); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALCHEZZAR, DONE); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - } - void InfernalCleanup() - { - // Infernal Cleanup - for(GUIDVector::const_iterator itr = m_vInfernalGuids.begin(); itr!= m_vInfernalGuids.end(); ++itr) - { - Creature *pInfernal = m_creature->GetMap()->GetCreature(*itr); - if (pInfernal && pInfernal->isAlive()) - { - pInfernal->SetVisibility(VISIBILITY_OFF); - pInfernal->SetDeathState(JUST_DIED); - } - } - m_vInfernalGuids.clear(); + if (m_pInstance) + m_pInstance->SetData(TYPE_MALCHEZZAR, IN_PROGRESS); } - void AxesCleanup() + void JustReachedHome() override { - for (uint8 i = 0; i < 2; ++i) - { - Creature* pAxe = m_creature->GetMap()->GetCreature(m_aAxeGuid[i]); - if (pAxe && pAxe->isAlive()) - pAxe->DealDamage(pAxe, pAxe->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_aAxeGuid[i].Clear(); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_MALCHEZZAR, FAIL); + + // Remove the summoned axe - which is considered a guardian + m_creature->RemoveGuardians(); } - void ClearWeapons() + void JustSummoned(Creature* pSummoned) override { - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); - - //damage - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg); - m_creature->UpdateDamagePhysical(BASE_ATTACK); + if (pSummoned->GetEntry() == NPC_NETHERSPITE_INFERNAL) + pSummoned->CastSpell(pSummoned, SPELL_HELLFIRE, false); + else if (pSummoned->GetEntry() == NPC_MALCHEZARS_AXE) + pSummoned->SetInCombatWithZone(); } - void EnfeebleHealthEffect() + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override { - const SpellEntry *info = GetSpellStore()->LookupEntry(SPELL_ENFEEBLE_EFFECT); - if (!info) - return; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - std::vector targets; - - if (tList.empty()) - return; - - //begin + 1 , so we don't target the one with the highest threat - ThreatList::const_iterator itr = tList.begin(); - std::advance(itr, 1); - for(; itr!= tList.end(); ++itr) //store the threat list in a different container + // Target selection is already handled properly in core (doesn't affect tank) + if (pSpellEntry->Id == SPELL_ENFEEBLE && pTarget->GetTypeId() == TYPEID_PLAYER) { - Unit *target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - //only on alive players - if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); + // Workaround to handle health set to 1 + m_aEnfeebleTargetGuid[m_uiEnfeebleIndex] = pTarget->GetObjectGuid(); + m_auiEnfeebleHealth[m_uiEnfeebleIndex] = pTarget->GetHealth(); + pTarget->SetHealth(1); + ++m_uiEnfeebleIndex; } - - //cut down to size if we have more than 5 targets - while(targets.size() > 5) - targets.erase(targets.begin()+rand()%targets.size()); - - int i = 0; - for(std::vector::iterator iter = targets.begin(); iter!= targets.end(); ++iter, ++i) - { - Unit *target = *iter; - if (target) - { - m_aEnfeebleTargetGuid[i] = target->GetObjectGuid(); - m_auiEnfeebleHealth[i] = target->GetHealth(); - - target->CastSpell(target, SPELL_ENFEEBLE, true, 0, 0, m_creature->GetObjectGuid()); - target->SetHealth(1); - } - } - } - void EnfeebleResetHealth() + // Wrapper to reset health of the Enfeebled targets + void DoHandleEnfeebleHealthReset() { - for(int i = 0; i < 5; ++i) + for (int i = 0; i < m_uiEnfeebleIndex; ++i) { Player* pTarget = m_creature->GetMap()->GetPlayer(m_aEnfeebleTargetGuid[i]); @@ -344,319 +187,165 @@ struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI m_aEnfeebleTargetGuid[i].Clear(); m_auiEnfeebleHealth[i] = 0; } - } - void SummonInfernal() - { - InfernalPoint *point = NULL; - float posX,posY,posZ; - if ((m_creature->GetMapId() != 532) || m_positions.empty()) - { - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 60, posX, posY, posZ); - } - else - { - std::vector::iterator itr = m_positions.begin()+rand()%m_positions.size(); - point = *itr; - m_positions.erase(itr); - - posX = point->x; - posY = point->y; - posZ = INFERNAL_Z; - } - - Creature *Infernal = m_creature->SummonCreature(NETHERSPITE_INFERNAL, posX, posY, posZ, 0, TEMPSUMMON_TIMED_DESPAWN, 180000); - - if (Infernal) - { - Infernal->SetDisplayId(INFERNAL_MODEL_INVISIBLE); - Infernal->setFaction(m_creature->getFaction()); - - netherspite_infernalAI* pInfernalAI = dynamic_cast(Infernal->AI()); - - if (pInfernalAI) - { - if (point) - pInfernalAI->pPoint = point; - - pInfernalAI->m_malchezaarGuid = m_creature->GetObjectGuid(); - } - - m_vInfernalGuids.push_back(Infernal->GetObjectGuid()); - DoCastSpellIfCan(Infernal, SPELL_INFERNAL_RELAY); - } - - DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + m_uiEnfeebleIndex = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiEnfeebleResetTimer) - { - if (m_uiEnfeebleResetTimer <= uiDiff) //Let's not forget to reset that - { - EnfeebleResetHealth(); - m_uiEnfeebleResetTimer=0; - } - else - m_uiEnfeebleResetTimer -= uiDiff; - } - - if (m_creature->hasUnitState(UNIT_STAT_STUNNED)) //While shifting to m_uiPhase 2 m_malchezaarGuid stuns himself - return; - - if (m_creature->GetTargetGuid() != m_creature->getVictim()->GetObjectGuid()) - m_creature->SetTargetGuid(m_creature->getVictim()->GetObjectGuid()); - + // Phase 1 - over 60% HP if (m_uiPhase == 1) { + // transition to phase 2 if (m_creature->GetHealthPercent() < 60.0f) { - m_creature->InterruptNonMeleeSpells(false); - - m_uiPhase = 2; - - //animation - DoCastSpellIfCan(m_creature, SPELL_EQUIP_AXES); - - //text - DoScriptText(SAY_AXE_TOSS1, m_creature); - - //passive thrash aura - m_creature->CastSpell(m_creature, SPELL_THRASH_AURA, true); - - //models - SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE); - - //damage - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 2*cinfo->mindmg); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 2*cinfo->maxdmg); - m_creature->UpdateDamagePhysical(BASE_ATTACK); - - m_creature->SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg); - m_creature->SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg); - //Sigh, updating only works on main attack , do it manually .... - m_creature->SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, cinfo->mindmg); - m_creature->SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, cinfo->maxdmg); + if (DoCastSpellIfCan(m_creature, SPELL_EQUIP_AXES, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_THRASH_AURA, CAST_TRIGGERED); + DoScriptText(SAY_AXE_TOSS1, m_creature); - m_creature->SetAttackTime(OFF_ATTACK, (m_creature->GetAttackTime(BASE_ATTACK)*150)/100); + SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE); + m_creature->SetAttackTime(BASE_ATTACK, ATTACK_TIMER_AXES); + m_uiPhase = 2; + } } } + // Phase 2 - over 30% HP else if (m_uiPhase == 2) { + // transition to phase 3 if (m_creature->GetHealthPercent() < 30.0f) { - InfernalTimer = 15000; - - m_uiPhase = 3; - - ClearWeapons(); - - //remove thrash - m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); - - DoScriptText(SAY_AXE_TOSS2, m_creature); - - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - for (uint32 i = 0; i < 2; ++i) + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_AXES) == CAST_OK) { - Creature* pAxe = m_creature->SummonCreature(MALCHEZARS_AXE, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); - if (pAxe) - { - pAxe->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pAxe->setFaction(m_creature->getFaction()); - - m_aAxeGuid[i] = pAxe->GetObjectGuid(); - if (pTarget) - { - pAxe->AI()->AttackStart(pTarget); - // pAxe->getThreatManager().tauntApply(pTarget); //Taunt Apply and fade out does not work properly - // So we'll use a hack to add a lot of threat to our pTarget - pAxe->AddThreat(pTarget, 10000000.0f); - } - } - } + DoCastSpellIfCan(m_creature, SPELL_ENFEEBLE_EFFECT, CAST_TRIGGERED); + DoScriptText(SAY_SPECIAL3, m_creature); - if (m_uiShadowNovaTimer > 35000) - m_uiShadowNovaTimer = m_uiEnfeebleTimer + 5000; + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + m_creature->SetAttackTime(BASE_ATTACK, ATTACK_TIMER_DEFAULT); - return; - } + // Reset Enfeebled targets if necessary + DoHandleEnfeebleHealthReset(); + m_uiEnfeebleResetTimer = 0; - if (SunderArmorTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR); - SunderArmorTimer = urand(10000, 18000); + m_creature->RemoveAurasDueToSpell(SPELL_THRASH_AURA); + m_uiShadowNovaTimer = m_uiEnfeebleTimer + 5000; + m_uiInfernalTimer = 15000; + m_uiPhase = 3; + return; + } } - else - SunderArmorTimer -= uiDiff; - if (m_uiCleave_Timer < uiDiff) + if (m_uiSunderArmorTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleave_Timer = urand(6000, 12000); - + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDER_ARMOR) == CAST_OK) + m_uiSunderArmorTimer = urand(10000, 18000); } else - m_uiCleave_Timer -= uiDiff; + m_uiSunderArmorTimer -= uiDiff; } + // Phase 3 else { - if (m_uiAxesTargetSwitchTimer < uiDiff) - { - m_uiAxesTargetSwitchTimer = urand(7500, 20000); - - Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (target) - { - for(int i = 0; i < 2; ++i) - { - Creature *axe = m_creature->GetMap()->GetCreature(m_aAxeGuid[i]); - if (axe) - { - float threat = 1000000.0f; - if (axe->getVictim() && m_creature->getThreatManager().getThreat(axe->getVictim())) - { - threat = axe->getThreatManager().getThreat(axe->getVictim()); - axe->getThreatManager().modifyThreatPercent(axe->getVictim(), -100); - } - if (target) - axe->AddThreat(target, threat); - //axe->getThreatManager().tauntFadeOut(axe->getVictim()); - //axe->getThreatManager().tauntApply(target); - } - } - } - } - else - m_uiAxesTargetSwitchTimer -= uiDiff; - if (m_uiAmplifyDamageTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_AMPLIFY_DAMAGE); - - m_uiAmplifyDamageTimer = urand(20000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_AMPLIFY_DAMAGE) == CAST_OK) + m_uiAmplifyDamageTimer = urand(20000, 30000); } else m_uiAmplifyDamageTimer -= uiDiff; } - //Time for global and double timers - if (InfernalTimer < uiDiff) + // Summon an infernal on timer + if (m_uiInfernalTimer < uiDiff) { - SummonInfernal(); - InfernalTimer = m_uiPhase == 3 ? 14500 : 44500; //15 secs in m_uiPhase 3, 45 otherwise + if (DoCastSpellIfCan(m_creature, SPELL_INFERNAL_RELAY_SUMMON) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + m_uiInfernalTimer = m_uiPhase == 3 ? 17000 : 45000; + } } else - InfernalTimer -= uiDiff; + m_uiInfernalTimer -= uiDiff; - if (m_uiShadowNovaTimer < uiDiff) + // Cast shadow nova - on timer during phase 3, or after Enfeeble during phases 1 and 2 + if (m_uiShadowNovaTimer) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWNOVA); - m_uiShadowNovaTimer = m_uiPhase == 3 ? 31000 : -1; + if (m_uiShadowNovaTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_NOVA) == CAST_OK) + m_uiShadowNovaTimer = m_uiPhase == 3 ? 30000 : 0; + } + else + m_uiShadowNovaTimer -= uiDiff; } - else - m_uiShadowNovaTimer -= uiDiff; + // Cast SW pain during phase 1 and 3 if (m_uiPhase != 2) { if (m_uiSWPainTimer < uiDiff) { - Unit* target = NULL; - if (m_uiPhase == 1) - target = m_creature->getVictim(); // the tank - else //anyone but the tank - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - - if (target) - DoCastSpellIfCan(target, SPELL_SW_PAIN); - - m_uiSWPainTimer = 20000; + if (DoCastSpellIfCan(m_uiPhase == 1 ? m_creature->getVictim() : m_creature, m_uiPhase == 1 ? SPELL_SW_PAIN_PHASE1 : SPELL_SW_PAIN_PHASE3) == CAST_OK) + m_uiSWPainTimer = 20000; } else m_uiSWPainTimer -= uiDiff; } + // Cast Enfeeble during phase 1 and 2 if (m_uiPhase != 3) { if (m_uiEnfeebleTimer < uiDiff) { - EnfeebleHealthEffect(); - m_uiEnfeebleTimer = 30000; - m_uiShadowNovaTimer = 5000; - m_uiEnfeebleResetTimer = 9000; + if (DoCastSpellIfCan(m_creature, SPELL_ENFEEBLE) == CAST_OK) + { + m_uiEnfeebleTimer = 30000; + m_uiShadowNovaTimer = 5000; + m_uiEnfeebleResetTimer = 9000; + } } else m_uiEnfeebleTimer -= uiDiff; } - if (m_uiPhase==2) - DoMeleeAttacksIfReady(); - else - DoMeleeAttackIfReady(); - } - - void DoMeleeAttacksIfReady() - { - // Check if pTarget is valid - if (!m_creature->getVictim()) - return; - - if (!m_creature->IsNonMeleeSpellCasted(false) && m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + if (m_uiEnfeebleResetTimer) { - //Check for base attack - if (m_creature->isAttackReady()) - { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - //Check for offhand attack - if (m_creature->isAttackReady(OFF_ATTACK)) + if (m_uiEnfeebleResetTimer <= uiDiff) { - m_creature->AttackerStateUpdate(m_creature->getVictim(), OFF_ATTACK); - m_creature->resetAttackTimer(OFF_ATTACK); + DoHandleEnfeebleHealthReset(); + m_uiEnfeebleResetTimer = 0; } - } - } - - void Cleanup(Creature *infernal, InfernalPoint *point) - { - for(GUIDVector::iterator itr = m_vInfernalGuids.begin(); itr!= m_vInfernalGuids.end(); ++itr) - if (*itr == infernal->GetObjectGuid()) - { - m_vInfernalGuids.erase(itr); - break; + else + m_uiEnfeebleResetTimer -= uiDiff; } - m_positions.push_back(point); + DoMeleeAttackIfReady(); } }; -void netherspite_infernalAI::Cleanup() +CreatureAI* GetAI_boss_malchezaar(Creature* pCreature) { - Creature* pMalchezaar = m_creature->GetMap()->GetCreature(m_malchezaarGuid); - - if (pMalchezaar && pMalchezaar->isAlive()) - { - if (boss_malchezaarAI* pMalAI = dynamic_cast(pMalchezaar->AI())) - pMalAI->Cleanup(m_creature, pPoint); - } + return new boss_malchezaarAI(pCreature); } -CreatureAI* GetAI_netherspite_infernal(Creature* pCreature) +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_infernal_targetAI : public Scripted_NoMovementAI { - return new netherspite_infernalAI(pCreature); -} + npc_infernal_targetAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } -CreatureAI* GetAI_boss_malchezaar(Creature* pCreature) + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_infernal_target(Creature* pCreature) { - return new boss_malchezaarAI(pCreature); + return new npc_infernal_targetAI(pCreature); } void AddSC_boss_prince_malchezaar() @@ -669,7 +358,7 @@ void AddSC_boss_prince_malchezaar() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "netherspite_infernal"; - pNewScript->GetAI = &GetAI_netherspite_infernal; + pNewScript->Name = "npc_infernal_target"; + pNewScript->GetAI = &GetAI_npc_infernal_target; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp b/scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp index fdd5e01e6..898fa8eef 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_shade_of_aran.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,13 +17,12 @@ /* ScriptData SDName: Boss_Shade_of_Aran SD%Complete: 95 -SDComment: Flame wreath missing cast animation, mods won't trigger. +SDComment: When drinking mana, it should remove all negative damage auras and should sit. Timers may need adjustments. SDCategory: Karazhan EndScriptData */ #include "precompiled.h" #include "karazhan.h" -#include "GameObject.h" enum { @@ -36,55 +35,61 @@ enum SAY_BLIZZARD2 = -1532079, SAY_EXPLOSION1 = -1532080, SAY_EXPLOSION2 = -1532081, - SAY_DRINK = -1532082, //Low Mana / AoE Pyroblast + SAY_DRINK = -1532082, // Low Mana / AoE Pyroblast SAY_ELEMENTALS = -1532083, SAY_KILL1 = -1532084, SAY_KILL2 = -1532085, SAY_TIMEOVER = -1532086, SAY_DEATH = -1532087, - SAY_ATIESH = -1532088, //Atiesh is equipped by a raid member + SAY_ATIESH = -1532088, // Atiesh is equipped by a raid member - //Spells + // basic spells SPELL_FROSTBOLT = 29954, SPELL_FIREBALL = 29953, - SPELL_ARCMISSLE = 29955, - SPELL_CHAINSOFICE = 29991, - SPELL_DRAGONSBREATH = 29964, - SPELL_MASSSLOW = 30035, - SPELL_FLAME_WREATH = 29946, - SPELL_AOE_CS = 29961, - SPELL_PLAYERPULL = 32265, - SPELL_AEXPLOSION = 29973, - SPELL_MASS_POLY = 29963, - SPELL_BLINK_CENTER = 29967, - SPELL_ELEMENTALS = 29962, - SPELL_CONJURE = 29975, + SPELL_ARCANE_MISSILES = 29955, + // SPELL_DRAGONS_BREATH = 29964, // not used since 2.1.0 + SPELL_CHAINS_OF_ICE = 29991, + SPELL_COUNTERSPELL = 29961, + // SPELL_COMBUSTION = 29977, // spell not confirmed + // SPELL_PRESENCE_OF_MIND = 29976, // spell not confirmed + // SPELL_WATER_BREAK = 39177, // purpose unk + + // low mana spells + SPELL_MASS_POLYMORPH = 29963, + SPELL_CONJURE_WATER = 29975, SPELL_DRINK = 30024, - SPELL_POTION = 32453, - SPELL_AOE_PYROBLAST = 29978, + SPELL_MANA_POTION = 32453, + SPELL_PYROBLAST = 29978, - SPELL_EXPLOSION = 20476, - SPELL_KNOCKBACK_500 = 11027, + // super spells + SPELL_FLAME_WREATH = 30004, // triggers 29946 on targets + SPELL_SUMMON_BLIZZARD = 29969, // script target on npc 17161 - triggers spell 29952 on target + SPELL_BLINK_CENTER = 29967, + SPELL_MASSIVE_MAGNETIC_PULL = 29979, // triggers 30010 on target + SPELL_MASS_SLOW = 30035, + SPELL_ARCANE_EXPLOSION = 29973, - //Creature Spells - SPELL_CIRCULAR_BLIZZARD = 29951, //29952 is the REAL circular blizzard that leaves persistant blizzards that last for 10 seconds - SPELL_WATERBOLT = 31012, - SPELL_SHADOW_PYRO = 29978, + // summon elemental spells + SPELL_SUMMON_WATER_ELEM_1 = 29962, + SPELL_SUMMON_WATER_ELEM_2 = 37051, + SPELL_SUMMON_WATER_ELEM_3 = 37052, + SPELL_SUMMON_WATER_ELEM_4 = 37053, - //Creatures + // Creatures NPC_WATER_ELEMENTAL = 17167, NPC_SHADOW_OF_ARAN = 18254, - NPC_ARAN_BLIZZARD = 17161 + + MAX_SHADOWS_OF_ARAN = 5, // this is not confirmed }; -enum SuperSpell +enum SuperSpells { - SUPER_FLAME = 0, - SUPER_BLIZZARD, - SUPER_AE, + SUPER_FLAME_WREATH = 0, + SUPER_BLIZZARD = 1, + SUPER_ARCANE_EXPL = 2, }; -struct MANGOS_DLL_DECL boss_aranAI : public ScriptedAI +struct boss_aranAI : public ScriptedAI { boss_aranAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -94,75 +99,59 @@ struct MANGOS_DLL_DECL boss_aranAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiSecondarySpell_Timer; - uint32 m_uiNormalCast_Timer; - uint32 m_uiSuperCast_Timer; - uint32 m_uiBerserk_Timer; - uint32 m_uiCloseDoor_Timer; // Don't close the door right on aggro in case some people are still entering. + uint32 m_uiSecondarySpellTimer; + uint32 m_uiNormalCastTimer; + uint32 m_uiSuperCastTimer; + uint32 m_uiBerserkTimer; uint8 m_uiLastSuperSpell; + uint8 m_uiLastNormalSpell; - uint32 m_uiFlameWreath_Timer; - uint32 m_uiFlameWreathCheck_Timer; - ObjectGuid m_aFlameWreathTargetGuid[3]; - float m_fFWTargPosX[3]; - float m_fFWTargPosY[3]; - - uint32 m_uiCurrentNormalSpell; - uint32 m_uiArcaneCooldown; - uint32 m_uiFireCooldown; - uint32 m_uiFrostCooldown; - - uint32 m_uiDrinkInturrupt_Timer; + uint32 m_uiManaRecoveryTimer; + uint8 m_uiManaRecoveryStage; bool m_bElementalsSpawned; - bool m_bDrinking; + bool m_bIsDrinking; bool m_bDrinkInturrupted; - void Reset() + void Reset() override { - m_uiSecondarySpell_Timer = 5000; - m_uiNormalCast_Timer = 0; - m_uiSuperCast_Timer = 35000; - m_uiBerserk_Timer = 720000; - m_uiCloseDoor_Timer = 15000; + m_uiLastSuperSpell = urand(SUPER_FLAME_WREATH, SUPER_ARCANE_EXPL); + m_uiLastNormalSpell = urand(0, 2); - m_uiLastSuperSpell = urand(0, 2); + m_uiSecondarySpellTimer = 5000; + m_uiNormalCastTimer = 0; + m_uiSuperCastTimer = 35000; + m_uiManaRecoveryTimer = 0; + m_uiManaRecoveryStage = 0; + m_uiBerserkTimer = 12 * MINUTE * IN_MILLISECONDS; - m_uiFlameWreath_Timer = 0; - m_uiFlameWreathCheck_Timer = 0; + m_bElementalsSpawned = false; + m_bIsDrinking = false; + m_bDrinkInturrupted = false; - m_uiCurrentNormalSpell = 0; - m_uiArcaneCooldown = 0; - m_uiFireCooldown = 0; - m_uiFrostCooldown = 0; - - m_uiDrinkInturrupt_Timer = 10000; - - m_bElementalsSpawned = false; - m_bDrinking = false; - m_bDrinkInturrupted = false; - - if (m_pInstance) - m_pInstance->SetData(TYPE_ARAN, NOT_STARTED); + SetCombatMovement(true); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); + // Remove the summoned elementals - which are considered guardians + m_creature->RemoveGuardians(); + if (m_pInstance) m_pInstance->SetData(TYPE_ARAN, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -173,136 +162,107 @@ struct MANGOS_DLL_DECL boss_aranAI : public ScriptedAI m_pInstance->SetData(TYPE_ARAN, IN_PROGRESS); } - void FlameWreathEffect() + void JustReachedHome() override { - std::vector targets; + if (m_pInstance) + m_pInstance->SetData(TYPE_ARAN, FAIL); - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - if (tList.empty()) - return; + // Remove the summoned elementals - which are considered guardians + m_creature->RemoveGuardians(); + } - //store the threat list in a different container - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (!m_bDrinkInturrupted && m_bIsDrinking && uiDamage > 0) { - Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); + if (!m_creature->HasAura(SPELL_DRINK)) + return; - //only on alive players - if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) - targets.push_back(pTarget); + if (DoCastSpellIfCan(m_creature, SPELL_MANA_POTION) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_DRINK); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiManaRecoveryTimer = 1000; + m_uiManaRecoveryStage = 2; + m_bDrinkInturrupted = true; + } } + } - //cut down to size if we have more than 3 targets - while(targets.size() > 3) - targets.erase(targets.begin()+rand()%targets.size()); - - uint32 i = 0; - for(std::vector::iterator itr = targets.begin(); itr!= targets.end(); ++itr) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - if (*itr) - { - m_aFlameWreathTargetGuid[i] = (*itr)->GetObjectGuid(); - m_fFWTargPosX[i] = (*itr)->GetPositionX(); - m_fFWTargPosY[i] = (*itr)->GetPositionY(); - m_creature->CastSpell((*itr), SPELL_FLAME_WREATH, true); - ++i; - } + case NPC_WATER_ELEMENTAL: + case NPC_SHADOW_OF_ARAN: + pSummoned->SetInCombatWithZone(); + break; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiCloseDoor_Timer) + // Start drinking when below 20% mana + if (!m_bIsDrinking && m_creature->GetPowerType() == POWER_MANA && (m_creature->GetPower(POWER_MANA) * 100 / m_creature->GetMaxPower(POWER_MANA)) < 20) { - if (m_uiCloseDoor_Timer <= uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_MASS_POLYMORPH) == CAST_OK) { - if (m_pInstance) - { - if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(GO_PRIVATE_LIBRARY_DOOR)) - pDoor->SetGoState(GO_STATE_READY); - - m_uiCloseDoor_Timer = 0; - } + DoScriptText(SAY_DRINK, m_creature); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + + m_uiManaRecoveryStage = 0; + m_uiManaRecoveryTimer = 2000; + m_bDrinkInturrupted = false; + m_bIsDrinking = true; + return; } - else - m_uiCloseDoor_Timer -= uiDiff; - } - - //Cooldowns for casts - if (m_uiArcaneCooldown) - { - if (m_uiArcaneCooldown >= uiDiff) - m_uiArcaneCooldown -= uiDiff; - else - m_uiArcaneCooldown = 0; } - if (m_uiFireCooldown) + if (m_bIsDrinking) { - if (m_uiFireCooldown >= uiDiff) - m_uiFireCooldown -= uiDiff; - else - m_uiFireCooldown = 0; - } - - if (m_uiFrostCooldown) - { - if (m_uiFrostCooldown >= uiDiff) - m_uiFrostCooldown -= uiDiff; - else - m_uiFrostCooldown = 0; - } - - if (!m_bDrinking && m_creature->GetMaxPower(POWER_MANA) && (m_creature->GetPower(POWER_MANA)*100 / m_creature->GetMaxPower(POWER_MANA)) < 20) - { - m_bDrinking = true; - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(SAY_DRINK, m_creature); - - if (!m_bDrinkInturrupted) + // Do the mana recovery process + if (m_uiManaRecoveryTimer < uiDiff) { - m_creature->CastSpell(m_creature, SPELL_MASS_POLY, true); - m_creature->CastSpell(m_creature, SPELL_CONJURE, false); - m_creature->CastSpell(m_creature, SPELL_DRINK, false); - m_creature->SetStandState(UNIT_STAND_STATE_SIT); - m_uiDrinkInturrupt_Timer = 10000; + switch (m_uiManaRecoveryStage) + { + case 0: + if (DoCastSpellIfCan(m_creature, SPELL_CONJURE_WATER) == CAST_OK) + m_uiManaRecoveryTimer = 2000; + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_DRINK) == CAST_OK) + { + m_creature->SetStandState(UNIT_STAND_STATE_SIT); + m_uiManaRecoveryTimer = 5000; + } + break; + case 2: + if (DoCastSpellIfCan(m_creature, SPELL_PYROBLAST) == CAST_OK) + { + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + m_uiManaRecoveryTimer = 2000; + m_bIsDrinking = false; + } + break; + } + ++m_uiManaRecoveryStage; } - } - - //Drink Inturrupt - if (m_bDrinking && m_bDrinkInturrupted) - { - m_bDrinking = false; - m_creature->RemoveAurasDueToSpell(SPELL_DRINK); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->SetPower(POWER_MANA, m_creature->GetMaxPower(POWER_MANA)-32000); - m_creature->CastSpell(m_creature, SPELL_POTION, false); - } - - //Drink Inturrupt Timer - if (m_bDrinking && !m_bDrinkInturrupted) - { - if (m_uiDrinkInturrupt_Timer >= uiDiff) - m_uiDrinkInturrupt_Timer -= uiDiff; else - { - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->CastSpell(m_creature, SPELL_POTION, true); - m_creature->CastSpell(m_creature, SPELL_AOE_PYROBLAST, false); - m_bDrinkInturrupted = true; - m_bDrinking = false; - } - } + m_uiManaRecoveryTimer -= uiDiff; - //Don't execute any more code if we are drinking - if (m_bDrinking) + // no other spells during mana recovery return; + } - //Normal casts - if (m_uiNormalCast_Timer < uiDiff) + // Normal spell casts + if (m_uiNormalCastTimer < uiDiff) { if (!m_creature->IsNonMeleeSpellCasted(false)) { @@ -310,227 +270,126 @@ struct MANGOS_DLL_DECL boss_aranAI : public ScriptedAI if (!pTarget) return; - uint32 auiSpells[3]; - uint8 uiAvailableSpells = 0; + uint8 uiCurrentSpell = urand(0, 2); + uint32 uiCurrentSpellId = 0; - //Check for what spells are not on cooldown - if (!m_uiArcaneCooldown) - auiSpells[uiAvailableSpells++] = SPELL_ARCMISSLE; - if (!m_uiFireCooldown) - auiSpells[uiAvailableSpells++] = SPELL_FIREBALL; - if (!m_uiFrostCooldown) - auiSpells[uiAvailableSpells++] = SPELL_FROSTBOLT; + // randomize so it won't be the same spell twice in a row + while (uiCurrentSpell == m_uiLastNormalSpell) + uiCurrentSpell = urand(0, 2); - //If no available spells wait 1 second and try again - if (uiAvailableSpells) + m_uiLastNormalSpell = uiCurrentSpell; + + switch (uiCurrentSpell) { - m_uiCurrentNormalSpell = auiSpells[rand() % uiAvailableSpells]; - DoCastSpellIfCan(pTarget, m_uiCurrentNormalSpell); + case 0: + uiCurrentSpellId = SPELL_ARCANE_MISSILES; + m_uiNormalCastTimer = urand(6000, 7000); + break; + case 1: + uiCurrentSpellId = SPELL_FIREBALL; + m_uiNormalCastTimer = urand(2000, 3000); + break; + case 2: + uiCurrentSpellId = SPELL_FROSTBOLT; + m_uiNormalCastTimer = urand(2000, 3000); + break; } + + if (uiCurrentSpellId) + DoCastSpellIfCan(pTarget, uiCurrentSpellId); } - m_uiNormalCast_Timer = 1000; } else - m_uiNormalCast_Timer -= uiDiff; + m_uiNormalCastTimer -= uiDiff; - if (m_uiSecondarySpell_Timer < uiDiff) + // Secondary spells + if (m_uiSecondarySpellTimer < uiDiff) { - switch(urand(0, 1)) + CanCastResult spellResult = CAST_OK; + + switch (urand(0, 1)) { case 0: - DoCastSpellIfCan(m_creature, SPELL_AOE_CS); + spellResult = DoCastSpellIfCan(m_creature, SPELL_COUNTERSPELL); break; case 1: if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_CHAINSOFICE); + spellResult = DoCastSpellIfCan(pUnit, SPELL_CHAINS_OF_ICE); break; } - m_uiSecondarySpell_Timer = urand(5000, 20000); + if (spellResult == CAST_OK) + m_uiSecondarySpellTimer = urand(5000, 20000); } else - m_uiSecondarySpell_Timer -= uiDiff; + m_uiSecondarySpellTimer -= uiDiff; - if (m_uiSuperCast_Timer < uiDiff) + if (m_uiSuperCastTimer < uiDiff) { - uint8 auiAvailable[2]; - - switch (m_uiLastSuperSpell) - { - case SUPER_AE: - auiAvailable[0] = SUPER_FLAME; - auiAvailable[1] = SUPER_BLIZZARD; - break; - case SUPER_FLAME: - auiAvailable[0] = SUPER_AE; - auiAvailable[1] = SUPER_BLIZZARD; - break; - case SUPER_BLIZZARD: - auiAvailable[0] = SUPER_FLAME; - auiAvailable[1] = SUPER_AE; - break; - } - - m_uiLastSuperSpell = auiAvailable[urand(0, 2)]; - - switch (m_uiLastSuperSpell) + if (!m_creature->IsNonMeleeSpellCasted(false)) { - case SUPER_AE: - DoScriptText(urand(0, 1) ? SAY_EXPLOSION1 : SAY_EXPLOSION2, m_creature); - - m_creature->CastSpell(m_creature, SPELL_BLINK_CENTER, true); - m_creature->CastSpell(m_creature, SPELL_PLAYERPULL, true); - m_creature->CastSpell(m_creature, SPELL_MASSSLOW, true); - m_creature->CastSpell(m_creature, SPELL_AEXPLOSION, false); - break; - - case SUPER_FLAME: - DoScriptText(urand(0, 1) ? SAY_FLAMEWREATH1 : SAY_FLAMEWREATH2, m_creature); + uint8 uiAvailableSpell = urand(SUPER_FLAME_WREATH, SUPER_ARCANE_EXPL); - m_uiFlameWreath_Timer = 20000; - m_uiFlameWreathCheck_Timer = 500; + // randomize so it won't be the same spell twice in a row + while (uiAvailableSpell == m_uiLastSuperSpell) + uiAvailableSpell = urand(SUPER_FLAME_WREATH, SUPER_ARCANE_EXPL); - for (uint8 i = 0; i < 3; ++i) - m_aFlameWreathTargetGuid[i].Clear(); + m_uiLastSuperSpell = uiAvailableSpell; - FlameWreathEffect(); - break; - - case SUPER_BLIZZARD: - DoScriptText(urand(0, 1) ? SAY_BLIZZARD1 : SAY_BLIZZARD2, m_creature); - - if (Creature* pSpawn = m_creature->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000)) - { - pSpawn->setFaction(m_creature->getFaction()); - pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false); - } - break; + switch (m_uiLastSuperSpell) + { + case SUPER_ARCANE_EXPL: + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_BLINK_CENTER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_MASSIVE_MAGNETIC_PULL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_MASS_SLOW, CAST_TRIGGERED); + + DoScriptText(urand(0, 1) ? SAY_EXPLOSION1 : SAY_EXPLOSION2, m_creature); + } + break; + case SUPER_FLAME_WREATH: + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_WREATH) == CAST_OK) + DoScriptText(urand(0, 1) ? SAY_FLAMEWREATH1 : SAY_FLAMEWREATH2, m_creature); + break; + case SUPER_BLIZZARD: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_BLIZZARD) == CAST_OK) + DoScriptText(urand(0, 1) ? SAY_BLIZZARD1 : SAY_BLIZZARD2, m_creature); + break; + } + m_uiSuperCastTimer = 30000; } - - m_uiSuperCast_Timer = urand(35000, 40000); } else - m_uiSuperCast_Timer -= uiDiff; + m_uiSuperCastTimer -= uiDiff; if (!m_bElementalsSpawned && m_creature->GetHealthPercent() < 40.0f) { - m_bElementalsSpawned = true; - - for (uint32 i = 0; i < 4; ++i) - { - if (Creature* pElemental = m_creature->SummonCreature(NPC_WATER_ELEMENTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 90000)) - { - pElemental->Attack(m_creature->getVictim(), true); - pElemental->setFaction(m_creature->getFaction()); - } - } + DoCastSpellIfCan(m_creature, SPELL_SUMMON_WATER_ELEM_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_WATER_ELEM_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_WATER_ELEM_3, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_WATER_ELEM_4, CAST_TRIGGERED); DoScriptText(SAY_ELEMENTALS, m_creature); - } - - if (m_uiBerserk_Timer < uiDiff) - { - for (uint32 i = 0; i < 5; ++i) - { - if (Creature* pShadow = m_creature->SummonCreature(NPC_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) - { - pShadow->Attack(m_creature->getVictim(), true); - pShadow->setFaction(m_creature->getFaction()); - } - } - DoScriptText(SAY_TIMEOVER, m_creature); - - m_uiBerserk_Timer = 60000; + m_bElementalsSpawned = true; } - else - m_uiBerserk_Timer -= uiDiff; - //Flame Wreath check - if (m_uiFlameWreath_Timer) + // Berserk timer - the summons position is guesswork + if (m_uiBerserkTimer) { - if (m_uiFlameWreath_Timer >= uiDiff) - m_uiFlameWreath_Timer -= uiDiff; - else - m_uiFlameWreath_Timer = 0; - - if (m_uiFlameWreathCheck_Timer < uiDiff) + if (m_uiBerserkTimer <= uiDiff) { - for (uint32 i = 0; i < 3; ++i) - { - if (!m_aFlameWreathTargetGuid[i]) - continue; + for (uint8 i = 0; i < MAX_SHADOWS_OF_ARAN; ++i) + DoSpawnCreature(NPC_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); - Player* pPlayer = m_creature->GetMap()->GetPlayer(m_aFlameWreathTargetGuid[i]); - - if (pPlayer && !pPlayer->IsWithinDist2d(m_fFWTargPosX[i], m_fFWTargPosY[i], 3.0f)) - { - pPlayer->CastSpell(pPlayer, SPELL_EXPLOSION, true, 0, 0, m_creature->GetObjectGuid()); - pPlayer->CastSpell(pPlayer, SPELL_KNOCKBACK_500, true); - m_aFlameWreathTargetGuid[i].Clear(); - } - } - m_uiFlameWreathCheck_Timer = 500; + DoScriptText(SAY_TIMEOVER, m_creature); + m_uiBerserkTimer = 0; } else - m_uiFlameWreathCheck_Timer -= uiDiff; + m_uiBerserkTimer -= uiDiff; } - if (m_uiArcaneCooldown && m_uiFireCooldown && m_uiFrostCooldown) - DoMeleeAttackIfReady(); - } - - void DamageTaken(Unit* pAttacker, uint32 &damage) - { - if (!m_bDrinkInturrupted && m_bDrinking && damage) - m_bDrinkInturrupted = true; - } - - void SpellHit(Unit* pAttacker, const SpellEntry* Spell) - { - //We only care about inturrupt effects and only if they are durring a spell currently being casted - if ((Spell->Effect[0]!=SPELL_EFFECT_INTERRUPT_CAST && - Spell->Effect[1]!=SPELL_EFFECT_INTERRUPT_CAST && - Spell->Effect[2]!=SPELL_EFFECT_INTERRUPT_CAST) || !m_creature->IsNonMeleeSpellCasted(false)) - return; - - //Inturrupt effect - m_creature->InterruptNonMeleeSpells(false); - - //Normally we would set the cooldown equal to the spell duration - //but we do not have access to the DurationStore - - switch (m_uiCurrentNormalSpell) - { - case SPELL_ARCMISSLE: m_uiArcaneCooldown = 5000; break; - case SPELL_FIREBALL: m_uiFireCooldown = 5000; break; - case SPELL_FROSTBOLT: m_uiFrostCooldown = 5000; break; - } - } -}; - -struct MANGOS_DLL_DECL water_elementalAI : public ScriptedAI -{ - water_elementalAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiCast_Timer; - - void Reset() - { - m_uiCast_Timer = urand(2000, 5000); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiCast_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_WATERBOLT); - m_uiCast_Timer = urand(2000, 5000); - } - else - m_uiCast_Timer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -539,9 +398,20 @@ CreatureAI* GetAI_boss_aran(Creature* pCreature) return new boss_aranAI(pCreature); } -CreatureAI* GetAI_water_elemental(Creature* pCreature) +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_shade_of_aran_blizzardAI : public ScriptedAI +{ + npc_shade_of_aran_blizzardAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_shade_of_aran_blizzard(Creature* pCreature) { - return new water_elementalAI(pCreature); + return new npc_shade_of_aran_blizzardAI(pCreature); } void AddSC_boss_shade_of_aran() @@ -554,7 +424,7 @@ void AddSC_boss_shade_of_aran() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_aran_elemental"; - pNewScript->GetAI = &GetAI_water_elemental; + pNewScript->Name = "npc_shade_of_aran_blizzard"; + pNewScript->GetAI = &GetAI_npc_shade_of_aran_blizzard; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp b/scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp index b78f58c4b..3d2f5212b 100644 --- a/scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp +++ b/scripts/eastern_kingdoms/karazhan/boss_terestian_illhoof.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Terestian_Illhoof -SD%Complete: 95 -SDComment: Complete! Needs adjustments to use spell though. +SD%Complete: 100 +SDComment: SDCategory: Karazhan EndScriptData */ @@ -35,192 +35,137 @@ enum SAY_SUMMON1 = -1532071, SAY_SUMMON2 = -1532072, + // spells SPELL_SUMMON_DEMONCHAINS = 30120, // Summons demonic chains that maintain the ritual of sacrifice. - SPELL_DEMON_CHAINS = 30206, // Instant - Visual Effect - SPELL_ENRAGE = 23537, // Increases the caster's attack speed by 50% and the Physical damage it deals by 219 to 281 for 10 min. SPELL_SHADOW_BOLT = 30055, // Hurls a bolt of dark magic at an enemy, inflicting Shadow damage. SPELL_SACRIFICE = 30115, // Teleports and adds the debuff SPELL_BERSERK = 32965, // Increases attack speed by 75%. Periodically casts Shadow Bolt Volley. - SPELL_SUMMON_IMP = 30066, // Summons Kil'rek - - SPELL_SUMMON_FIENDISH_IMP = 30184, SPELL_FIENDISH_PORTAL = 30171, // Opens portal and summons Fiendish Portal, 2 sec cast SPELL_FIENDISH_PORTAL_1 = 30179, // Opens portal and summons Fiendish Portal, instant cast - SPELL_FIREBOLT = 30050, // Blasts a target for 150 Fire damage. + // Chains spells + SPELL_DEMON_CHAINS = 30206, // Instant - Visual Effect + + // Portal spells + SPELL_SUMMON_FIENDISH_IMP = 30184, + // Kilrek SPELL_BROKEN_PACT = 30065, // All damage taken increased by 25%. - SPELL_AMPLIFY_FLAMES = 30053, // Increases the Fire damage taken by an enemy by 500 for 25 sec. + // summoned npcs NPC_DEMONCHAINS = 17248, NPC_FIENDISHIMP = 17267, NPC_PORTAL = 17265, NPC_KILREK = 17229 }; -struct MANGOS_DLL_DECL mob_demon_chainAI : public ScriptedAI -{ - mob_demon_chainAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - ObjectGuid m_sacrificeGuid; - - void Reset(){} - - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - - void JustDied(Unit* pKiller) - { - if (m_sacrificeGuid) - { - if (Player* pSacrifice = m_creature->GetMap()->GetPlayer(m_sacrificeGuid)) - pSacrifice->RemoveAurasDueToSpell(SPELL_SACRIFICE); - } - } -}; - -struct MANGOS_DLL_DECL boss_terestianAI : public ScriptedAI +struct boss_terestianAI : public ScriptedAI { boss_terestianAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bSummonKilrek = true; Reset(); } ScriptedInstance* m_pInstance; - ObjectGuid m_aPortalGuid[2]; + ObjectGuid m_sacrificeGuid; uint32 m_uiSummonKilrekTimer; - uint32 m_uiSacrifice_Timer; - uint32 m_uiShadowbolt_Timer; - uint32 m_uiSummon_Timer; - uint32 m_uiBerserk_Timer; + uint32 m_uiSacrificeTimer; + uint32 m_uiShadowboltTimer; + uint32 m_uiSummonTimer; + uint32 m_uiBerserkTimer; - bool m_bSummonKilrek; bool m_bSummonedPortals; - bool m_bBerserk; - void Reset() + void Reset() override { - m_uiSummonKilrekTimer = 5000; - m_uiSacrifice_Timer = 30000; - m_uiShadowbolt_Timer = 5000; - m_uiSummon_Timer = 10000; - m_uiBerserk_Timer = 600000; + m_uiSummonKilrekTimer = 0; + m_uiSacrificeTimer = 30000; + m_uiShadowboltTimer = 5000; + m_uiSummonTimer = 10000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; m_bSummonedPortals = false; - m_bBerserk = false; - - if (!m_pInstance) - return; - - for(uint8 i = 0; i < 2; ++i) - { - if (m_aPortalGuid[i]) - { - if (Creature* pPortal = m_pInstance->instance->GetCreature(m_aPortalGuid[i])) - pPortal->ForcedDespawn(); - - m_aPortalGuid[i].Clear(); - } - } - - if (!m_creature->isAlive()) - return; - - m_pInstance->SetData(TYPE_TERESTIAN, NOT_STARTED); - - if (!m_creature->GetPet()) - m_bSummonKilrek = true; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (Pet* pKilrek = m_creature->GetPet()) - pKilrek->SetInCombatWithZone(); - DoScriptText(SAY_AGGRO, m_creature); + if (!m_creature->GetPet()) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_IMP); + if (m_pInstance) m_pInstance->SetData(TYPE_TERESTIAN, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override { - switch(pSummoned->GetEntry()) + if (m_pInstance) + m_pInstance->SetData(TYPE_TERESTIAN, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { case NPC_PORTAL: - { - if (m_aPortalGuid[0]) - { - m_aPortalGuid[1] = pSummoned->GetObjectGuid(); - - if (npc_fiendish_portalAI* pPortalAI = dynamic_cast(pSummoned->AI())) - pPortalAI->m_uiSummonTimer = 10000; - } - else + if (!m_bSummonedPortals) { - m_aPortalGuid[0] = pSummoned->GetObjectGuid(); + m_bSummonedPortals = true; DoCastSpellIfCan(m_creature, SPELL_FIENDISH_PORTAL_1, CAST_TRIGGERED); } - break; - } case NPC_KILREK: m_creature->RemoveAurasDueToSpell(SPELL_BROKEN_PACT); + pSummoned->SetInCombatWithZone(); + break; + case NPC_DEMONCHAINS: + pSummoned->CastSpell(pSummoned, SPELL_DEMON_CHAINS, false); break; } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { - if (pSummoned->GetEntry() == NPC_KILREK) + switch (pSummoned->GetEntry()) { - DoCastSpellIfCan(m_creature, SPELL_BROKEN_PACT, CAST_TRIGGERED); - m_bSummonKilrek = true; + case NPC_KILREK: + pSummoned->CastSpell(m_creature, SPELL_BROKEN_PACT, true); + m_uiSummonKilrekTimer = 30000; + break; + case NPC_DEMONCHAINS: + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_sacrificeGuid)) + pPlayer->RemoveAurasDueToSpell(SPELL_SACRIFICE); + break; } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - if (!m_pInstance) - return; - - for(uint8 i = 0; i < 2; ++i) - { - if (m_aPortalGuid[i]) - { - if (Creature* pPortal = m_pInstance->instance->GetCreature(m_aPortalGuid[i])) - pPortal->ForcedDespawn(); - - m_aPortalGuid[i].Clear(); - } - } - - m_pInstance->SetData(TYPE_TERESTIAN, DONE); + if (m_pInstance) + m_pInstance->SetData(TYPE_TERESTIAN, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_bSummonKilrek) + // Respawn Kilrek if killed + if (m_uiSummonKilrekTimer) { - if (m_uiSummonKilrekTimer < uiDiff) + if (m_uiSummonKilrekTimer <= uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_IMP) == CAST_OK) - { - m_uiSummonKilrekTimer = 45000; - m_bSummonKilrek = false; - } + m_uiSummonKilrekTimer = 0; } else m_uiSummonKilrekTimer -= uiDiff; @@ -229,90 +174,102 @@ struct MANGOS_DLL_DECL boss_terestianAI : public ScriptedAI if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiSacrifice_Timer < uiDiff) + if (m_uiSacrificeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_SACRIFICE, SELECT_FLAG_PLAYER)) { - DoCastSpellIfCan(pTarget, SPELL_SACRIFICE, CAST_TRIGGERED); - - if (Creature* pChains = m_creature->SummonCreature(NPC_DEMONCHAINS, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 21000)) + if (DoCastSpellIfCan(pTarget, SPELL_SACRIFICE) == CAST_OK) { - if (mob_demon_chainAI* pDemonAI = dynamic_cast(pChains->AI())) - pDemonAI->m_sacrificeGuid = pTarget->GetObjectGuid(); - - pChains->CastSpell(pChains, SPELL_DEMON_CHAINS, true); - + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DEMONCHAINS, CAST_TRIGGERED); DoScriptText(urand(0, 1) ? SAY_SACRIFICE1 : SAY_SACRIFICE2, m_creature); - - m_uiSacrifice_Timer = 30000; + m_sacrificeGuid = pTarget->GetObjectGuid(); + m_uiSacrificeTimer = 43000; } } } else - m_uiSacrifice_Timer -= uiDiff; + m_uiSacrificeTimer -= uiDiff; - if (m_uiShadowbolt_Timer < uiDiff) + if (m_uiShadowboltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT); - m_uiShadowbolt_Timer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT) == CAST_OK) + m_uiShadowboltTimer = 10000; } else - m_uiShadowbolt_Timer -= uiDiff; + m_uiShadowboltTimer -= uiDiff; - if (!m_bSummonedPortals) + if (m_uiSummonTimer) { - if (m_uiSummon_Timer < uiDiff) + if (m_uiSummonTimer <= uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_FIENDISH_PORTAL, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_FIENDISH_PORTAL) == CAST_OK) { DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); - m_bSummonedPortals = true; + m_uiSummonTimer = 0; } } else - m_uiSummon_Timer -= uiDiff; + m_uiSummonTimer -= uiDiff; } - if (!m_bBerserk) + if (m_uiBerserkTimer) { - if (m_uiBerserk_Timer < uiDiff) + if (m_uiBerserkTimer <= uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_INTERRUPT_PREVIOUS); - m_bBerserk = true; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 0; } else - m_uiBerserk_Timer -= uiDiff; + m_uiBerserkTimer -= uiDiff; } DoMeleeAttackIfReady(); } }; -npc_fiendish_portalAI::npc_fiendish_portalAI(Creature* pCreature) : ScriptedAI(pCreature), - m_uiSummonTimer(5000) +struct npc_fiendish_portalAI : public ScriptedAI { - Reset(); -} + npc_fiendish_portalAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } -void npc_fiendish_portalAI::Reset() -{ -} + uint32 m_uiSummonTimer; -void npc_fiendish_portalAI::JustSummoned(Creature* pSummoned) -{ - pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); - pSummoned->SetInCombatWithZone(); -} + void Reset() override + { + m_uiSummonTimer = 5000; + } -void npc_fiendish_portalAI::UpdateAI(const uint32 uiDiff) -{ - if (m_uiSummonTimer < uiDiff) + void JustSummoned(Creature* pSummoned) override + { + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); + pSummoned->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIENDISH_IMP); - m_uiSummonTimer = 10000; + if (m_uiSummonTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIENDISH_IMP) == CAST_OK) + m_uiSummonTimer = 5000; + } + else + m_uiSummonTimer -= uiDiff; } - else - m_uiSummonTimer -= uiDiff; +}; + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct mob_demon_chainAI : public Scripted_NoMovementAI +{ + mob_demon_chainAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_boss_terestian_illhoof(Creature* pCreature) +{ + return new boss_terestianAI(pCreature); } CreatureAI* GetAI_npc_fiendish_portal(Creature* pCreature) @@ -325,11 +282,6 @@ CreatureAI* GetAI_mob_demon_chain(Creature* pCreature) return new mob_demon_chainAI(pCreature); } -CreatureAI* GetAI_boss_terestian_illhoof(Creature* pCreature) -{ - return new boss_terestianAI(pCreature); -} - void AddSC_boss_terestian_illhoof() { Script* pNewScript; diff --git a/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp b/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp index 0003d4b36..ebcb6db98 100644 --- a/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp +++ b/scripts/eastern_kingdoms/karazhan/bosses_opera.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Bosses_Opera -SD%Complete: 90 -SDComment: Oz, Hood, and RAJ event implemented. RAJ event requires more testing. +SD%Complete: 95 +SDComment: Oz, Hood, and RAJ event implemented. Spell timers may need adjustments. SDCategory: Karazhan EndScriptData */ @@ -28,79 +28,64 @@ EndScriptData */ /*** OPERA WIZARD OF OZ EVENT *****/ /*********************************/ -#define SAY_DOROTHEE_DEATH -1532025 -#define SAY_DOROTHEE_SUMMON -1532026 -#define SAY_DOROTHEE_TITO_DEATH -1532027 -#define SAY_DOROTHEE_AGGRO -1532028 - -#define SAY_ROAR_AGGRO -1532029 -#define SAY_ROAR_DEATH -1532030 -#define SAY_ROAR_SLAY -1532031 - -#define SAY_STRAWMAN_AGGRO -1532032 -#define SAY_STRAWMAN_DEATH -1532033 -#define SAY_STRAWMAN_SLAY -1532034 - -#define SAY_TINHEAD_AGGRO -1532035 -#define SAY_TINHEAD_DEATH -1532036 -#define SAY_TINHEAD_SLAY -1532037 -#define EMOTE_RUST -1532038 - -#define SAY_CRONE_AGGRO -1532039 -#define SAY_CRONE_AGGRO2 -1532040 -#define SAY_CRONE_DEATH -1532041 -#define SAY_CRONE_SLAY -1532042 - -/**** Spells ****/ -// Dorothee -#define SPELL_WATERBOLT 31012 -#define SPELL_SCREAM 31013 -#define SPELL_SUMMONTITO 31014 - -// Tito -#define SPELL_YIPPING 31015 - -// Strawman -#define SPELL_BRAIN_BASH 31046 -#define SPELL_BRAIN_WIPE 31069 -#define SPELL_BURNING_STRAW 31075 - -// Tinhead -#define SPELL_CLEAVE 31043 -#define SPELL_RUST 31086 - -// Roar -#define SPELL_MANGLE 31041 -#define SPELL_SHRED 31042 -#define SPELL_FRIGHTENED_SCREAM 31013 - -// Crone -#define SPELL_CHAIN_LIGHTNING 32337 - -// Cyclone -#define SPELL_KNOCKBACK 32334 -#define SPELL_CYCLONE_VISUAL 32332 - -/** Creature Entries **/ -#define CREATURE_TITO 17548 -#define CREATURE_CYCLONE 18412 -#define CREATURE_CRONE 18168 - -void SummonCroneIfReady(ScriptedInstance* pInstance, Creature* pCreature) +enum { - pInstance->SetData(DATA_OPERA_OZ_DEATHCOUNT, SPECIAL); // Increment DeathCount - - if (pInstance->GetData(DATA_OPERA_OZ_DEATHCOUNT) == 4) - { - if (Creature* pCrone = pCreature->SummonCreature(CREATURE_CRONE, -10891.96f, -1755.95f, pCreature->GetPositionZ(), 4.64f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR*2*IN_MILLISECONDS)) - { - if (pCreature->getVictim()) - pCrone->AI()->AttackStart(pCreature->getVictim()); - } - } + SAY_DOROTHEE_DEATH = -1532025, + SAY_DOROTHEE_SUMMON = -1532026, + SAY_DOROTHEE_TITO_DEATH = -1532027, + SAY_DOROTHEE_AGGRO = -1532028, + + SAY_ROAR_AGGRO = -1532029, + SAY_ROAR_DEATH = -1532030, + SAY_ROAR_SLAY = -1532031, + + SAY_STRAWMAN_AGGRO = -1532032, + SAY_STRAWMAN_DEATH = -1532033, + SAY_STRAWMAN_SLAY = -1532034, + + SAY_TINHEAD_AGGRO = -1532035, + SAY_TINHEAD_DEATH = -1532036, + SAY_TINHEAD_SLAY = -1532037, + EMOTE_RUST = -1532038, + + SAY_CRONE_AGGRO = -1532039, + SAY_CRONE_AGGRO2 = -1532040, + SAY_CRONE_DEATH = -1532041, + SAY_CRONE_SLAY = -1532042, + + /**** Spells ****/ + // Dorothee + SPELL_WATERBOLT = 31012, + SPELL_SCREAM = 31013, + SPELL_SUMMONTITO = 31014, + + // Strawman + SPELL_BRAIN_BASH = 31046, + SPELL_BRAIN_WIPE = 31069, + SPELL_CONFLAG_PROC = 31073, // procs 31075 on fire damage + + // Tinhead + SPELL_CLEAVE = 31043, + SPELL_RUST = 31086, + + // Roar + SPELL_MANGLE = 31041, + SPELL_SHRED = 31042, + SPELL_FRIGHTENED_SCREAM = 31013, + + // Crone + SPELL_CHAIN_LIGHTNING = 32337, + + // Cyclone + SPELL_CYCLONE = 32334, + SPELL_CYCLONE_VISUAL = 32332, + + /** Creature Entries **/ + NPC_TITO = 17548, + NPC_CYCLONE = 18412, }; -struct MANGOS_DLL_DECL boss_dorotheeAI : public ScriptedAI +struct boss_dorotheeAI : public ScriptedAI { boss_dorotheeAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -110,164 +95,130 @@ struct MANGOS_DLL_DECL boss_dorotheeAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 AggroTimer; + uint32 m_uiAggroTimer; + uint32 m_uiIntroTimer; - uint32 WaterBoltTimer; - uint32 FearTimer; - uint32 SummonTitoTimer; + uint32 m_uiWaterBoltTimer; + uint32 m_uiFearTimer; + uint32 m_uiSummonTitoTimer; - bool SummonedTito; - bool TitoDied; + bool m_bTitoDied; - void Reset() + void Reset() override { - AggroTimer = 500; + m_uiIntroTimer = 2000; + m_uiAggroTimer = 12000; - WaterBoltTimer = 5000; - FearTimer = 15000; - SummonTitoTimer = 47500; + m_uiWaterBoltTimer = 5000; + m_uiFearTimer = 15000; + m_uiSummonTitoTimer = 47500; - SummonedTito = false; - TitoDied = false; + m_bTitoDied = false; } - void Aggro(Unit* who) + void JustReachedHome() override { - DoScriptText(SAY_DOROTHEE_AGGRO, m_creature); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); - void JustReachedHome() - { m_creature->ForcedDespawn(); } - void SummonTito(); // See below - - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DOROTHEE_DEATH, m_creature); - - if (m_pInstance) - SummonCroneIfReady(m_pInstance, m_creature); } - void AttackStart(Unit* who) + void MoveInLineOfSight(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + // Allow a short delay before attacking + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::AttackStart(who); + ScriptedAI::MoveInLineOfSight(pWho); } - void MoveInLineOfSight(Unit* who) + void JustSummoned(Creature* pSummoned) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } - ScriptedAI::MoveInLineOfSight(who); + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_TITO) + { + DoScriptText(SAY_DOROTHEE_TITO_DEATH, m_creature); + m_bTitoDied = true; + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (AggroTimer) + if (m_uiIntroTimer) { - if (AggroTimer <= diff) + if (m_uiIntroTimer <= uiDiff) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; + DoScriptText(SAY_DOROTHEE_AGGRO, m_creature); + m_uiIntroTimer = 0; + } + else + m_uiIntroTimer -= uiDiff; + } + + if (m_uiAggroTimer) + { + if (m_uiAggroTimer <= uiDiff) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetInCombatWithZone(); + m_uiAggroTimer = 0; + } + else + m_uiAggroTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (WaterBoltTimer < diff) + if (m_uiWaterBoltTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_WATERBOLT); - - WaterBoltTimer = TitoDied ? 1500 : 5000; - }else WaterBoltTimer -= diff; - - if (FearTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SCREAM); - FearTimer = 30000; - }else FearTimer -= diff; + { + if (DoCastSpellIfCan(pTarget, SPELL_WATERBOLT) == CAST_OK) + m_uiWaterBoltTimer = m_bTitoDied ? 1500 : 5000; + } + } + else + m_uiWaterBoltTimer -= uiDiff; - if (!SummonedTito) + if (m_uiFearTimer < uiDiff) { - if (SummonTitoTimer < diff) - SummonTito(); - else SummonTitoTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SCREAM) == CAST_OK) + m_uiFearTimer = 30000; } + else + m_uiFearTimer -= uiDiff; - DoMeleeAttackIfReady(); - } -}; - -struct MANGOS_DLL_DECL mob_titoAI : public ScriptedAI -{ - mob_titoAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - ObjectGuid m_dorotheeGuid; - uint32 YipTimer; - - void Reset() - { - YipTimer = 10000; - } - - void JustDied(Unit* killer) - { - if (m_dorotheeGuid) + if (m_uiSummonTitoTimer) { - Creature* Dorothee = m_creature->GetMap()->GetCreature(m_dorotheeGuid); - if (Dorothee && Dorothee->isAlive()) + if (m_uiSummonTitoTimer <= uiDiff) { - if (boss_dorotheeAI* pDoroAI = dynamic_cast(Dorothee->AI())) - pDoroAI->TitoDied = true; - - DoScriptText(SAY_DOROTHEE_TITO_DEATH, Dorothee); + if (DoCastSpellIfCan(m_creature, SPELL_SUMMONTITO) == CAST_OK) + { + DoScriptText(SAY_DOROTHEE_SUMMON, m_creature); + m_uiSummonTitoTimer = 0; + } } + else + m_uiSummonTitoTimer -= uiDiff; } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (YipTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_YIPPING); - YipTimer = 10000; - }else YipTimer -= diff; DoMeleeAttackIfReady(); } }; -void boss_dorotheeAI::SummonTito() -{ - if (Creature* pTito = m_creature->SummonCreature(CREATURE_TITO, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) - { - DoScriptText(SAY_DOROTHEE_SUMMON, m_creature); - - if (mob_titoAI* pTitoAI = dynamic_cast(pTito->AI())) - pTitoAI->m_dorotheeGuid = m_creature->GetObjectGuid(); - - pTito->AI()->AttackStart(m_creature->getVictim()); - - SummonedTito = true; - TitoDied = false; - } -} - -struct MANGOS_DLL_DECL boss_strawmanAI : public ScriptedAI +struct boss_strawmanAI : public ScriptedAI { boss_strawmanAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -277,102 +228,98 @@ struct MANGOS_DLL_DECL boss_strawmanAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 AggroTimer; - uint32 BrainBashTimer; - uint32 BrainWipeTimer; + uint32 m_uiAggroTimer; + uint32 m_uiBrainBashTimer; + uint32 m_uiBrainWipeTimer; - void Reset() + void Reset() override { - AggroTimer = 13000; - BrainBashTimer = 5000; - BrainWipeTimer = 7000; + m_uiAggroTimer = 27000; + m_uiBrainBashTimer = 5000; + m_uiBrainWipeTimer = 7000; } - void AttackStart(Unit* who) + void MoveInLineOfSight(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::AttackStart(who); + ScriptedAI::MoveInLineOfSight(pWho); } - void MoveInLineOfSight(Unit* who) + void AttackStart(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::AttackStart(pWho); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { + DoCastSpellIfCan(m_creature, SPELL_CONFLAG_PROC); DoScriptText(SAY_STRAWMAN_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { - m_creature->ForcedDespawn(); - } - - void SpellHit(Unit* caster, const SpellEntry *Spell) - { - if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && !urand(0, 1)) - { - /* - if (not direct damage(aoe,dot)) - return; - */ + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); - DoCastSpellIfCan(m_creature, SPELL_BURNING_STRAW, true); - } + m_creature->ForcedDespawn(); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_STRAWMAN_DEATH, m_creature); - - if (m_pInstance) - SummonCroneIfReady(m_pInstance, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_STRAWMAN_SLAY, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (AggroTimer) + if (m_uiAggroTimer) { - if (AggroTimer <= diff) + if (m_uiAggroTimer <= uiDiff) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetInCombatWithZone(); + m_uiAggroTimer = 0; + } + else + m_uiAggroTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (BrainBashTimer < diff) + if (m_uiBrainBashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BRAIN_BASH); - BrainBashTimer = 15000; - }else BrainBashTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BRAIN_BASH) == CAST_OK) + m_uiBrainBashTimer = 15000; + } + else + m_uiBrainBashTimer -= uiDiff; - if (BrainWipeTimer < diff) + if (m_uiBrainWipeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_BRAIN_WIPE); - - BrainWipeTimer = 20000; - }else BrainWipeTimer -= diff; + { + if (DoCastSpellIfCan(pTarget, SPELL_BRAIN_WIPE) == CAST_OK) + m_uiBrainWipeTimer = 20000; + } + } + else + m_uiBrainWipeTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL boss_tinheadAI : public ScriptedAI +struct boss_tinheadAI : public ScriptedAI { boss_tinheadAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -382,99 +329,97 @@ struct MANGOS_DLL_DECL boss_tinheadAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 AggroTimer; - uint32 CleaveTimer; - uint32 RustTimer; - - uint8 RustCount; + uint32 m_uiAggroTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiRustTimer; - void Reset() + void Reset() override { - AggroTimer = 15000; - CleaveTimer = 5000; - RustTimer = 30000; - - RustCount = 0; + m_uiAggroTimer = 37000; + m_uiCleaveTimer = 5000; + m_uiRustTimer = 30000; } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_TINHEAD_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); + m_creature->ForcedDespawn(); } - void AttackStart(Unit* who) + void MoveInLineOfSight(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::AttackStart(who); + ScriptedAI::MoveInLineOfSight(pWho); } - void MoveInLineOfSight(Unit* who) + void AttackStart(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::AttackStart(pWho); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_TINHEAD_DEATH, m_creature); - - if (m_pInstance) - SummonCroneIfReady(m_pInstance, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_TINHEAD_SLAY, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (AggroTimer) + if (m_uiAggroTimer) { - if (AggroTimer <= diff) + if (m_uiAggroTimer <= uiDiff) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetInCombatWithZone(); + m_uiAggroTimer = 0; + } + else + m_uiAggroTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (CleaveTimer < diff) + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - CleaveTimer = 5000; - }else CleaveTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 5000; + } + else + m_uiCleaveTimer -= uiDiff; - if (RustCount < 8) + if (m_uiRustTimer < uiDiff) { - if (RustTimer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_RUST) == CAST_OK) { - if (DoCastSpellIfCan(m_creature, SPELL_RUST) == CAST_OK) - { - ++RustCount; - - DoScriptText(EMOTE_RUST, m_creature); - RustTimer = 6000; - } - }else RustTimer -= diff; + DoScriptText(EMOTE_RUST, m_creature); + m_uiRustTimer = 6000; + } } + else + m_uiRustTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL boss_roarAI : public ScriptedAI +struct boss_roarAI : public ScriptedAI { boss_roarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -484,95 +429,106 @@ struct MANGOS_DLL_DECL boss_roarAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 AggroTimer; - uint32 MangleTimer; - uint32 ShredTimer; - uint32 ScreamTimer; + uint32 m_uiAggroTimer; + uint32 m_uiMangleTimer; + uint32 m_uiShredTimer; + uint32 m_uiScreamTimer; - void Reset() + void Reset() override { - AggroTimer = 20000; - MangleTimer = 5000; - ShredTimer = 10000; - ScreamTimer = 15000; + m_uiAggroTimer = 17000; + m_uiMangleTimer = 5000; + m_uiShredTimer = 10000; + m_uiScreamTimer = 15000; } - void MoveInLineOfSight(Unit* who) + void MoveInLineOfSight(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::MoveInLineOfSight(pWho); } - void AttackStart(Unit* who) + void AttackStart(Unit* pWho) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return; - ScriptedAI::AttackStart(who); + ScriptedAI::AttackStart(pWho); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_ROAR_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); + m_creature->ForcedDespawn(); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_ROAR_DEATH, m_creature); - - if (m_pInstance) - SummonCroneIfReady(m_pInstance, m_creature); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_ROAR_SLAY, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (AggroTimer) + if (m_uiAggroTimer) { - if (AggroTimer <= diff) + if (m_uiAggroTimer <= uiDiff) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - AggroTimer = 0; - }else AggroTimer -= diff; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetInCombatWithZone(); + m_uiAggroTimer = 0; + } + else + m_uiAggroTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (MangleTimer < diff) + if (m_uiMangleTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE); - MangleTimer = urand(5000, 8000); - }else MangleTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE) == CAST_OK) + m_uiMangleTimer = urand(5000, 8000); + } + else + m_uiMangleTimer -= uiDiff; - if (ShredTimer < diff) + if (m_uiShredTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHRED); - ShredTimer = urand(10000, 15000); - }else ShredTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHRED) == CAST_OK) + m_uiShredTimer = urand(10000, 15000); + } + else + m_uiShredTimer -= uiDiff; - if (ScreamTimer < diff) + if (m_uiScreamTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FRIGHTENED_SCREAM); - ScreamTimer = urand(20000, 30000); - }else ScreamTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_FRIGHTENED_SCREAM) == CAST_OK) + m_uiScreamTimer = urand(20000, 30000); + } + else + m_uiScreamTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI +static const float afCycloneSpawnLoc[4] = { -10907.68f, -1778.651f, 90.56018f, 0.61f}; + +struct boss_croneAI : public ScriptedAI { boss_croneAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -582,28 +538,30 @@ struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 CycloneTimer; - uint32 ChainLightningTimer; + uint32 m_uiChainLightningTimer; - void Reset() + void Reset() override { - CycloneTimer = 30000; - ChainLightningTimer = 10000; + m_uiChainLightningTimer = 10000; } - void JustReachedHome() + void JustReachedHome() override { + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); + m_creature->ForcedDespawn(); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(urand(0, 1) ? SAY_CRONE_AGGRO : SAY_CRONE_AGGRO2, m_creature); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + // spawn the cyclone on aggro + m_creature->SummonCreature(NPC_CYCLONE, afCycloneSpawnLoc[0], afCycloneSpawnLoc[1], afCycloneSpawnLoc[2], afCycloneSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_CRONE_DEATH, m_creature); @@ -611,65 +569,33 @@ struct MANGOS_DLL_DECL boss_croneAI : public ScriptedAI m_pInstance->SetData(TYPE_OPERA, DONE); } - void UpdateAI(const uint32 diff) + void JustSummoned(Creature* pSummoned) override + { + pSummoned->CastSpell(pSummoned, SPELL_CYCLONE, true); + pSummoned->CastSpell(pSummoned, SPELL_CYCLONE_VISUAL, true); + pSummoned->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 15.0f); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (CycloneTimer < diff) - { - Creature* Cyclone = DoSpawnCreature(CREATURE_CYCLONE, rand()%10, rand()%10, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); - if (Cyclone) - Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_VISUAL, true); - CycloneTimer = 30000; - }else CycloneTimer -= diff; - - if (ChainLightningTimer < diff) + if (m_uiChainLightningTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING); - ChainLightningTimer = 15000; - }else ChainLightningTimer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiChainLightningTimer = 15000; + } + } + else + m_uiChainLightningTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_cycloneAI : public ScriptedAI -{ - mob_cycloneAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - uint32 MoveTimer; - - void Reset() - { - MoveTimer = 1000; - } - - void MoveInLineOfSight(Unit* who) { } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->HasAura(SPELL_KNOCKBACK, EFFECT_INDEX_0)) - DoCastSpellIfCan(m_creature, SPELL_KNOCKBACK, CAST_TRIGGERED); - - if (MoveTimer < diff) - { - float x,y,z; - m_creature->GetPosition(x,y,z); - float PosX, PosY, PosZ; - m_creature->GetRandomPoint(x,y,z,10, PosX, PosY, PosZ); - m_creature->GetMotionMaster()->MovePoint(0, PosX, PosY, PosZ); - MoveTimer = urand(5000, 8000); - }else MoveTimer -= diff; - } -}; - CreatureAI* GetAI_boss_dorothee(Creature* pCreature) { return new boss_dorotheeAI(pCreature); @@ -695,49 +621,43 @@ CreatureAI* GetAI_boss_crone(Creature* pCreature) return new boss_croneAI(pCreature); } -CreatureAI* GetAI_mob_tito(Creature* pCreature) -{ - return new mob_titoAI(pCreature); -} - -CreatureAI* GetAI_mob_cyclone(Creature* pCreature) -{ - return new mob_cycloneAI(pCreature); -} - /**************************************/ /**** Opera Red Riding Hood Event ****/ /************************************/ -/**** Yells for the Wolf ****/ -#define SAY_WOLF_AGGRO -1532043 -#define SAY_WOLF_SLAY -1532044 -#define SAY_WOLF_HOOD -1532045 -#define SOUND_WOLF_DEATH 9275 //Only sound on death, no text. - -/**** Spells For The Wolf ****/ -#define SPELL_LITTLE_RED_RIDING_HOOD 30768 -#define SPELL_TERRIFYING_HOWL 30752 -#define SPELL_WIDE_SWIPE 30761 - -#define GOSSIP_GRANDMA "What phat lewtz you have grandmother?" - -/**** The Wolf's Entry ****/ -#define CREATURE_BIG_BAD_WOLF 17521 +enum +{ + /**** Yells for the Wolf ****/ + SAY_WOLF_AGGRO = -1532043, + SAY_WOLF_SLAY = -1532044, + SAY_WOLF_HOOD = -1532045, + SOUND_WOLF_DEATH = 9275, // Only sound on death, no text. + + /**** Spells For The Wolf ****/ + SPELL_PICK_RED_RIDING_HOOD = 30769, // targeting spell - triggers 30768 + SPELL_TERRIFYING_HOWL = 30752, + SPELL_WIDE_SWIPE = 30761, + + GOSSIP_ITEM_GRANDMA = -3532005, + TEXT_ID_GRANDMA = 8990, + + /**** The Wolf's Entry ****/ + NPC_BIG_BAD_WOLF = 17521 +}; bool GossipHello_npc_grandmother(Player* pPlayer, Creature* pCreature) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_GRANDMA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(8990, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GRANDMA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_GRANDMA, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_grandmother(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_grandmother(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF) { - if (Creature* pBigBadWolf = pCreature->SummonCreature(CREATURE_BIG_BAD_WOLF, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR*2*IN_MILLISECONDS)) + if (Creature* pBigBadWolf = pCreature->SummonCreature(NPC_BIG_BAD_WOLF, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) pBigBadWolf->AI()->AttackStart(pPlayer); pCreature->ForcedDespawn(); @@ -746,7 +666,7 @@ bool GossipSelect_npc_grandmother(Player* pPlayer, Creature* pCreature, uint32 u return true; } -struct MANGOS_DLL_DECL boss_bigbadwolfAI : public ScriptedAI +struct boss_bigbadwolfAI : public ScriptedAI { boss_bigbadwolfAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -756,38 +676,31 @@ struct MANGOS_DLL_DECL boss_bigbadwolfAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 ChaseTimer; - uint32 FearTimer; - uint32 SwipeTimer; - - ObjectGuid m_hoodGuid; - float TempThreat; + uint32 m_uiRedRidingHoodTimer; + uint32 m_uiFearTimer; + uint32 m_uiSwipeTimer; - bool IsChasing; - - void Reset() + void Reset() override { - ChaseTimer = 30000; - FearTimer = urand(25000, 35000); - SwipeTimer = 5000; - - m_hoodGuid.Clear(); - TempThreat = 0; - - IsChasing = false; + m_uiRedRidingHoodTimer = 30000; + m_uiFearTimer = urand(25000, 35000); + m_uiSwipeTimer = 5000; } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_WOLF_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); + m_creature->ForcedDespawn(); } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoPlaySoundToSet(m_creature, SOUND_WOLF_DEATH); @@ -795,65 +708,39 @@ struct MANGOS_DLL_DECL boss_bigbadwolfAI : public ScriptedAI m_pInstance->SetData(TYPE_OPERA, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); - - if (ChaseTimer < diff) + if (m_uiRedRidingHoodTimer < uiDiff) { - if (!IsChasing) + if (DoCastSpellIfCan(m_creature, SPELL_PICK_RED_RIDING_HOOD) == CAST_OK) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_LITTLE_RED_RIDING_HOOD, SELECT_FLAG_PLAYER)) - { - DoScriptText(SAY_WOLF_HOOD, m_creature); - DoCastSpellIfCan(target, SPELL_LITTLE_RED_RIDING_HOOD, CAST_TRIGGERED); - - TempThreat = m_creature->getThreatManager().getThreat(target); - if (TempThreat) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - m_hoodGuid = target->GetObjectGuid(); - m_creature->AddThreat(target, 1000000.0f); - ChaseTimer = 20000; - IsChasing = true; - } - } - else - { - IsChasing = false; - - if (Player* target = m_creature->GetMap()->GetPlayer(m_hoodGuid)) - { - m_hoodGuid.Clear(); - - if (m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - m_creature->AddThreat(target, TempThreat); - TempThreat = 0; - } - - ChaseTimer = 40000; + DoScriptText(SAY_WOLF_HOOD, m_creature); + m_uiRedRidingHoodTimer = 30000; } - }else ChaseTimer -= diff; - - if (IsChasing) - return; + } + else + m_uiRedRidingHoodTimer -= uiDiff; - if (FearTimer < diff) + if (m_uiFearTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TERRIFYING_HOWL); - FearTimer = urand(25000, 35000); - }else FearTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_TERRIFYING_HOWL) == CAST_OK) + m_uiFearTimer = 24000; + } + else + m_uiFearTimer -= uiDiff; - if (SwipeTimer < diff) + if (m_uiSwipeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_WIDE_SWIPE); - SwipeTimer = urand(25000, 30000); - }else SwipeTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_WIDE_SWIPE) == CAST_OK) + m_uiSwipeTimer = urand(25000, 30000); + } + else + m_uiSwipeTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; @@ -866,582 +753,519 @@ CreatureAI* GetAI_boss_bigbadwolf(Creature* pCreature) /******** Opera Romeo and Juliet Event *******/ /********************************************/ -/**** Speech *****/ -#define SAY_JULIANNE_AGGRO -1532046 -#define SAY_JULIANNE_ENTER -1532047 -#define SAY_JULIANNE_DEATH01 -1532048 -#define SAY_JULIANNE_DEATH02 -1532049 -#define SAY_JULIANNE_RESURRECT -1532050 -#define SAY_JULIANNE_SLAY -1532051 - -#define SAY_ROMULO_AGGRO -1532052 -#define SAY_ROMULO_DEATH -1532053 -#define SAY_ROMULO_ENTER -1532054 -#define SAY_ROMULO_RESURRECT -1532055 -#define SAY_ROMULO_SLAY -1532056 - -/***** Spells For Julianne *****/ -#define SPELL_BLINDING_PASSION 30890 -#define SPELL_DEVOTION 30887 -#define SPELL_ETERNAL_AFFECTION 30878 -#define SPELL_POWERFUL_ATTRACTION 30889 -#define SPELL_DRINK_POISON 30907 - -/***** Spells For Romulo ****/ -#define SPELL_BACKWARD_LUNGE 30815 -#define SPELL_DARING 30841 -#define SPELL_DEADLY_SWATHE 30817 -#define SPELL_POISON_THRUST 30822 - -/**** Other Misc. Spells ****/ -#define SPELL_UNDYING_LOVE 30951 -#define SPELL_RES_VISUAL 24171 - -/*** Misc. Information ****/ -#define CREATURE_ROMULO 17533 -#define ROMULO_X -10900 -#define ROMULO_Y -1758 - -enum RAJPhase +enum +{ + /**** Speech *****/ + SAY_JULIANNE_AGGRO = -1532046, + SAY_JULIANNE_ENTER = -1532047, + SAY_JULIANNE_DEATH01 = -1532048, + SAY_JULIANNE_DEATH02 = -1532049, + SAY_JULIANNE_RESURRECT = -1532050, + SAY_JULIANNE_SLAY = -1532051, + + SAY_ROMULO_AGGRO = -1532052, + SAY_ROMULO_DEATH = -1532053, + SAY_ROMULO_ENTER = -1532054, + SAY_ROMULO_RESURRECT = -1532055, + SAY_ROMULO_SLAY = -1532056, + + /***** Spells For Julianne *****/ + SPELL_BLINDING_PASSION = 30890, + SPELL_DEVOTION = 30887, + SPELL_ETERNAL_AFFECTION = 30878, + SPELL_POWERFUL_ATTRACTION = 30889, + SPELL_DRINK_POISON = 30907, + + /***** Spells For Romulo ****/ + SPELL_BACKWARD_LUNGE = 30815, + SPELL_DARING = 30841, + SPELL_DEADLY_SWATHE = 30817, + SPELL_POISON_THRUST = 30822, + + /**** Other Misc. Spells ****/ + SPELL_FULL_HEALTH = 43979, // res effect on Julianne + SPELL_UNDYING_LOVE = 30951, // res effect on Romulo +}; + +enum OperaPhase { PHASE_JULIANNE = 0, PHASE_ROMULO = 1, PHASE_BOTH = 2, }; -void PretendToDie(Creature* pCreature) -{ - pCreature->InterruptNonMeleeSpells(true); - pCreature->RemoveAllAuras(); - pCreature->SetHealth(0); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pCreature->GetMotionMaster()->MovementExpired(false); - pCreature->GetMotionMaster()->MoveIdle(); - pCreature->SetStandState(UNIT_STAND_STATE_DEAD); -}; +static const float afRomuloSpawnLoc[4] = { -10893.62f, -1760.78f, 90.55f, 4.76f}; -void Resurrect(Creature* target) -{ - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - target->SetHealth(target->GetMaxHealth()); - target->SetStandState(UNIT_STAND_STATE_STAND); - target->CastSpell(target, SPELL_RES_VISUAL, true); - if (target->getVictim()) - { - target->GetMotionMaster()->MoveChase(target->getVictim()); - target->AI()->AttackStart(target->getVictim()); - } - else - target->GetMotionMaster()->Initialize(); -}; - -struct MANGOS_DLL_DECL boss_julianneAI : public ScriptedAI +struct boss_julianneAI : public ScriptedAI { boss_julianneAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - EntryYellTimer = 1000; - AggroYellTimer = 10000; - IsFakingDeath = false; Reset(); } ScriptedInstance* m_pInstance; - uint32 EntryYellTimer; - uint32 AggroYellTimer; - - ObjectGuid m_romuloGuid; - uint32 Phase; + OperaPhase m_Phase; - uint32 BlindingPassionTimer; - uint32 DevotionTimer; - uint32 EternalAffectionTimer; - uint32 PowerfulAttractionTimer; - uint32 SummonRomuloTimer; - uint32 ResurrectTimer; - uint32 DrinkPoisonTimer; - uint32 ResurrectSelfTimer; + uint32 m_uiBlindingPassionTimer; + uint32 m_uiDevotionTimer; + uint32 m_uiEternalAffectionTimer; + uint32 m_uiPowerfulAttractionTimer; + uint32 m_uiSummonRomuloTimer; + uint32 m_uiResurrectSelfTimer; - bool IsFakingDeath; - bool SummonedRomulo; - bool RomuloDead; + bool m_bIsFakingDeath; - void Reset() + void Reset() override { - m_romuloGuid.Clear(); - Phase = PHASE_JULIANNE; + m_Phase = PHASE_JULIANNE; - BlindingPassionTimer = 30000; - DevotionTimer = 15000; - EternalAffectionTimer = 25000; - PowerfulAttractionTimer = 5000; - SummonRomuloTimer = 10000; - ResurrectTimer = 10000; - DrinkPoisonTimer = 0; - ResurrectSelfTimer = 0; + m_uiBlindingPassionTimer = 30000; + m_uiDevotionTimer = 15000; + m_uiEternalAffectionTimer = 25000; + m_uiPowerfulAttractionTimer = 5000; + m_uiSummonRomuloTimer = 0; + m_uiResurrectSelfTimer = 0; - if (IsFakingDeath) - { - Resurrect(m_creature); - IsFakingDeath = false; - } + m_bIsFakingDeath = false; + } - SummonedRomulo = false; - RomuloDead = false; + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_JULIANNE_AGGRO, m_creature); } - void AttackStart(Unit* who) + void JustReachedHome() override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); - ScriptedAI::AttackStart(who); + m_creature->ForcedDespawn(); } - void MoveInLineOfSight(Unit* who) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + if (uiDamage < m_creature->GetHealth()) return; - ScriptedAI::MoveInLineOfSight(who); - } + uiDamage = 0; - void JustReachedHome() - { - m_creature->ForcedDespawn(); - } + if (m_bIsFakingDeath) + return; - void SpellHit(Unit* caster, const SpellEntry *Spell) - { - if (Spell->Id == SPELL_DRINK_POISON) + if (m_Phase == PHASE_JULIANNE) { - DoScriptText(SAY_JULIANNE_DEATH01, m_creature); - DrinkPoisonTimer = 2500; + // Prepare fake death + if (DoCastSpellIfCan(m_creature, SPELL_DRINK_POISON, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + m_Phase = PHASE_BOTH; + m_bIsFakingDeath = true; + m_uiSummonRomuloTimer = 12000; + } + } + else if (m_Phase == PHASE_BOTH) + { + // set fake death and allow 10 sec timer to kill Romulos + DoScriptText(SAY_JULIANNE_DEATH02, m_creature); + DoSetFakeDeath(); + m_uiResurrectSelfTimer = 10000; } } - void DamageTaken(Unit* done_by, uint32 &damage); - - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { - DoScriptText(SAY_JULIANNE_DEATH02, m_creature); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); if (m_pInstance) m_pInstance->SetData(TYPE_OPERA, DONE); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* pVictim) override { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + DoScriptText(SAY_JULIANNE_SLAY, m_creature); } - void UpdateAI(const uint32 diff); -}; - -struct MANGOS_DLL_DECL boss_romuloAI : public ScriptedAI -{ - boss_romuloAI(Creature* pCreature) : ScriptedAI(pCreature) + void JustSummoned(Creature* pSummoned) override { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - EntryYellTimer = 8000; - AggroYellTimer = 15000; + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - ScriptedInstance* m_pInstance; - - ObjectGuid m_julianneGuid; - uint32 Phase; - - uint32 EntryYellTimer; - uint32 AggroYellTimer; - uint32 BackwardLungeTimer; - uint32 DaringTimer; - uint32 DeadlySwatheTimer; - uint32 PoisonThrustTimer; - uint32 ResurrectTimer; - - bool IsFakingDeath; - bool JulianneDead; - - void Reset() + // Wrapper to set fake death + void DoSetFakeDeath() { - m_julianneGuid.Clear(); - Phase = PHASE_ROMULO; - - BackwardLungeTimer = 15000; - DaringTimer = 20000; - DeadlySwatheTimer = 25000; - PoisonThrustTimer = 10000; - ResurrectTimer = 10000; + m_bIsFakingDeath = true; - IsFakingDeath = false; - JulianneDead = false; + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); } - void JustReachedHome() + // Wrapper to remove fake death + void DoRemoveFakeDeath() { - m_creature->ForcedDespawn(); - } + m_bIsFakingDeath = false; - void DamageTaken(Unit* done_by, uint32 &damage); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); + } - void Aggro(Unit* who) + // Wrapper to start phase 3 + void DoHandleRomuloResurrect() { - DoScriptText(SAY_ROMULO_AGGRO, m_creature); - - if (m_julianneGuid) + if (DoCastSpellIfCan(m_creature, SPELL_UNDYING_LOVE) == CAST_OK) { - Creature* Julianne = m_creature->GetMap()->GetCreature(m_julianneGuid); - - if (Julianne && Julianne->getVictim()) - m_creature->AddThreat(Julianne->getVictim()); + DoCastSpellIfCan(m_creature, SPELL_FULL_HEALTH, CAST_TRIGGERED); + DoScriptText(SAY_JULIANNE_RESURRECT, m_creature); + DoRemoveFakeDeath(); } } - void MoveInLineOfSight(Unit* who) - { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustDied(Unit* killer) - { - DoScriptText(SAY_ROMULO_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_OPERA, DONE); - } - - void KilledUnit(Unit* victim) - { - DoScriptText(SAY_ROMULO_SLAY, m_creature); - } - - void UpdateAI(const uint32 diff); -}; - -void boss_julianneAI::DamageTaken(Unit* done_by, uint32 &damage) -{ - if (damage < m_creature->GetHealth()) - return; - - //anything below only used if incoming damage will kill - - if (Phase == PHASE_JULIANNE) - { - damage = 0; - - //this means already drinking, so return - if (IsFakingDeath) - return; - - m_creature->InterruptNonMeleeSpells(true); - DoCastSpellIfCan(m_creature, SPELL_DRINK_POISON); - - IsFakingDeath = true; - return; - } - - if (Phase == PHASE_ROMULO) - { - error_log("SD2: boss_julianneAI: cannot take damage in PHASE_ROMULO, why was i here?"); - damage = 0; - return; - } - - if (Phase == PHASE_BOTH) + void UpdateAI(const uint32 uiDiff) override { - //if this is true then we have to kill romulo too - if (RomuloDead) + // spawn Romulo on timer after fake death + if (m_uiSummonRomuloTimer) { - if (Creature* Romulo = m_creature->GetMap()->GetCreature(m_romuloGuid)) + if (m_uiSummonRomuloTimer <= uiDiff) { - Romulo->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Romulo->GetMotionMaster()->Clear(); - Romulo->SetDeathState(JUST_DIED); - Romulo->CombatStop(true); - Romulo->DeleteThreatList(); - Romulo->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + m_creature->SummonCreature(NPC_ROMULO, afRomuloSpawnLoc[0], afRomuloSpawnLoc[1], afRomuloSpawnLoc[2], afRomuloSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiSummonRomuloTimer = 0; } - return; + else + m_uiSummonRomuloTimer -= uiDiff; } - //if not already returned, then romulo is alive and we can pretend die - if (Creature* Romulo = m_creature->GetMap()->GetCreature(m_romuloGuid)) + if (m_uiResurrectSelfTimer) { - PretendToDie(m_creature); - IsFakingDeath = true; - - if (boss_romuloAI* pRomAI = dynamic_cast(Romulo->AI())) + if (m_uiResurrectSelfTimer <= uiDiff) { - pRomAI->ResurrectTimer = 10000; - pRomAI->JulianneDead = true; + if (m_pInstance) + { + if (Creature* pRomulo = m_pInstance->GetSingleCreatureFromStorage(NPC_ROMULO)) + { + // if Romulos is dead, then self kill + if (pRomulo->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + pRomulo->DealDamage(pRomulo, pRomulo->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + else + { + DoRemoveFakeDeath(); + DoCastSpellIfCan(m_creature, SPELL_FULL_HEALTH, CAST_TRIGGERED); + } + } + } + m_uiResurrectSelfTimer = 0; } - - damage = 0; - return; + else + m_uiResurrectSelfTimer -= uiDiff; } - } - error_log("SD2: boss_julianneAI: DamageTaken reach end of code, that should not happen."); -} - -void boss_romuloAI::DamageTaken(Unit* done_by, uint32 &damage) -{ - if (damage < m_creature->GetHealth()) - return; - - //anything below only used if incoming damage will kill + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - if (Phase == PHASE_ROMULO) - { - DoScriptText(SAY_ROMULO_DEATH, m_creature); - PretendToDie(m_creature); - IsFakingDeath = true; - Phase = PHASE_BOTH; + // don't use spells during transition + if (m_bIsFakingDeath) + return; - if (Creature* Julianne = m_creature->GetMap()->GetCreature(m_julianneGuid)) + if (m_uiBlindingPassionTimer < uiDiff) { - if (boss_julianneAI* pJulAI = dynamic_cast(Julianne->AI())) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - pJulAI->ResurrectSelfTimer = 10000; - pJulAI->RomuloDead = true; + if (DoCastSpellIfCan(pTarget, SPELL_BLINDING_PASSION) == CAST_OK) + m_uiBlindingPassionTimer = urand(30000, 45000); } } + else + m_uiBlindingPassionTimer -= uiDiff; - damage = 0; - return; - } + if (m_uiDevotionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEVOTION) == CAST_OK) + m_uiDevotionTimer = urand(15000, 45000); + } + else + m_uiDevotionTimer -= uiDiff; - if (Phase == PHASE_BOTH) - { - if (JulianneDead) + if (m_uiPowerfulAttractionTimer < uiDiff) { - if (Creature* Julianne = m_creature->GetMap()->GetCreature(m_julianneGuid)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - Julianne->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Julianne->GetMotionMaster()->Clear(); - Julianne->SetDeathState(JUST_DIED); - Julianne->CombatStop(true); - Julianne->DeleteThreatList(); - Julianne->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + if (DoCastSpellIfCan(pTarget, SPELL_POWERFUL_ATTRACTION) == CAST_OK) + m_uiPowerfulAttractionTimer = urand(5000, 30000); } - return; } + else + m_uiPowerfulAttractionTimer -= uiDiff; - if (Creature* Julianne = m_creature->GetMap()->GetCreature(m_julianneGuid)) + if (m_uiEternalAffectionTimer < uiDiff) { - PretendToDie(m_creature); - IsFakingDeath = true; - - if (boss_julianneAI* pJulAI = dynamic_cast(Julianne->AI())) + if (Unit* pTarget = DoSelectLowestHpFriendly(30.0f)) { - pJulAI->ResurrectTimer = 10000; - pJulAI->RomuloDead = true; + if (DoCastSpellIfCan(pTarget, SPELL_ETERNAL_AFFECTION) == CAST_OK) + m_uiEternalAffectionTimer = urand(45000, 60000); } - - damage = 0; - return; } - } + else + m_uiEternalAffectionTimer -= uiDiff; - error_log("SD2: boss_romuloAI: DamageTaken reach end of code, that should not happen."); -} + DoMeleeAttackIfReady(); + } +}; -void boss_julianneAI::UpdateAI(const uint32 diff) +bool EffectDummyCreature_spell_drink_poison(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - if (EntryYellTimer) + // always check spellid and effectindex + if (uiSpellId == SPELL_DRINK_POISON && uiEffIndex == EFFECT_INDEX_0) { - if (EntryYellTimer <= diff) - { - DoScriptText(SAY_JULIANNE_ENTER, m_creature); - EntryYellTimer = 0; - }else EntryYellTimer -= diff; - } + // Set fake death on poison + if (boss_julianneAI* pJulianneAI = dynamic_cast(pCreatureTarget->AI())) + pJulianneAI->DoSetFakeDeath(); - if (AggroYellTimer) - { - if (AggroYellTimer <= diff) - { - DoScriptText(SAY_JULIANNE_AGGRO, m_creature); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->setFaction(16); - AggroYellTimer = 0; - }else AggroYellTimer -= diff; + DoScriptText(SAY_JULIANNE_DEATH01, pCreatureTarget); + + // always return true when we are handling this spell and effect + return true; } - if (DrinkPoisonTimer) + return false; +} + +struct boss_romuloAI : public ScriptedAI +{ + boss_romuloAI(Creature* pCreature) : ScriptedAI(pCreature) { - //will do this 2secs after spell hit. this is time to display visual as expected - if (DrinkPoisonTimer <= diff) - { - PretendToDie(m_creature); - Phase = PHASE_ROMULO; - SummonRomuloTimer = 10000; - DrinkPoisonTimer = 0; - }else DrinkPoisonTimer -= diff; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); } - if (Phase == PHASE_ROMULO && !SummonedRomulo) - { - if (SummonRomuloTimer < diff) - { - if (Creature* pRomulo = m_creature->SummonCreature(CREATURE_ROMULO, ROMULO_X, ROMULO_Y, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR*2*IN_MILLISECONDS)) - { - m_romuloGuid = pRomulo->GetObjectGuid(); + ScriptedInstance* m_pInstance; - if (boss_romuloAI* pRomAI = dynamic_cast(pRomulo->AI())) - { - pRomAI->m_julianneGuid = m_creature->GetObjectGuid(); - pRomAI->Phase = PHASE_ROMULO; - } + OperaPhase m_Phase; - //why? - pRomulo->setFaction(16); + uint32 m_uiBackwardLungeTimer; + uint32 m_uiDaringTimer; + uint32 m_uiDeadlySwatheTimer; + uint32 m_uiPoisonThrustTimer; + uint32 m_uiResurrectTimer; + uint32 m_uiResurrectSelfTimer; - pRomulo->SetInCombatWithZone(); - } - SummonedRomulo = true; - }else SummonRomuloTimer -= diff; - } + bool m_bIsFakingDeath; - if (ResurrectSelfTimer) + void Reset() override { - if (ResurrectSelfTimer <= diff) - { - Resurrect(m_creature); - Phase = PHASE_BOTH; - IsFakingDeath = false; + m_Phase = PHASE_ROMULO; - if (m_creature->getVictim()) - AttackStart(m_creature->getVictim()); + m_uiBackwardLungeTimer = 15000; + m_uiDaringTimer = 20000; + m_uiDeadlySwatheTimer = 25000; + m_uiPoisonThrustTimer = 10000; + m_uiResurrectTimer = 0; + m_uiResurrectSelfTimer = 0; - ResurrectSelfTimer = 0; - ResurrectTimer = 1000; - }else ResurrectSelfTimer -= diff; + m_bIsFakingDeath = false; } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || IsFakingDeath) - return; + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, FAIL); + + m_creature->ForcedDespawn(); + } - if (RomuloDead) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (ResurrectTimer < diff) - { - Creature* pRomulo = m_creature->GetMap()->GetCreature(m_romuloGuid); - boss_romuloAI* pRomAI = dynamic_cast(pRomulo->AI()); + if (uiDamage < m_creature->GetHealth()) + return; - if (pRomulo && pRomAI && pRomAI->IsFakingDeath) - { - DoScriptText(SAY_JULIANNE_RESURRECT, m_creature); - Resurrect(pRomulo); + uiDamage = 0; - pRomAI->IsFakingDeath = false; + if (m_Phase == PHASE_ROMULO) + { + DoScriptText(SAY_ROMULO_DEATH, m_creature); + DoSetFakeDeath(); + m_Phase = PHASE_BOTH; + m_uiResurrectTimer = 10000; + } + else if (m_Phase == PHASE_BOTH) + { + // set fake death and allow 10 sec timer to kill Julianne + DoSetFakeDeath(); + m_uiResurrectSelfTimer = 10000; + } + } - RomuloDead = false; - ResurrectTimer = 10000; - } - }else ResurrectTimer -= diff; + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_ROMULO_AGGRO, m_creature); } - if (BlindingPassionTimer < diff) + void JustDied(Unit* /*pKiller*/) override { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_BLINDING_PASSION); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - BlindingPassionTimer = urand(30000, 45000); - } else BlindingPassionTimer -= diff; + if (m_pInstance) + m_pInstance->SetData(TYPE_OPERA, DONE); + } - if (DevotionTimer < diff) + void KilledUnit(Unit* pVictim) override { - DoCastSpellIfCan(m_creature, SPELL_DEVOTION); - DevotionTimer = urand(15000, 45000); - } else DevotionTimer -= diff; + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; - if (PowerfulAttractionTimer < diff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_POWERFUL_ATTRACTION); + DoScriptText(SAY_ROMULO_SLAY, m_creature); + } - PowerfulAttractionTimer = urand(5000, 30000); - } else PowerfulAttractionTimer -= diff; + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // remove fake death on res + if (pSpell->Id == SPELL_UNDYING_LOVE && pCaster->GetEntry() == NPC_JULIANNE) + DoRemoveFakeDeath(); + } - if (EternalAffectionTimer < diff) + // Wrapper to set fake death + void DoSetFakeDeath() { - if (urand(0, 1) && SummonedRomulo) - { - Creature* Romulo = m_creature->GetMap()->GetCreature(m_romuloGuid); - if (Romulo && Romulo->isAlive() && !RomuloDead) - DoCastSpellIfCan(Romulo, SPELL_ETERNAL_AFFECTION); - } else DoCastSpellIfCan(m_creature, SPELL_ETERNAL_AFFECTION); + m_bIsFakingDeath = true; - EternalAffectionTimer = urand(45000, 60000); - } else EternalAffectionTimer -= diff; + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + } - DoMeleeAttackIfReady(); -} + // Wrapper to remove fake death + void DoRemoveFakeDeath() + { + m_bIsFakingDeath = false; -void boss_romuloAI::UpdateAI(const uint32 diff) -{ - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || IsFakingDeath) - return; + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); + } - if (JulianneDead) + void UpdateAI(const uint32 uiDiff) override { - if (ResurrectTimer < diff) + // Resurrect both of them at the beginning of phase 3 + if (m_uiResurrectTimer) { - Creature* pJulianne = m_creature->GetMap()->GetCreature(m_julianneGuid); - boss_julianneAI* pJulAI = dynamic_cast(pJulianne->AI()); + if (m_uiResurrectTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pJulianne = m_pInstance->GetSingleCreatureFromStorage(NPC_JULIANNE)) + { + if (boss_julianneAI* pJulianneAI = dynamic_cast(pJulianne->AI())) + pJulianneAI->DoHandleRomuloResurrect(); + } + } + m_uiResurrectTimer = 0; + } + else + m_uiResurrectTimer -= uiDiff; + } - if (pJulianne && pJulAI && pJulAI->IsFakingDeath) + if (m_uiResurrectSelfTimer) + { + if (m_uiResurrectSelfTimer <= uiDiff) { - DoScriptText(SAY_ROMULO_RESURRECT, m_creature); - Resurrect(pJulianne); + if (m_pInstance) + { + if (Creature* pJulianne = m_pInstance->GetSingleCreatureFromStorage(NPC_JULIANNE)) + { + // if Julianne is dead, then self kill + if (pJulianne->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + pJulianne->DealDamage(pJulianne, pJulianne->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + else + { + DoRemoveFakeDeath(); + DoScriptText(SAY_ROMULO_RESURRECT, m_creature); + DoCastSpellIfCan(m_creature, SPELL_FULL_HEALTH, CAST_TRIGGERED); + } + } + } + m_uiResurrectSelfTimer = 0; + } + else + m_uiResurrectSelfTimer -= uiDiff; + } - pJulAI->IsFakingDeath = false; + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - JulianneDead = false; - ResurrectTimer = 10000; - } - } else ResurrectTimer -= diff; - } + // don't use spells on fake death + if (m_bIsFakingDeath) + return; - if (BackwardLungeTimer < diff) - { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (target && !m_creature->HasInArc(M_PI_F, target)) + if (m_uiBackwardLungeTimer < uiDiff) { - DoCastSpellIfCan(target, SPELL_BACKWARD_LUNGE); - BackwardLungeTimer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_BACKWARD_LUNGE) == CAST_OK) + m_uiBackwardLungeTimer = urand(15000, 30000); } - }else BackwardLungeTimer -= diff; - - if (DaringTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_DARING); - DaringTimer = urand(20000, 40000); - }else DaringTimer -= diff; + else + m_uiBackwardLungeTimer -= uiDiff; - if (DeadlySwatheTimer < diff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_DEADLY_SWATHE); + if (m_uiDaringTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARING) == CAST_OK) + m_uiDaringTimer = urand(20000, 40000); + } + else + m_uiDaringTimer -= uiDiff; - DeadlySwatheTimer = urand(15000, 25000); - }else DeadlySwatheTimer -= diff; + if (m_uiDeadlySwatheTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEADLY_SWATHE) == CAST_OK) + m_uiDeadlySwatheTimer = urand(15000, 25000); + } + } + else + m_uiDeadlySwatheTimer -= uiDiff; - if (PoisonThrustTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISON_THRUST); - PoisonThrustTimer = urand(10000, 20000); - }else PoisonThrustTimer -= diff; + if (m_uiPoisonThrustTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISON_THRUST) == CAST_OK) + m_uiPoisonThrustTimer = urand(10000, 20000); + } + else + m_uiPoisonThrustTimer -= uiDiff; - DoMeleeAttackIfReady(); -} + DoMeleeAttackIfReady(); + } +}; CreatureAI* GetAI_boss_julianne(Creature* pCreature) { @@ -1459,60 +1283,51 @@ void AddSC_bosses_opera() // Oz pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_dorothee; pNewScript->Name = "boss_dorothee"; + pNewScript->GetAI = &GetAI_boss_dorothee; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_strawman; pNewScript->Name = "boss_strawman"; + pNewScript->GetAI = &GetAI_boss_strawman; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_tinhead; pNewScript->Name = "boss_tinhead"; + pNewScript->GetAI = &GetAI_boss_tinhead; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_roar; pNewScript->Name = "boss_roar"; + pNewScript->GetAI = &GetAI_boss_roar; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_crone; pNewScript->Name = "boss_crone"; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->GetAI = &GetAI_mob_tito; - pNewScript->Name = "mob_tito"; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->GetAI = &GetAI_mob_cyclone; - pNewScript->Name = "mob_cyclone"; + pNewScript->GetAI = &GetAI_boss_crone; pNewScript->RegisterSelf(); // Hood pNewScript = new Script; + pNewScript->Name = "npc_grandmother"; pNewScript->pGossipHello = &GossipHello_npc_grandmother; pNewScript->pGossipSelect = &GossipSelect_npc_grandmother; - pNewScript->Name = "npc_grandmother"; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_bigbadwolf; pNewScript->Name = "boss_bigbadwolf"; + pNewScript->GetAI = &GetAI_boss_bigbadwolf; pNewScript->RegisterSelf(); // Romeo And Juliet pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_julianne; pNewScript->Name = "boss_julianne"; + pNewScript->GetAI = &GetAI_boss_julianne; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_drink_poison; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->GetAI = &GetAI_boss_romulo; pNewScript->Name = "boss_romulo"; + pNewScript->GetAI = &GetAI_boss_romulo; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/chess_event.cpp b/scripts/eastern_kingdoms/karazhan/chess_event.cpp index 7f1373f99..25d49f891 100644 --- a/scripts/eastern_kingdoms/karazhan/chess_event.cpp +++ b/scripts/eastern_kingdoms/karazhan/chess_event.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,1750 @@ /* ScriptData SDName: chess_event -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 80 +SDComment: Chess AI could use some improvements. SDCategory: Karazhan EndScriptData */ #include "precompiled.h" +#include "karazhan.h" + +enum +{ + // texts + EMOTE_LIFT_CURSE = -1532131, + EMOTE_CHEAT = -1532132, + + SOUND_ID_GAME_BEGIN = 10338, + SOUND_ID_LOSE_PAWN_PLAYER_1 = 10339, + SOUND_ID_LOSE_PAWN_PLAYER_2 = 10340, + SOUND_ID_LOSE_PAWN_PLAYER_3 = 10341, + SOUND_ID_LOSE_PAWN_MEDIVH_1 = 10342, + SOUND_ID_LOSE_PAWN_MEDIVH_2 = 10343, + SOUND_ID_LOSE_PAWN_MEDIVH_3 = 10344, + SOUND_ID_LOSE_ROOK_PLAYER = 10345, + SOUND_ID_LOSE_ROOK_MEDIVH = 10346, + SOUND_ID_LOSE_BISHOP_PLAYER = 10347, + SOUND_ID_LOSE_BISHOP_MEDIVH = 10348, + SOUND_ID_LOSE_KNIGHT_PLAYER = 10349, + SOUND_ID_LOSE_KNIGHT_MEDIVH = 10350, + SOUND_ID_LOSE_QUEEN_PLAYER = 10351, + SOUND_ID_LOSE_QUEEN_MEDIVH = 10352, + SOUND_ID_CHECK_PLAYER = 10353, + SOUND_ID_CHECK_MEDIVH = 10354, + SOUND_ID_WIN_PLAYER = 10355, + SOUND_ID_WIN_MEDIVH = 10356, + SOUND_ID_CHEAT_1 = 10357, + SOUND_ID_CHEAT_2 = 10358, + SOUND_ID_CHEAT_3 = 10359, + + // movement spells + SPELL_MOVE_GENERIC = 30012, // spell which sends the signal to move - handled in core + SPELL_MOVE_1 = 32312, // spell which selects AI move square (for short range pieces) + SPELL_MOVE_2 = 37388, // spell which selects AI move square (for long range pieces) + // SPELL_MOVE_PAWN = 37146, // individual move spells (used only by controlled npcs) + // SPELL_MOVE_KNIGHT = 37144, + // SPELL_MOVE_QUEEN = 37148, + // SPELL_MOVE_ROCK = 37151, + // SPELL_MOVE_BISHOP = 37152, + // SPELL_MOVE_KING = 37153, + + // additional movement spells + SPELL_CHANGE_FACING = 30284, // spell which sends the initial facing request - handled in core + SPELL_FACE_SQUARE = 30270, // change facing - finalize facing update + + SPELL_MOVE_TO_SQUARE = 30253, // spell which sends the move response from the square to the piece + SPELL_MOVE_COOLDOWN = 30543, // add some cooldown to movement + SPELL_MOVE_MARKER = 32261, // white beam visual - used to mark the movement as complete + SPELL_DISABLE_SQUARE = 32745, // used by the White / Black triggers on the squares when a chess piece moves into place + SPELL_IS_SQUARE_USED = 39400, // cast when a chess piece moves to another square + // SPELL_SQUARED_OCCUPIED = 39399, // triggered by 39400; used to check if the square is occupied (if hits a target); Missing in 2.4.3 + + // generic spells + SPELL_IN_GAME = 30532, // teleport player near the entrance + SPELL_CONTROL_PIECE = 30019, // control a chess piece + SPELL_RECENTLY_IN_GAME = 30529, // debuff on player after chess piece uncharm + + SPELL_CHESS_AI_ATTACK_TIMER = 32226, // melee action timer - triggers 32225 + SPELL_ACTION_MELEE = 32225, // handle melee attacks + SPELL_MELEE_DAMAGE = 32247, // melee damage spell - used by all chess pieces + // SPELL_AI_SNAPSHOT_TIMER = 37440, // used to trigger spell 32260; purpose and usage unk + // SPELL_DISABLE_SQUARE_SELF = 32260, // used when a piece moves to another square + // SPELL_AI_ACTION_TIMER = 37504, // handle some kind of event check. Cast by npc 17459. Currently the way it works is unk + // SPELL_DISABLE_SQUARE = 30271, // not used + // SPELL_FIND_ENEMY = 32303, // not used + // SPELL_MOVE_NEAR_UNIT = 30417, // not used + // SPELL_GET_EMPTY_SQUARE = 30418, // not used + // SPELL_FACE_NEARBY_ENEMY = 37787, // not used + // SPELL_POST_MOVE_FACING = 38011, // not used + + // melee action spells + SPELL_MELEE_FOOTMAN = 32227, + SPELL_MELEE_WATER_ELEM = 37142, + SPELL_MELEE_CHARGER = 37143, + SPELL_MELEE_CLERIC = 37147, + SPELL_MELEE_CONJURER = 37149, + SPELL_MELEE_KING_LLANE = 37150, + SPELL_MELEE_GRUNT = 32228, + SPELL_MELEE_DAEMON = 37220, + SPELL_MELEE_NECROLYTE = 37337, + SPELL_MELEE_WOLF = 37339, + SPELL_MELEE_WARLOCK = 37345, + SPELL_MELEE_WARCHIEF_BLACKHAND = 37348, + + // cheat spells + SPELL_HAND_OF_MEDIVH_HORDE = 39338, // triggers 39339 + SPELL_HAND_OF_MEDIVH_ALLIANCE = 39342, // triggers 39339 + SPELL_FURY_OF_MEDIVH_HORDE = 39341, // triggers 39343 + SPELL_FURY_OF_MEDIVH_ALLIANCE = 39344, // triggers 39345 + SPELL_FURY_OF_MEDIVH_AURA = 39383, + // SPELL_FULL_HEAL_HORDE = 39334, // spells are not confirmed (probably removed after 2.4.3) + // SPELL_FULL_HEAL_ALLIANCE = 39335, + + // spells used by the chess npcs + SPELL_HEROISM = 37471, // human king + SPELL_SWEEP = 37474, + SPELL_BLOODLUST = 37472, // orc king + SPELL_CLEAVE = 37476, + SPELL_HEROIC_BLOW = 37406, // human pawn + SPELL_SHIELD_BLOCK = 37414, + SPELL_VICIOUS_STRIKE = 37413, // orc pawn + SPELL_WEAPON_DEFLECTION = 37416, + SPELL_SMASH = 37453, // human knight + SPELL_STOMP = 37498, + SPELL_BITE = 37454, // orc knight + SPELL_HOWL = 37502, + SPELL_ELEMENTAL_BLAST = 37462, // human queen + SPELL_RAIN_OF_FIRE = 37465, + SPELL_FIREBALL = 37463, // orc queen + // SPELL_POISON_CLOUD = 37469, + SPELL_POISON_CLOUD_ACTION = 37775, // triggers 37469 - acts as a target selector spell for orc queen + SPELL_HEALING = 37455, // human bishop + SPELL_HOLY_LANCE = 37459, + // SPELL_SHADOW_MEND = 37456, // orc bishop + SPELL_SHADOW_MEND_ACTION = 37824, // triggers 37456 - acts as a target selector spell for orc bishop + SPELL_SHADOW_SPEAR = 37461, + SPELL_GEYSER = 37427, // human rook + SPELL_WATER_SHIELD = 37432, + SPELL_HELLFIRE = 37428, // orc rook + SPELL_FIRE_SHIELD = 37434, + + // spells used to transform side trigger when npc dies + SPELL_TRANSFORM_FOOTMAN = 39350, + SPELL_TRANSFORM_CHARGER = 39352, + SPELL_TRANSFORM_CLERIC = 39353, + SPELL_TRANSFORM_WATER_ELEM = 39354, + SPELL_TRANSFORM_CONJURER = 39355, + SPELL_TRANSFORM_KING_LLANE = 39356, + SPELL_TRANSFORM_GRUNT = 39357, + SPELL_TRANSFORM_WOLF = 39358, + SPELL_TRANSFORM_NECROLYTE = 39359, + SPELL_TRANSFORM_DAEMON = 39360, + SPELL_TRANSFORM_WARLOCK = 39361, + SPELL_TRANSFORM_BLACKHAND = 39362, + + // generic npcs + // NPC_SQUARE_OUTSIDE_B = 17316, // used to check the interior of the board + // NPC_SQUARE_OUTSIDE_W = 17317, // not used in our script; keep for reference only + NPC_FURY_MEDIVH_VISUAL = 22521, // has aura 39383 + + // gossip texts + GOSSIP_ITEM_ORC_GRUNT = -3532006, + GOSSIP_ITEM_ORC_WOLF = -3532007, + GOSSIP_ITEM_SUMMONED_DEAMON = -3532008, + GOSSIP_ITEM_ORC_WARLOCK = -3532009, + GOSSIP_ITEM_ORC_NECROLYTE = -3532010, + GOSSIP_ITEM_WARCHIEF_BLACKHAND = -3532011, + GOSSIP_ITEM_HUMAN_FOOTMAN = -3532012, + GOSSIP_ITEM_HUMAN_CHARGER = -3532013, + GOSSIP_ITEM_WATER_ELEMENTAL = -3532014, + GOSSIP_ITEM_HUMAN_CONJURER = -3532015, + GOSSIP_ITEM_HUMAN_CLERIC = -3532016, + GOSSIP_ITEM_KING_LLANE = -3532017, + GOSSIP_ITEM_RESET_BOARD = -3532018, + + // gossip menu + GOSSIP_MENU_ID_GRUNT = 10425, + GOSSIP_MENU_ID_WOLF = 10439, + GOSSIP_MENU_ID_WARLOCK = 10440, + GOSSIP_MENU_ID_NECROLYTE = 10434, + GOSSIP_MENU_ID_DEAMON = 10426, + GOSSIP_MENU_ID_BLACKHAND = 10442, + GOSSIP_MENU_ID_FOOTMAN = 8952, + GOSSIP_MENU_ID_CHARGER = 10414, + GOSSIP_MENU_ID_CONJURER = 10417, + GOSSIP_MENU_ID_CLERIC = 10416, + GOSSIP_MENU_ID_ELEMENTAL = 10413, + GOSSIP_MENU_ID_LLANE = 10418, + GOSSIP_MENU_ID_MEDIVH = 10506, + GOSSIP_MENU_ID_MEDIVH_BEATEN = 10718, + + // misc + TARGET_TYPE_RANDOM = 1, + TARGET_TYPE_FRIENDLY = 2, +}; + +/*###### +## npc_echo_of_medivh +######*/ + +struct npc_echo_of_medivhAI : public ScriptedAI +{ + npc_echo_of_medivhAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + Reset(); + } + + instance_karazhan* m_pInstance; + + uint32 m_uiCheatTimer; + + void Reset() override + { + m_uiCheatTimer = 90000; + } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FURY_MEDIVH_VISUAL) + pSummoned->CastSpell(pSummoned, SPELL_FURY_OF_MEDIVH_AURA, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_CHESS) != IN_PROGRESS) + return; + + if (m_uiCheatTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, urand(0, 1) ? (m_pInstance->GetPlayerTeam() == ALLIANCE ? SPELL_HAND_OF_MEDIVH_HORDE : SPELL_HAND_OF_MEDIVH_ALLIANCE) : + (m_pInstance->GetPlayerTeam() == ALLIANCE ? SPELL_FURY_OF_MEDIVH_ALLIANCE : SPELL_FURY_OF_MEDIVH_HORDE)); + + switch (urand(0, 2)) + { + case 0: DoPlaySoundToSet(m_creature, SOUND_ID_CHEAT_1); break; + case 1: DoPlaySoundToSet(m_creature, SOUND_ID_CHEAT_2); break; + case 2: DoPlaySoundToSet(m_creature, SOUND_ID_CHEAT_3); break; + } + + DoScriptText(EMOTE_CHEAT, m_creature); + m_uiCheatTimer = 90000; + } + else + m_uiCheatTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_echo_of_medivh(Creature* pCreature) +{ + return new npc_echo_of_medivhAI(pCreature); +} + +bool GossipHello_npc_echo_of_medivh(Player* pPlayer, Creature* pCreature) +{ + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_CHESS) != DONE && pInstance->GetData(TYPE_CHESS) != SPECIAL) + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_MEDIVH, pCreature->GetObjectGuid()); + else + { + if (pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RESET_BOARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_MEDIVH_BEATEN, pCreature->GetObjectGuid()); + } + + return true; + } + + return false; +} + +bool GossipSelect_npc_echo_of_medivh(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + // reset the board + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + pInstance->SetData(TYPE_CHESS, DONE); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## npc_chess_piece_generic +######*/ + +struct npc_chess_piece_genericAI : public ScriptedAI +{ + npc_chess_piece_genericAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + Reset(); + } + + instance_karazhan* m_pInstance; + + ObjectGuid m_currentSquareGuid; + + uint32 m_uiMoveTimer; + uint32 m_uiMoveCommandTimer; + uint32 m_uiSpellCommandTimer; + + bool m_bIsPrimarySpell; + float m_fCurrentOrientation; + + void Reset() override + { + m_uiMoveTimer = 0; + m_uiMoveCommandTimer = 1000; + m_uiSpellCommandTimer = m_creature->HasAura(SPELL_CONTROL_PIECE) ? 0 : 1000; + m_bIsPrimarySpell = true; + + // cancel move timer for player faction npcs or for friendly games + if (m_pInstance) + { + if ((m_pInstance->GetPlayerTeam() == ALLIANCE && m_creature->getFaction() == FACTION_ID_CHESS_ALLIANCE) || + (m_pInstance->GetPlayerTeam() == HORDE && m_creature->getFaction() == FACTION_ID_CHESS_HORDE) || + m_pInstance->GetData(TYPE_CHESS) == DONE) + m_uiMoveCommandTimer = 0; + } + } + + // no default attacking or evading + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void EnterEvadeMode() override { } + + void JustDied(Unit* /*pKiller*/) override + { + if (Creature* pSquare = m_creature->GetMap()->GetCreature(m_currentSquareGuid)) + pSquare->RemoveAllAuras(); + + // ToDo: remove corpse after 10 sec + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // handle move event + if (eventType == AI_EVENT_CUSTOM_A) + { + // clear the current square + if (Creature* pSquare = m_creature->GetMap()->GetCreature(m_currentSquareGuid)) + pSquare->RemoveAllAuras(); + + m_currentSquareGuid = pInvoker->GetObjectGuid(); + m_uiMoveTimer = 2000; + } + // handle encounter start event + else if (eventType == AI_EVENT_CUSTOM_B) + { + // reset the variables + Reset(); + m_currentSquareGuid = pInvoker->GetObjectGuid(); + + // ToDo: enable this when the scope of the spell is clear + //if (Creature* pStalker = m_pInstance->GetSingleCreatureFromStorage(NPC_WAITING_ROOM_STALKER)) + // pStalker->CastSpell(pStalker, SPELL_AI_ACTION_TIMER, true); + + //DoCastSpellIfCan(m_creature, SPELL_AI_SNAPSHOT_TIMER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CHESS_AI_ATTACK_TIMER, CAST_TRIGGERED); + + pInvoker->CastSpell(pInvoker, SPELL_DISABLE_SQUARE, true); + pInvoker->CastSpell(pInvoker, SPELL_IS_SQUARE_USED, true); + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // update facing + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 5.0f)) + DoCastSpellIfCan(pTarget, SPELL_CHANGE_FACING); + else + m_creature->SetFacingTo(m_fCurrentOrientation); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // do a soft reset when the piece is controlled + if (pCaster->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_CONTROL_PIECE) + Reset(); + } + + // Function which returns a random target by type and range + Unit* GetTargetByType(uint8 uiType, float fRange, float fArc = M_PI_F) + { + if (!m_pInstance) + return NULL; + + uint32 uiTeam = m_creature->getFaction() == FACTION_ID_CHESS_ALLIANCE ? FACTION_ID_CHESS_HORDE : FACTION_ID_CHESS_ALLIANCE; + + // get friendly list for this type + if (uiType == TARGET_TYPE_FRIENDLY) + uiTeam = m_creature->getFaction(); + + // Get the list of enemies + GuidList lTempList; + std::vector vTargets; + vTargets.reserve(lTempList.size()); + + m_pInstance->GetChessPiecesByFaction(lTempList, uiTeam); + for (GuidList::const_iterator itr = lTempList.begin(); itr != lTempList.end(); ++itr) + { + Creature* pTemp = m_creature->GetMap()->GetCreature(*itr); + if (pTemp && pTemp->isAlive()) + { + // check for specified range targets and angle; Note: to be checked if the angle is right + if (fRange && !m_creature->isInFrontInMap(pTemp, fRange, fArc)) + continue; + + // skip friendly targets which are at full HP + if (uiType == TARGET_TYPE_FRIENDLY && pTemp->GetHealth() == pTemp->GetMaxHealth()) + continue; + + vTargets.push_back(pTemp); + } + } + + if (vTargets.empty()) + return NULL; + + return vTargets[urand(0, vTargets.size() - 1)]; + } + + // Function to get a square as close as possible to the enemy + Unit* GetMovementSquare() + { + if (!m_pInstance) + return NULL; + + // define distance based on the spell radius + // this will replace the targeting sysmte of spells SPELL_MOVE_1 and SPELL_MOVE_2 + float fRadius = 10.0f; + std::list lSquaresList; + + // some pieces have special distance + switch (m_creature->GetEntry()) + { + case NPC_HUMAN_CONJURER: + case NPC_ORC_WARLOCK: + case NPC_HUMAN_CHARGER: + case NPC_ORC_WOLF: + fRadius = 15.0f; + break; + } + + // get all available squares for movement + GetCreatureListWithEntryInGrid(lSquaresList, m_creature, NPC_SQUARE_BLACK, fRadius); + GetCreatureListWithEntryInGrid(lSquaresList, m_creature, NPC_SQUARE_WHITE, fRadius); + + if (lSquaresList.empty()) + return NULL; + + // Get the list of enemies + GuidList lTempList; + std::list lEnemies; + + m_pInstance->GetChessPiecesByFaction(lTempList, m_creature->getFaction() == FACTION_ID_CHESS_ALLIANCE ? FACTION_ID_CHESS_HORDE : FACTION_ID_CHESS_ALLIANCE); + for (GuidList::const_iterator itr = lTempList.begin(); itr != lTempList.end(); ++itr) + { + Creature* pTemp = m_creature->GetMap()->GetCreature(*itr); + if (pTemp && pTemp->isAlive()) + lEnemies.push_back(pTemp); + } + + if (lEnemies.empty()) + return NULL; + + // Sort the enemies by distance and the squares compared to the distance to the closest enemy + lEnemies.sort(ObjectDistanceOrder(m_creature)); + lSquaresList.sort(ObjectDistanceOrder(lEnemies.front())); + + return lSquaresList.front(); + } + + virtual uint32 DoCastPrimarySpell() { return 5000; } + virtual uint32 DoCastSecondarySpell() { return 5000; } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance || m_pInstance->GetData(TYPE_CHESS) != IN_PROGRESS) + return; + + // issue move command + if (m_uiMoveCommandTimer) + { + if (m_uiMoveCommandTimer <= uiDiff) + { + // just update facing if some enemy is near + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 5.0f)) + DoCastSpellIfCan(pTarget, SPELL_CHANGE_FACING); + else + { + // the npc doesn't have a 100% chance to move; also there should be some GCD check in core for this part + if (roll_chance_i(15)) + { + // Note: in a normal case the target would be chosen using the spells above + // However, because the core doesn't support special targeting, we'll provide explicit target + //uint32 uiMoveSpell = SPELL_MOVE_1; + //switch (m_creature->GetEntry()) + //{ + // case NPC_HUMAN_CONJURER: + // case NPC_ORC_WARLOCK: + // case NPC_HUMAN_CHARGER: + // case NPC_ORC_WOLF: + // uiMoveSpell = SPELL_MOVE_2; + // break; + //} + //DoCastSpellIfCan(m_creature, uiMoveSpell, CAST_TRIGGERED); + + // workaround which provides specific move target + if (Unit* pTarget = GetMovementSquare()) + DoCastSpellIfCan(pTarget, SPELL_MOVE_GENERIC, CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS); + + m_fCurrentOrientation = m_creature->GetOrientation(); + } + } + + m_uiMoveCommandTimer = 5000; + } + else + m_uiMoveCommandTimer -= uiDiff; + } + + // issue spell command + if (m_uiSpellCommandTimer) + { + if (m_uiSpellCommandTimer <= uiDiff) + { + // alternate the spells and also reset the timer + m_uiSpellCommandTimer = m_bIsPrimarySpell ? DoCastPrimarySpell() : DoCastSecondarySpell(); + m_bIsPrimarySpell = !m_bIsPrimarySpell; + } + else + m_uiSpellCommandTimer -= uiDiff; + } + + // finish move timer + if (m_uiMoveTimer) + { + if (m_uiMoveTimer <= uiDiff) + { + if (Creature* pSquare = m_creature->GetMap()->GetCreature(m_currentSquareGuid)) + { + DoCastSpellIfCan(pSquare, SPELL_MOVE_MARKER, CAST_TRIGGERED); + m_creature->GetMotionMaster()->MovePoint(1, pSquare->GetPositionX(), pSquare->GetPositionY(), pSquare->GetPositionZ()); + } + m_uiMoveTimer = 0; + } + else + m_uiMoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + } +}; + +bool GossipSelect_npc_chess_generic(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + // start event when used on the king + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + // teleport at the entrance and control the chess piece + pPlayer->CastSpell(pPlayer, SPELL_IN_GAME, true); + pPlayer->CastSpell(pCreature, SPELL_CONTROL_PIECE, true); + + if (pInstance->GetData(TYPE_CHESS) == NOT_STARTED) + pInstance->SetData(TYPE_CHESS, IN_PROGRESS); + else if (pInstance->GetData(TYPE_CHESS) == DONE) + pInstance->SetData(TYPE_CHESS, SPECIAL); + } + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +bool EffectDummyCreature_npc_chess_generic(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // movement perform spell + if (uiSpellId == SPELL_MOVE_TO_SQUARE && uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() == TYPEID_UNIT) + { + pCaster->CastSpell(pCaster, SPELL_DISABLE_SQUARE, true); + pCaster->CastSpell(pCaster, SPELL_IS_SQUARE_USED, true); + + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_MOVE_COOLDOWN, true); + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + } + + return true; + } + // generic melee tick + else if (uiSpellId == SPELL_ACTION_MELEE && uiEffIndex == EFFECT_INDEX_0) + { + uint32 uiMeleeSpell = 0; + + switch (pCreatureTarget->GetEntry()) + { + case NPC_KING_LLANE: uiMeleeSpell = SPELL_MELEE_KING_LLANE; break; + case NPC_HUMAN_CHARGER: uiMeleeSpell = SPELL_MELEE_CHARGER; break; + case NPC_HUMAN_CLERIC: uiMeleeSpell = SPELL_MELEE_CLERIC; break; + case NPC_HUMAN_CONJURER: uiMeleeSpell = SPELL_MELEE_CONJURER; break; + case NPC_HUMAN_FOOTMAN: uiMeleeSpell = SPELL_MELEE_FOOTMAN; break; + case NPC_CONJURED_WATER_ELEMENTAL: uiMeleeSpell = SPELL_MELEE_WATER_ELEM; break; + case NPC_WARCHIEF_BLACKHAND: uiMeleeSpell = SPELL_MELEE_WARCHIEF_BLACKHAND; break; + case NPC_ORC_GRUNT: uiMeleeSpell = SPELL_MELEE_GRUNT; break; + case NPC_ORC_NECROLYTE: uiMeleeSpell = SPELL_MELEE_NECROLYTE; break; + case NPC_ORC_WARLOCK: uiMeleeSpell = SPELL_MELEE_WARLOCK; break; + case NPC_ORC_WOLF: uiMeleeSpell = SPELL_MELEE_WOLF; break; + case NPC_SUMMONED_DAEMON: uiMeleeSpell = SPELL_MELEE_DAEMON; break; + } + + pCreatureTarget->CastSpell(pCreatureTarget, uiMeleeSpell, true); + return true; + } + // square facing + else if (uiSpellId == SPELL_FACE_SQUARE && uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() == TYPEID_UNIT) + pCreatureTarget->SetFacingToObject(pCaster); + + return true; + } + + return false; +} + +/*###### +## npc_king_llane +######*/ + +struct npc_king_llaneAI : public npc_chess_piece_genericAI +{ + npc_king_llaneAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) + { + m_bIsAttacked = false; + Reset(); + } + + bool m_bIsAttacked; + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!uiDamage || !m_bIsAttacked || !m_pInstance || pDoneBy->GetTypeId() != TYPEID_UNIT) + return; + + if (Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH)) + { + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + DoPlaySoundToSet(pMedivh, SOUND_ID_CHECK_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_CHECK_MEDIVH); + } + + m_bIsAttacked = true; + } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetData(TYPE_CHESS) == SPECIAL) + m_pInstance->SetData(TYPE_CHESS, DONE); + else + { + if (m_pInstance->GetPlayerTeam() == HORDE) + { + DoPlaySoundToSet(pMedivh, SOUND_ID_WIN_PLAYER); + DoScriptText(EMOTE_LIFT_CURSE, pMedivh); + + m_pInstance->SetData(TYPE_CHESS, DONE); + } + else + { + DoPlaySoundToSet(pMedivh, SOUND_ID_WIN_MEDIVH); + m_pInstance->SetData(TYPE_CHESS, FAIL); + } + } + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_KING_LLANE, FACTION_ID_CHESS_ALLIANCE, true); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 20.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_HEROISM); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_HEROISM); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 10.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_SWEEP); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_SWEEP); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_king_llane(Creature* pCreature) +{ + return new npc_king_llaneAI(pCreature); +} + +bool GossipHello_npc_king_llane(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (instance_karazhan* pInstance = (instance_karazhan*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) != DONE && pPlayer->GetTeam() == ALLIANCE) || pInstance->IsFriendlyGameReady()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KING_LLANE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_LLANE, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_warchief_blackhand +######*/ + +struct npc_warchief_blackhandAI : public npc_chess_piece_genericAI +{ + npc_warchief_blackhandAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) + { + m_bIsAttacked = false; + Reset(); + } + + bool m_bIsAttacked; + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (!uiDamage || !m_bIsAttacked || !m_pInstance || pDoneBy->GetTypeId() != TYPEID_UNIT) + return; + + if (Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH)) + { + if (m_pInstance->GetPlayerTeam() == HORDE) + DoPlaySoundToSet(pMedivh, SOUND_ID_CHECK_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_CHECK_MEDIVH); + } + + m_bIsAttacked = true; + } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetData(TYPE_CHESS) == SPECIAL) + m_pInstance->SetData(TYPE_CHESS, DONE); + else + { + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + { + DoPlaySoundToSet(pMedivh, SOUND_ID_WIN_PLAYER); + DoScriptText(EMOTE_LIFT_CURSE, pMedivh); + + m_pInstance->SetData(TYPE_CHESS, DONE); + } + else + { + DoPlaySoundToSet(pMedivh, SOUND_ID_WIN_MEDIVH); + m_pInstance->SetData(TYPE_CHESS, FAIL); + } + } + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_BLACKHAND, FACTION_ID_CHESS_HORDE, true); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 20.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_BLOODLUST); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_BLOODLUST); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 10.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_CLEAVE); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_CLEAVE); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_warchief_blackhand(Creature* pCreature) +{ + return new npc_warchief_blackhandAI(pCreature); +} + +bool GossipHello_npc_warchief_blackhand(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (instance_karazhan* pInstance = (instance_karazhan*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_CHESS) != DONE && pPlayer->GetTeam() == HORDE || pInstance->IsFriendlyGameReady()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WARCHIEF_BLACKHAND, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_BLACKHAND, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_human_conjurer +######*/ + +struct npc_human_conjurerAI : public npc_chess_piece_genericAI +{ + npc_human_conjurerAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_QUEEN_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_QUEEN_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_CONJURER, FACTION_ID_CHESS_ALLIANCE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 20.0f)) + { + DoCastSpellIfCan(pTarget, SPELL_ELEMENTAL_BLAST); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_ELEMENTAL_BLAST); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 25.0f)) + { + DoCastSpellIfCan(pTarget, SPELL_RAIN_OF_FIRE); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_RAIN_OF_FIRE); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_human_conjurer(Creature* pCreature) +{ + return new npc_human_conjurerAI(pCreature); +} + +bool GossipHello_npc_human_conjurer(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == ALLIANCE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_HUMAN_CONJURER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_CONJURER, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_orc_warlock +######*/ + +struct npc_orc_warlockAI : public npc_chess_piece_genericAI +{ + npc_orc_warlockAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == HORDE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_QUEEN_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_QUEEN_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_WARLOCK, FACTION_ID_CHESS_HORDE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 20.0f)) + { + DoCastSpellIfCan(pTarget, SPELL_FIREBALL); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_FIREBALL); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 25.0f)) + { + DoCastSpellIfCan(pTarget, SPELL_POISON_CLOUD_ACTION); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_POISON_CLOUD_ACTION); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_orc_warlock(Creature* pCreature) +{ + return new npc_orc_warlockAI(pCreature); +} + +bool GossipHello_npc_orc_warlock(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == HORDE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ORC_WARLOCK, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_WARLOCK, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_human_footman +######*/ + +struct npc_human_footmanAI : public npc_chess_piece_genericAI +{ + npc_human_footmanAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + { + switch (urand(0, 2)) + { + case 0: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_PLAYER_1); break; + case 1: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_PLAYER_2); break; + case 2: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_PLAYER_3); break; + } + } + else + { + switch (urand(0, 2)) + { + case 0: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_MEDIVH_1); break; + case 1: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_MEDIVH_2); break; + case 2: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_MEDIVH_3); break; + } + } + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_FOOTMAN, FACTION_ID_CHESS_ALLIANCE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 8.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_HEROIC_BLOW); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_HEROIC_BLOW); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 8.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_SHIELD_BLOCK); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_SHIELD_BLOCK); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_human_footman(Creature* pCreature) +{ + return new npc_human_footmanAI(pCreature); +} + +bool GossipHello_npc_human_footman(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == ALLIANCE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_HUMAN_FOOTMAN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_FOOTMAN, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_orc_grunt +######*/ + +struct npc_orc_gruntAI : public npc_chess_piece_genericAI +{ + npc_orc_gruntAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == HORDE) + { + switch (urand(0, 2)) + { + case 0: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_PLAYER_1); break; + case 1: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_PLAYER_2); break; + case 2: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_PLAYER_3); break; + } + } + else + { + switch (urand(0, 2)) + { + case 0: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_MEDIVH_1); break; + case 1: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_MEDIVH_2); break; + case 2: DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_PAWN_MEDIVH_3); break; + } + } + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_GRUNT, FACTION_ID_CHESS_HORDE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 8.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_VICIOUS_STRIKE); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_VICIOUS_STRIKE); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 8.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_WEAPON_DEFLECTION); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_WEAPON_DEFLECTION); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_orc_grunt(Creature* pCreature) +{ + return new npc_orc_gruntAI(pCreature); +} + +bool GossipHello_npc_orc_grunt(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == HORDE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ORC_GRUNT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_GRUNT, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_water_elemental +######*/ + +struct npc_water_elementalAI : public npc_chess_piece_genericAI +{ + npc_water_elementalAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_ROOK_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_ROOK_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_WATER_ELEM, FACTION_ID_CHESS_ALLIANCE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 9.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_GEYSER); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_GEYSER); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 9.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_WATER_SHIELD); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_WATER_SHIELD); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_water_elemental(Creature* pCreature) +{ + return new npc_water_elementalAI(pCreature); +} + +bool GossipHello_npc_water_elemental(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == ALLIANCE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WATER_ELEMENTAL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_ELEMENTAL, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_summoned_daemon +######*/ + +struct npc_summoned_daemonAI : public npc_chess_piece_genericAI +{ + npc_summoned_daemonAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == HORDE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_ROOK_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_ROOK_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_DAEMON, FACTION_ID_CHESS_HORDE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 9.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_HELLFIRE); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_HELLFIRE); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 9.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_FIRE_SHIELD); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_FIRE_SHIELD); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_summoned_daemon(Creature* pCreature) +{ + return new npc_summoned_daemonAI(pCreature); +} + +bool GossipHello_npc_summoned_daemon(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == HORDE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SUMMONED_DEAMON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_DEAMON, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_human_charger +######*/ + +struct npc_human_chargerAI : public npc_chess_piece_genericAI +{ + npc_human_chargerAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_KNIGHT_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_KNIGHT_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_CHARGER, FACTION_ID_CHESS_ALLIANCE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 8.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_SMASH); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_SMASH); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 10.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_STOMP); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_STOMP); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_human_charger(Creature* pCreature) +{ + return new npc_human_chargerAI(pCreature); +} + +bool GossipHello_npc_human_charger(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == ALLIANCE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_HUMAN_CHARGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_CHARGER, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_orc_wolf +######*/ + +struct npc_orc_wolfAI : public npc_chess_piece_genericAI +{ + npc_orc_wolfAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == HORDE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_KNIGHT_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_KNIGHT_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_WOLF, FACTION_ID_CHESS_HORDE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 8.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_BITE); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_BITE); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 10.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_HOWL); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_HOWL); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_orc_wolf(Creature* pCreature) +{ + return new npc_orc_wolfAI(pCreature); +} + +bool GossipHello_npc_orc_wolf(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == HORDE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ORC_WOLF, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_WOLF, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_human_cleric +######*/ + +struct npc_human_clericAI : public npc_chess_piece_genericAI +{ + npc_human_clericAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == ALLIANCE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_BISHOP_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_BISHOP_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_CLERIC, FACTION_ID_CHESS_ALLIANCE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_FRIENDLY, 25.0f)) + { + DoCastSpellIfCan(pTarget, SPELL_HEALING); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_HEALING); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 18.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_HOLY_LANCE); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_HOLY_LANCE); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_human_cleric(Creature* pCreature) +{ + return new npc_human_clericAI(pCreature); +} + +bool GossipHello_npc_human_cleric(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == ALLIANCE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_HUMAN_CLERIC, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_CLERIC, pCreature->GetObjectGuid()); + return true; +} + +/*###### +## npc_orc_necrolyte +######*/ + +struct npc_orc_necrolyteAI : public npc_chess_piece_genericAI +{ + npc_orc_necrolyteAI(Creature* pCreature) : npc_chess_piece_genericAI(pCreature) { Reset(); } + + void JustDied(Unit* pKiller) override + { + npc_chess_piece_genericAI::JustDied(pKiller); + + if (!m_pInstance) + return; + + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH); + if (!pMedivh) + return; + + if (m_pInstance->GetPlayerTeam() == HORDE) + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_BISHOP_PLAYER); + else + DoPlaySoundToSet(pMedivh, SOUND_ID_LOSE_BISHOP_MEDIVH); + + m_pInstance->DoMoveChessPieceToSides(SPELL_TRANSFORM_NECROLYTE, FACTION_ID_CHESS_HORDE); + } + + uint32 DoCastPrimarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_FRIENDLY, 25.0f)) + { + DoCastSpellIfCan(pTarget, SPELL_SHADOW_MEND_ACTION); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_SHADOW_MEND_ACTION); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } + + uint32 DoCastSecondarySpell() override + { + if (Unit* pTarget = GetTargetByType(TARGET_TYPE_RANDOM, 18.0f, M_PI_F / 12)) + { + DoCastSpellIfCan(m_creature, SPELL_SHADOW_SPEAR); + + // reset timer based on spell values + const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_SHADOW_SPEAR); + return pSpell->RecoveryTime ? pSpell->RecoveryTime : pSpell->CategoryRecoveryTime; + } + + return 5000; + } +}; + +CreatureAI* GetAI_npc_orc_necrolyte(Creature* pCreature) +{ + return new npc_orc_necrolyteAI(pCreature); +} + +bool GossipHello_npc_orc_necrolyte(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->HasAura(SPELL_RECENTLY_IN_GAME) || pCreature->HasAura(SPELL_CONTROL_PIECE)) + return true; + + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if ((pInstance->GetData(TYPE_CHESS) == IN_PROGRESS && pPlayer->GetTeam() == HORDE) || pInstance->GetData(TYPE_CHESS) == SPECIAL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ORC_NECROLYTE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_NECROLYTE, pCreature->GetObjectGuid()); + return true; +} void AddSC_chess_event() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_echo_of_medivh"; + pNewScript->GetAI = GetAI_npc_echo_of_medivh; + pNewScript->pGossipHello = GossipHello_npc_echo_of_medivh; + pNewScript->pGossipSelect = GossipSelect_npc_echo_of_medivh; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_king_llane"; + pNewScript->GetAI = GetAI_npc_king_llane; + pNewScript->pGossipHello = GossipHello_npc_king_llane; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_warchief_blackhand"; + pNewScript->GetAI = GetAI_npc_warchief_blackhand; + pNewScript->pGossipHello = GossipHello_npc_warchief_blackhand; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_human_conjurer"; + pNewScript->GetAI = GetAI_npc_human_conjurer; + pNewScript->pGossipHello = GossipHello_npc_human_conjurer; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_orc_warlock"; + pNewScript->GetAI = GetAI_npc_orc_warlock; + pNewScript->pGossipHello = GossipHello_npc_orc_warlock; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_human_footman"; + pNewScript->GetAI = GetAI_npc_human_footman; + pNewScript->pGossipHello = GossipHello_npc_human_footman; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_orc_grunt"; + pNewScript->GetAI = GetAI_npc_orc_grunt; + pNewScript->pGossipHello = GossipHello_npc_orc_grunt; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_water_elemental"; + pNewScript->GetAI = GetAI_npc_water_elemental; + pNewScript->pGossipHello = GossipHello_npc_water_elemental; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_summoned_daemon"; + pNewScript->GetAI = GetAI_npc_summoned_daemon; + pNewScript->pGossipHello = GossipHello_npc_summoned_daemon; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_human_charger"; + pNewScript->GetAI = GetAI_npc_human_charger; + pNewScript->pGossipHello = GossipHello_npc_human_charger; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_orc_wolf"; + pNewScript->GetAI = GetAI_npc_orc_wolf; + pNewScript->pGossipHello = GossipHello_npc_orc_wolf; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_human_cleric"; + pNewScript->GetAI = GetAI_npc_human_cleric; + pNewScript->pGossipHello = GossipHello_npc_human_cleric; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_orc_necrolyte"; + pNewScript->GetAI = GetAI_npc_orc_necrolyte; + pNewScript->pGossipHello = GossipHello_npc_orc_necrolyte; + pNewScript->pGossipSelect = GossipSelect_npc_chess_generic; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_chess_generic; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp b/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp index 124e0aa9c..6f5fefc4d 100644 --- a/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp +++ b/scripts/eastern_kingdoms/karazhan/instance_karazhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Instance_Karazhan SD%Complete: 70 -SDComment: Instance Script for Karazhan to help in various encounters. TODO: GameObject visibility for Opera event. +SDComment: Instance Script for Karazhan to help in various encounters. SDCategory: Karazhan EndScriptData */ @@ -39,7 +39,14 @@ EndScriptData */ */ instance_karazhan::instance_karazhan(Map* pMap) : ScriptedInstance(pMap), - m_uiOzDeathCount(0) + m_uiOperaEvent(0), + m_uiOzDeathCount(0), + m_uiTeam(0), + m_uiChessResetTimer(0), + m_uiNightbaneResetTimer(0), + m_uiAllianceStalkerCount(0), + m_uiHordeStalkerCount(0), + m_bFriendlyGame(false) { Initialize(); } @@ -47,77 +54,134 @@ instance_karazhan::instance_karazhan(Map* pMap) : ScriptedInstance(pMap), void instance_karazhan::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - // 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered. - m_uiOperaEvent = urand(EVENT_OZ, EVENT_RAJ); } bool instance_karazhan::IsEncounterInProgress() const { for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { if (m_auiEncounter[i] == IN_PROGRESS) return true; + } return false; } +void instance_karazhan::OnPlayerEnter(Player* pPlayer) +{ + if (!m_uiTeam) // very first player to enter + m_uiTeam = pPlayer->GetTeam(); + + // If the opera event is already set, return + if (GetData(TYPE_OPERA_PERFORMANCE) != 0) + return; + + // Set the Opera Performance type on the first player enter + SetData(TYPE_OPERA_PERFORMANCE, urand(OPERA_EVENT_WIZARD_OZ, OPERA_EVENT_ROMULO_AND_JUL)); +} + void instance_karazhan::OnCreatureCreate(Creature* pCreature) { switch (pCreature->GetEntry()) { + case NPC_ATTUMEN: + case NPC_MIDNIGHT: case NPC_MOROES: + case NPC_BARNES: case NPC_NIGHTBANE: + case NPC_NETHERSPITE: + case NPC_JULIANNE: + case NPC_ROMULO: + case NPC_LADY_KEIRA_BERRYBUCK: + case NPC_LADY_CATRIONA_VON_INDI: + case NPC_LORD_CRISPIN_FERENCE: + case NPC_BARON_RAFE_DREUGER: + case NPC_BARONESS_DOROTHEA_MILLSTIPE: + case NPC_LORD_ROBIN_DARIS: + case NPC_IMAGE_OF_MEDIVH: + case NPC_IMAGE_OF_ARCANAGOS: + case NPC_ECHO_MEDIVH: + case NPC_CHESS_VICTORY_CONTROLLER: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_NIGHTBANE_HELPER: + if (pCreature->GetPositionZ() < 100.0f) + m_lNightbaneGroundTriggers.push_back(pCreature->GetObjectGuid()); + else + m_lNightbaneAirTriggers.push_back(pCreature->GetObjectGuid()); + break; + case NPC_INVISIBLE_STALKER: + if (pCreature->GetPositionY() < -1870.0f) + m_lChessHordeStalkerList.push_back(pCreature->GetObjectGuid()); + else + m_lChessAllianceStalkerList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_CHESS_STATUS_BAR: + if (pCreature->GetPositionY() < -1870.0f) + m_HordeStatusGuid = pCreature->GetObjectGuid(); + else + m_AllianceStatusGuid = pCreature->GetObjectGuid(); + break; + case NPC_HUMAN_CHARGER: + case NPC_HUMAN_CLERIC: + case NPC_HUMAN_CONJURER: + case NPC_HUMAN_FOOTMAN: + case NPC_CONJURED_WATER_ELEMENTAL: + case NPC_KING_LLANE: + m_lChessPiecesAlliance.push_back(pCreature->GetObjectGuid()); + break; + case NPC_ORC_GRUNT: + case NPC_ORC_NECROLYTE: + case NPC_ORC_WARLOCK: + case NPC_ORC_WOLF: + case NPC_SUMMONED_DAEMON: + case NPC_WARCHIEF_BLACKHAND: + m_lChessPiecesHorde.push_back(pCreature->GetObjectGuid()); + break; } } void instance_karazhan::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - case GO_STAGE_CURTAIN: - break; case GO_STAGE_DOOR_LEFT: - if (m_auiEncounter[4] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_STAGE_DOOR_RIGHT: - if (m_auiEncounter[4] == DONE) + if (m_auiEncounter[3] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_PRIVATE_LIBRARY_DOOR: - break; - case GO_MASSIVE_DOOR: - break; - case GO_GAMESMANS_HALL_DOOR: - break; case GO_GAMESMANS_HALL_EXIT_DOOR: - break; - case GO_NETHERSPACE_DOOR: + if (m_auiEncounter[8] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_SIDE_ENTRANCE_DOOR: - if (m_auiEncounter[4] != DONE) - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); - else + if (m_auiEncounter[3] == DONE) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); break; + case GO_STAGE_CURTAIN: + case GO_PRIVATE_LIBRARY_DOOR: + case GO_MASSIVE_DOOR: + case GO_GAMESMANS_HALL_DOOR: + case GO_NETHERSPACE_DOOR: case GO_DUST_COVERED_CHEST: + case GO_MASTERS_TERRACE_DOOR_1: + case GO_MASTERS_TERRACE_DOOR_2: + case GO_BLACKENED_URN: break; + // Opera event backgrounds case GO_OZ_BACKDROP: - case GO_OZ_HAY: - // if (m_uiOperaEvent == EVENT_OZ) // TODO - respawn, store for later respawn? - return; case GO_HOOD_BACKDROP: - case GO_HOOD_TREE: case GO_HOOD_HOUSE: - // if (m_uiOperaEvent == EVENT_HOOD) // TODO - respawn, store for later respawn? - return; case GO_RAJ_BACKDROP: case GO_RAJ_MOON: case GO_RAJ_BALCONY: - // if (m_uiOperaEvent == EVENT_RAJ) // TODO - respawn, store for later respawn? + break; + case GO_OZ_HAY: + m_lOperaHayGuidList.push_back(pGo->GetObjectGuid()); + return; + case GO_HOOD_TREE: + m_lOperaTreeGuidList.push_back(pGo->GetObjectGuid()); return; default: @@ -128,71 +192,140 @@ void instance_karazhan::OnObjectCreate(GameObject* pGo) void instance_karazhan::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ATTUMEN: - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; + if (uiData == FAIL) + { + // Respawn Midnight on Fail + if (Creature* pMidnight = GetSingleCreatureFromStorage(NPC_MIDNIGHT)) + { + if (!pMidnight->isAlive()) + pMidnight->Respawn(); + } + } break; case TYPE_MOROES: - if (m_auiEncounter[1] != DONE) - m_auiEncounter[1] = uiData; - break; case TYPE_MAIDEN: - m_auiEncounter[2] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_OPERA: - m_auiEncounter[3] = uiData; + // Don't store the same data twice + if (uiData == m_auiEncounter[uiType]) + break; + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + m_uiOzDeathCount = 0; if (uiData == DONE) { DoUseDoorOrButton(GO_STAGE_DOOR_LEFT); DoUseDoorOrButton(GO_STAGE_DOOR_RIGHT); DoToggleGameObjectFlags(GO_SIDE_ENTRANCE_DOOR, GO_FLAG_LOCKED, false); } + // use curtain only for event start or fail + else + DoUseDoorOrButton(GO_STAGE_CURTAIN); break; case TYPE_CURATOR: - m_auiEncounter[4] = uiData; - break; case TYPE_TERESTIAN: - m_auiEncounter[5] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_ARAN: - m_auiEncounter[6] = uiData; - if (uiData != IN_PROGRESS) - DoUseDoorOrButton(GO_PRIVATE_LIBRARY_DOOR); + if (uiData == FAIL || uiData == DONE) + DoToggleGameObjectFlags(GO_PRIVATE_LIBRARY_DOOR, GO_FLAG_LOCKED, false); + if (uiData == IN_PROGRESS) + DoToggleGameObjectFlags(GO_PRIVATE_LIBRARY_DOOR, GO_FLAG_LOCKED, true); + m_auiEncounter[uiType] = uiData; break; case TYPE_NETHERSPITE: - m_auiEncounter[7] = uiData; + m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_MASSIVE_DOOR); break; case TYPE_CHESS: if (uiData == DONE) - DoRespawnGameObject(GO_DUST_COVERED_CHEST, DAY); - m_auiEncounter[8] = uiData; + { + // doors and loot are not handled for friendly games + if (GetData(TYPE_CHESS) != SPECIAL) + { + DoUseDoorOrButton(GO_GAMESMANS_HALL_EXIT_DOOR); + DoRespawnGameObject(GO_DUST_COVERED_CHEST, DAY); + DoToggleGameObjectFlags(GO_DUST_COVERED_CHEST, GO_FLAG_NO_INTERACT, false); + } + + // cast game end spells + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH)) + { + pMedivh->CastSpell(pMedivh, SPELL_FORCE_KILL_BUNNY, true); + pMedivh->CastSpell(pMedivh, SPELL_GAME_OVER, true); + pMedivh->CastSpell(pMedivh, SPELL_CLEAR_BOARD, true); + } + if (Creature* pController = GetSingleCreatureFromStorage(NPC_CHESS_VICTORY_CONTROLLER)) + pController->CastSpell(pController, SPELL_VICTORY_VISUAL, true); + + // remove silence debuff + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->RemoveAurasDueToSpell(SPELL_GAME_IN_SESSION); + } + + m_bFriendlyGame = false; + m_uiChessResetTimer = 35000; + } + else if (uiData == FAIL) + { + // clean the board for reset + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_ECHO_MEDIVH)) + { + pMedivh->CastSpell(pMedivh, SPELL_GAME_OVER, true); + pMedivh->CastSpell(pMedivh, SPELL_CLEAR_BOARD, true); + } + + // remove silence debuff + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->RemoveAurasDueToSpell(SPELL_GAME_IN_SESSION); + } + + m_uiChessResetTimer = 35000; + } + else if (uiData == IN_PROGRESS || uiData == SPECIAL) + DoPrepareChessEvent(); + m_auiEncounter[uiType] = uiData; break; case TYPE_MALCHEZZAR: - m_auiEncounter[9] = uiData; + DoUseDoorOrButton(GO_NETHERSPACE_DOOR); + m_auiEncounter[uiType] = uiData; break; case TYPE_NIGHTBANE: - m_auiEncounter[10] = uiData; - break; + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_MASTERS_TERRACE_DOOR_1); + DoUseDoorOrButton(GO_MASTERS_TERRACE_DOOR_2); - case DATA_OPERA_OZ_DEATHCOUNT: - if (uiData == SPECIAL) - ++m_uiOzDeathCount; - else if (uiData == IN_PROGRESS) - m_uiOzDeathCount = 0; - return; + // reset event on timer + if (uiData == FAIL) + m_uiNightbaneResetTimer = 30000; + break; + // Store the event type for the Opera + case TYPE_OPERA_PERFORMANCE: + m_uiOperaEvent = uiData; + break; } - if (uiData == DONE) + // Also save the opera performance, once it's set + if (uiData == DONE || uiType == TYPE_OPERA_PERFORMANCE) { OUT_SAVE_INST_DATA; std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9] << " " << m_auiEncounter[10]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_uiOperaEvent; m_strInstData = saveStream.str(); @@ -201,28 +334,15 @@ void instance_karazhan::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_karazhan::GetData(uint32 uiType) +uint32 instance_karazhan::GetData(uint32 uiType) const { - switch (uiType) - { - case TYPE_ATTUMEN: return m_auiEncounter[0]; - case TYPE_MOROES: return m_auiEncounter[1]; - case TYPE_MAIDEN: return m_auiEncounter[2]; - case TYPE_OPERA: return m_auiEncounter[3]; - case TYPE_CURATOR: return m_auiEncounter[4]; - case TYPE_TERESTIAN: return m_auiEncounter[5]; - case TYPE_ARAN: return m_auiEncounter[6]; - case TYPE_NETHERSPITE: return m_auiEncounter[7]; - case TYPE_CHESS: return m_auiEncounter[8]; - case TYPE_MALCHEZZAR: return m_auiEncounter[9]; - case TYPE_NIGHTBANE: return m_auiEncounter[10]; - - case DATA_OPERA_PERFORMANCE: return m_uiOperaEvent; - case DATA_OPERA_OZ_DEATHCOUNT: return m_uiOzDeathCount; + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - default: - return 0; - } + if (uiType == TYPE_OPERA_PERFORMANCE) + return m_uiOperaEvent; + + return 0; } void instance_karazhan::Load(const char* chrIn) @@ -238,16 +358,274 @@ void instance_karazhan::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_uiOperaEvent; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. m_auiEncounter[i] = NOT_STARTED; + } OUT_LOAD_INST_DATA_COMPLETE; } +void instance_karazhan::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_DOROTHEE: + case NPC_ROAR: + case NPC_TINHEAD: + case NPC_STRAWMAN: + ++m_uiOzDeathCount; + // Summon Chrone when all 4 Oz mobs are killed + if (m_uiOzDeathCount == MAX_OZ_OPERA_MOBS) + { + if (Creature* pCrone = pCreature->SummonCreature(NPC_CRONE, afChroneSpawnLoc[0], afChroneSpawnLoc[1], afChroneSpawnLoc[2], afChroneSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + if (pCreature->getVictim()) + pCrone->AI()->AttackStart(pCreature->getVictim()); + } + } + break; + } +} + +void instance_karazhan::DoPrepareChessEvent() +{ + // Allow all the chess pieces to init start position + for (GuidList::const_iterator itr = m_lChessPiecesAlliance.begin(); itr != m_lChessPiecesAlliance.end(); ++itr) + { + if (Creature* pChessPiece = instance->GetCreature(*itr)) + { + Creature* pSquare = GetClosestCreatureWithEntry(pChessPiece, NPC_SQUARE_BLACK, 2.0f); + if (!pSquare) + pSquare = GetClosestCreatureWithEntry(pChessPiece, NPC_SQUARE_WHITE, 2.0f); + if (!pSquare) + { + script_error_log("Instance Karazhan: ERROR Failed to properly load the Chess square for %s.", pChessPiece->GetGuidStr().c_str()); + return; + } + + // send event which will prepare the current square + pChessPiece->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, pSquare, pChessPiece); + } + } + + for (GuidList::const_iterator itr = m_lChessPiecesHorde.begin(); itr != m_lChessPiecesHorde.end(); ++itr) + { + if (Creature* pChessPiece = instance->GetCreature(*itr)) + { + Creature* pSquare = GetClosestCreatureWithEntry(pChessPiece, NPC_SQUARE_BLACK, 2.0f); + if (!pSquare) + pSquare = GetClosestCreatureWithEntry(pChessPiece, NPC_SQUARE_WHITE, 2.0f); + if (!pSquare) + { + script_error_log("Instance Karazhan: ERROR Failed to properly load the Chess square for %s.", pChessPiece->GetGuidStr().c_str()); + return; + } + + // send event which will prepare the current square + pChessPiece->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, pSquare, pChessPiece); + } + } + + // add silence debuff + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->CastSpell(pPlayer, SPELL_GAME_IN_SESSION, true); + } + + m_uiAllianceStalkerCount = 0; + m_uiHordeStalkerCount = 0; + m_vHordeStalkers.clear(); + m_vAllianceStalkers.clear(); + + // sort stalkers depending on side + std::list lStalkers; + for (GuidList::const_iterator itr = m_lChessHordeStalkerList.begin(); itr != m_lChessHordeStalkerList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + lStalkers.push_back(pTemp); + } + + if (lStalkers.empty()) + { + script_error_log("Instance Karazhan: ERROR Failed to properly load the horde side stalkers for the Chess Event."); + return; + } + + // get the proper statusBar npc + Creature* pStatusBar = instance->GetCreature(m_HordeStatusGuid); + if (!pStatusBar) + return; + + lStalkers.sort(ObjectDistanceOrder(pStatusBar)); + for (std::list::const_iterator itr = lStalkers.begin(); itr != lStalkers.end(); ++itr) + m_vHordeStalkers.push_back((*itr)->GetObjectGuid()); + + lStalkers.clear(); + for (GuidList::const_iterator itr = m_lChessAllianceStalkerList.begin(); itr != m_lChessAllianceStalkerList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + lStalkers.push_back(pTemp); + } + + if (lStalkers.empty()) + { + script_error_log("Instance Karazhan: ERROR Failed to properly load the alliance side stalkers for the Chess Event."); + return; + } + + // get the proper statusBar npc + pStatusBar = instance->GetCreature(m_AllianceStatusGuid); + if (!pStatusBar) + return; + + lStalkers.sort(ObjectDistanceOrder(pStatusBar)); + for (std::list::const_iterator itr = lStalkers.begin(); itr != lStalkers.end(); ++itr) + m_vAllianceStalkers.push_back((*itr)->GetObjectGuid()); +} + +void instance_karazhan::DoMoveChessPieceToSides(uint32 uiSpellId, uint32 uiFaction, bool bGameEnd /*= false*/) +{ + // assign proper faction variables + GuidVector& vStalkers = uiFaction == FACTION_ID_CHESS_ALLIANCE ? m_vAllianceStalkers : m_vHordeStalkers; + uint32 uiCount = uiFaction == FACTION_ID_CHESS_ALLIANCE ? m_uiAllianceStalkerCount : m_uiHordeStalkerCount; + + // get the proper statusBar npc + Creature* pStatusBar = instance->GetCreature(uiFaction == FACTION_ID_CHESS_ALLIANCE ? m_AllianceStatusGuid : m_HordeStatusGuid); + if (!pStatusBar) + return; + + if (vStalkers.size() < uiCount + 1) + return; + + // handle stalker transformation + if (Creature* pStalker = instance->GetCreature(vStalkers[uiCount])) + { + // need to provide specific target, in order to ensure the logic of the event + pStatusBar->CastSpell(pStalker, uiSpellId, true); + uiFaction == FACTION_ID_CHESS_ALLIANCE ? ++m_uiAllianceStalkerCount : ++m_uiHordeStalkerCount; + } + + // handle emote on end game + if (bGameEnd) + { + // inverse factions + vStalkers.clear(); + vStalkers = uiFaction == FACTION_ID_CHESS_ALLIANCE ? m_vHordeStalkers : m_vAllianceStalkers; + + for (GuidVector::const_iterator itr = vStalkers.begin(); itr != vStalkers.end(); ++itr) + { + if (Creature* pStalker = instance->GetCreature(*itr)) + pStalker->HandleEmote(EMOTE_STATE_APPLAUD); + } + } +} + +void instance_karazhan::DoPrepareOperaStage(Creature* pOrganizer) +{ + if (!pOrganizer) + return; + + debug_log("SD2: Barnes Opera Event - Introduction complete - preparing encounter %d", GetData(TYPE_OPERA_PERFORMANCE)); + + // summon the bosses and respawn the stage background + switch (GetData(TYPE_OPERA_PERFORMANCE)) + { + case OPERA_EVENT_WIZARD_OZ: + for (uint8 i = 0; i < MAX_OZ_OPERA_MOBS; ++i) + pOrganizer->SummonCreature(aOperaLocOz[i].uiEntry, aOperaLocOz[i].fX, aOperaLocOz[i].fY, aOperaLocOz[i].fZ, aOperaLocOz[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0); + DoRespawnGameObject(GO_OZ_BACKDROP, 12 * HOUR); + for (GuidList::const_iterator itr = m_lOperaHayGuidList.begin(); itr != m_lOperaHayGuidList.end(); ++itr) + DoRespawnGameObject(*itr, 12 * HOUR); + break; + case OPERA_EVENT_RED_RIDING_HOOD: + pOrganizer->SummonCreature(aOperaLocWolf.uiEntry, aOperaLocWolf.fX, aOperaLocWolf.fY, aOperaLocWolf.fZ, aOperaLocWolf.fO, TEMPSUMMON_DEAD_DESPAWN, 0); + DoRespawnGameObject(GO_HOOD_BACKDROP, 12 * HOUR); + DoRespawnGameObject(GO_HOOD_HOUSE, 12 * HOUR); + for (GuidList::const_iterator itr = m_lOperaTreeGuidList.begin(); itr != m_lOperaTreeGuidList.end(); ++itr) + DoRespawnGameObject(*itr, 12 * HOUR); + break; + case OPERA_EVENT_ROMULO_AND_JUL: + pOrganizer->SummonCreature(aOperaLocJul.uiEntry, aOperaLocJul.fX, aOperaLocJul.fY, aOperaLocJul.fZ, aOperaLocJul.fO, TEMPSUMMON_DEAD_DESPAWN, 0); + DoRespawnGameObject(GO_RAJ_BACKDROP, 12 * HOUR); + DoRespawnGameObject(GO_RAJ_MOON, 12 * HOUR); + DoRespawnGameObject(GO_RAJ_BALCONY, 12 * HOUR); + break; + } + + SetData(TYPE_OPERA, IN_PROGRESS); +} + +void instance_karazhan::Update(uint32 uiDiff) +{ + if (m_uiChessResetTimer) + { + // respawn all chess pieces and side stalkers on the original position + if (m_uiChessResetTimer <= uiDiff) + { + for (GuidList::const_iterator itr = m_lChessPiecesAlliance.begin(); itr != m_lChessPiecesAlliance.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->Respawn(); + } + for (GuidList::const_iterator itr = m_lChessPiecesHorde.begin(); itr != m_lChessPiecesHorde.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->Respawn(); + } + + for (GuidList::const_iterator itr = m_lChessAllianceStalkerList.begin(); itr != m_lChessAllianceStalkerList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + { + pTemp->Respawn(); + pTemp->HandleEmote(EMOTE_STATE_NONE); + } + } + for (GuidList::const_iterator itr = m_lChessHordeStalkerList.begin(); itr != m_lChessHordeStalkerList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + { + pTemp->Respawn(); + pTemp->HandleEmote(EMOTE_STATE_NONE); + } + } + + if (GetData(TYPE_CHESS) == FAIL) + SetData(TYPE_CHESS, NOT_STARTED); + else if (GetData(TYPE_CHESS) == DONE) + m_bFriendlyGame = true; + + m_uiChessResetTimer = 0; + } + else + m_uiChessResetTimer -= uiDiff; + } + + // reset Nightbane encounter + if (m_uiNightbaneResetTimer) + { + if (m_uiNightbaneResetTimer <= uiDiff) + { + if (Creature* pNightbane = GetSingleCreatureFromStorage(NPC_NIGHTBANE)) + pNightbane->Respawn(); + + if (GameObject* pUrn = GetSingleGameObjectFromStorage(GO_BLACKENED_URN)) + pUrn->ResetDoorOrButton(); + + m_uiNightbaneResetTimer = 0; + } + else + m_uiNightbaneResetTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_karazhan(Map* pMap) { return new instance_karazhan(pMap); diff --git a/scripts/eastern_kingdoms/karazhan/karazhan.cpp b/scripts/eastern_kingdoms/karazhan/karazhan.cpp index 651f4432b..3d91c2682 100644 --- a/scripts/eastern_kingdoms/karazhan/karazhan.cpp +++ b/scripts/eastern_kingdoms/karazhan/karazhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,13 +17,16 @@ /* ScriptData SDName: Karazhan SD%Complete: 100 -SDComment: Support for Barnes (Opera controller) and Berthold (Doorman). +SDComment: Quest support: 9645. Support for Barnes (Opera controller) and Berthold (Doorman). SDCategory: Karazhan EndScriptData */ /* ContentData npc_barnes npc_berthold +npc_image_of_medivh +npc_image_arcanagos +event_spell_medivh_journal EndContentData */ #include "precompiled.h" @@ -34,276 +37,140 @@ EndContentData */ # npc_barnesAI ######*/ -#define GOSSIP_READY "I'm not an actor." - -#define SAY_READY "Splendid, I'm going to get the audience ready. Break a leg!" -#define SAY_OZ_INTRO1 "Finally, everything is in place. Are you ready for your big stage debut?" -#define OZ_GOSSIP1 "I'm not an actor." -#define SAY_OZ_INTRO2 "Don't worry, you'll be fine. You look like a natural!" -#define OZ_GOSSIP2 "Ok, I'll give it a try, then." - -#define SAY_RAJ_INTRO1 "The romantic plays are really tough, but you'll do better this time. You have TALENT. Ready?" -#define RAJ_GOSSIP1 "I've never been more ready." - -#define OZ_GM_GOSSIP1 "[GM] Change event to EVENT_OZ" -#define OZ_GM_GOSSIP2 "[GM] Change event to EVENT_HOOD" -#define OZ_GM_GOSSIP3 "[GM] Change event to EVENT_RAJ" - -struct Dialogue -{ - int32 iTextId; - uint32 uiTimer; -}; - -static Dialogue aOzDialogue[4]= -{ - {-1532103, 6000}, - {-1532104, 18000}, - {-1532105, 9000}, - {-1532106, 15000} -}; - -static Dialogue aHoodDialogue[4]= -{ - {-1532107, 6000}, - {-1532108, 10000}, - {-1532109, 14000}, - {-1532110, 15000} -}; - -static Dialogue aRAJDialogue[4]= -{ - {-1532111, 5000}, - {-1532112, 7000}, - {-1532113, 14000}, - {-1532114, 14000} -}; - -struct Spawn -{ - uint32 uiEntry; - float fPosX; -}; - -// Entries and spawn locations for creatures in Oz event -Spawn aSpawns_OZ[4]= +enum { - {17535, -10896.0f}, // Dorothee - {17546, -10891.0f}, // Roar - {17547, -10884.0f}, // Tinhead - {17543, -10902.0f}, // Strawman + SAY_BARNES_EVENT_START = -1532115, + + SAY_BARNES_OZ_1 = -1532103, + SAY_BARNES_OZ_2 = -1532104, + SAY_BARNES_OZ_3 = -1532105, + SAY_BARNES_OZ_4 = -1532106, + + SAY_BARNES_HOOD_1 = -1532107, + SAY_BARNES_HOOD_2 = -1532108, + SAY_BARNES_HOOD_3 = -1532109, + SAY_BARNES_HOOD_4 = -1532110, + + SAY_BARNES_RAJ_1 = -1532111, + SAY_BARNES_RAJ_2 = -1532112, + SAY_BARNES_RAJ_3 = -1532113, + SAY_BARNES_RAJ_4 = -1532114, + + // ToDo: it's not very clear which is the gossip sequence for event FAIL case + GOSSIP_ITEM_OPERA_1 = -3532001, + GOSSIP_ITEM_OPERA_2 = -3532002, + GOSSIP_ITEM_JUL_WIPE = -3532003, + GOSSIP_ITEM_WOLF_WIPE = -3532004, + + TEXT_ID_OPERA_1 = 8970, + TEXT_ID_OPERA_2 = 8971, + TEXT_ID_OPERA_WOLF_WIPE = 8975, + TEXT_ID_OPERA_OZ_WIPE = 8781, // guesswork, not confirmed + // TEXT_ID_OPERA_JUL_WIPE = ????, // Item not found in DB: "The romantic plays are really tough, but you'll do better this time. You have TALENT. Ready?" + + // SPELL_SPOTLIGHT = 25824, // in creature_template_addon + SPELL_TUXEDO = 32616, + + NPC_SPOTLIGHT = 19525, }; -Spawn Spawn_HOOD = {17603, -10892.0f}; // Grandmother -Spawn Spawn_RAJ = {17534, -10900.0f}; // Julianne -enum +static const DialogueEntry aIntroDialogue[] = { - NPC_SPOTLIGHT = 19525, - - SPELL_SPOTLIGHT = 25824, - SPELL_TUXEDO = 32616 + {SAY_BARNES_OZ_1, NPC_BARNES, 6000}, + {SAY_BARNES_OZ_2, NPC_BARNES, 18000}, + {SAY_BARNES_OZ_3, NPC_BARNES, 9000}, + {SAY_BARNES_OZ_4, NPC_BARNES, 15000}, + {OPERA_EVENT_WIZARD_OZ, 0, 0}, + {SAY_BARNES_HOOD_1, NPC_BARNES, 6000}, + {SAY_BARNES_HOOD_2, NPC_BARNES, 10000}, + {SAY_BARNES_HOOD_3, NPC_BARNES, 14000}, + {SAY_BARNES_HOOD_4, NPC_BARNES, 15000}, + {OPERA_EVENT_RED_RIDING_HOOD, 0, 0}, + {SAY_BARNES_RAJ_1, NPC_BARNES, 5000}, + {SAY_BARNES_RAJ_2, NPC_BARNES, 7000}, + {SAY_BARNES_RAJ_3, NPC_BARNES, 14000}, + {SAY_BARNES_RAJ_4, NPC_BARNES, 14000}, + {OPERA_EVENT_ROMULO_AND_JUL, 0, 0}, + {0, 0, 0}, }; -const float SPAWN_Z = 90.5f; -const float SPAWN_Y = -1758.0f; -const float SPAWN_O = 4.738f; - -struct MANGOS_DLL_DECL npc_barnesAI : public npc_escortAI +struct npc_barnesAI : public npc_escortAI, private DialogueHelper { - npc_barnesAI(Creature* pCreature) : npc_escortAI(pCreature) + npc_barnesAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aIntroDialogue) { - m_bRaidWiped = false; - m_uiEventId = 0; - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); } - ScriptedInstance* m_pInstance; + instance_karazhan* m_pInstance; ObjectGuid m_spotlightGuid; - uint32 m_uiTalkCount; - uint32 m_uiTalkTimer; - uint32 m_uiWipeTimer; - uint32 m_uiEventId; - - bool m_bPerformanceReady; - bool m_bRaidWiped; - - void Reset() + void Reset() override { m_spotlightGuid.Clear(); - - m_uiTalkCount = 0; - m_uiTalkTimer = 2000; - m_uiWipeTimer = 5000; - - m_bPerformanceReady = false; - - if (m_pInstance) - m_uiEventId = m_pInstance->GetData(DATA_OPERA_PERFORMANCE); } - void StartEvent() + void JustSummoned(Creature* pSummoned) override { - if (!m_pInstance) - return; - - m_pInstance->SetData(TYPE_OPERA, IN_PROGRESS); - - //resets count for this event, in case earlier failed - if (m_uiEventId == EVENT_OZ) - m_pInstance->SetData(DATA_OPERA_OZ_DEATHCOUNT, IN_PROGRESS); - - Start(false, NULL, NULL, true); + if (pSummoned->GetEntry() == NPC_SPOTLIGHT) + m_spotlightGuid = pSummoned->GetObjectGuid(); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { if (!m_pInstance) return; - switch(uiPointId) + switch (uiPointId) { case 0: - m_creature->CastSpell(m_creature, SPELL_TUXEDO, false); + DoCastSpellIfCan(m_creature, SPELL_TUXEDO); m_pInstance->DoUseDoorOrButton(GO_STAGE_DOOR_LEFT); break; case 4: - m_uiTalkCount = 0; - SetEscortPaused(true); - - if (Creature* pSpotlight = m_creature->SummonCreature(NPC_SPOTLIGHT, - m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0.0f, - TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000)) + switch (m_pInstance->GetData(TYPE_OPERA_PERFORMANCE)) { - pSpotlight->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pSpotlight->CastSpell(pSpotlight, SPELL_SPOTLIGHT, false); - m_spotlightGuid = pSpotlight->GetObjectGuid(); + case OPERA_EVENT_WIZARD_OZ: + StartNextDialogueText(SAY_BARNES_OZ_1); + break; + case OPERA_EVENT_RED_RIDING_HOOD: + StartNextDialogueText(SAY_BARNES_HOOD_1); + break; + case OPERA_EVENT_ROMULO_AND_JUL: + StartNextDialogueText(SAY_BARNES_RAJ_1); + break; } + SetEscortPaused(true); + m_creature->SummonCreature(NPC_SPOTLIGHT, 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0); break; case 8: m_pInstance->DoUseDoorOrButton(GO_STAGE_DOOR_LEFT); - m_bPerformanceReady = true; break; case 9: - PrepareEncounter(); - m_pInstance->DoUseDoorOrButton(GO_STAGE_CURTAIN); - break; - } - } - - void Talk(uint32 uiCount) - { - int32 iTextId = 0; - - switch(m_uiEventId) - { - case EVENT_OZ: - if (aOzDialogue[uiCount].iTextId) - iTextId = aOzDialogue[uiCount].iTextId; - if (aOzDialogue[uiCount].uiTimer) - m_uiTalkTimer = aOzDialogue[uiCount].uiTimer; - break; - - case EVENT_HOOD: - if (aHoodDialogue[uiCount].iTextId) - iTextId = aHoodDialogue[uiCount].iTextId; - if (aHoodDialogue[uiCount].uiTimer) - m_uiTalkTimer = aHoodDialogue[uiCount].uiTimer; - break; - - case EVENT_RAJ: - if (aRAJDialogue[uiCount].iTextId) - iTextId = aRAJDialogue[uiCount].iTextId; - if (aRAJDialogue[uiCount].uiTimer) - m_uiTalkTimer = aRAJDialogue[uiCount].uiTimer; + m_pInstance->DoPrepareOperaStage(m_creature); break; } - - if (iTextId) - DoScriptText(iTextId, m_creature); } - void PrepareEncounter() + void JustDidDialogueStep(int32 iEntry) override { - debug_log("SD2: Barnes Opera Event - Introduction complete - preparing encounter %d", m_uiEventId); - - switch(m_uiEventId) + switch (iEntry) { - case EVENT_OZ: - for(int i=0; i < 4; ++i) - m_creature->SummonCreature(aSpawns_OZ[i].uiEntry, aSpawns_OZ[i].fPosX, SPAWN_Y, SPAWN_Z, SPAWN_O, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR*2*IN_MILLISECONDS); - break; - case EVENT_HOOD: - m_creature->SummonCreature(Spawn_HOOD.uiEntry, Spawn_HOOD.fPosX, SPAWN_Y, SPAWN_Z, SPAWN_O, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR*2*IN_MILLISECONDS); - break; - case EVENT_RAJ: - m_creature->SummonCreature(Spawn_RAJ.uiEntry, Spawn_RAJ.fPosX, SPAWN_Y, SPAWN_Z, SPAWN_O, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, HOUR*2*IN_MILLISECONDS); - break; - default: - error_log("SD2: Barnes Opera Event - Wrong EventId set: %d", m_uiEventId); + case OPERA_EVENT_WIZARD_OZ: + case OPERA_EVENT_RED_RIDING_HOOD: + case OPERA_EVENT_ROMULO_AND_JUL: + // Despawn spotlight and resume escort + if (Creature* pSpotlight = m_creature->GetMap()->GetCreature(m_spotlightGuid)) + pSpotlight->ForcedDespawn(); + SetEscortPaused(false); break; } - - m_bRaidWiped = false; } - void UpdateEscortAI(const uint32 uiDiff) - { - if (HasEscortState(STATE_ESCORT_PAUSED)) - { - if (m_uiTalkTimer < uiDiff) - { - if (m_uiTalkCount > 3) - { - if (Creature* pSpotlight = m_creature->GetMap()->GetCreature(m_spotlightGuid)) - pSpotlight->ForcedDespawn(); - - SetEscortPaused(false); - return; - } - - Talk(m_uiTalkCount++); - } - else - m_uiTalkTimer -= uiDiff; - } - - if (m_bPerformanceReady) - { - if (!m_bRaidWiped) - { - if (m_uiWipeTimer < uiDiff) - { - Map *pMap = m_creature->GetMap(); - if (!pMap->IsDungeon()) - return; - - Map::PlayerList const &PlayerList = pMap->GetPlayers(); - if (PlayerList.isEmpty()) - return; - - m_bRaidWiped = true; - for(Map::PlayerList::const_iterator i = PlayerList.begin();i != PlayerList.end(); ++i) - { - if (i->getSource()->isAlive() && !i->getSource()->isGameMaster()) - { - m_bRaidWiped = false; - break; - } - } - - if (m_bRaidWiped) - EnterEvadeMode(); - - m_uiWipeTimer = 15000; - } - else - m_uiWipeTimer -= uiDiff; - } - } - } + void UpdateEscortAI(const uint32 uiDiff) { DialogueUpdate(uiDiff); } }; CreatureAI* GetAI_npc_barnesAI(Creature* pCreature) @@ -315,66 +182,71 @@ bool GossipHello_npc_barnes(Player* pPlayer, Creature* pCreature) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) { - // Check for death of Moroes and if opera event is not done already - if (pInstance->GetData(TYPE_MOROES) == DONE && pInstance->GetData(TYPE_OPERA) != DONE) + // Check if opera event is not yet in progress + if (pInstance->GetData(TYPE_OPERA) == IN_PROGRESS || pInstance->GetData(TYPE_OPERA) == DONE) + return true; + + // Check for death of Moroes + if (pInstance->GetData(TYPE_MOROES) == DONE) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, OZ_GOSSIP1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_OPERA_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - if (pPlayer->isGameMaster()) // for GMs we add the possibility to change the event + // for GMs we add the possibility to change the event + if (pPlayer->isGameMaster()) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, OZ_GM_GOSSIP1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, OZ_GM_GOSSIP2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, OZ_GM_GOSSIP3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "[GM] Change event to EVENT_OZ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "[GM] Change event to EVENT_HOOD", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "[GM] Change event to EVENT_RAJ", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); } - if (npc_barnesAI* pBarnesAI = dynamic_cast(pCreature->AI())) - { - if (!pBarnesAI->m_bRaidWiped) - pPlayer->SEND_GOSSIP_MENU(8970, pCreature->GetObjectGuid()); - else - pPlayer->SEND_GOSSIP_MENU(8975, pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_OPERA_1, pCreature->GetObjectGuid()); - return true; - } + return true; } } - pPlayer->SEND_GOSSIP_MENU(8978, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_barnes(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_barnes(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - npc_barnesAI* pBarnesAI = dynamic_cast(pCreature->AI()); - - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, OZ_GOSSIP2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(8971, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_OPERA_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_OPERA_2, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: pPlayer->CLOSE_GOSSIP_MENU(); - if (pBarnesAI) - pBarnesAI->StartEvent(); + DoScriptText(SAY_BARNES_EVENT_START, pCreature); + // start the stage escort + if (npc_barnesAI* pBarnesAI = dynamic_cast(pCreature->AI())) + pBarnesAI->Start(false, NULL, NULL, true); break; + // GM gossip options case GOSSIP_ACTION_INFO_DEF+3: pPlayer->CLOSE_GOSSIP_MENU(); - if (pBarnesAI && pPlayer->isGameMaster()) - pBarnesAI->m_uiEventId = EVENT_OZ; - outstring_log("SD2: %s manually set Opera event to EVENT_OZ", pPlayer->GetGuidStr().c_str()); + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + pInstance->SetData(TYPE_OPERA_PERFORMANCE, OPERA_EVENT_WIZARD_OZ); + outstring_log("SD2: %s manually set Opera event to EVENT_OZ", pPlayer->GetGuidStr().c_str()); + } break; case GOSSIP_ACTION_INFO_DEF+4: pPlayer->CLOSE_GOSSIP_MENU(); - if (pBarnesAI && pPlayer->isGameMaster()) - pBarnesAI->m_uiEventId = EVENT_HOOD; - outstring_log("SD2: %s manually set Opera event to EVENT_HOOD", pPlayer->GetGuidStr().c_str()); + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + pInstance->SetData(TYPE_OPERA_PERFORMANCE, OPERA_EVENT_RED_RIDING_HOOD); + outstring_log("SD2: %s manually set Opera event to EVENT_HOOD", pPlayer->GetGuidStr().c_str()); + } break; case GOSSIP_ACTION_INFO_DEF+5: pPlayer->CLOSE_GOSSIP_MENU(); - if (pBarnesAI && pPlayer->isGameMaster()) - pBarnesAI->m_uiEventId = EVENT_RAJ; - outstring_log("SD2: %s manually set Opera event to EVENT_RAJ", pPlayer->GetGuidStr().c_str()); + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + pInstance->SetData(TYPE_OPERA_PERFORMANCE, OPERA_EVENT_ROMULO_AND_JUL); + outstring_log("SD2: %s manually set Opera event to EVENT_RAJ", pPlayer->GetGuidStr().c_str()); + } break; } @@ -387,25 +259,25 @@ bool GossipSelect_npc_barnes(Player* pPlayer, Creature* pCreature, uint32 uiSend enum { + GOSSIP_ITEM_TELEPORT = -3532000, + SPELL_TELEPORT = 39567 }; -#define GOSSIP_ITEM_TELEPORT "Teleport me to the Guardian's Library" - bool GossipHello_npc_berthold(Player* pPlayer, Creature* pCreature) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) { // Check if Shade of Aran event is done if (pInstance->GetData(TYPE_ARAN) == DONE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); } pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_berthold(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_berthold(Player* pPlayer, Creature* /*pCreature*/, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) pPlayer->CastSpell(pPlayer, SPELL_TELEPORT, true); @@ -414,6 +286,227 @@ bool GossipSelect_npc_berthold(Player* pPlayer, Creature* pCreature, uint32 uiSe return true; } +/*###### +# npc_image_of_medivh +######*/ + +enum +{ + // yells + SAY_MEDIVH_1 = -1532116, + SAY_ARCANAGOS_2 = -1532117, + SAY_MEDIVH_3 = -1532118, + SAY_ARCANAGOS_4 = -1532119, + SAY_MEDIVH_5 = -1532120, + SAY_ARCANAGOS_6 = -1532121, + EMOTE_CAST_SPELL = -1532122, + SAY_ARCANAGOS_7 = -1532123, + SAY_MEDIVH_8 = -1532124, + + // spells + // Arcanagos + // SPELL_NOTIFY_FLEE = 30985, // not used - allow Medivh to return inside after the dragon has escaped + // SPELL_PREPARE_FIREBALL= 30970, // not used - allow Medivh to cast fireball + SPELL_REFLECTION = 30969, + // SPELL_SHOOT_FIREBALL = 30968, // not used + SPELL_FIREBALL_REFLECT = 30971, + + // Medivh + // SPELL_FROST_BREATH = 30974, // not used + SPELL_CONFLAG_BLAST = 30977, // cast on Arcanagos + SPELL_EVOCATION = 30972, // prepare the Conflagration Blast + SPELL_FIREBALL = 30967, + // SPELL_FLY_TO_DEATH = 30936, // not used - inform the dragon to move to death Location + SPELL_MANA_SHIELD = 30973, + + // NPC_ARCANAGOS_CREDIT = 17665, // purpose unk + + QUEST_MASTERS_TERRACE = 9645, + + POINT_ID_INTRO = 1, + POINT_ID_DESPAWN = 2, +}; + +/* Notes for future development of the event: + * this whole event includes a lot of guesswork + * the dummy spells usage is unk; for the moment they are not used + * also all coords are guesswork + */ +static const float afMedivhSpawnLoc[4] = { -11153.18f, -1889.65f, 91.47f, 2.07f}; +static const float afMedivhExitLoc[3] = { -11121.81f, -1881.24f, 91.47f}; + +static const float afArcanagosSpawnLoc[4] = { -11242.66f, -1778.55f, 125.35f, 0.0f}; +static const float afArcanagosMoveLoc[3] = { -11170.28f, -1865.09f, 125.35f}; +static const float afArcanagosFleeLoc[3] = { -11003.70f, -1760.18f, 180.25f}; + +static const DialogueEntry aMedivhDialogue[] = +{ + {NPC_IMAGE_OF_MEDIVH, 0, 10000}, + {SAY_MEDIVH_1, NPC_IMAGE_OF_MEDIVH, 6000}, + {SAY_ARCANAGOS_2, NPC_IMAGE_OF_ARCANAGOS, 10000}, + {SAY_MEDIVH_3, NPC_IMAGE_OF_MEDIVH, 6000}, + {SAY_ARCANAGOS_4, NPC_IMAGE_OF_ARCANAGOS, 8000}, + {SAY_MEDIVH_5, NPC_IMAGE_OF_MEDIVH, 7000}, + {SAY_ARCANAGOS_6, NPC_IMAGE_OF_ARCANAGOS, 0}, + {SPELL_MANA_SHIELD, 0, 4000}, + {EMOTE_CAST_SPELL, NPC_IMAGE_OF_MEDIVH, 5000}, + {SPELL_CONFLAG_BLAST, 0, 1000}, + {SAY_ARCANAGOS_7, NPC_IMAGE_OF_ARCANAGOS, 10000}, + {SAY_MEDIVH_8, NPC_IMAGE_OF_MEDIVH, 0}, + {0, 0, 0}, +}; + +struct npc_image_of_medivhAI : public ScriptedAI, private DialogueHelper +{ + npc_image_of_medivhAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aMedivhDialogue) + { + m_pInstance = (instance_karazhan*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_karazhan* m_pInstance; + + ObjectGuid m_eventStarterGuid; + + void Reset() override { } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_IMAGE_OF_ARCANAGOS) + { + pSummoned->SetLevitate(true); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(POINT_ID_INTRO, afArcanagosMoveLoc[0], afArcanagosMoveLoc[1], afArcanagosMoveLoc[2]); + pSummoned->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_IMAGE_OF_ARCANAGOS) + return; + + switch (uiPointId) + { + case POINT_ID_INTRO: + StartNextDialogueText(NPC_IMAGE_OF_MEDIVH); + break; + case POINT_ID_DESPAWN: + pSummoned->ForcedDespawn(); + m_creature->ForcedDespawn(10000); + m_creature->GetMotionMaster()->MovePoint(0, afMedivhExitLoc[0], afMedivhExitLoc[1], afMedivhExitLoc[2]); + // complete quest + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_eventStarterGuid)) + pPlayer->GroupEventHappens(QUEST_MASTERS_TERRACE, m_creature); + break; + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_FIREBALL_REFLECT && pCaster->GetEntry() == NPC_IMAGE_OF_ARCANAGOS) + { + StartNextDialogueText(SPELL_MANA_SHIELD); + DoCastSpellIfCan(m_creature, SPELL_MANA_SHIELD); + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case SAY_ARCANAGOS_6: + if (Creature* pDragon = m_pInstance->GetSingleCreatureFromStorage(NPC_IMAGE_OF_ARCANAGOS)) + DoCastSpellIfCan(pDragon, SPELL_FIREBALL); + break; + case EMOTE_CAST_SPELL: + DoCastSpellIfCan(m_creature, SPELL_EVOCATION); + break; + case SPELL_CONFLAG_BLAST: + m_creature->RemoveAurasDueToSpell(SPELL_EVOCATION); + if (Creature* pDragon = m_pInstance->GetSingleCreatureFromStorage(NPC_IMAGE_OF_ARCANAGOS)) + { + DoCastSpellIfCan(pDragon, SPELL_CONFLAG_BLAST, CAST_TRIGGERED); + pDragon->GetMotionMaster()->MovePoint(POINT_ID_DESPAWN, afArcanagosFleeLoc[0], afArcanagosFleeLoc[1], afArcanagosFleeLoc[2]); + } + break; + } + } + + void SetEventStarter(ObjectGuid m_starterGuid) { m_eventStarterGuid = m_starterGuid; } + + void UpdateAI(const uint32 uiDiff) { DialogueUpdate(uiDiff); } +}; + +CreatureAI* GetAI_npc_image_of_medivhAI(Creature* pCreature) +{ + return new npc_image_of_medivhAI(pCreature); +} + +/*###### +# npc_image_arcanagos +######*/ + +struct npc_image_arcanagosAI : public ScriptedAI +{ + npc_image_arcanagosAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_FIREBALL && pCaster->GetEntry() == NPC_IMAGE_OF_MEDIVH) + { + // !!!Workaround Alert!!! - the spell should be cast on Medivh without changing the unit flags! + pCaster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + DoCastSpellIfCan(pCaster, SPELL_FIREBALL_REFLECT, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_REFLECTION, CAST_TRIGGERED); + + pCaster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_image_arcanagosAI(Creature* pCreature) +{ + return new npc_image_arcanagosAI(pCreature); +} + +/*###### +# event_spell_medivh_journal +######*/ + +bool ProcessEventId_event_spell_medivh_journal(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + { + // Summon Medivh and Arcanagos + if (Creature* pMedivh = ((Player*)pSource)->SummonCreature(NPC_IMAGE_OF_MEDIVH, afMedivhSpawnLoc[0], afMedivhSpawnLoc[1], afMedivhSpawnLoc[2], afMedivhSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pMedivh->SummonCreature(NPC_IMAGE_OF_ARCANAGOS, afArcanagosSpawnLoc[0], afArcanagosSpawnLoc[1], afArcanagosSpawnLoc[2], afArcanagosSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + + // store the player who started the event + if (npc_image_of_medivhAI* pMedivhAI = dynamic_cast(pMedivh->AI())) + pMedivhAI->SetEventStarter(pSource->GetObjectGuid()); + } + } + + return true; +} + void AddSC_karazhan() { Script* pNewScript; @@ -430,4 +523,19 @@ void AddSC_karazhan() pNewScript->pGossipHello = &GossipHello_npc_berthold; pNewScript->pGossipSelect = &GossipSelect_npc_berthold; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_image_of_medivh"; + pNewScript->GetAI = &GetAI_npc_image_of_medivhAI; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_image_arcanagos"; + pNewScript->GetAI = &GetAI_npc_image_arcanagosAI; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_medivh_journal"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_medivh_journal; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/karazhan/karazhan.h b/scripts/eastern_kingdoms/karazhan/karazhan.h index f070375d1..08c5806bb 100644 --- a/scripts/eastern_kingdoms/karazhan/karazhan.h +++ b/scripts/eastern_kingdoms/karazhan/karazhan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,6 +8,7 @@ enum { MAX_ENCOUNTER = 11, + MAX_OZ_OPERA_MOBS = 4, TYPE_ATTUMEN = 0, TYPE_MOROES = 1, @@ -20,13 +21,62 @@ enum TYPE_CHESS = 8, TYPE_MALCHEZZAR = 9, TYPE_NIGHTBANE = 10, + TYPE_OPERA_PERFORMANCE = 11, // no regular encounter - just store one random opera event - DATA_OPERA_PERFORMANCE = 11, - DATA_OPERA_OZ_DEATHCOUNT = 12, - + NPC_ATTUMEN = 15550, + NPC_MIDNIGHT = 16151, NPC_MOROES = 15687, + NPC_BARNES = 16812, // NPC_TERESTIAN = 15688, NPC_NIGHTBANE = 17225, + NPC_NIGHTBANE_HELPER = 17260, + NPC_NETHERSPITE = 15689, + NPC_ECHO_MEDIVH = 16816, + NPC_INVISIBLE_STALKER = 22519, // placeholder for dead chess npcs + NPC_CHESS_STATUS_BAR = 22520, // npc that controlls the transformation of dead pieces + NPC_CHESS_VICTORY_CONTROLLER = 22524, + // NPC_CHESS_SOUND_BUNNY = 21921, // npc that handles the encounter sounds + // NPC_WAITING_ROOM_STALKER = 17459, // trigger which marks the teleport location of the players; also used to cast some control spells during the game + NPC_SQUARE_WHITE = 17208, // chess white square + NPC_SQUARE_BLACK = 17305, // chess black square + // NPC_SQUARE_OUTSIDE_BLACK = 17316, // outside chess black square + // NPC_SQUARE_OUTSIDE_WHITE = 17317, // outside chess white square + + // Moroes event related + NPC_LADY_KEIRA_BERRYBUCK = 17007, + NPC_LADY_CATRIONA_VON_INDI = 19872, + NPC_LORD_CRISPIN_FERENCE = 19873, + NPC_BARON_RAFE_DREUGER = 19874, + NPC_BARONESS_DOROTHEA_MILLSTIPE = 19875, + NPC_LORD_ROBIN_DARIS = 19876, + + // Opera event + NPC_DOROTHEE = 17535, + NPC_ROAR = 17546, + NPC_TINHEAD = 17547, + NPC_STRAWMAN = 17543, + NPC_CRONE = 18168, + NPC_GRANDMOTHER = 17603, + NPC_JULIANNE = 17534, + NPC_ROMULO = 17533, + + // The Master's Terrace quest related + NPC_IMAGE_OF_MEDIVH = 17651, + NPC_IMAGE_OF_ARCANAGOS = 17652, + + // Chess event + NPC_ORC_GRUNT = 17469, // pawn + NPC_ORC_WOLF = 21748, // knight + NPC_ORC_WARLOCK = 21750, // queen + NPC_ORC_NECROLYTE = 21747, // bishop + NPC_SUMMONED_DAEMON = 21726, // rook + NPC_WARCHIEF_BLACKHAND = 21752, // king + NPC_HUMAN_FOOTMAN = 17211, // pawn + NPC_HUMAN_CHARGER = 21664, // knight + NPC_HUMAN_CONJURER = 21683, // queen + NPC_HUMAN_CLERIC = 21682, // bishop + NPC_CONJURED_WATER_ELEMENTAL = 21160, // rook + NPC_KING_LLANE = 21684, // king GO_STAGE_CURTAIN = 183932, GO_STAGE_DOOR_LEFT = 184278, @@ -38,6 +88,9 @@ enum GO_NETHERSPACE_DOOR = 185134, GO_SIDE_ENTRANCE_DOOR = 184275, GO_DUST_COVERED_CHEST = 185119, + GO_MASTERS_TERRACE_DOOR_1 = 184274, + GO_MASTERS_TERRACE_DOOR_2 = 184280, + GO_BLACKENED_URN = 194092, // Opera event stage decoration GO_OZ_BACKDROP = 183442, @@ -48,52 +101,107 @@ enum GO_RAJ_BACKDROP = 183443, GO_RAJ_MOON = 183494, GO_RAJ_BALCONY = 183495, + + // Chess event spells + SPELL_CLEAR_BOARD = 37366, // spell cast to clear the board at the end of the event + SPELL_GAME_IN_SESSION = 39331, // debuff on players received while the game is in session + SPELL_FORCE_KILL_BUNNY = 45260, // triggers 45259 + SPELL_GAME_OVER = 39401, // cast by Medivh on game end + SPELL_VICTORY_VISUAL = 39395, // cast by the Victory controller on game end + + FACTION_ID_CHESS_HORDE = 1689, + FACTION_ID_CHESS_ALLIANCE = 1690, }; enum OperaEvents { - EVENT_OZ = 1, - EVENT_HOOD = 2, - EVENT_RAJ = 3 + OPERA_EVENT_WIZARD_OZ = 1, + OPERA_EVENT_RED_RIDING_HOOD = 2, + OPERA_EVENT_ROMULO_AND_JUL = 3 +}; + +struct OperaSpawns +{ + uint32 uiEntry; + float fX, fY, fZ, fO; }; -class MANGOS_DLL_DECL instance_karazhan : public ScriptedInstance +static const OperaSpawns aOperaLocOz[MAX_OZ_OPERA_MOBS] = +{ + {NPC_DOROTHEE, -10896.65f, -1757.62f, 90.55f, 4.86f}, + {NPC_ROAR, -10889.53f, -1758.10f, 90.55f, 4.57f}, + {NPC_TINHEAD, -10883.84f, -1758.85f, 90.55f, 4.53f}, + {NPC_STRAWMAN, -10902.11f, -1756.45f, 90.55f, 4.66f}, +}; + +static const OperaSpawns aOperaLocWolf = {NPC_GRANDMOTHER, -10892.01f, -1758.01f, 90.55f, 4.73f}; +static const OperaSpawns aOperaLocJul = {NPC_JULIANNE, -10893.56f, -1760.43f, 90.55f, 4.55f}; + +static const float afChroneSpawnLoc[4] = { -10893.11f, -1757.85f, 90.55f, 4.60f}; + +class instance_karazhan : public ScriptedInstance { public: instance_karazhan(Map* pMap); ~instance_karazhan() {} - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureDeath(Creature* pCreature) override; - void Load(const char* chrIn); - const char* Save() { return m_strInstData.c_str(); } + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void DoPrepareOperaStage(Creature* pOrganizer); + + uint32 GetPlayerTeam() { return m_uiTeam; } + bool IsFriendlyGameReady() { return m_bFriendlyGame; } + void DoMoveChessPieceToSides(uint32 uiSpellId, uint32 uiFaction, bool bGameEnd = false); + void GetChessPiecesByFaction(GuidList& lList, uint32 uiFaction) { lList = uiFaction == FACTION_ID_CHESS_ALLIANCE ? m_lChessPiecesAlliance : m_lChessPiecesHorde; } + + void GetNightbaneTriggers(GuidList& lList, bool bGround) { lList = bGround ? m_lNightbaneGroundTriggers : m_lNightbaneAirTriggers; } + + void Load(const char* chrIn) override; + const char* Save() const override { return m_strInstData.c_str(); } + + void Update(uint32 uiDiff) override; private: + void DoPrepareChessEvent(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; uint32 m_uiOperaEvent; uint32 m_uiOzDeathCount; -}; + uint32 m_uiTeam; // Team of first entered player, used for the Chess event + uint32 m_uiChessResetTimer; + uint32 m_uiNightbaneResetTimer; -class MANGOS_DLL_DECL npc_fiendish_portalAI : public ScriptedAI -{ - public: - npc_fiendish_portalAI(Creature* pCreature); - ~npc_fiendish_portalAI() {} + uint8 m_uiAllianceStalkerCount; + uint8 m_uiHordeStalkerCount; + + bool m_bFriendlyGame; + + ObjectGuid m_HordeStatusGuid; + ObjectGuid m_AllianceStatusGuid; - void Reset(); - void JustSummoned(Creature* pSummoned); - void UpdateAI(const uint32 uiDiff); + GuidList m_lOperaTreeGuidList; + GuidList m_lOperaHayGuidList; + GuidList m_lNightbaneGroundTriggers; + GuidList m_lNightbaneAirTriggers; - uint32 m_uiSummonTimer; + GuidList m_lChessHordeStalkerList; + GuidList m_lChessAllianceStalkerList; + GuidList m_lChessPiecesAlliance; + GuidList m_lChessPiecesHorde; + GuidVector m_vHordeStalkers; + GuidVector m_vAllianceStalkers; }; #endif diff --git a/scripts/eastern_kingdoms/loch_modan.cpp b/scripts/eastern_kingdoms/loch_modan.cpp index 0cf5d9161..54a453fd6 100644 --- a/scripts/eastern_kingdoms/loch_modan.cpp +++ b/scripts/eastern_kingdoms/loch_modan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,16 +39,16 @@ bool GossipHello_npc_mountaineer_pebblebitty(Player* pPlayer, Creature* pCreatur pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (!pPlayer->GetQuestRewardStatus(3181) == 1) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Open the gate please, i need to get to Searing Gorge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Open the gate please, i need to get to Searing Gorge", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_mountaineer_pebblebitty(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_mountaineer_pebblebitty(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "But i need to get there, now open the gate!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); @@ -104,11 +104,11 @@ struct Location static const Location m_afAmbushSpawn[] = { - {-5691.93f,-3745.91f,319.159f, 2.21f}, - {-5706.98f,-3745.39f,318.728f, 1.04f} + { -5691.93f, -3745.91f, 319.159f, 2.21f}, + { -5706.98f, -3745.39f, 318.728f, 1.04f} }; -struct MANGOS_DLL_DECL npc_miranAI: public npc_escortAI +struct npc_miranAI: public npc_escortAI { npc_miranAI(Creature* pCreature): npc_escortAI(pCreature) { @@ -117,13 +117,13 @@ struct MANGOS_DLL_DECL npc_miranAI: public npc_escortAI uint8 m_uiDwarves; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) m_uiDwarves = 0; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { @@ -140,7 +140,7 @@ struct MANGOS_DLL_DECL npc_miranAI: public npc_escortAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_DARK_IRON_DWARF) { @@ -150,7 +150,7 @@ struct MANGOS_DLL_DECL npc_miranAI: public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_DARK_IRON_DWARF) { @@ -166,7 +166,7 @@ bool QuestAccept_npc_miran(Player* pPlayer, Creature* pCreature, const Quest* pQ { if (pQuest->GetQuestId() == QUEST_PROTECTING_THE_SHIPMENT) { - if (npc_miranAI* pEscortAI = dynamic_cast(pCreature->AI())) + if (npc_miranAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); } return true; diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp index 26a0b53ad..40b42e78f 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp +++ b/scripts/eastern_kingdoms/magisters_terrace/boss_felblood_kaelthas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,18 +16,18 @@ /* ScriptData SDName: Boss_Felblood_Kaelthas -SD%Complete: 80 -SDComment: Normal and Heroic Support. Issues: Arcane Spheres do not initially follow targets. +SD%Complete: 90 +SDComment: Minor adjustments required; Timers. SDCategory: Magisters' Terrace EndScriptData */ #include "precompiled.h" #include "magisters_terrace.h" -#include "WorldPacket.h" enum { - SAY_AGGRO = -1585023, // This yell should be done when the room is cleared. For now, set it as a movelineofsight yell. + SAY_INTRO_1 = -1585023, // This yell should be done when the room is cleared. For now, set it as a movelineofsight yell. + SAY_INTRO_2 = -1585030, SAY_PHOENIX = -1585024, SAY_FLAMESTRIKE = -1585025, SAY_GRAVITY_LAPSE = -1585026, @@ -38,38 +38,66 @@ enum // Phase 1 spells SPELL_FIREBALL = 44189, // Deals 2700-3300 damage at current target SPELL_FIREBALL_H = 46164, // 4950-6050 - SPELL_PHOENIX = 44194, // Summons a phoenix - SPELL_PHOENIX_BURN = 44197, // A spell Phoenix uses to damage everything around - SPELL_REBIRTH_DMG = 44196, // DMG if a Phoenix rebirth happen - - SPELL_FLAME_STRIKE_DUMMY = 44191, // Flamestrike indicator before the damage SPELL_FLAME_STRIKE = 44192, // Summons the trigger + animation (projectile) - SPELL_SHOCK_BARRIER = 46165, // Heroic only; 10k damage shield, followed by Pyroblast SPELL_PYROBLAST = 36819, // Heroic only; 45-55k fire damage // Phase 2 spells - SPELL_GRAVITY_LAPSE_INITIAL = 44224, // Cast at the beginning of every Gravity Lapse - SPELL_GRAVITY_LAPSE_CHANNEL = 44251, // Channeled; blue beam animation to every enemy in range - SPELL_TELEPORT_CENTER = 44218, // Should teleport people to the center. Requires DB entry in spell_target_position. - SPELL_GRAVITY_LAPSE_FLY = 44227, // Hastens flyspeed and allows flying for 1 minute. For some reason removes 44226. + SPELL_GRAVITY_LAPSE = 44224, // Cast at the beginning of every Gravity Lapse + SPELL_GRAVITY_LAPSE_VISUAL = 44251, // Channeled; blue beam animation to every enemy in range - when removed the Gravity Lapse auras are removed from players + SPELL_TELEPORT_CENTER = 44218, // Teleport the boss in the center. Requires DB entry in spell_target_position. + SPELL_GRAVITY_LAPSE_FLY = 44227, // Hastens flyspeed and allows flying for 1 minute. Requires aura stacking exception for 44226. SPELL_GRAVITY_LAPSE_DOT = 44226, // Knocks up in the air and applies a 300 DPS DoT. - SPELL_ARCANE_SPHERE_PASSIVE = 44263, // Passive auras on Arcane Spheres + SPELL_ARCANE_SPHERE_SUMMON = 44265, // Summons 1 arcane sphere SPELL_POWER_FEEDBACK = 44233, // Stuns him, making him take 50% more damage for 10 seconds. Cast after Gravity Lapse + // Summoned spells + SPELL_ARCANE_SPHERE_PASSIVE = 44263, // Passive auras on Arcane Spheres + SPELL_FLAME_STRIKE_DUMMY = 44191, // Flamestrike indicator before the damage + SPELL_EMBER_BLAST = 44199, // On Phoenix death + SPELL_PHOENIX_BURN = 44197, // A spell Phoenix uses to damage everything around + SPELL_REBIRTH_DMG = 44196, // DMG if a Phoenix rebirth happen + + // Summoned creatures NPC_FLAME_STRIKE_TRIGGER = 24666, NPC_PHOENIX = 24674, NPC_PHOENIX_EGG = 24675, NPC_ARCANE_SPHERE = 24708, + + MAX_ARCANE_SPHERES = 3, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_INTRO_1, NPC_KAELTHAS, 16000}, + {EMOTE_ONESHOT_LAUGH, 0, 2000}, + {EMOTE_STATE_TALK, 0, 2000}, + {SAY_INTRO_2, NPC_KAELTHAS, 16000}, + {NPC_PHOENIX, 0, 0}, + {SAY_DEATH, NPC_KAELTHAS, 4000}, + {EMOTE_ONESHOT_POINT, 0, 5000}, + {EMOTE_ONESHOT_ROAR, 0, 3000}, + {NPC_PHOENIX_EGG, 0, 0}, + {0, 0, 0}, }; -struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI +// Spells used to teleport players for Gravity Lapse +static const uint32 aGravityLapseSpells[] = {44219, 44220, 44221, 44222, 44223}; + +/*###### +## boss_felblood_kaelthas +######*/ + +struct boss_felblood_kaelthasAI : public ScriptedAI, private DialogueHelper { - boss_felblood_kaelthasAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_felblood_kaelthasAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + m_bHasTaunted = false; Reset(); } @@ -79,168 +107,181 @@ struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI uint32 m_uiFireballTimer; uint32 m_uiPhoenixTimer; uint32 m_uiFlameStrikeTimer; - uint32 m_uiCombatPulseTimer; // Heroic only + uint32 m_uiShockBarrierTimer; uint32 m_uiPyroblastTimer; uint32 m_uiGravityLapseTimer; - uint32 m_uiGravityLapsePhase; - // 0 = No Gravity Lapse - // 1 = Casting Gravity Lapse visual - // 2 = Teleported people to self - // 3 = Knocked people up in the air - // 4 = Applied an aura that allows them to fly, channeling visual, relased Arcane Orbs. + uint32 m_uiGravityLapseStage; + uint8 m_uiGravityIndex; + bool m_bIsFirstPhase; bool m_bFirstGravityLapse; bool m_bHasTaunted; - uint8 m_uiPhase; - // 0 = Not started - // 1 = Fireball; Summon Phoenix; Flamestrike - // 2 = Gravity Lapses - - void Reset() + void Reset() override { - // TODO: Timers - m_uiFireballTimer = 0; - m_uiPhoenixTimer = 10000; - m_uiFlameStrikeTimer = 25000; - m_uiCombatPulseTimer = 0; + m_uiFireballTimer = 0; + m_uiPhoenixTimer = 10000; + m_uiFlameStrikeTimer = 25000; - m_uiPyroblastTimer = 60000; + m_uiPyroblastTimer = 0; + m_uiShockBarrierTimer = 60000; - m_uiGravityLapseTimer = 0; - m_uiGravityLapsePhase = 0; + m_uiGravityLapseTimer = 1000; + m_uiGravityLapseStage = 0; + m_uiGravityIndex = 0; - m_bFirstGravityLapse = true; - m_bHasTaunted = false; + m_bFirstGravityLapse = true; + m_bIsFirstPhase = true; - m_uiPhase = 0; + SetCombatMovement(true); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - DoScriptText(SAY_DEATH, m_creature); - if (m_pInstance) m_pInstance->SetData(TYPE_KAELTHAS, DONE); } - void DamageTaken(Unit* pDealer, uint32& uiDamage) - { - if (uiDamage > m_creature->GetHealth()) - RemoveGravityLapse(); // Remove Gravity Lapse so that players fall to ground if they kill him when in air. - } - - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_KAELTHAS, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_KAELTHAS, FAIL); } - void MoveInLineOfSight(Unit* pWho) + // Boss has an interesting speech before killed, so we need to fake death (without stand state) and allow him to finish his theatre + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override { - if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 40.0)) + if (uiDamage < m_creature->GetHealth()) + return; + + // Make sure it won't die by accident + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) { - DoScriptText(SAY_AGGRO, m_creature); - m_bHasTaunted = true; + uiDamage = 0; + return; } - ScriptedAI::MoveInLineOfSight(pWho); + uiDamage = 0; + RemoveGravityLapse(); + StartNextDialogueText(SAY_DEATH); + m_creature->HandleEmote(EMOTE_STATE_TALK); + + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); } - void JustSummoned(Creature* pSummoned) + void MoveInLineOfSight(Unit* pWho) override { - switch (pSummoned->GetEntry()) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->IsWithinDistInMap(pWho, 40.0) && m_creature->IsWithinLOSInMap(pWho)) { - case NPC_FLAME_STRIKE_TRIGGER: - pSummoned->CastSpell(pSummoned, SPELL_FLAME_STRIKE_DUMMY, false, NULL, NULL, m_creature->GetObjectGuid()); - break; - case NPC_PHOENIX: - // TODO ThreatList and Flag removal likely wrong - pSummoned->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE); - SetThreatList(pSummoned); - - if (m_creature->getVictim()) - pSummoned->AI()->AttackStart(m_creature->getVictim()); - break; + StartNextDialogueText(SAY_INTRO_1); + m_creature->HandleEmote(EMOTE_STATE_TALK); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_bHasTaunted = true; } - } - void SetThreatList(Creature* SummonedUnit) - { - if (!SummonedUnit) + // Allow him to finish intro + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) return; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - if (pUnit && pUnit->isAlive()) - { - float threat = m_creature->getThreatManager().getThreat(pUnit); - SummonedUnit->AddThreat(pUnit, threat); - } + case EMOTE_ONESHOT_LAUGH: + m_creature->HandleEmote(EMOTE_ONESHOT_LAUGH); + break; + case EMOTE_STATE_TALK: + m_creature->HandleEmote(EMOTE_STATE_TALK); + break; + case NPC_PHOENIX: + m_creature->HandleEmote(EMOTE_STATE_NONE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + break; + case EMOTE_ONESHOT_POINT: + m_creature->HandleEmote(EMOTE_ONESHOT_POINT); + break; + case EMOTE_ONESHOT_ROAR: + m_creature->HandleEmote(EMOTE_ONESHOT_ROAR); + break; + case NPC_PHOENIX_EGG: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + break; } } - void TeleportPlayersToSelf() + void AttackStart(Unit* pWho) override { - DoCastSpellIfCan(m_creature, SPELL_TELEPORT_CENTER, CAST_TRIGGERED); - - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) + if (m_creature->Attack(pWho, true)) { - Unit* pUnit = m_creature->GetMap()->GetUnit(*i); - - if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) - pUnit->CastSpell(pUnit, SPELL_TELEPORT_CENTER, true); + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); } } - void CastGravityLapseKnockUp() + void JustSummoned(Creature* pSummoned) override { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + if (pSummoned->GetEntry() == NPC_FLAME_STRIKE_TRIGGER) + pSummoned->CastSpell(pSummoned, SPELL_FLAME_STRIKE_DUMMY, false, NULL, NULL, m_creature->GetObjectGuid()); + else { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - // Knockback into the air - if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_DOT, true, 0, 0, m_creature->GetObjectGuid()); + // Attack or follow target + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (pSummoned->GetEntry() == NPC_ARCANE_SPHERE) + pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0, 0); + else + pSummoned->AI()->AttackStart(pTarget); + } } } - // players can't cast "fly" spells unless in map 530. Has to be done a while after they get knocked into the air... - void CastGravityLapseFly() + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) + // Handle Gravity Lapse on targets + if (pSpell->Id == SPELL_GRAVITY_LAPSE && pTarget->GetTypeId() == TYPEID_PLAYER) { - Unit* pUnit = m_creature->GetMap()->GetUnit(*i); - - // Also needs an exception in spell system. - if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_FLY, true, 0, 0, m_creature->GetObjectGuid()); + DoCastSpellIfCan(pTarget, aGravityLapseSpells[m_uiGravityIndex], CAST_TRIGGERED); + pTarget->CastSpell(pTarget, SPELL_GRAVITY_LAPSE_FLY, true, 0, 0, m_creature->GetObjectGuid()); + pTarget->CastSpell(pTarget, SPELL_GRAVITY_LAPSE_DOT, true, 0, 0, m_creature->GetObjectGuid()); + ++m_uiGravityIndex; } } + // Wrapper to remove Gravity Lapse - this should be removed on aura 44251 expires void RemoveGravityLapse() { - std::vector vGuids; + GuidVector vGuids; m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) + + for (GuidVector::const_iterator itr = vGuids.begin(); itr != vGuids.end(); ++itr) { - Unit* pUnit = m_creature->GetMap()->GetUnit(*i); + Unit* pUnit = m_creature->GetMap()->GetUnit(*itr); if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) { @@ -250,184 +291,181 @@ struct MANGOS_DLL_DECL boss_felblood_kaelthasAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + DialogueUpdate(uiDiff); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - switch (m_uiPhase) + // Don't use spells during the epilogue + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + return; + + if (m_bIsFirstPhase) { - case 0: + // *Heroic mode only: + if (!m_bIsRegularMode) { - // *Heroic mode only: - if (!m_bIsRegularMode) + if (m_uiShockBarrierTimer < uiDiff) { - if (m_uiPyroblastTimer < uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_SHOCK_BARRIER) == CAST_OK) { - m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); - m_creature->InterruptSpell(CURRENT_GENERIC_SPELL); - DoCastSpellIfCan(m_creature, SPELL_SHOCK_BARRIER, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PYROBLAST); - m_uiPyroblastTimer = 60000; + m_uiPyroblastTimer = 1000; + m_uiShockBarrierTimer = 60000; + } + } + else + m_uiShockBarrierTimer -= uiDiff; + + if (m_uiPyroblastTimer) + { + if (m_uiPyroblastTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PYROBLAST) == CAST_OK) + m_uiPyroblastTimer = 0; } else m_uiPyroblastTimer -= uiDiff; } + } - if (m_uiFireballTimer < uiDiff) + if (m_uiFireballTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FIREBALL : SPELL_FIREBALL_H) == CAST_OK) - m_uiFireballTimer = urand(2000, 6000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FIREBALL : SPELL_FIREBALL_H) == CAST_OK) + m_uiFireballTimer = urand(2000, 4000); } - else - m_uiFireballTimer -= uiDiff; + } + else + m_uiFireballTimer -= uiDiff; - if (m_uiPhoenixTimer < uiDiff) + if (m_uiPhoenixTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PHOENIX) == CAST_OK) { - if (DoCastSpellIfCan(m_creature, SPELL_PHOENIX) == CAST_OK) - { - DoScriptText(SAY_PHOENIX, m_creature); - m_uiPhoenixTimer = 60000; - } + DoScriptText(SAY_PHOENIX, m_creature); + m_uiPhoenixTimer = 45000; } - else - m_uiPhoenixTimer -= uiDiff; + } + else + m_uiPhoenixTimer -= uiDiff; - if (m_uiFlameStrikeTimer < uiDiff) + if (m_uiFlameStrikeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(pTarget, SPELL_FLAME_STRIKE) == CAST_OK) { - DoCastSpellIfCan(pTarget, SPELL_FLAME_STRIKE, CAST_INTERRUPT_PREVIOUS); DoScriptText(SAY_FLAMESTRIKE, m_creature); + m_uiFlameStrikeTimer = urand(15000, 25000); } - m_uiFlameStrikeTimer = urand(15000, 25000); } - else - m_uiFlameStrikeTimer -= uiDiff; + } + else + m_uiFlameStrikeTimer -= uiDiff; - // Below 50% - if (m_creature->GetHealthPercent() < 50.0f) + // Below 50% + if (m_creature->GetHealthPercent() < 50.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT_CENTER, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); - m_creature->StopMoving(); + SetCombatMovement(false); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); - m_uiGravityLapseTimer = 0; - m_uiGravityLapsePhase = 0; - m_uiPhase = 1; - return; + m_bIsFirstPhase = false; } - - DoMeleeAttackIfReady(); - - break; } - case 1: + + DoMeleeAttackIfReady(); + } + else + { + if (m_uiGravityLapseTimer < uiDiff) { - if (m_uiGravityLapseTimer < uiDiff) + switch (m_uiGravityLapseStage) { - switch (m_uiGravityLapsePhase) - { - case 0: - if (m_bFirstGravityLapse) // Different yells at 50%, and at every following Gravity Lapse + case 0: + // Cast Gravity Lapse on Players + if (DoCastSpellIfCan(m_creature, SPELL_GRAVITY_LAPSE) == CAST_OK) + { + if (m_bFirstGravityLapse) { DoScriptText(SAY_GRAVITY_LAPSE, m_creature); m_bFirstGravityLapse = false; - - if (m_pInstance) - { - if (GameObject* pKaelLeft = m_pInstance->GetSingleGameObjectFromStorage(GO_KAEL_STATUE_LEFT)) - pKaelLeft->SetGoState(GO_STATE_ACTIVE); - - if (GameObject* pKaelRight = m_pInstance->GetSingleGameObjectFromStorage(GO_KAEL_STATUE_RIGHT)) - pKaelRight->SetGoState(GO_STATE_ACTIVE); - } } else - { DoScriptText(SAY_RECAST_GRAVITY, m_creature); - } - DoCastSpellIfCan(m_creature, SPELL_GRAVITY_LAPSE_INITIAL); - m_uiGravityLapseTimer = 2000 + uiDiff;// Don't interrupt the visual spell - m_uiGravityLapsePhase = 1; - break; - - case 1: - TeleportPlayersToSelf(); - m_uiGravityLapseTimer = 1000; - m_uiGravityLapsePhase = 2; - break; - - case 2: - CastGravityLapseKnockUp(); - m_uiGravityLapseTimer = 1000; - m_uiGravityLapsePhase = 3; - break; - - case 3: - CastGravityLapseFly(); - m_uiGravityLapseTimer = 30000; - m_uiGravityLapsePhase = 4; - - for(uint8 i = 0; i < 3; ++i) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - { - if (Creature* Orb = DoSpawnCreature(NPC_ARCANE_SPHERE, 5, 5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000)) - Orb->AI()->AttackStart(pTarget); - } - } - - DoCastSpellIfCan(m_creature, SPELL_GRAVITY_LAPSE_CHANNEL); - break; + m_uiGravityLapseTimer = 2000; + m_uiGravityIndex = 0; + ++m_uiGravityLapseStage; + } + break; + case 1: + // Summon spheres and apply the Gravity Lapse visual - upon visual expire, the gravity lapse is removed + if (DoCastSpellIfCan(m_creature, SPELL_GRAVITY_LAPSE_VISUAL) == CAST_OK) + { + for (uint8 i = 0; i < MAX_ARCANE_SPHERES; ++i) + DoCastSpellIfCan(m_creature, SPELL_ARCANE_SPHERE_SUMMON, CAST_TRIGGERED); - case 4: - m_creature->InterruptNonMeleeSpells(false); + m_uiGravityLapseTimer = 30000; + ++m_uiGravityLapseStage; + } + break; + case 2: + // Cast Power Feedback and stay stunned for 10 secs - also break the statues if they are not broken + if (DoCastSpellIfCan(m_creature, SPELL_POWER_FEEDBACK) == CAST_OK) + { DoScriptText(SAY_TIRED, m_creature); - DoCastSpellIfCan(m_creature, SPELL_POWER_FEEDBACK); RemoveGravityLapse(); m_uiGravityLapseTimer = 10000; - m_uiGravityLapsePhase = 0; - break; - } + m_uiGravityLapseStage = 0; + } + break; } - else - m_uiGravityLapseTimer -= uiDiff; - - break; } + else + m_uiGravityLapseTimer -= uiDiff; } } }; -struct MANGOS_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI +/*###### +## mob_felkael_phoenix +######*/ + +struct mob_felkael_phoenixAI : public ScriptedAI { - mob_felkael_phoenixAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + mob_felkael_phoenixAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - ScriptedInstance* m_pInstance; uint32 m_uiBurnTimer; - uint32 m_uiDeathTimer; - bool m_bRebirth; + bool m_bFakeDeath; - void Reset() + void Reset() override { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - m_creature->CastSpell(m_creature, SPELL_PHOENIX_BURN, true); - m_uiBurnTimer = 2000; - m_uiDeathTimer = 3000; - m_bRebirth = false; m_bFakeDeath = false; } - void DamageTaken(Unit* pKiller, uint32& uiDamage) + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_PHOENIX_BURN); + } + + void EnterEvadeMode() override + { + // Don't evade during ember blast + if (m_bFakeDeath) + return; + + ScriptedAI::EnterEvadeMode(); + } + + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; @@ -437,69 +475,80 @@ struct MANGOS_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI { uiDamage = 0; return; - } - // Don't really die in all phases of Kael'Thas - if (m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS) == IN_PROGRESS) - { - // prevent death - uiDamage = 0; - m_bFakeDeath = true; - - m_creature->InterruptNonMeleeSpells(false); - m_creature->SetHealth(0); - m_creature->StopMoving(); - m_creature->ClearComboPointHolders(); - m_creature->RemoveAllAurasOnDeath(); - m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->ClearAllReactives(); - m_creature->SetTargetGuid(ObjectGuid()); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - } + + // prevent death + uiDamage = 0; + DoSetFakeDeath(); + } + + void DoSetFakeDeath() + { + m_bFakeDeath = true; + + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + // Spawn egg and make invisible + DoCastSpellIfCan(m_creature, SPELL_EMBER_BLAST, CAST_TRIGGERED); + m_creature->SummonCreature(NPC_PHOENIX_EGG, 0, 0, 0, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 10000); } - void UpdateAI(const uint32 uiDiff) + void SummonedCreatureDespawn(Creature* /*pSummoned*/) override { + m_creature->RemoveAurasDueToSpell(SPELL_EMBER_BLAST); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // If we are fake death, we cast rebirth and after that we kill the phoenix to spawn the egg. - if (m_bFakeDeath) + // Remove fake death on egg despawn after 10 secs + if (DoCastSpellIfCan(m_creature, SPELL_REBIRTH_DMG) == CAST_OK) { - if (!m_bRebirth) - { - DoCastSpellIfCan(m_creature, SPELL_REBIRTH_DMG); - m_bRebirth = true; - } + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); + m_bFakeDeath = false; - if (m_bRebirth) - { + DoCastSpellIfCan(m_creature, SPELL_PHOENIX_BURN, CAST_TRIGGERED); + } + } - if (m_uiDeathTimer < uiDiff) - { - m_creature->SummonCreature(NPC_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - m_bRebirth = false; - } - else - m_uiDeathTimer -= uiDiff; - } + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override + { + // Self kill if the egg is killed + if (m_bFakeDeath) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_bFakeDeath) return; + // ToDo: research if this is correct and how can this be done by spell if (m_uiBurnTimer < uiDiff) { - //spell Burn should possible do this, but it doesn't, so do this for now. - uint32 dmg = urand(1650,2050); - m_creature->DealDamage(m_creature, dmg, 0, DOT, SPELL_SCHOOL_MASK_FIRE, NULL, false); - m_uiBurnTimer += 2000; + // spell Burn should possible do this, but it doesn't, so do this for now. + uint32 uiDmg = urand(1650, 2050); + if (uiDmg > m_creature->GetHealth()) + DoSetFakeDeath(); + else + m_creature->DealDamage(m_creature, uiDmg, 0, DOT, SPELL_SCHOOL_MASK_FIRE, NULL, false); + + m_uiBurnTimer = 2000; } else m_uiBurnTimer -= uiDiff; @@ -508,68 +557,70 @@ struct MANGOS_DLL_DECL mob_felkael_phoenixAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_felkael_phoenix_eggAI : public ScriptedAI -{ - mob_felkael_phoenix_eggAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} +/*###### +## mob_felkael_phoenix_egg +######*/ - uint32 m_uiHatchTimer; +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct mob_felkael_phoenix_eggAI : public Scripted_NoMovementAI +{ + mob_felkael_phoenix_eggAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - void Reset() - { - m_uiHatchTimer = 10000; - } + void Reset() override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; - void MoveInLineOfSight(Unit* pWho) {} - void AttackStart(Unit* pWho) {} +/*###### +## mob_arcane_sphere +######*/ - void UpdateAI(const uint32 uiDiff) +struct mob_arcane_sphereAI : public ScriptedAI +{ + mob_arcane_sphereAI(Creature* pCreature) : ScriptedAI(pCreature) { - if (m_uiHatchTimer < uiDiff) - { - m_creature->SummonCreature(NPC_PHOENIX, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000); - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else - m_uiHatchTimer -= uiDiff; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); } -}; -struct MANGOS_DLL_DECL mob_arcane_sphereAI : public ScriptedAI -{ - mob_arcane_sphereAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + ScriptedInstance* m_pInstance; uint32 m_uiDespawnTimer; uint32 m_uiChangeTargetTimer; - void Reset() + void Reset() override { - m_uiDespawnTimer = 30000; + m_uiDespawnTimer = 30000; m_uiChangeTargetTimer = urand(6000, 12000); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoCastSpellIfCan(m_creature, SPELL_ARCANE_SPHERE_PASSIVE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ARCANE_SPHERE_PASSIVE); } - void UpdateAI(const uint32 uiDiff) + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override { + // Should despawn when aura 44251 expires if (m_uiDespawnTimer < uiDiff) { m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - return; + m_uiDespawnTimer = 0; } else m_uiDespawnTimer -= uiDiff; - // Note: This check was reversed for some unknown reason, changed to usual behaviour! - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - if (m_uiChangeTargetTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (!m_pInstance) + return; + + // Follow the target - do not attack + if (Creature* pKael = m_pInstance->GetSingleCreatureFromStorage(NPC_KAELTHAS)) { - m_creature->TauntApply(pTarget); // Useless Workaround - AttackStart(pTarget); + if (Unit* pTarget = pKael->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->GetMotionMaster()->MoveFollow(pTarget, 0, 0); } m_uiChangeTargetTimer = urand(5000, 15000); diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp index 7ff2dd39a..2329c8af7 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp +++ b/scripts/eastern_kingdoms/magisters_terrace/boss_priestess_delrissa.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,307 +16,257 @@ /* ScriptData SDName: Boss_Priestess_Delrissa -SD%Complete: 65 -SDComment: No Heroic support yet. Needs further testing. Several scripts for pets disabled, not seem to require any special script. +SD%Complete: 90 +SDComment: Script handles Delrissa and her companions AI. They need special PvP-like behavior. Timers need adjustments SDCategory: Magister's Terrace EndScriptData */ #include "precompiled.h" #include "magisters_terrace.h" -struct Speech -{ - int32 id; -}; - -static Speech LackeyDeath[]= -{ - {-1585013}, - {-1585014}, - {-1585015}, - {-1585016}, -}; - -static Speech PlayerDeath[]= -{ - {-1585017}, - {-1585018}, - {-1585019}, - {-1585020}, - {-1585021}, -}; - enum { - SAY_AGGRO = -1585012, - SAY_DEATH = -1585022, - - SPELL_DISPEL_MAGIC = 27609, - SPELL_FLASH_HEAL = 17843, - SPELL_SW_PAIN_NORMAL = 14032, - SPELL_SW_PAIN_HEROIC = 15654, - SPELL_SHIELD = 44291, - SPELL_RENEW_NORMAL = 44174, - SPELL_RENEW_HEROIC = 46192, - - MAX_ACTIVE_LACKEY = 4 + SAY_AGGRO = -1585012, + SAY_DEATH = -1585022, + + SPELL_HEALING_POTION = 15503, + SPELL_DISPEL_MAGIC = 27609, + SPELL_MEDALLION = 46227, + SPELL_FLASH_HEAL = 17843, + SPELL_SHADOW_WORD_PAIN = 14032, + SPELL_SHADOW_WORD_PAIN_H = 15654, + SPELL_SCREAM = 27610, + SPELL_SHIELD = 44291, // maybe 44175? + SPELL_SHIELD_H = 46193, + SPELL_RENEW = 44174, + SPELL_RENEW_H = 46192, + + MAX_COMPANIONS = 8, }; -const float fOrientation = 4.98f; -const float fZLocation = -19.921f; +static const int32 aPlayerDeath[] = { -1585017, -1585018, -1585019, -1585020, -1585021}; +static const uint32 aDelrissaLackeys[MAX_COMPANIONS] = {NPC_KAGANI, NPC_ELLRYS, NPC_ERAMAS, NPC_YAZZAI, NPC_SALARIS, NPC_GARAXXAS, NPC_APOKO, NPC_ZELFAN}; -float LackeyLocations[4][2]= +static const float aLackeyLocations[MAX_DELRISSA_ADDS][4] = { - {123.77f, 17.6007f}, - {131.731f, 15.0827f}, - {121.563f, 15.6213f}, - {129.988f, 17.2355f}, + {123.77f, 17.6007f, -19.921f, 4.98f}, + {131.731f, 15.0827f, -19.921f, 4.98f}, + {121.563f, 15.6213f, -19.921f, 4.98f}, + {129.988f, 17.2355f, -19.921f, 4.98f}, }; -const uint32 m_auiAddEntries[] = -{ - 24557, //Kagani Nightstrike - 24558, //Elris Duskhallow - 24554, //Eramas Brightblaze - 24561, //Yazzaj - 24559, //Warlord Salaris - 24555, //Garaxxas - 24553, //Apoko - 24556, //Zelfan -}; +/*###### +## boss_priestess_delrissa +######*/ -struct MANGOS_DLL_DECL boss_priestess_delrissaAI : public ScriptedAI +struct boss_priestess_delrissaAI : public ScriptedAI { boss_priestess_delrissaAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - LackeyEntryList.clear(); Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - std::vector LackeyEntryList; - ObjectGuid m_aLackeyGuid[MAX_ACTIVE_LACKEY]; - - uint8 PlayersKilled; + std::vector m_vuiLackeyEnties; - uint32 HealTimer; - uint32 RenewTimer; - uint32 ShieldTimer; - uint32 SWPainTimer; - uint32 DispelTimer; + uint32 m_uiHealTimer; + uint32 m_uiRenewTimer; + uint32 m_uiShieldTimer; + uint32 m_uiSWPainTimer; + uint32 m_uiDispelTimer; + uint32 m_uiScreamTimer; + uint32 m_uiMedallionTimer; + uint8 m_uiPlayersKilled; - void Reset() + void Reset() override { - PlayersKilled = 0; - - HealTimer = 15000; - RenewTimer = 10000; - ShieldTimer = 2000; - SWPainTimer = 5000; - DispelTimer = 7500; - - InitializeLackeys(); + m_uiHealTimer = 15000; + m_uiRenewTimer = 10000; + m_uiShieldTimer = 2000; + m_uiSWPainTimer = 5000; + m_uiDispelTimer = 7500; + m_uiScreamTimer = 9000; + m_uiPlayersKilled = 0; + m_uiMedallionTimer = urand(1000, 2000); + + DoInitializeCompanions(); } - //this mean she at some point evaded - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_DELRISSA, FAIL); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { - DoScriptText(SAY_AGGRO, m_creature); + if (pWho->GetTypeId() != TYPEID_PLAYER) + return; - for(uint8 i = 0; i < MAX_ACTIVE_LACKEY; ++i) - { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[i])) - { - if (!pAdd->getVictim()) - { - pWho->SetInCombatWith(pAdd); - pAdd->AddThreat(pWho); - } - } - } + DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_DELRISSA, IN_PROGRESS); } - void InitializeLackeys() + // Summon four random adds to help during the fight + void DoInitializeCompanions() { - //can be called if creature are dead, so avoid + // can be called if creature are dead, so avoid if (!m_creature->isAlive()) return; - uint8 j = 0; - - //it's empty, so first time - if (LackeyEntryList.empty()) + // it's empty, so first time + if (m_vuiLackeyEnties.empty()) { - //pre-allocate size for speed - LackeyEntryList.resize((sizeof(m_auiAddEntries) / sizeof(uint32))); - - //fill vector array with entries from creature array - for(uint8 i = 0; i < LackeyEntryList.size(); ++i) - LackeyEntryList[i] = m_auiAddEntries[i]; + // pre-allocate size for speed + m_vuiLackeyEnties.resize(MAX_COMPANIONS); - //remove random entries - while(LackeyEntryList.size() > MAX_ACTIVE_LACKEY) - LackeyEntryList.erase(LackeyEntryList.begin() + rand()%LackeyEntryList.size()); + // fill vector array with entries from creature array + for (uint8 i = 0; i < MAX_COMPANIONS; ++i) + m_vuiLackeyEnties[i] = aDelrissaLackeys[i]; - //summon all the remaining in vector - for(std::vector::iterator itr = LackeyEntryList.begin(); itr != LackeyEntryList.end(); ++itr) - { - if (Creature* pAdd = m_creature->SummonCreature((*itr), LackeyLocations[j][0], LackeyLocations[j][1], fZLocation, fOrientation, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_aLackeyGuid[j] = pAdd->GetObjectGuid(); + std::random_shuffle(m_vuiLackeyEnties.begin(), m_vuiLackeyEnties.end()); - ++j; - } + // Summon the 4 entries + for (uint8 i = 0; i < MAX_DELRISSA_ADDS; ++i) + m_creature->SummonCreature(m_vuiLackeyEnties[i], aLackeyLocations[i][0], aLackeyLocations[i][1], aLackeyLocations[i][2], aLackeyLocations[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); } + // Resummon the killed adds else { - for(std::vector::iterator itr = LackeyEntryList.begin(); itr != LackeyEntryList.end(); ++itr) + if (!m_pInstance) + return; + + for (uint8 i = 0; i < MAX_DELRISSA_ADDS; ++i) { - Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[j]); + // If we already have the creature on the map, then don't summon it + if (m_pInstance->GetSingleCreatureFromStorage(m_vuiLackeyEnties[i], true)) + continue; - //object already removed, not exist - if (!pAdd) - { - if (Creature* pAdd = m_creature->SummonCreature((*itr), LackeyLocations[j][0], LackeyLocations[j][1], fZLocation, fOrientation, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_aLackeyGuid[j] = pAdd->GetObjectGuid(); - } - ++j; + m_creature->SummonCreature(m_vuiLackeyEnties[i], aLackeyLocations[i][0], aLackeyLocations[i][1], aLackeyLocations[i][2], aLackeyLocations[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); } } } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* pVictim) override { - if (victim->GetTypeId() != TYPEID_PLAYER) + if (pVictim->GetTypeId() != TYPEID_PLAYER) return; - DoScriptText(PlayerDeath[PlayersKilled].id, m_creature); + DoScriptText(aPlayerDeath[m_uiPlayersKilled], m_creature); + ++m_uiPlayersKilled; - if (PlayersKilled < 4) - ++PlayersKilled; + // reset counter + if (m_uiPlayersKilled == 5) + m_uiPlayersKilled = 0; } - void JustDied(Unit* killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); if (!m_pInstance) return; - if (m_pInstance->GetData(TYPE_DELRISSA_DEATH_COUNT) == MAX_ACTIVE_LACKEY) + // Remove lootable flag if the lackeys are not killed + if (m_pInstance->GetData(TYPE_DELRISSA) == SPECIAL) m_pInstance->SetData(TYPE_DELRISSA, DONE); else - { - if (m_creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) - m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - } + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (HealTimer < diff) + if (m_uiHealTimer < uiDiff) { - uint32 health = m_creature->GetHealth(); - Creature* target = m_creature; - - for(uint8 i = 0; i < MAX_ACTIVE_LACKEY; ++i) + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[i])) - { - if (pAdd->isAlive() && pAdd->GetHealth() < health) - target = pAdd; - } + if (DoCastSpellIfCan(pTarget, SPELL_FLASH_HEAL) == CAST_OK) + m_uiHealTimer = urand(15000, 20000); } + } + else + m_uiHealTimer -= uiDiff; - DoCastSpellIfCan(target, SPELL_FLASH_HEAL); - HealTimer = 15000; - }else HealTimer -= diff; - - if (RenewTimer < diff) + if (m_uiRenewTimer < uiDiff) { - Creature* target = m_creature; - - if (urand(0, 1)) + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[rand()%MAX_ACTIVE_LACKEY])) - { - if (pAdd->isAlive()) - target = pAdd; - } + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_RENEW : SPELL_RENEW_H) == CAST_OK) + m_uiRenewTimer = urand(5000, 10000); } + } + else + m_uiRenewTimer -= uiDiff; - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_RENEW_NORMAL : SPELL_RENEW_HEROIC); - RenewTimer = 5000; - }else RenewTimer -= diff; + if (m_uiShieldTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHIELD : SPELL_SHIELD_H) == CAST_OK) + m_uiShieldTimer = urand(30000, 35000); + } + else + m_uiShieldTimer -= uiDiff; - if (ShieldTimer < diff) + if (m_uiDispelTimer < uiDiff) { - Creature* target = m_creature; + Unit* pTarget = NULL; + std::list lTempList = DoFindFriendlyCC(50.0f); + + if (!lTempList.empty()) + pTarget = *(lTempList.begin()); + else + pTarget = DoSelectLowestHpFriendly(50.0f); - if (urand(0, 1)) + if (pTarget) { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[rand()%MAX_ACTIVE_LACKEY])) - { - if (pAdd->isAlive() && !pAdd->HasAura(SPELL_SHIELD)) - target = pAdd; - } + if (DoCastSpellIfCan(pTarget, SPELL_DISPEL_MAGIC) == CAST_OK) + m_uiDispelTimer = urand(12000, 15000); } + } + else + m_uiDispelTimer -= uiDiff; - DoCastSpellIfCan(target, SPELL_SHIELD); - ShieldTimer = 7500; - }else ShieldTimer -= diff; - - if (DispelTimer < diff) + // Use the Medallion if CC - only on heroic. Not sure how many times they are allowed to use it. + if (!m_bIsRegularMode && m_uiMedallionTimer) { - Unit* target = NULL; - bool friendly = false; - - if (urand(0, 1)) - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - else + if (m_creature->isFrozen() || m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT)) { - friendly = true; - - if (urand(0, 1)) - target = m_creature; - else + if (m_uiMedallionTimer <= uiDiff) { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[rand()%MAX_ACTIVE_LACKEY])) - { - if (pAdd->isAlive()) - target = pAdd; - } + if (DoCastSpellIfCan(m_creature, SPELL_MEDALLION, CAST_TRIGGERED) == CAST_OK) + m_uiMedallionTimer = 0; } + else + m_uiMedallionTimer -= uiDiff; } + } - if (target) - DoCastSpellIfCan(target, SPELL_DISPEL_MAGIC); - - DispelTimer = 12000; - }else DispelTimer -= diff; - - if (SWPainTimer < diff) + if (m_uiSWPainTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SW_PAIN_NORMAL : SPELL_SW_PAIN_HEROIC); + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_WORD_PAIN : SPELL_SHADOW_WORD_PAIN_H) == CAST_OK) + m_uiSWPainTimer = 10000; + } + } + else + m_uiSWPainTimer -= uiDiff; - SWPainTimer = 10000; - }else SWPainTimer -= diff; + if (m_uiScreamTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SCREAM) == CAST_OK) + m_uiScreamTimer = urand(15000, 20000); + } + else + m_uiScreamTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -327,28 +277,27 @@ CreatureAI* GetAI_boss_priestess_delrissa(Creature* pCreature) return new boss_priestess_delrissaAI(pCreature); } -enum -{ - SPELL_HEALING_POTION = 15503 -}; +/*###### +## priestess_companion_common +######*/ -//all 8 possible lackey use this common -struct MANGOS_DLL_DECL boss_priestess_lackey_commonAI : public ScriptedAI +struct priestess_companion_commonAI : public ScriptedAI { - boss_priestess_lackey_commonAI(Creature* pCreature) : ScriptedAI(pCreature) + priestess_companion_commonAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); - AcquireGuids(); } ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - ObjectGuid m_aLackeyGuid[MAX_ACTIVE_LACKEY]; uint32 m_uiResetThreatTimer; + uint32 m_uiMedallionTimer; bool m_bUsedPotion; - void Reset() + void Reset() override { m_bUsedPotion = false; @@ -357,118 +306,66 @@ struct MANGOS_DLL_DECL boss_priestess_lackey_commonAI : public ScriptedAI // We do not know what this system is based upon, but one theory is class (healers=high threat, dps=medium, etc) // We reset their threat frequently as an alternative until such a system exist m_uiResetThreatTimer = urand(5000, 15000); - - // in case she is not alive and Reset was for some reason called, respawn her (most likely party wipe after killing her) - if (Creature* pDelrissa = m_pInstance->GetSingleCreatureFromStorage(NPC_DELRISSA)) - { - if (!pDelrissa->isAlive()) - pDelrissa->Respawn(); - } + m_uiMedallionTimer = urand(1000, 2000); } - void EnterCombat(Unit* pWho) + void KilledUnit(Unit* pVictim) override { - if (!pWho) + if (!m_pInstance) return; - if (m_pInstance) - { - for(uint8 i = 0; i < MAX_ACTIVE_LACKEY; ++i) - { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[i])) - { - if (!pAdd->getVictim() && pAdd != m_creature) - { - pWho->SetInCombatWith(pAdd); - pAdd->AddThreat(pWho); - } - } - } - - if (Creature* pDelrissa = m_pInstance->GetSingleCreatureFromStorage(NPC_DELRISSA)) - { - if (pDelrissa->isAlive() && !pDelrissa->getVictim()) - { - pWho->SetInCombatWith(pDelrissa); - pDelrissa->AddThreat(pWho); - } - } - } - - Aggro(pWho); + if (Creature* pDelrissa = m_pInstance->GetSingleCreatureFromStorage(NPC_DELRISSA)) + pDelrissa->AI()->KilledUnit(pVictim); } - void JustDied(Unit* pKiller) + // Return true to handle shared timers and MeleeAttack + virtual bool UpdateCompanionAI(const uint32 /*uiDiff*/) { return true; } + + void UpdateAI(const uint32 uiDiff) override { - if (!m_pInstance) + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - Creature* pDelrissa = m_pInstance->GetSingleCreatureFromStorage(NPC_DELRISSA); - uint32 uiLackeyDeathCount = m_pInstance->GetData(TYPE_DELRISSA_DEATH_COUNT); - - if (!pDelrissa) + // Call specific virtual function + if (!UpdateCompanionAI(uiDiff)) return; - //should delrissa really yell if dead? - DoScriptText(LackeyDeath[uiLackeyDeathCount].id, pDelrissa); - - m_pInstance->SetData(TYPE_DELRISSA_DEATH_COUNT, SPECIAL); - - //increase local var, since we now may have four dead - ++uiLackeyDeathCount; - - if (uiLackeyDeathCount == MAX_ACTIVE_LACKEY) + if (!m_bUsedPotion && m_creature->GetHealthPercent() < 25.0f) { - //time to make her lootable and complete event if she died before lackeys - if (!pDelrissa->isAlive()) - { - if (!pDelrissa->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE)) - pDelrissa->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); - - m_pInstance->SetData(TYPE_DELRISSA, DONE); - } + if (DoCastSpellIfCan(m_creature, SPELL_HEALING_POTION) == CAST_OK) + m_bUsedPotion = true; } - } - - void KilledUnit(Unit* pVictim) - { - if (!m_pInstance) - return; - - if (Creature* pDelrissa = m_pInstance->GetSingleCreatureFromStorage(NPC_DELRISSA)) - pDelrissa->AI()->KilledUnit(pVictim); - } - void AcquireGuids() - { - if (!m_pInstance) - return; - - if (Creature* pDelrissa = m_pInstance->GetSingleCreatureFromStorage(NPC_DELRISSA)) + // Change target + if (m_uiResetThreatTimer < uiDiff) { - boss_priestess_delrissaAI* pDelrissaAI = dynamic_cast(pDelrissa->AI()); - - if (!pDelrissaAI) - return; - - for(uint8 i = 0; i < MAX_ACTIVE_LACKEY; ++i) - m_aLackeyGuid[i] = pDelrissaAI->m_aLackeyGuid[i]; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + DoResetThreat(); + AttackStart(pTarget); + m_uiResetThreatTimer = urand(5000, 15000); + } } - } + else + m_uiResetThreatTimer -= uiDiff; - void UpdateAI(const uint32 uiDiff) - { - if (!m_bUsedPotion && m_creature->GetHealthPercent() < 25.0f) + // Use the Medallion if CC - only on heroic. Not sure how many times they are allowed to use it. + if (!m_bIsRegularMode && m_uiMedallionTimer) { - DoCastSpellIfCan(m_creature, SPELL_HEALING_POTION); - m_bUsedPotion = true; + if (m_creature->isFrozen() || m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT)) + { + if (m_uiMedallionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MEDALLION, CAST_TRIGGERED) == CAST_OK) + m_uiMedallionTimer = 0; + } + else + m_uiMedallionTimer -= uiDiff; + } } - if (m_uiResetThreatTimer < uiDiff) - { - DoResetThreat(); - m_uiResetThreatTimer = urand(5000, 15000); - }else m_uiResetThreatTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -479,234 +376,297 @@ enum SPELL_KICK = 27613, SPELL_VANISH = 44290, SPELL_BACKSTAB = 15657, - SPELL_EVISCERATE = 27611 + SPELL_BACKSTAB_H = 15582, + SPELL_EVISCERATE = 27611, + SPELL_EVISCERATE_H = 46189, }; -struct MANGOS_DLL_DECL boss_kagani_nightstrikeAI : public boss_priestess_lackey_commonAI +/*###### +## npc_kagani_nightstrike - Rogue +######*/ + +struct npc_kagani_nightstrikeAI : public priestess_companion_commonAI { - //Rogue - boss_kagani_nightstrikeAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_kagani_nightstrikeAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Gouge_Timer; - uint32 Kick_Timer; - uint32 Vanish_Timer; - uint32 Eviscerate_Timer; - uint32 Wait_Timer; - bool InVanish; + uint32 m_uiGougeTimer; + uint32 m_uiKickTimer; + uint32 m_uiVanishTimer; + uint32 m_uiEviscerateTimer; + uint32 m_uiVanishEndTimer; - void Reset() + void Reset() override { - Gouge_Timer = 5500; - Kick_Timer = 7000; - Vanish_Timer = 2000; - Eviscerate_Timer = 6000; - Wait_Timer = 5000; - InVanish = false; - m_creature->SetVisibility(VISIBILITY_ON); - - boss_priestess_lackey_commonAI::Reset(); + m_uiGougeTimer = 5500; + m_uiKickTimer = 7000; + m_uiVanishTimer = 2000; + m_uiEviscerateTimer = 6000; + m_uiVanishEndTimer = 0; + + priestess_companion_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void EnterEvadeMode() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_uiVanishEndTimer) return; - boss_priestess_lackey_commonAI::UpdateAI(diff); + ScriptedAI::EnterEvadeMode(); + } - if (Vanish_Timer < diff) + bool UpdateCompanionAI(const uint32 uiDiff) + { + if (m_uiVanishEndTimer) { - DoCastSpellIfCan(m_creature, SPELL_VANISH); - - Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - DoResetThreat(); - - if (pUnit) - m_creature->AddThreat(pUnit, 1000.0f); + if (m_uiVanishEndTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature->getVictim(), SPELL_BACKSTAB, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_KIDNEY_SHOT, CAST_TRIGGERED); + m_uiVanishEndTimer = 0; + } + else + m_uiVanishEndTimer -= uiDiff; - InVanish = true; - Vanish_Timer = 30000; - Wait_Timer = 10000; - }else Vanish_Timer -= diff; + return false; + } - if (InVanish) + if (m_uiVanishTimer < uiDiff) { - if (Wait_Timer < diff) + if (DoCastSpellIfCan(m_creature, SPELL_VANISH) == CAST_OK) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BACKSTAB, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_KIDNEY_SHOT, CAST_TRIGGERED); - m_creature->SetVisibility(VISIBILITY_ON); // ...? Hacklike - InVanish = false; - }else Wait_Timer -= diff; + // Prefer targets with mana + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_POWER_MANA)) + { + DoResetThreat(); + AttackStart(pTarget); + } + + m_uiVanishTimer = 30000; + m_uiVanishEndTimer = 10000; + } } + else + m_uiVanishTimer -= uiDiff; - if (Gouge_Timer < diff) + if (m_uiGougeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE); - Gouge_Timer = 5500; - }else Gouge_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE) == CAST_OK) + m_uiGougeTimer = 5500; + } + else + m_uiGougeTimer -= uiDiff; - if (Kick_Timer < diff) + if (m_uiKickTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_KICK); - Kick_Timer = 7000; - }else Kick_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KICK) == CAST_OK) + m_uiKickTimer = 7000; + } + else + m_uiKickTimer -= uiDiff; - if (Eviscerate_Timer < diff) + if (m_uiEviscerateTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_EVISCERATE); - Eviscerate_Timer = 4000; - }else Eviscerate_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_EVISCERATE : SPELL_EVISCERATE_H) == CAST_OK) + m_uiEviscerateTimer = 4000; + } + else + m_uiEviscerateTimer -= uiDiff; - if (!InVanish) - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_boss_kagani_nightstrike(Creature* pCreature) +CreatureAI* GetAI_npc_kagani_nightstrike(Creature* pCreature) { - return new boss_kagani_nightstrikeAI(pCreature); + return new npc_kagani_nightstrikeAI(pCreature); } enum { SPELL_IMMOLATE = 44267, + SPELL_IMMOLATE_H = 46191, SPELL_SHADOW_BOLT = 12471, + SPELL_SHADOW_BOLT_H = 15232, SPELL_SEED_OF_CORRUPTION = 44141, SPELL_CURSE_OF_AGONY = 14875, + SPELL_CURSE_OF_AGONY_H = 46190, SPELL_FEAR = 38595, - SPELL_IMP_FIREBALL = 44164, - SPELL_SUMMON_IMP = 44163 + SPELL_DEATH_COIL = 44142, + SPELL_SUMMON_IMP = 44163, + + NPC_FIZZLE = 24656, }; -struct MANGOS_DLL_DECL boss_ellris_duskhallowAI : public boss_priestess_lackey_commonAI +/*###### +## npc_ellris_duskhallow - Warlock +######*/ + +struct npc_ellris_duskhallowAI : public priestess_companion_commonAI { - //Warlock - boss_ellris_duskhallowAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_ellris_duskhallowAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Immolate_Timer; - uint32 Shadow_Bolt_Timer; - uint32 Seed_of_Corruption_Timer; - uint32 Curse_of_Agony_Timer; - uint32 Fear_Timer; + uint32 m_uiImmolateTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiSeedCorruptionTimer; + uint32 m_uiCurseAgonyTimer; + uint32 m_uiFearTimer; + uint32 m_uiDeathCoilTimer; - void Reset() + void Reset() override { - Immolate_Timer = 6000; - Shadow_Bolt_Timer = 3000; - Seed_of_Corruption_Timer = 2000; - Curse_of_Agony_Timer = 1000; - Fear_Timer = 10000; - - boss_priestess_lackey_commonAI::Reset(); + m_uiImmolateTimer = 6000; + m_uiShadowBoltTimer = 3000; + m_uiSeedCorruptionTimer = 2000; + m_uiCurseAgonyTimer = 1000; + m_uiFearTimer = 10000; + m_uiDeathCoilTimer = 8000; + + priestess_companion_commonAI::Reset(); + + // Check if we already have an imp summoned + if (!GetClosestCreatureWithEntry(m_creature, NPC_FIZZLE, 50.0f)) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_IMP); } - void Aggro(Unit* pWho) + void AttackStart(Unit* pWho) override { - DoCastSpellIfCan(m_creature,SPELL_SUMMON_IMP); + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } } - void UpdateAI(const uint32 diff) + bool UpdateCompanionAI(const uint32 uiDiff) { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); - - if (Immolate_Timer < diff) + if (m_uiImmolateTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_IMMOLATE); - Immolate_Timer = 6000; - }else Immolate_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_IMMOLATE : SPELL_IMMOLATE_H) == CAST_OK) + m_uiImmolateTimer = 6000; + } + } + else + m_uiImmolateTimer -= uiDiff; - if (Shadow_Bolt_Timer < diff) + if (m_uiShadowBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOW_BOLT); - Shadow_Bolt_Timer = 5000; - }else Shadow_Bolt_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT_H) == CAST_OK) + m_uiShadowBoltTimer = 5000; + } + } + else + m_uiShadowBoltTimer -= uiDiff; - if (Seed_of_Corruption_Timer < diff) + if (m_uiSeedCorruptionTimer < uiDiff) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_SEED_OF_CORRUPTION); - - Seed_of_Corruption_Timer = 10000; - }else Seed_of_Corruption_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SEED_OF_CORRUPTION) == CAST_OK) + m_uiSeedCorruptionTimer = 10000; + } + } + else + m_uiSeedCorruptionTimer -= uiDiff; - if (Curse_of_Agony_Timer < diff) + if (m_uiCurseAgonyTimer < uiDiff) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_CURSE_OF_AGONY); - - Curse_of_Agony_Timer = 13000; - }else Curse_of_Agony_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CURSE_OF_AGONY : SPELL_CURSE_OF_AGONY_H) == CAST_OK) + m_uiCurseAgonyTimer = 13000; + } + } + else + m_uiCurseAgonyTimer -= uiDiff; - if (Fear_Timer < diff) + if (m_uiFearTimer < uiDiff) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_FEAR); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = 10000; + } + } + else + m_uiFearTimer -= uiDiff; - Fear_Timer = 10000; - }else Fear_Timer -= diff; + if (m_uiDeathCoilTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEATH_COIL) == CAST_OK) + m_uiDeathCoilTimer = urand(8000, 13000); + } + } + else + m_uiDeathCoilTimer -= uiDiff; - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_ellris_duskhallow(Creature* pCreature) +CreatureAI* GetAI_npc_ellris_duskhallow(Creature* pCreature) { - return new boss_ellris_duskhallowAI(pCreature); + return new npc_ellris_duskhallowAI(pCreature); } enum { SPELL_KNOCKDOWN = 11428, + SPELL_KNOCKDOWN_H = 46183, SPELL_SNAP_KICK = 46182 }; -struct MANGOS_DLL_DECL boss_eramas_brightblazeAI : public boss_priestess_lackey_commonAI +/*###### +## npc_eramas_brightblaze - Monk +######*/ + +struct npc_eramas_brightblazeAI : public priestess_companion_commonAI { - //Monk - boss_eramas_brightblazeAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_eramas_brightblazeAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Knockdown_Timer; - uint32 Snap_Kick_Timer; + uint32 m_uiKnockdownTimer; + uint32 m_uiSnapKickTimer; - void Reset() + void Reset() override { - Knockdown_Timer = 6000; - Snap_Kick_Timer = 4500; + m_uiKnockdownTimer = 6000; + m_uiSnapKickTimer = 4500; - boss_priestess_lackey_commonAI::Reset(); + priestess_companion_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + bool UpdateCompanionAI(const uint32 uiDiff) { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); - - if (Knockdown_Timer < diff) + if (m_uiKnockdownTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKDOWN); - Knockdown_Timer = 6000; - }else Knockdown_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_KNOCKDOWN : SPELL_KNOCKDOWN_H) == CAST_OK) + m_uiKnockdownTimer = 6000; + } + else + m_uiKnockdownTimer -= uiDiff; - if (Snap_Kick_Timer < diff) + if (m_uiSnapKickTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SNAP_KICK); - Snap_Kick_Timer = 4500; - }else Snap_Kick_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SNAP_KICK) == CAST_OK) + m_uiSnapKickTimer = 4500; + } + else + m_uiSnapKickTimer -= uiDiff; - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_eramas_brightblaze(Creature* pCreature) +CreatureAI* GetAI_npc_eramas_brightblaze(Creature* pCreature) { - return new boss_eramas_brightblazeAI(pCreature); + return new npc_eramas_brightblazeAI(pCreature); } enum @@ -714,108 +674,143 @@ enum SPELL_POLYMORPH = 13323, SPELL_ICE_BLOCK = 27619, SPELL_BLIZZARD = 44178, - SPELL_ICE_LANCE = 46194, - SPELL_CONE_OF_COLD = 38384, + SPELL_BLIZZARD_H = 46195, + SPELL_ICE_LANCE = 44176, + SPELL_ICE_LANCE_H = 46194, + SPELL_CONE_OF_COLD = 12611, + SPELL_CONE_OF_COLD_H = 38384, SPELL_FROSTBOLT = 15043, + SPELL_FROSTBOLT_H = 15530, SPELL_BLINK = 14514 }; -struct MANGOS_DLL_DECL boss_yazzaiAI : public boss_priestess_lackey_commonAI +/*###### +## npc_yazzai - Mage +######*/ + +struct npc_yazzaiAI : public priestess_companion_commonAI { - //Mage - boss_yazzaiAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_yazzaiAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - bool HasIceBlocked; + bool m_bHasIceBlocked; - uint32 Polymorph_Timer; - uint32 Ice_Block_Timer; - uint32 Wait_Timer; - uint32 Blizzard_Timer; - uint32 Ice_Lance_Timer; - uint32 Cone_of_Cold_Timer; - uint32 Frostbolt_Timer; - uint32 Blink_Timer; + uint32 m_uiPolymorphTimer; + uint32 m_uiIceBlockTimer; + uint32 m_uiWait_Timer; + uint32 m_uiBlizzardTimer; + uint32 m_uiIceLanceTimer; + uint32 m_uiConeColdTimer; + uint32 m_uiFrostboltTimer; + uint32 m_uiBlinkTimer; - void Reset() + void Reset() override { - HasIceBlocked = false; - - Polymorph_Timer = 1000; - Ice_Block_Timer = 20000; - Wait_Timer = 10000; - Blizzard_Timer = 8000; - Ice_Lance_Timer = 12000; - Cone_of_Cold_Timer = 10000; - Frostbolt_Timer = 3000; - Blink_Timer = 8000; - - boss_priestess_lackey_commonAI::Reset(); + m_bHasIceBlocked = false; + + m_uiPolymorphTimer = 1000; + m_uiIceBlockTimer = 20000; + m_uiWait_Timer = 10000; + m_uiBlizzardTimer = 8000; + m_uiIceLanceTimer = 12000; + m_uiConeColdTimer = 10000; + m_uiFrostboltTimer = 3000; + m_uiBlinkTimer = 8000; + + priestess_companion_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void AttackStart(Unit* pWho) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } + } - if (Polymorph_Timer < diff) + bool UpdateCompanionAI(const uint32 uiDiff) + { + if (m_uiPolymorphTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target, SPELL_POLYMORPH); - Polymorph_Timer = 20000; + if (DoCastSpellIfCan(pTarget, SPELL_POLYMORPH) == CAST_OK) + m_uiPolymorphTimer = 20000; } - }else Polymorph_Timer -= diff; + } + else + m_uiPolymorphTimer -= uiDiff; - if (m_creature->GetHealthPercent() < 35.0f && !HasIceBlocked) + if (m_creature->GetHealthPercent() < 35.0f && !m_bHasIceBlocked) { - DoCastSpellIfCan(m_creature, SPELL_ICE_BLOCK); - HasIceBlocked = true; + if (DoCastSpellIfCan(m_creature, SPELL_ICE_BLOCK) == CAST_OK) + m_bHasIceBlocked = true; } - if (Blizzard_Timer < diff) + if (m_uiBlizzardTimer < uiDiff) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_BLIZZARD); - - Blizzard_Timer = 8000; - }else Blizzard_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_BLIZZARD : SPELL_BLIZZARD_H) == CAST_OK) + m_uiBlizzardTimer = urand(8000, 15000); + } + } + else + m_uiBlizzardTimer -= uiDiff; - if (Ice_Lance_Timer < diff) + if (m_uiIceLanceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICE_LANCE); - Ice_Lance_Timer = 12000; - }else Ice_Lance_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ICE_LANCE : SPELL_ICE_LANCE_H) == CAST_OK) + m_uiIceLanceTimer = 12000; + } + } + else + m_uiIceLanceTimer -= uiDiff; - if (Cone_of_Cold_Timer < diff) + if (m_uiConeColdTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONE_OF_COLD); - Cone_of_Cold_Timer = 10000; - }else Cone_of_Cold_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CONE_OF_COLD : SPELL_CONE_OF_COLD_H) == CAST_OK) + m_uiConeColdTimer = 10000; + } + else + m_uiConeColdTimer -= uiDiff; - if (Frostbolt_Timer < diff) + if (m_uiFrostboltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROSTBOLT); - Frostbolt_Timer = 8000; - }else Frostbolt_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FROSTBOLT : SPELL_FROSTBOLT_H) == CAST_OK) + m_uiFrostboltTimer = 8000; + } + } + else + m_uiFrostboltTimer -= uiDiff; - if (Blink_Timer < diff) + if (m_uiBlinkTimer < uiDiff) { - //if anybody is in melee range than escape by blink - if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) - DoCastSpellIfCan(m_creature, SPELL_BLINK); - - Blink_Timer = 8000; - }else Blink_Timer -= diff; + // if anybody is in melee range than escape by blink + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLINK) == CAST_OK) + m_uiBlinkTimer = 8000; + } + else + m_uiBlinkTimer = 2000; + } + else + m_uiBlinkTimer -= uiDiff; - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_yazzai(Creature* pCreature) +CreatureAI* GetAI_npc_yazzai(Creature* pCreature) { - return new boss_yazzaiAI(pCreature); + return new npc_yazzaiAI(pCreature); } enum @@ -829,429 +824,451 @@ enum SPELL_MORTAL_STRIKE = 44268 }; -struct MANGOS_DLL_DECL boss_warlord_salarisAI : public boss_priestess_lackey_commonAI +/*###### +## npc_warlord_salaris - Warrior +######*/ + +struct npc_warlord_salarisAI : public priestess_companion_commonAI { - //Warrior - boss_warlord_salarisAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_warlord_salarisAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Intercept_Stun_Timer; - uint32 Disarm_Timer; - uint32 Piercing_Howl_Timer; - uint32 Frightening_Shout_Timer; - uint32 Hamstring_Timer; - uint32 Mortal_Strike_Timer; + uint32 m_uiInterceptStunTimer; + uint32 m_uiDisarmTimer; + uint32 m_uiPiercingHowlTimer; + uint32 m_uiFrighteningShoutTimer; + uint32 m_uiHamstringTimer; + uint32 m_uiMortalStrikeTimer; - void Reset() + void Reset() override { - Intercept_Stun_Timer = 500; - Disarm_Timer = 6000; - Piercing_Howl_Timer = 10000; - Frightening_Shout_Timer = 18000; - Hamstring_Timer = 4500; - Mortal_Strike_Timer = 8000; - - boss_priestess_lackey_commonAI::Reset(); + m_uiInterceptStunTimer = 500; + m_uiDisarmTimer = 6000; + m_uiPiercingHowlTimer = 10000; + m_uiFrighteningShoutTimer = 18000; + m_uiHamstringTimer = 4500; + m_uiMortalStrikeTimer = 8000; + + priestess_companion_commonAI::Reset(); } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, SPELL_BATTLE_SHOUT); } - void UpdateAI(const uint32 diff) + bool UpdateCompanionAI(const uint32 uiDiff) { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); - - if (Intercept_Stun_Timer < diff) + if (m_uiInterceptStunTimer < uiDiff) { - //if nobody is in melee range than try to use Intercept - if (!m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) + // if nobody is in melee range than try to use Intercept + if (!m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_INTERCEPT_STUN, SELECT_FLAG_IN_LOS)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_INTERCEPT_STUN, SELECT_FLAG_NOT_IN_MELEE_RANGE | SELECT_FLAG_IN_LOS)) { if (DoCastSpellIfCan(pTarget, SPELL_INTERCEPT_STUN) == CAST_OK) - Intercept_Stun_Timer = 10000; + m_uiInterceptStunTimer = 10000; } } else - Intercept_Stun_Timer = 2000; - }else - Intercept_Stun_Timer -= diff; + m_uiInterceptStunTimer = 2000; + } + else + m_uiInterceptStunTimer -= uiDiff; - if (Disarm_Timer < diff) + if (m_uiDisarmTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DISARM); - Disarm_Timer = 6000; - }else Disarm_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DISARM) == CAST_OK) + m_uiDisarmTimer = 6000; + } + else + m_uiDisarmTimer -= uiDiff; - if (Hamstring_Timer < diff) + if (m_uiHamstringTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING); - Hamstring_Timer = 4500; - }else Hamstring_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING) == CAST_OK) + m_uiHamstringTimer = 4500; + } + else + m_uiHamstringTimer -= uiDiff; - if (Mortal_Strike_Timer < diff) + if (m_uiMortalStrikeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - Mortal_Strike_Timer = 4500; - }else Mortal_Strike_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiMortalStrikeTimer = 4500; + } + else + m_uiMortalStrikeTimer -= uiDiff; - if (Piercing_Howl_Timer < diff) + if (m_uiPiercingHowlTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PIERCING_HOWL); - Piercing_Howl_Timer = 10000; - }else Piercing_Howl_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PIERCING_HOWL) == CAST_OK) + m_uiPiercingHowlTimer = 10000; + } + else + m_uiPiercingHowlTimer -= uiDiff; - if (Frightening_Shout_Timer < diff) + if (m_uiFrighteningShoutTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT); - Frightening_Shout_Timer = 18000; - }else Frightening_Shout_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT) == CAST_OK) + m_uiFrighteningShoutTimer = 18000; + } + else + m_uiFrighteningShoutTimer -= uiDiff; - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_warlord_salaris(Creature* pCreature) +CreatureAI* GetAI_npc_warlord_salaris(Creature* pCreature) { - return new boss_warlord_salarisAI(pCreature); + return new npc_warlord_salarisAI(pCreature); } enum { SPELL_AIMED_SHOT = 44271, SPELL_SHOOT = 15620, + SPELL_SHOOT_H = 22907, SPELL_CONCUSSIVE_SHOT = 27634, SPELL_MULTI_SHOT = 31942, + SPELL_MULTI_SHOT_H = 44285, SPELL_WING_CLIP = 44286, SPELL_FREEZING_TRAP = 44136, NPC_SLIVER = 24552 }; -struct MANGOS_DLL_DECL boss_garaxxasAI : public boss_priestess_lackey_commonAI -{ - //Hunter - boss_garaxxasAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) - { - SetCombatMovement(false); - Reset(); - } +/*###### +## npc_garaxxas - Hunter +######*/ - ObjectGuid m_petGuid; +struct npc_garaxxasAI : public priestess_companion_commonAI +{ + npc_garaxxasAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Aimed_Shot_Timer; - uint32 Shoot_Timer; - uint32 Concussive_Shot_Timer; - uint32 Multi_Shot_Timer; - uint32 Wing_Clip_Timer; - uint32 Freezing_Trap_Timer; + uint32 m_uiAimedShotTimer; + uint32 m_uiShootTimer; + uint32 m_uiConcussiveShotTimer; + uint32 m_uiMultiShotTimer; + uint32 m_uiWingClipTimer; + uint32 m_uiFreezingTrapTimer; - void Reset() + void Reset() override { - Aimed_Shot_Timer = 6000; - Shoot_Timer = 2500; - Concussive_Shot_Timer = 8000; - Multi_Shot_Timer = 10000; - Wing_Clip_Timer = 4000; - Freezing_Trap_Timer = 15000; - - Creature* pPet = m_creature->GetMap()->GetCreature(m_petGuid); - if (!pPet) - m_creature->SummonCreature(NPC_SLIVER, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); - - boss_priestess_lackey_commonAI::Reset(); + m_uiAimedShotTimer = 6000; + m_uiShootTimer = 2500; + m_uiConcussiveShotTimer = 8000; + m_uiMultiShotTimer = 10000; + m_uiWingClipTimer = 4000; + m_uiFreezingTrapTimer = 15000; + + priestess_companion_commonAI::Reset(); + + // Check if the pet was killed + if (!GetClosestCreatureWithEntry(m_creature, NPC_SLIVER, 50.0f)) + m_creature->SummonCreature(NPC_SLIVER, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); } - void JustSummoned(Creature* pSummoned) + void AttackStart(Unit* pWho) override { - m_petGuid = pSummoned->GetObjectGuid(); + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } } - void UpdateAI(const uint32 diff) + bool UpdateCompanionAI(const uint32 uiDiff) { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); - if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) { - if (Wing_Clip_Timer < diff) + if (m_uiWingClipTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_WING_CLIP); - Wing_Clip_Timer = 4000; - }else Wing_Clip_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_WING_CLIP) == CAST_OK) + m_uiWingClipTimer = 4000; + } + else + m_uiWingClipTimer -= uiDiff; - if (Freezing_Trap_Timer < diff) + if (m_uiFreezingTrapTimer < uiDiff) { - //attempt find go summoned from spell (casted by m_creature) - GameObject* pGo = m_creature->GetGameObject(SPELL_FREEZING_TRAP); - - //if we have a pGo, we need to wait (only one trap at a time) - if (pGo) - Freezing_Trap_Timer = 2500; - else - { - //if pGo does not exist, then we can cast - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FREEZING_TRAP); - Freezing_Trap_Timer = 15000; - } - }else Freezing_Trap_Timer -= diff; - - DoMeleeAttackIfReady(); + if (DoCastSpellIfCan(m_creature, SPELL_FREEZING_TRAP) == CAST_OK) + m_uiFreezingTrapTimer = urand(15000, 30000); + } + else + m_uiFreezingTrapTimer -= uiDiff; } else { - if (Concussive_Shot_Timer < diff) + if (m_uiConcussiveShotTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONCUSSIVE_SHOT); - Concussive_Shot_Timer = 8000; - }else Concussive_Shot_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CONCUSSIVE_SHOT) == CAST_OK) + m_uiConcussiveShotTimer = 8000; + } + } + else + m_uiConcussiveShotTimer -= uiDiff; - if (Multi_Shot_Timer < diff) + if (m_uiMultiShotTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MULTI_SHOT); - Multi_Shot_Timer = 10000; - }else Multi_Shot_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_MULTI_SHOT : SPELL_MULTI_SHOT_H) == CAST_OK) + m_uiMultiShotTimer = 10000; + } + } + else + m_uiMultiShotTimer -= uiDiff; - if (Aimed_Shot_Timer < diff) + if (m_uiAimedShotTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_AIMED_SHOT); - Aimed_Shot_Timer = 6000; - }else Aimed_Shot_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_AIMED_SHOT) == CAST_OK) + m_uiAimedShotTimer = 6000; + } + } + else + m_uiAimedShotTimer -= uiDiff; - if (Shoot_Timer < diff) + if (m_uiShootTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOOT); - Shoot_Timer = 2500; - }else Shoot_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHOOT : SPELL_SHOOT_H) == CAST_OK) + m_uiShootTimer = 2500; + } + } + else + m_uiShootTimer -= uiDiff; } + + return true; } }; -CreatureAI* GetAI_garaxxas(Creature* pCreature) +CreatureAI* GetAI_npc_garaxxas(Creature* pCreature) { - return new boss_garaxxasAI(pCreature); + return new npc_garaxxasAI(pCreature); } enum { - SPELL_WINDFURY_TOTEM = 27621, SPELL_WAR_STOMP = 46026, SPELL_PURGE = 27626, SPELL_LESSER_HEALING_WAVE = 44256, + SPELL_LESSER_HEALING_WAVE_H = 46181, SPELL_FROST_SHOCK = 21401, + SPELL_FROST_SHOCK_H = 46180, + SPELL_WINDFURY_TOTEM = 27621, SPELL_FIRE_NOVA_TOTEM = 44257, SPELL_EARTHBIND_TOTEM = 15786 }; -struct MANGOS_DLL_DECL boss_apokoAI : public boss_priestess_lackey_commonAI +/*###### +## npc_apoko - Shaman +######*/ + +struct npc_apokoAI : public priestess_companion_commonAI { - //Shaman - boss_apokoAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_apokoAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Totem_Timer; - uint8 Totem_Amount; - uint32 War_Stomp_Timer; - uint32 Purge_Timer; - uint32 Healing_Wave_Timer; - uint32 Frost_Shock_Timer; + uint32 m_uiTotemTimer; + uint32 m_uiWarStompTimer; + uint32 m_uiPurgeTimer; + uint32 m_uiHealingWaveTimer; + uint32 m_uiFrostShockTimer; - void Reset() + void Reset() override { - Totem_Timer = 2000; - Totem_Amount = 1; - War_Stomp_Timer = 10000; - Purge_Timer = 8000; - Healing_Wave_Timer = 5000; - Frost_Shock_Timer = 7000; - - boss_priestess_lackey_commonAI::Reset(); + m_uiTotemTimer = 0; + m_uiWarStompTimer = 10000; + m_uiPurgeTimer = 8000; + m_uiHealingWaveTimer = 5000; + m_uiFrostShockTimer = 7000; + + priestess_companion_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + bool UpdateCompanionAI(const uint32 uiDiff) { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); - - if (Totem_Timer < diff) + if (m_uiTotemTimer < uiDiff) { - switch(urand(0, 2)) + // It's not very clear how exactly these spells should be cast + switch (urand(0, 2)) { - case 0: DoCastSpellIfCan(m_creature, SPELL_WINDFURY_TOTEM); break; + case 0: DoCastSpellIfCan(m_creature, SPELL_WINDFURY_TOTEM); break; case 1: DoCastSpellIfCan(m_creature, SPELL_FIRE_NOVA_TOTEM); break; case 2: DoCastSpellIfCan(m_creature, SPELL_EARTHBIND_TOTEM); break; } - ++Totem_Amount; - Totem_Timer = Totem_Amount*2000; - }else Totem_Timer -= diff; + m_uiTotemTimer = urand(2000, 6000); + } + else + m_uiTotemTimer -= uiDiff; - if (War_Stomp_Timer < diff) + if (m_uiWarStompTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP); - War_Stomp_Timer = 10000; - }else War_Stomp_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP) == CAST_OK) + m_uiWarStompTimer = 10000; + } + else + m_uiWarStompTimer -= uiDiff; - if (Purge_Timer < diff) + if (m_uiPurgeTimer < uiDiff) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_PURGE); - - Purge_Timer = 15000; - }else Purge_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_PURGE) == CAST_OK) + m_uiPurgeTimer = 15000; + } + } + else + m_uiPurgeTimer -= uiDiff; - if (Frost_Shock_Timer < diff) + if (m_uiFrostShockTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK); - Frost_Shock_Timer = 7000; - }else Frost_Shock_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FROST_SHOCK : SPELL_FROST_SHOCK_H) == CAST_OK) + m_uiFrostShockTimer = 7000; + } + else + m_uiFrostShockTimer -= uiDiff; - if (Healing_Wave_Timer < diff) + if (m_uiHealingWaveTimer < uiDiff) { - // std::vector::iterator itr = Group.begin() + rand()%Group.size(); - // ObjectGuid guid = (*itr)->guid; - // if (guid) - // { - // Unit* pAdd = m_creature->GetMap()->GetUnit((*itr)->guid); - // if (pAdd && pAdd->isAlive()) - // { - DoCastSpellIfCan(m_creature, SPELL_LESSER_HEALING_WAVE); - Healing_Wave_Timer = 5000; - // } - // } - }else Healing_Wave_Timer -= diff; + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_LESSER_HEALING_WAVE : SPELL_LESSER_HEALING_WAVE_H) == CAST_OK) + m_uiHealingWaveTimer = 5000; + } + } + else + m_uiHealingWaveTimer -= uiDiff; - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_apoko(Creature* pCreature) +CreatureAI* GetAI_npc_apoko(Creature* pCreature) { - return new boss_apokoAI(pCreature); + return new npc_apokoAI(pCreature); } enum { SPELL_GOBLIN_DRAGON_GUN = 44272, + SPELL_GOBLIN_DRAGON_GUN_H = 46185, SPELL_ROCKET_LAUNCH = 44137, + SPELL_ROCKET_LAUNCH_H = 46187, SPELL_RECOMBOBULATE = 44274, SPELL_HIGH_EXPLOSIVE_SHEEP = 44276, SPELL_FEL_IRON_BOMB = 46024, - SPELL_SHEEP_EXPLOSION = 44279 + SPELL_FEL_IRON_BOMB_H = 46184, }; -struct MANGOS_DLL_DECL boss_zelfanAI : public boss_priestess_lackey_commonAI +/*###### +## npc_zelfan - Engineer +######*/ + +struct npc_zelfanAI : public priestess_companion_commonAI { - //Engineer - boss_zelfanAI(Creature* pCreature) : boss_priestess_lackey_commonAI(pCreature) { Reset(); } + npc_zelfanAI(Creature* pCreature) : priestess_companion_commonAI(pCreature) { Reset(); } - uint32 Goblin_Dragon_Gun_Timer; - uint32 Rocket_Launch_Timer; - uint32 Recombobulate_Timer; - uint32 High_Explosive_Sheep_Timer; - uint32 Fel_Iron_Bomb_Timer; + uint32 m_uiGoblinDragonGunTimer; + uint32 m_uiRocketLaunchTimer; + uint32 m_uiRecombobulateTimer; + uint32 m_uiHighExplosiveSheepTimer; + uint32 m_uiFelIronBombTimer; - void Reset() + void Reset() override { - Goblin_Dragon_Gun_Timer = 20000; - Rocket_Launch_Timer = 7000; - Recombobulate_Timer = 4000; - High_Explosive_Sheep_Timer = 10000; - Fel_Iron_Bomb_Timer = 15000; + m_uiGoblinDragonGunTimer = 20000; + m_uiRocketLaunchTimer = 7000; + m_uiRecombobulateTimer = 4000; + m_uiHighExplosiveSheepTimer = 10000; + m_uiFelIronBombTimer = 15000; - boss_priestess_lackey_commonAI::Reset(); + priestess_companion_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void JustSummoned(Creature* pSummoned) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - boss_priestess_lackey_commonAI::UpdateAI(diff); + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } - if (Goblin_Dragon_Gun_Timer < diff) + bool UpdateCompanionAI(const uint32 uiDiff) + { + if (m_uiGoblinDragonGunTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOBLIN_DRAGON_GUN); - Goblin_Dragon_Gun_Timer = 10000; - }else Goblin_Dragon_Gun_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_GOBLIN_DRAGON_GUN : SPELL_GOBLIN_DRAGON_GUN_H) == CAST_OK) + m_uiGoblinDragonGunTimer = urand(10000, 20000); + } + else + m_uiGoblinDragonGunTimer -= uiDiff; - if (Rocket_Launch_Timer < diff) + if (m_uiRocketLaunchTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ROCKET_LAUNCH); - Rocket_Launch_Timer = 9000; - }else Rocket_Launch_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ROCKET_LAUNCH : SPELL_ROCKET_LAUNCH_H) == CAST_OK) + m_uiRocketLaunchTimer = 9000; + } + } + else + m_uiRocketLaunchTimer -= uiDiff; - if (Fel_Iron_Bomb_Timer < diff) + if (m_uiFelIronBombTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEL_IRON_BOMB); - Fel_Iron_Bomb_Timer = 15000; - }else Fel_Iron_Bomb_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FEL_IRON_BOMB : SPELL_FEL_IRON_BOMB_H) == CAST_OK) + m_uiFelIronBombTimer = 15000; + } + } + else + m_uiFelIronBombTimer -= uiDiff; - if (Recombobulate_Timer < diff) + if (m_uiRecombobulateTimer < uiDiff) { - for(uint8 i = 0; i < MAX_ACTIVE_LACKEY; ++i) + // Note: this should be casted only on Polyformed targets + Unit* pTarget = NULL; + std::list lTempList = DoFindFriendlyCC(50.0f); + + if (!lTempList.empty()) + pTarget = *(lTempList.begin()); + else + pTarget = DoSelectLowestHpFriendly(50.0f); + + if (pTarget) { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aLackeyGuid[i])) - { - if (pAdd->IsPolymorphed()) - { - DoCastSpellIfCan(pAdd, SPELL_RECOMBOBULATE); - break; - } - } + if (DoCastSpellIfCan(pTarget, SPELL_RECOMBOBULATE) == CAST_OK) + m_uiRecombobulateTimer = 2000; } - Recombobulate_Timer = 2000; - }else Recombobulate_Timer -= diff; + } + else + m_uiRecombobulateTimer -= uiDiff; - if (High_Explosive_Sheep_Timer < diff) + if (m_uiHighExplosiveSheepTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_HIGH_EXPLOSIVE_SHEEP); - High_Explosive_Sheep_Timer = 65000; - }else High_Explosive_Sheep_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_HIGH_EXPLOSIVE_SHEEP) == CAST_OK) + m_uiHighExplosiveSheepTimer = 65000; + } + else + m_uiHighExplosiveSheepTimer -= uiDiff; - DoMeleeAttackIfReady(); + return true; } }; -CreatureAI* GetAI_zelfan(Creature* pCreature) +CreatureAI* GetAI_npc_zelfan(Creature* pCreature) { - return new boss_zelfanAI(pCreature); + return new npc_zelfanAI(pCreature); } -//struct MANGOS_DLL_DECL mob_high_explosive_sheepAI : public ScriptedAI -//{ -// mob_high_explosive_sheepAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} -// -// uint32 Explosion_Timer; -// -// void Reset() -// { -// Explosion_Timer = 60000; -// } -// -// void JustDied(Unit *Killer){} -// -// void UpdateAI(const uint32 diff) -// { -// if (Explosion_Timer < diff) -// { -// DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHEEP_EXPLOSION); -// }else -// Explosion_Timer -= diff; -// } -//}; - -//CreatureAI* GetAI_mob_high_explosive_sheep(Creature* pCreature) -//{ -// return new mob_high_explosive_sheepAI(pCreature); -//}; - void AddSC_boss_priestess_delrissa() { Script* pNewScript; @@ -1262,47 +1279,42 @@ void AddSC_boss_priestess_delrissa() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_kagani_nightstrike"; - pNewScript->GetAI = &GetAI_boss_kagani_nightstrike; + pNewScript->Name = "npc_kagani_nightstrike"; + pNewScript->GetAI = &GetAI_npc_kagani_nightstrike; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_ellris_duskhallow"; - pNewScript->GetAI = &GetAI_ellris_duskhallow; + pNewScript->Name = "npc_ellris_duskhallow"; + pNewScript->GetAI = &GetAI_npc_ellris_duskhallow; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_eramas_brightblaze"; - pNewScript->GetAI = &GetAI_eramas_brightblaze; + pNewScript->Name = "npc_eramas_brightblaze"; + pNewScript->GetAI = &GetAI_npc_eramas_brightblaze; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_yazzai"; - pNewScript->GetAI = &GetAI_yazzai; + pNewScript->Name = "npc_yazzai"; + pNewScript->GetAI = &GetAI_npc_yazzai; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_warlord_salaris"; - pNewScript->GetAI = &GetAI_warlord_salaris; + pNewScript->Name = "npc_warlord_salaris"; + pNewScript->GetAI = &GetAI_npc_warlord_salaris; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_garaxxas"; - pNewScript->GetAI = &GetAI_garaxxas; + pNewScript->Name = "npc_garaxxas"; + pNewScript->GetAI = &GetAI_npc_garaxxas; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_apoko"; - pNewScript->GetAI = &GetAI_apoko; + pNewScript->Name = "npc_apoko"; + pNewScript->GetAI = &GetAI_npc_apoko; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "boss_zelfan"; - pNewScript->GetAI = &GetAI_zelfan; + pNewScript->Name = "npc_zelfan"; + pNewScript->GetAI = &GetAI_npc_zelfan; pNewScript->RegisterSelf(); - - /*pNewScript = new Script; - pNewScript->Name = "mob_high_explosive_sheep"; - pNewScript->GetAI = &GetAI_mob_high_explosive_sheep; - pNewScript->RegisterSelf();*/ } diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp index 555453bee..e1c00a20c 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp +++ b/scripts/eastern_kingdoms/magisters_terrace/boss_selin_fireheart.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Selin_Fireheart SD%Complete: 90 -SDComment: Heroic and Normal Support. Needs further testing. +SDComment: Timers. SDCategory: Magister's Terrace EndScriptData */ @@ -34,20 +34,24 @@ enum SAY_DEATH = -1585005, EMOTE_CRYSTAL = -1585006, - // Crystal effect spells - SPELL_FEL_CRYSTAL_COSMETIC = 44374, - SPELL_FEL_CRYSTAL_DUMMY = 44329, - SPELL_FEL_CRYSTAL_VISUAL = 44355, - SPELL_MANA_RAGE = 44320, // This spell triggers 44321, which changes scale and regens mana Requires an entry in spell_script_target - // Selin's spells SPELL_DRAIN_LIFE = 44294, + SPELL_DRAIN_LIFE_H = 46155, SPELL_FEL_EXPLOSION = 44314, - SPELL_DRAIN_MANA = 46153, // Heroic only + // SPELL_FEL_CRYSTAL_DUMMY = 44329, // used by Selin to select a nearby Crystal - not used in script + SPELL_MANA_RAGE = 44320, // This spell triggers 44321, which changes scale and regens mana Requires an entry in spell_script_target + + // Crystal spells and npcs + SPELL_FEL_CRYSTAL_COSMETIC = 44374, // cosmetic - used by the guys around Selin + SPELL_FEL_CRYSTAL_VISUAL = 44355, // cosmetic + + NPC_HUSK = 24690, + NPC_SKULER = 24688, + NPC_BRUISER = 24689, }; -struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI +struct boss_selin_fireheartAI : public ScriptedAI { boss_selin_fireheartAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -59,179 +63,126 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI instance_magisters_terrace* m_pInstance; bool m_bIsRegularMode; - GUIDList m_lCrystalGuids; - uint32 m_uiDrainLifeTimer; uint32 m_uiDrainManaTimer; uint32 m_uiFelExplosionTimer; uint32 m_uiDrainCrystalTimer; - uint32 m_uiEmpowerTimer; + uint32 m_uiManaRageTimer; - bool m_bIsDraining; bool m_bDrainingCrystal; - ObjectGuid m_crystalGuid; // This will help us create a pointer to the crystal we are draining. We store GUIDs, never units in case unit is deleted/offline (offline if player of course). + ObjectGuid m_crystalGuid; - void Reset() + void Reset() override { - m_uiDrainLifeTimer = urand(3000, 7000); - m_uiDrainManaTimer = m_uiDrainLifeTimer + 5000; + m_uiDrainLifeTimer = urand(3000, 7000); + m_uiDrainManaTimer = m_uiDrainLifeTimer + 5000; m_uiFelExplosionTimer = 2100; - m_uiDrainCrystalTimer = urand(10000, 15000); - m_uiDrainCrystalTimer = urand(20000, 25000); - m_uiEmpowerTimer = 10000; + m_uiDrainCrystalTimer = m_bIsRegularMode ? urand(20000, 25000) : urand(10000, 15000); + m_uiManaRageTimer = 0; - m_bIsDraining = false; - m_bDrainingCrystal = false; - m_crystalGuid.Clear(); + m_bDrainingCrystal = false; } - void SelectNearestCrystal() + // Get the closest alive crystal for draining + bool DoSelectNearestCrystal() { - if (m_lCrystalGuids.empty()) - return; - - m_crystalGuid.Clear(); - Creature* pCrystal = NULL; - Creature* pCrystalChosen = NULL; - - for (GUIDList::const_iterator itr = m_lCrystalGuids.begin(); itr != m_lCrystalGuids.end(); ++itr) - { - pCrystal = m_creature->GetMap()->GetCreature(*itr); + // Wait to finish casting + if (m_creature->IsNonMeleeSpellCasted(false)) + return false; - if (pCrystal && pCrystal->isAlive()) - { - // select nearest - if (!pCrystalChosen || m_creature->GetDistanceOrder(pCrystal, pCrystalChosen, false)) - { - m_crystalGuid = pCrystal->GetObjectGuid(); - pCrystalChosen = pCrystal; // Store a copy of pCrystal so we don't need to recreate a pointer to closest crystal for the movement and yell. - } - } - } - if (pCrystalChosen) + if (Creature* pCrystal = GetClosestCreatureWithEntry(m_creature, NPC_FEL_CRYSTAL, 60.0f)) { + m_crystalGuid = pCrystal->GetObjectGuid(); DoScriptText(SAY_ENERGY, m_creature); DoScriptText(EMOTE_CRYSTAL, m_creature); + m_creature->InterruptNonMeleeSpells(false); - pCrystalChosen->CastSpell(pCrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true); - - float x, y, z; // coords that we move to, close to the crystal. - pCrystalChosen->GetClosePoint(x, y, z, m_creature->GetObjectBoundingRadius(), CONTACT_DISTANCE); - - m_creature->SetWalk(false); - m_creature->GetMotionMaster()->MovePoint(1, x, y, z); + float fX, fY, fZ; + SetCombatMovement(false); + m_creature->GetContactPoint(pCrystal, fX, fY, fZ, INTERACTION_DISTANCE); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); m_bDrainingCrystal = true; - } - } - - void ShatterRemainingCrystals() - { - if (m_lCrystalGuids.empty()) - return; - for (GUIDList::const_iterator itr = m_lCrystalGuids.begin(); itr != m_lCrystalGuids.end(); ++itr) - { - //Creature* pCrystal = m_creature->GetMap()->GetCreature(FelCrystals[i]); - Creature* pCrystal = m_creature->GetMap()->GetCreature(*itr); - - if (pCrystal && pCrystal->isAlive()) - pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + return true; } + + return false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) - { m_pInstance->SetData(TYPE_SELIN, IN_PROGRESS); - - if (m_lCrystalGuids.empty()) - { - // Get and output crystals - m_pInstance->GetFelCrystalList(m_lCrystalGuids); - for (GUIDList::const_iterator itr = m_lCrystalGuids.begin(); itr != m_lCrystalGuids.end(); ++itr) - debug_log("SD2: Selin: Added Fel Crystal %s to list", ObjectGuid(*itr).GetString().c_str()); - } - } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - { m_pInstance->SetData(TYPE_SELIN, FAIL); - - for (GUIDList::const_iterator itr = m_lCrystalGuids.begin(); itr != m_lCrystalGuids.end(); ++itr) - { - if (Creature* pCrystal = m_creature->GetMap()->GetCreature(*itr)) - { - if (!pCrystal->isAlive()) - pCrystal->Respawn(); // Let MaNGOS handle setting death state, etc. - - // Only need to set unselectable flag. You can't attack unselectable units so non_attackable flag is not necessary here. - pCrystal->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - } - } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { - if (uiType == POINT_MOTION_TYPE && uiPointId == 1) + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + Creature* pCrystal = m_creature->GetMap()->GetCreature(m_crystalGuid); + if (pCrystal && pCrystal->isAlive()) { - Creature* pCrystalChosen = m_creature->GetMap()->GetCreature(m_crystalGuid); - if (pCrystalChosen && pCrystalChosen->isAlive()) + if (DoCastSpellIfCan(pCrystal, SPELL_MANA_RAGE) == CAST_OK) { - // Make the crystal attackable - // We also remove NON_ATTACKABLE in case the database has it set. - pCrystalChosen->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE + UNIT_FLAG_NOT_SELECTABLE); - pCrystalChosen->CastSpell(m_creature, SPELL_MANA_RAGE, true); - m_bIsDraining = true; - } - else - { - // Make an error message in case something weird happened here - error_log("SD2: Selin Fireheart unable to drain crystal as the crystal is either dead or deleted.."); - m_bDrainingCrystal = false; + // Allow the crystal to be killed + pCrystal->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiManaRageTimer = 10000; } } + else + { + // Make an error message in case something weird happened here + script_error_log("Selin Fireheart unable to drain crystal as the crystal is either dead or deleted.."); + m_bDrainingCrystal = false; + } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - if (!m_pInstance) - return; - - m_pInstance->SetData(TYPE_SELIN, DONE); // Encounter complete! + if (m_pInstance) + m_pInstance->SetData(TYPE_SELIN, DONE); + } - ShatterRemainingCrystals(); + // Mark the Mana Rage as complete + void ManaRageComplete() + { + m_bDrainingCrystal = false; + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!m_bDrainingCrystal) { - uint32 uiMaxPowerMana = m_creature->GetMaxPower(POWER_MANA); - if (uiMaxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / uiMaxPowerMana) < 10)) + if (m_creature->GetPower(POWER_MANA) * 100 / m_creature->GetMaxPower(POWER_MANA) < 10) { if (m_uiDrainLifeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pTarget, SPELL_DRAIN_LIFE) == CAST_OK) + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_DRAIN_LIFE : SPELL_DRAIN_LIFE_H) == CAST_OK) m_uiDrainLifeTimer = 10000; } } @@ -243,16 +194,23 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI { if (m_uiDrainManaTimer < uiDiff) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (!pTarget) - pTarget = m_creature->getVictim(); - - if (DoCastSpellIfCan(pTarget, SPELL_DRAIN_MANA) == CAST_OK) - m_uiDrainManaTimer = 10000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_DRAIN_MANA, SELECT_FLAG_POWER_MANA)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DRAIN_MANA) == CAST_OK) + m_uiDrainManaTimer = 10000; + } } else m_uiDrainManaTimer -= uiDiff; } + + if (m_uiDrainCrystalTimer < uiDiff) + { + if (DoSelectNearestCrystal()) + m_uiDrainCrystalTimer = m_bIsRegularMode ? urand(20000, 25000) : urand(10000, 15000); + } + else + m_uiDrainCrystalTimer -= uiDiff; } if (m_uiFelExplosionTimer < uiDiff) @@ -263,49 +221,26 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI else m_uiFelExplosionTimer -= uiDiff; - // If below 10% mana, start recharging - uiMaxPowerMana = m_creature->GetMaxPower(POWER_MANA); - if (uiMaxPowerMana && ((m_creature->GetPower(POWER_MANA)*100 / uiMaxPowerMana) < 10)) - { - if (m_uiDrainCrystalTimer < uiDiff) - { - SelectNearestCrystal(); - - if (m_bIsRegularMode) - m_uiDrainCrystalTimer = urand(20000, 25000); - else - m_uiDrainCrystalTimer = urand(10000, 15000); - - } - else - m_uiDrainCrystalTimer -= uiDiff; - } - DoMeleeAttackIfReady(); } - else // if m_bDrainingCrystal + else { - if (m_bIsDraining) + if (m_uiManaRageTimer) { - if (m_uiEmpowerTimer < uiDiff) + if (m_uiManaRageTimer <= uiDiff) { - m_bIsDraining = false; - m_bDrainingCrystal = false; - DoScriptText(SAY_EMPOWERED, m_creature); + ManaRageComplete(); - Creature* CrystalChosen = m_creature->GetMap()->GetCreature(m_crystalGuid); - if (CrystalChosen && CrystalChosen->isAlive()) - // Use Deal Damage to kill it, not SetDeathState. - CrystalChosen->DealDamage(CrystalChosen, CrystalChosen->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + // Kill the drained crystal + Creature* pCrystalChosen = m_creature->GetMap()->GetCreature(m_crystalGuid); + if (pCrystalChosen && pCrystalChosen->isAlive()) + pCrystalChosen->DealDamage(pCrystalChosen, pCrystalChosen->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_crystalGuid.Clear(); - - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiManaRageTimer = 0; } else - m_uiEmpowerTimer -= uiDiff; + m_uiManaRageTimer -= uiDiff; } } } @@ -316,39 +251,59 @@ CreatureAI* GetAI_boss_selin_fireheart(Creature* pCreature) return new boss_selin_fireheartAI(pCreature); }; -struct MANGOS_DLL_DECL mob_fel_crystalAI : public ScriptedAI +struct mob_fel_crystalAI : public ScriptedAI { mob_fel_crystalAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - void UpdateAI(const uint32 uiDiff) {} + GuidSet m_sWretchedGuids; + + uint32 m_uiVisualTimer; + + void Reset() override + { + m_uiVisualTimer = 1000; + m_sWretchedGuids.clear(); + } + + void AttackStart(Unit* /*pWho*/) override {} - void JustDied(Unit* killer) + void MoveInLineOfSight(Unit* pWho) override + { + // Cosmetic spell + if (m_sWretchedGuids.find(pWho->GetObjectGuid()) == m_sWretchedGuids.end() && pWho->IsWithinDist(m_creature, 5.0f) && pWho->isAlive() && + (pWho->GetEntry() == NPC_SKULER || pWho->GetEntry() == NPC_BRUISER || pWho->GetEntry() == NPC_HUSK)) + { + pWho->CastSpell(m_creature, SPELL_FEL_CRYSTAL_COSMETIC, false); + m_sWretchedGuids.insert(pWho->GetObjectGuid()); + } + } + + void JustDied(Unit* /*pKiller*/) override { if (ScriptedInstance* pInstance = (ScriptedInstance*)m_creature->GetInstanceData()) { Creature* pSelin = pInstance->GetSingleCreatureFromStorage(NPC_SELIN_FIREHEART); + if (!pSelin || !pSelin->isAlive()) + return; - if (pSelin && pSelin->isAlive()) - { - boss_selin_fireheartAI* pSelinAI = dynamic_cast(pSelin->AI()); - - if (pSelinAI && pSelinAI->m_crystalGuid == m_creature->GetObjectGuid()) - { - // Set this to false if we are the creature that Selin is draining so his AI flows properly - pSelinAI->m_bDrainingCrystal = false; - pSelinAI->m_bIsDraining = false; - pSelinAI->m_uiEmpowerTimer = 10000; + // Mark Mana rage as completed + pSelin->InterruptNonMeleeSpells(false); + if (boss_selin_fireheartAI* pBossAI = dynamic_cast(pSelin->AI())) + pBossAI->ManaRageComplete(); + } + } - if (pSelin->getVictim()) - { - pSelin->AI()->AttackStart(pSelin->getVictim()); - pSelin->GetMotionMaster()->MoveChase(pSelin->getVictim()); - } - } + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiVisualTimer) + { + if (m_uiVisualTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FEL_CRYSTAL_VISUAL) == CAST_OK) + m_uiVisualTimer = 0; } + else + m_uiVisualTimer -= uiDiff; } } }; diff --git a/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp b/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp index 3026d0098..0d3d0ac10 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp +++ b/scripts/eastern_kingdoms/magisters_terrace/boss_vexallus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Vexallus SD%Complete: 90 -SDComment: Heroic and Normal support. Needs further testing. +SDComment: Timers. SDCategory: Magister's Terrace EndScriptData */ @@ -33,32 +33,30 @@ enum SAY_KILL = -1585010, EMOTE_DISCHARGE_ENERGY = -1585011, - //is this text for real? + // is this text for real? //#define SAY_DEATH "What...happen...ed." - //Pure energy spell info + // Pure energy spell info SPELL_ENERGY_BOLT = 46156, SPELL_ENERGY_FEEDBACK = 44335, + SPELL_ENERGY_PASSIVE = 44326, - //Vexallus spell info + // Vexallus spell info SPELL_CHAIN_LIGHTNING = 44318, - SPELL_CHAIN_LIGHTNING_H = 46380, //heroic spell + SPELL_CHAIN_LIGHTNING_H = 46380, // heroic spell SPELL_OVERLOAD = 44353, SPELL_ARCANE_SHOCK = 44319, - SPELL_ARCANE_SHOCK_H = 46381, //heroic spell + SPELL_ARCANE_SHOCK_H = 46381, // heroic spell - SPELL_SUMMON_PURE_ENERGY = 44322, //mod scale -10 - SPELL_SUMMON_PURE_ENERGY1_H = 46154, //mod scale -5 - SPELL_SUMMON_PURE_ENERGY2_H = 46159, //mod scale -5 + SPELL_SUMMON_PURE_ENERGY = 44322, // mod scale -10 + SPELL_SUMMON_PURE_ENERGY1_H = 46154, // mod scale -5 + SPELL_SUMMON_PURE_ENERGY2_H = 46159, // mod scale -5 - //Creatures + // Creatures NPC_PURE_ENERGY = 24745, - - INTERVAL_MODIFIER = 15, - INTERVAL_SWITCH = 6 }; -struct MANGOS_DLL_DECL boss_vexallusAI : public ScriptedAI +struct boss_vexallusAI : public ScriptedAI { boss_vexallusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -70,36 +68,39 @@ struct MANGOS_DLL_DECL boss_vexallusAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 ChainLightningTimer; - uint32 ArcaneShockTimer; - uint32 OverloadTimer; - uint32 IntervalHealthAmount; - bool Enraged; + uint32 m_uiChainLightningTimer; + uint32 m_uiArcaneShockTimer; + uint32 m_uiOverloadTimer; + uint32 m_uiIntervalHealthAmount; + bool m_bEnraged; - void Reset() + void Reset() override { - ChainLightningTimer = 8000; - ArcaneShockTimer = 5000; - OverloadTimer = 1200; - IntervalHealthAmount = 1; - Enraged = false; - - if (m_pInstance) - m_pInstance->SetData(TYPE_VEXALLUS, NOT_STARTED); + m_uiChainLightningTimer = 8000; + m_uiArcaneShockTimer = 5000; + m_uiOverloadTimer = 1200; + m_uiIntervalHealthAmount = 1; + m_bEnraged = false; } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_KILL, m_creature); } - void JustDied(Unit *victim) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VEXALLUS, FAIL); + } + + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_VEXALLUS, DONE); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -107,69 +108,76 @@ struct MANGOS_DLL_DECL boss_vexallusAI : public ScriptedAI m_pInstance->SetData(TYPE_VEXALLUS, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0.0f, 0.0f); - pSummoned->CastSpell(pSummoned, SPELL_ENERGY_BOLT, false, NULL, NULL, m_creature->GetObjectGuid()); + pSummoned->CastSpell(pSummoned, SPELL_ENERGY_PASSIVE, true, NULL, NULL, m_creature->GetObjectGuid()); + pSummoned->CastSpell(pSummoned, SPELL_ENERGY_BOLT, true, NULL, NULL, m_creature->GetObjectGuid()); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!Enraged) + if (!m_bEnraged) { - //used for check, when Vexallus cast adds 85%, 70%, 55%, 40%, 25% - if (m_creature->GetHealthPercent() <= float(100 - INTERVAL_MODIFIER*IntervalHealthAmount)) + // Enrage at 20% hp + if (m_creature->GetHealthPercent() < 20.0f) { - //increase amount, unless we're at 10%, then we switch and return - if (IntervalHealthAmount == INTERVAL_SWITCH) - { - Enraged = true; - return; - } - else - ++IntervalHealthAmount; + m_bEnraged = true; + return; + } + // used for check, when Vexallus cast adds 85%, 70%, 55%, 40%, 25% + if (m_creature->GetHealthPercent() <= float(100.0f - 15.0f * m_uiIntervalHealthAmount)) + { DoScriptText(SAY_ENERGY, m_creature); DoScriptText(EMOTE_DISCHARGE_ENERGY, m_creature); + ++m_uiIntervalHealthAmount; if (m_bIsRegularMode) - m_creature->CastSpell(m_creature, SPELL_SUMMON_PURE_ENERGY, true); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_PURE_ENERGY); else { - m_creature->CastSpell(m_creature, SPELL_SUMMON_PURE_ENERGY1_H, true); - m_creature->CastSpell(m_creature, SPELL_SUMMON_PURE_ENERGY2_H, true); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_PURE_ENERGY1_H, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_PURE_ENERGY2_H, CAST_TRIGGERED); } } - if (ChainLightningTimer < diff) + if (m_uiChainLightningTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING_H); - - ChainLightningTimer = 8000; - }else ChainLightningTimer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING_H) == CAST_OK) + m_uiChainLightningTimer = 8000; + } + } + else + m_uiChainLightningTimer -= uiDiff; - if (ArcaneShockTimer < diff) + if (m_uiArcaneShockTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_ARCANE_SHOCK : SPELL_ARCANE_SHOCK_H); - - ArcaneShockTimer = 8000; - }else ArcaneShockTimer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ARCANE_SHOCK : SPELL_ARCANE_SHOCK_H) == CAST_OK) + m_uiArcaneShockTimer = 8000; + } + } + else + m_uiArcaneShockTimer -= uiDiff; } else { - if (OverloadTimer < diff) + if (m_uiOverloadTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_OVERLOAD); - - OverloadTimer = 2000; - }else OverloadTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_OVERLOAD) == CAST_OK) + m_uiOverloadTimer = 2000; + } + else + m_uiOverloadTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -181,13 +189,13 @@ CreatureAI* GetAI_boss_vexallus(Creature* pCreature) return new boss_vexallusAI(pCreature); }; -struct MANGOS_DLL_DECL mob_pure_energyAI : public ScriptedAI +struct mob_pure_energyAI : public ScriptedAI { mob_pure_energyAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() { } + void Reset() override { } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (m_creature->IsTemporarySummon()) { @@ -206,8 +214,8 @@ struct MANGOS_DLL_DECL mob_pure_energyAI : public ScriptedAI } } - void MoveInLineOfSight(Unit *who) { } - void AttackStart(Unit *who) { } + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void AttackStart(Unit* /*pWho*/) override {} }; CreatureAI* GetAI_mob_pure_energy(Creature* pCreature) diff --git a/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp b/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp index 85b921e3f..c32e76dbf 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp +++ b/scripts/eastern_kingdoms/magisters_terrace/instance_magisters_terrace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Instance_Magisters_Terrace -SD%Complete: 60 -SDComment: Designed only for Selin Fireheart +SD%Complete: 80 +SDComment: SDCategory: Magister's Terrace EndScriptData */ @@ -48,6 +48,17 @@ void instance_magisters_terrace::OnCreatureCreate(Creature* pCreature) { case NPC_SELIN_FIREHEART: case NPC_DELRISSA: + case NPC_KALECGOS_DRAGON: + case NPC_KAELTHAS: + // insert Delrissa adds here, for better handling + case NPC_KAGANI: + case NPC_ELLRYS: + case NPC_ERAMAS: + case NPC_YAZZAI: + case NPC_SALARIS: + case NPC_GARAXXAS: + case NPC_APOKO: + case NPC_ZELFAN: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; case NPC_FEL_CRYSTAL: @@ -74,8 +85,7 @@ void instance_magisters_terrace::OnObjectCreate(GameObject* pGo) break; case GO_SELIN_ENCOUNTER_DOOR: case GO_KAEL_DOOR: - case GO_KAEL_STATUE_LEFT: - case GO_KAEL_STATUE_RIGHT: + case GO_ESCAPE_QUEL_DANAS: break; default: @@ -84,6 +94,36 @@ void instance_magisters_terrace::OnObjectCreate(GameObject* pGo) m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } +void instance_magisters_terrace::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_KAGANI: + case NPC_ELLRYS: + case NPC_ERAMAS: + case NPC_YAZZAI: + case NPC_SALARIS: + case NPC_GARAXXAS: + case NPC_APOKO: + case NPC_ZELFAN: + ++m_uiDelrissaDeathCount; + if (m_uiDelrissaDeathCount == MAX_DELRISSA_ADDS) + SetData(TYPE_DELRISSA, SPECIAL); + // yell on summoned death + if (Creature* pDelrissa = GetSingleCreatureFromStorage(NPC_DELRISSA)) + { + if (pDelrissa->isAlive()) + DoScriptText(aDelrissaAddDeath[m_uiDelrissaDeathCount - 1], pDelrissa); + else if (GetData(TYPE_DELRISSA) == SPECIAL) + { + SetData(TYPE_DELRISSA, DONE); + pDelrissa->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + } + } + break; + } +} + void instance_magisters_terrace::SetData(uint32 uiType, uint32 uiData) { switch (uiType) @@ -91,6 +131,30 @@ void instance_magisters_terrace::SetData(uint32 uiType, uint32 uiData) case TYPE_SELIN: if (uiData == DONE) DoUseDoorOrButton(GO_SELIN_DOOR); + if (uiData == FAIL) + { + // Reset crystals - respawn and kill is handled by creature linking + for (GuidList::const_iterator itr = m_lFelCrystalGuid.begin(); itr != m_lFelCrystalGuid.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + { + if (!pTemp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (pTemp->isAlive()) + pTemp->AI()->EnterEvadeMode(); + } + } + } + if (uiData == IN_PROGRESS) + { + // Stop channeling when the fight starts + for (GuidList::const_iterator itr = m_lFelCrystalGuid.begin(); itr != m_lFelCrystalGuid.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->InterruptNonMeleeSpells(false); + } + } DoUseDoorOrButton(GO_SELIN_ENCOUNTER_DOOR); m_auiEncounter[uiType] = uiData; break; @@ -108,14 +172,10 @@ void instance_magisters_terrace::SetData(uint32 uiType, uint32 uiData) break; case TYPE_KAELTHAS: DoUseDoorOrButton(GO_KAEL_DOOR); + if (uiData == DONE) + DoToggleGameObjectFlags(GO_ESCAPE_QUEL_DANAS, GO_FLAG_NO_INTERACT, false); m_auiEncounter[uiType] = uiData; break; - case TYPE_DELRISSA_DEATH_COUNT: - if (uiData == SPECIAL) - ++m_uiDelrissaDeathCount; - else - m_uiDelrissaDeathCount = 0; - return; } if (uiData == DONE) @@ -145,7 +205,7 @@ void instance_magisters_terrace::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -154,27 +214,12 @@ void instance_magisters_terrace::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_magisters_terrace::GetData(uint32 uiType) -{ - switch (uiType) - { - case TYPE_SELIN: return m_auiEncounter[0]; - case TYPE_VEXALLUS: return m_auiEncounter[1]; - case TYPE_DELRISSA: return m_auiEncounter[2]; - case TYPE_KAELTHAS: return m_auiEncounter[3]; - case TYPE_DELRISSA_DEATH_COUNT: return m_uiDelrissaDeathCount; - - default: - return 0; - } -} - -void instance_magisters_terrace::GetFelCrystalList(GUIDList& lList) +uint32 instance_magisters_terrace::GetData(uint32 uiType) const { - if (m_lFelCrystalGuid.empty()) - error_log("SD2: Magisters Terrace: No Fel Crystals loaded in Inst Data"); + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - lList = m_lFelCrystalGuid; + return 0; } InstanceData* GetInstanceData_instance_magisters_terrace(Map* pMap) diff --git a/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp b/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp index 5edb126ff..bc14bf5cb 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp +++ b/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,6 +26,7 @@ npc_kalecgos EndContentData */ #include "precompiled.h" +#include "magisters_terrace.h" /*###### ## npc_kalecgos @@ -35,84 +36,63 @@ enum { SPELL_TRANSFORM_TO_KAEL = 44670, SPELL_ORB_KILL_CREDIT = 46307, - NPC_KAEL = 24848, //human form entry - POINT_ID_LAND = 1 -}; + NPC_KALECGOS = 24848, // human form entry -const float afKaelLandPoint[] = {225.045f, -276.236f, -5.434f}; + MAP_ID_MAGISTER = 585, +}; -#define GOSSIP_ITEM_KAEL_1 "Who are you?" -#define GOSSIP_ITEM_KAEL_2 "What can we do to assist you?" -#define GOSSIP_ITEM_KAEL_3 "What brings you to the Sunwell?" -#define GOSSIP_ITEM_KAEL_4 "You're not alone here?" -#define GOSSIP_ITEM_KAEL_5 "What would Kil'jaeden want with a mortal woman?" +static const float afKaelLandPoint[4] = {200.36f, -270.77f, -8.73f, 0.01f}; // This is friendly keal that appear after used Orb. // If we assume DB handle summon, summon appear somewhere outside the platform where Orb is -struct MANGOS_DLL_DECL npc_kalecgosAI : public ScriptedAI +struct npc_kalecgosAI : public ScriptedAI { npc_kalecgosAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiTransformTimer; - void Reset() + void Reset() override { + // Check the map id because the same creature entry is involved in other scripted event in other instance + if (m_creature->GetMapId() != MAP_ID_MAGISTER) + return; + m_uiTransformTimer = 0; - // we must assume he appear as dragon somewhere outside the platform of orb, and then move directly to here - if (m_creature->GetEntry() != NPC_KAEL) - m_creature->GetMotionMaster()->MovePoint(POINT_ID_LAND, afKaelLandPoint[0], afKaelLandPoint[1], afKaelLandPoint[2]); + // Move the dragon to landing point + m_creature->GetMotionMaster()->MovePoint(1, afKaelLandPoint[0], afKaelLandPoint[1], afKaelLandPoint[2]); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; - if (uiPointId == POINT_ID_LAND) - m_uiTransformTimer = MINUTE*IN_MILLISECONDS; - } - - // some targeting issues with the spell, so use this workaround as temporary solution - void DoWorkaroundForQuestCredit() - { - Map* pMap = m_creature->GetMap(); - - if (!pMap || !pMap->IsRegularDifficulty()) - return; - - Map::PlayerList const &lList = pMap->GetPlayers(); - - if (lList.isEmpty()) - return; - - SpellEntry const* pSpell = GetSpellStore()->LookupEntry(SPELL_ORB_KILL_CREDIT); - - for(Map::PlayerList::const_iterator i = lList.begin(); i != lList.end(); ++i) + if (uiPointId) { - if (Player* pPlayer = i->getSource()) - { - if (pSpell && pSpell->EffectMiscValue[0]) - pPlayer->KilledMonsterCredit(pSpell->EffectMiscValue[0]); - } + m_creature->SetLevitate(false); + m_creature->SetFacingTo(afKaelLandPoint[3]); + m_uiTransformTimer = MINUTE * IN_MILLISECONDS; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiTransformTimer) { - if (m_uiTransformTimer < uiDiff) + if (m_uiTransformTimer <= uiDiff) { - m_creature->CastSpell(m_creature,SPELL_ORB_KILL_CREDIT,false); - DoWorkaroundForQuestCredit(); - // Transform and update entry, now ready for quest/read gossip - m_creature->CastSpell(m_creature,SPELL_TRANSFORM_TO_KAEL,false); - m_creature->UpdateEntry(NPC_KAEL); + if (DoCastSpellIfCan(m_creature, SPELL_TRANSFORM_TO_KAEL) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_ORB_KILL_CREDIT, CAST_TRIGGERED); + m_creature->UpdateEntry(NPC_KALECGOS); - m_uiTransformTimer = 0; - }else m_uiTransformTimer -= uiDiff; + m_uiTransformTimer = 0; + } + } + else + m_uiTransformTimer -= uiDiff; } } }; @@ -122,43 +102,18 @@ CreatureAI* GetAI_npc_kalecgos(Creature* pCreature) return new npc_kalecgosAI(pCreature); } -bool GossipHello_npc_kalecgos(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(12498, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_kalecgos(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool ProcessEventId_event_go_scrying_orb(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) { - switch(uiAction) + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(12500, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(12502, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(12606, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAEL_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(12607, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->SEND_GOSSIP_MENU(12608, pCreature->GetObjectGuid()); - break; + if (instance_magisters_terrace* pInstance = (instance_magisters_terrace*)((Player*)pSource)->GetInstanceData()) + { + // Check if the Dragon is already spawned and don't allow it to spawn it multiple times + if (pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON, true)) + return true; + } } - - return true; + return false; } void AddSC_magisters_terrace() @@ -168,7 +123,10 @@ void AddSC_magisters_terrace() pNewScript = new Script; pNewScript->Name = "npc_kalecgos"; pNewScript->GetAI = &GetAI_npc_kalecgos; - pNewScript->pGossipHello = &GossipHello_npc_kalecgos; - pNewScript->pGossipSelect = &GossipSelect_npc_kalecgos; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_go_scrying_orb"; + pNewScript->pProcessEventId = &ProcessEventId_event_go_scrying_orb; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h b/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h index faebfa347..955e6dc31 100644 --- a/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h +++ b/scripts/eastern_kingdoms/magisters_terrace/magisters_terrace.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,17 +8,28 @@ enum { MAX_ENCOUNTER = 4, + MAX_DELRISSA_ADDS = 4, TYPE_SELIN = 0, TYPE_VEXALLUS = 1, TYPE_DELRISSA = 2, TYPE_KAELTHAS = 3, - TYPE_DELRISSA_DEATH_COUNT = 4, - NPC_SELIN_FIREHEART = 24723, NPC_DELRISSA = 24560, NPC_FEL_CRYSTAL = 24722, + NPC_KALECGOS_DRAGON = 24844, + NPC_KAELTHAS = 24664, + + // Delrissa adds + NPC_KAGANI = 24557, + NPC_ELLRYS = 24558, + NPC_ERAMAS = 24554, + NPC_YAZZAI = 24561, + NPC_SALARIS = 24559, + NPC_GARAXXAS = 24555, + NPC_APOKO = 24553, + NPC_ZELFAN = 24556, GO_VEXALLUS_DOOR = 187896, GO_SELIN_DOOR = 187979, // SunwellRaid Gate 02 @@ -26,30 +37,30 @@ enum GO_SELIN_ENCOUNTER_DOOR = 188065, // Assembly Chamber Door GO_KAEL_DOOR = 188064, - GO_KAEL_STATUE_LEFT = 188165, - GO_KAEL_STATUE_RIGHT = 188166, + // GO_KAEL_STATUE_LEFT = 188165, // animation statues - they do not reset on fail + // GO_KAEL_STATUE_RIGHT = 188166, + GO_ESCAPE_QUEL_DANAS = 188173, }; -class MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance +static const int32 aDelrissaAddDeath[MAX_DELRISSA_ADDS] = { -1585013, -1585014, -1585015, -1585016}; + +class instance_magisters_terrace : public ScriptedInstance { public: instance_magisters_terrace(Map* pMap); - void Initialize(); - - // Was used, likely wrong for normal dungeon - //bool IsEncounterInProgress() const + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - uint32 GetData(uint32 uiType); - void SetData(uint32 uiType, uint32 uiData); + void OnCreatureDeath(Creature* pCreature) override; - void GetFelCrystalList(GUIDList& lList); + uint32 GetData(uint32 uiType) const override; + void SetData(uint32 uiType, uint32 uiData) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; @@ -57,7 +68,7 @@ class MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance uint32 m_uiDelrissaDeathCount; - GUIDList m_lFelCrystalGuid; + GuidList m_lFelCrystalGuid; }; #endif diff --git a/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp b/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp index 5e476b174..54d497cd8 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_baron_geddon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -34,7 +34,7 @@ enum SPELL_ARMAGEDDON = 20478 }; -struct MANGOS_DLL_DECL boss_baron_geddonAI : public ScriptedAI +struct boss_baron_geddonAI : public ScriptedAI { boss_baron_geddonAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -49,7 +49,7 @@ struct MANGOS_DLL_DECL boss_baron_geddonAI : public ScriptedAI uint32 m_uiIgniteManaTimer; uint32 m_uiLivingBombTimer; - void Reset() + void Reset() override { m_bIsArmageddon = false; m_uiInfernoTimer = 45000; @@ -57,25 +57,25 @@ struct MANGOS_DLL_DECL boss_baron_geddonAI : public ScriptedAI m_uiLivingBombTimer = 35000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GEDDON, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GEDDON, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GEDDON, NOT_STARTED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/molten_core/boss_garr.cpp b/scripts/eastern_kingdoms/molten_core/boss_garr.cpp index 3a23c617c..0b98d9127 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_garr.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_garr.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Garr -SD%Complete: 50 -SDComment: Garr's enrage is missing +SD%Complete: 80 +SDComment: Firesworn erruption needs to be revisited SDCategory: Molten Core EndScriptData */ @@ -29,16 +29,16 @@ enum // Garr spells SPELL_ANTIMAGICPULSE = 19492, SPELL_MAGMASHACKLES = 19496, - SPELL_ENRAGE = 19516, // TODO Stacking enrage (stacks to 10 times) + SPELL_ENRAGE = 19516, // Add spells SPELL_ERUPTION = 19497, SPELL_MASSIVE_ERUPTION = 20483, // TODO possible on death SPELL_IMMOLATE = 20294, - SPELL_SEPARATION_ANXIETY = 23492, // Used if separated too far from Garr, 21095 use unknown. + SPELL_SEPARATION_ANXIETY = 23492, // Used if separated too far from Garr }; -struct MANGOS_DLL_DECL boss_garrAI : public ScriptedAI +struct boss_garrAI : public ScriptedAI { boss_garrAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -51,31 +51,31 @@ struct MANGOS_DLL_DECL boss_garrAI : public ScriptedAI uint32 m_uiAntiMagicPulseTimer; uint32 m_uiMagmaShacklesTimer; - void Reset() + void Reset() override { m_uiAntiMagicPulseTimer = 25000; m_uiMagmaShacklesTimer = 15000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GARR, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GARR, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GARR, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -102,7 +102,7 @@ struct MANGOS_DLL_DECL boss_garrAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI +struct mob_fireswornAI : public ScriptedAI { mob_fireswornAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -115,13 +115,22 @@ struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI uint32 m_uiImmolateTimer; uint32 m_uiSeparationCheckTimer; - void Reset() + void Reset() override { m_uiImmolateTimer = urand(4000, 8000); // These times are probably wrong m_uiSeparationCheckTimer = 5000; } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + if (Creature* pGarr = m_pInstance->GetSingleCreatureFromStorage(NPC_GARR)) + pGarr->CastSpell(pGarr, SPELL_ENRAGE, true, NULL, NULL, m_creature->GetObjectGuid()); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -139,6 +148,9 @@ struct MANGOS_DLL_DECL mob_fireswornAI : public ScriptedAI if (m_uiSeparationCheckTimer < uiDiff) { + if (!m_pInstance) + return; + // Distance guesswork, but should be ok Creature* pGarr = m_pInstance->GetSingleCreatureFromStorage(NPC_GARR); if (pGarr && pGarr->isAlive() && !m_creature->IsWithinDist2d(pGarr->GetPositionX(), pGarr->GetPositionY(), 50.0f)) diff --git a/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp b/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp index 25aa81b2b..30aea5438 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_gehennas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Gehennas -SD%Complete: 90 -SDComment: +SD%Complete: 100 +SDComment: - SDCategory: Molten Core EndScriptData */ @@ -26,12 +26,13 @@ EndScriptData */ enum { - SPELL_SHADOW_BOLT = 19728, // 19729 exists too, but can be reflected + SPELL_GEHENNAS_CURSE = 19716, SPELL_RAIN_OF_FIRE = 19717, - SPELL_GEHENNAS_CURSE = 19716 + SPELL_SHADOW_BOLT_RANDOM = 19728, + SPELL_SHADOW_BOLT_TARGET = 19729, }; -struct MANGOS_DLL_DECL boss_gehennasAI : public ScriptedAI +struct boss_gehennasAI : public ScriptedAI { boss_gehennasAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -41,75 +42,78 @@ struct MANGOS_DLL_DECL boss_gehennasAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiShadowBoltTimer; - uint32 m_uiRainOfFireTimer; uint32 m_uiGehennasCurseTimer; + uint32 m_uiRainOfFireTimer; + uint32 m_uiShadowBoltRandomTimer; + uint32 m_uiShadowBoltTargetTimer; - void Reset() + void Reset() override { - m_uiShadowBoltTimer = 6000; - m_uiRainOfFireTimer = 10000; - m_uiGehennasCurseTimer = 12000; + m_uiGehennasCurseTimer = urand(5 * IN_MILLISECONDS, 10 * IN_MILLISECONDS); + m_uiRainOfFireTimer = urand(6 * IN_MILLISECONDS, 12 * IN_MILLISECONDS); + m_uiShadowBoltRandomTimer = urand(3 * IN_MILLISECONDS, 6 * IN_MILLISECONDS); + m_uiShadowBoltTargetTimer = urand(3 * IN_MILLISECONDS, 6 * IN_MILLISECONDS); } - void Aggro(Unit* pwho) + void Aggro(Unit* /*pwho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GEHENNAS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GEHENNAS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GEHENNAS, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // ShadowBolt Timer - if (m_uiShadowBoltTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - { - if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_BOLT) == CAST_OK) - m_uiShadowBoltTimer = 7000; - } - else // In case someone attempts soloing, we don't need to scan for targets every tick - m_uiShadowBoltTimer = 7000; - } - else - m_uiShadowBoltTimer -= uiDiff; - - // Rain of Fire Timer + // Rain_of_Fire-Timer if (m_uiRainOfFireTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(pTarget, SPELL_RAIN_OF_FIRE) == CAST_OK) - m_uiRainOfFireTimer = urand(4000, 12000); - } + if (DoCastSpellIfCan(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0), SPELL_RAIN_OF_FIRE) == CAST_OK) + m_uiRainOfFireTimer = urand(6 * IN_MILLISECONDS, 12 * IN_MILLISECONDS); } else m_uiRainOfFireTimer -= uiDiff; - // GehennasCurse Timer + // Gehennas_Curse-Timer if (m_uiGehennasCurseTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_GEHENNAS_CURSE) == CAST_OK) - m_uiGehennasCurseTimer = 30000; + m_uiGehennasCurseTimer = urand(25 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); } else m_uiGehennasCurseTimer -= uiDiff; + // Shadow_Bolt_Random-Timer + if (m_uiShadowBoltRandomTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0), SPELL_SHADOW_BOLT_RANDOM) == CAST_OK) + m_uiShadowBoltRandomTimer = urand(3 * IN_MILLISECONDS, 6 * IN_MILLISECONDS); + } + else + m_uiShadowBoltRandomTimer -= uiDiff; + + // Shadow_Bolt_Target-Timer + if (m_uiShadowBoltTargetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT_TARGET) == CAST_OK) + m_uiShadowBoltTargetTimer = urand(3 * IN_MILLISECONDS, 6 * IN_MILLISECONDS); + } + else + m_uiShadowBoltTargetTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; diff --git a/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp b/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp index 8338571c6..1afe36037 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_golemagg.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,12 +37,14 @@ enum SPELL_MANGLE = 19820 }; -struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI +struct boss_golemaggAI : public ScriptedAI { boss_golemaggAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); + + DoCastSpellIfCan(m_creature, SPELL_MAGMA_SPLASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } ScriptedInstance* m_pInstance; @@ -52,35 +54,35 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI uint32 m_uiBuffTimer; bool m_bEnraged; - void Reset() + void Reset() override { m_uiPyroblastTimer = 7 * IN_MILLISECONDS; m_uiEarthquakeTimer = 3 * IN_MILLISECONDS; m_uiBuffTimer = 1.5 * IN_MILLISECONDS; m_bEnraged = false; - - m_creature->CastSpell(m_creature, SPELL_MAGMA_SPLASH, true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GOLEMAGG, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GOLEMAGG, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GOLEMAGG, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_MAGMA_SPLASH, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -91,7 +93,7 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if (DoCastSpellIfCan(pTarget, SPELL_PYROBLAST) == CAST_OK) - m_uiPyroblastTimer = 7*IN_MILLISECONDS; + m_uiPyroblastTimer = 7 * IN_MILLISECONDS; } } else @@ -110,7 +112,7 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI if (m_uiEarthquakeTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_EARTHQUAKE) == CAST_OK) - m_uiEarthquakeTimer = 3*IN_MILLISECONDS; + m_uiEarthquakeTimer = 3 * IN_MILLISECONDS; } else m_uiEarthquakeTimer -= uiDiff; @@ -120,7 +122,7 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI if (m_uiBuffTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_GOLEMAGG_TRUST); - m_uiBuffTimer = 1.5*IN_MILLISECONDS; + m_uiBuffTimer = 1.5 * IN_MILLISECONDS; } else m_uiBuffTimer -= uiDiff; @@ -129,7 +131,7 @@ struct MANGOS_DLL_DECL boss_golemaggAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI +struct mob_core_ragerAI : public ScriptedAI { mob_core_ragerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -140,12 +142,12 @@ struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI ScriptedInstance* m_pInstance; uint32 m_uiMangleTimer; - void Reset() + void Reset() override { - m_uiMangleTimer = 7*IN_MILLISECONDS; // These times are probably wrong + m_uiMangleTimer = 7 * IN_MILLISECONDS; // These times are probably wrong } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (m_creature->GetHealthPercent() < 50.0f) { @@ -158,7 +160,7 @@ struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -167,7 +169,7 @@ struct MANGOS_DLL_DECL mob_core_ragerAI : public ScriptedAI if (m_uiMangleTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANGLE) == CAST_OK) - m_uiMangleTimer = 10*IN_MILLISECONDS; + m_uiMangleTimer = 10 * IN_MILLISECONDS; } else m_uiMangleTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp b/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp index 2f9322bc9..baa01ab71 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_lucifron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_SHADOWSHOCK = 19460 }; -struct MANGOS_DLL_DECL boss_lucifronAI : public ScriptedAI +struct boss_lucifronAI : public ScriptedAI { boss_lucifronAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -45,32 +45,32 @@ struct MANGOS_DLL_DECL boss_lucifronAI : public ScriptedAI uint32 m_uiLucifronCurseTimer; uint32 m_uiShadowShockTimer; - void Reset() + void Reset() override { m_uiImpendingDoomTimer = 10000; m_uiLucifronCurseTimer = 20000; m_uiShadowShockTimer = 6000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LUCIFRON, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LUCIFRON, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_LUCIFRON, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp b/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp index 629bd394c..69d8e5fda 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_magmadar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,7 +35,7 @@ enum SPELL_LAVABOMB_ALT = 19428 }; -struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI +struct boss_magmadarAI : public ScriptedAI { boss_magmadarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -49,14 +49,14 @@ struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI uint32 m_uiPanicTimer; uint32 m_uiLavabombTimer; - void Reset() + void Reset() override { m_uiFrenzyTimer = 30000; m_uiPanicTimer = 7000; m_uiLavabombTimer = 12000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, SPELL_MAGMASPIT, true); @@ -64,19 +64,19 @@ struct MANGOS_DLL_DECL boss_magmadarAI : public ScriptedAI m_pInstance->SetData(TYPE_MAGMADAR, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_MAGMADAR, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_MAGMADAR, NOT_STARTED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp b/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp index 098ed9090..7638cf72c 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_majordomo_executus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -63,7 +63,7 @@ enum SPELL_RAGNA_EMERGE = 20568, }; -struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI +struct boss_majordomoAI : public ScriptedAI { boss_majordomoAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -85,9 +85,9 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI bool m_bHasEncounterFinished; uint8 m_uiAddsKilled; uint8 m_uiSpeech; - GUIDList m_luiMajordomoAddsGUIDs; + GuidList m_luiMajordomoAddsGUIDs; - void Reset() + void Reset() override { m_uiMagicReflectionTimer = 30000; // Damage reflection first so we alternate m_uiDamageReflectionTimer = 15000; @@ -100,7 +100,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI m_uiSpeech = 0; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 4)) return; @@ -108,7 +108,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI DoScriptText(SAY_SLAY, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_RAGNAROS) return; @@ -119,24 +119,24 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI m_pInstance->SetData(TYPE_MAJORDOMO, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { - if (!m_bHasEncounterFinished) // Normal reached home, FAIL + if (!m_bHasEncounterFinished) // Normal reached home, FAIL { if (m_pInstance) m_pInstance->SetData(TYPE_MAJORDOMO, FAIL); } - else // Finished the encounter, DONE + else // Finished the encounter, DONE { // Exit combat - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->SetLootRecipient(NULL); // Set friendly m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - m_creature->setFaction(FACTION_MAJORDOMO_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_MAJORDOMO_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); // Reset orientation m_creature->SetFacingTo(m_aMajordomoLocations[0].m_fO); @@ -154,7 +154,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); // Prevent possible exploits with double summoning - if (Creature* pRagnaros = m_creature->GetMap()->GetCreature(m_ragnarosGuid)) + if (m_creature->GetMap()->GetCreature(m_ragnarosGuid)) return; DoScriptText(SAY_SUMMON_0, m_creature, pPlayer); @@ -163,7 +163,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI m_uiSpeech = 10; } - void JustRespawned() + void JustRespawned() override { // Encounter finished, need special treatment if (m_bHasEncounterFinished) @@ -178,12 +178,12 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FLAMEWAKER_HEALER || pSummoned->GetEntry() == NPC_FLAMEWAKER_ELITE) { m_luiMajordomoAddsGUIDs.push_back(pSummoned->GetObjectGuid()); - pSummoned->SetRespawnDelay(2*HOUR); + pSummoned->SetRespawnDelay(2 * HOUR); } else if (pSummoned->GetEntry() == NPC_RAGNAROS) { @@ -192,13 +192,13 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (pKiller->GetTypeId() == TYPEID_UNIT && pKiller->GetEntry() == NPC_RAGNAROS) DoScriptText(SAY_ARRIVAL4_MAJ, m_creature); } - void CorpseRemoved(uint32 &uiRespawnDelay) + void CorpseRemoved(uint32& uiRespawnDelay) override { uiRespawnDelay = urand(2 * HOUR, 3 * HOUR); @@ -210,7 +210,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FLAMEWAKER_HEALER || pSummoned->GetEntry() == NPC_FLAMEWAKER_ELITE) { @@ -232,7 +232,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI // Unsummon Majordomo adds void UnsummonMajordomoAdds() { - for (GUIDList::const_iterator itr = m_luiMajordomoAddsGUIDs.begin(); itr != m_luiMajordomoAddsGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiMajordomoAddsGUIDs.begin(); itr != m_luiMajordomoAddsGUIDs.end(); ++itr) { if (Creature* pAdd = m_creature->GetMap()->GetCreature(*itr)) if (pAdd->IsTemporarySummon()) @@ -242,7 +242,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI m_luiMajordomoAddsGUIDs.clear(); } - void DamageTaken(Unit* pDealer, uint32& uiDamage) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { if (uiDamage > m_creature->GetHealth()) { @@ -251,7 +251,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Handling of his combat-end speech and Ragnaros summoning if (m_uiSpeech) @@ -260,7 +260,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI { switch (m_uiSpeech) { - // Majordomo retreat event + // Majordomo retreat event case 1: DoScriptText(SAY_DEFEAT_1, m_creature); m_uiSpeechTimer = 7500; @@ -289,7 +289,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI m_uiSpeech = 0; break; - // Ragnaros Summon Event + // Ragnaros Summon Event case 10: DoScriptText(SAY_SUMMON_1, m_creature); ++m_uiSpeech; @@ -318,7 +318,7 @@ struct MANGOS_DLL_DECL boss_majordomoAI : public ScriptedAI // Summon Ragnaros if (m_pInstance) if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(GO_LAVA_STEAM)) - m_creature->SummonCreature(NPC_RAGNAROS, pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), fmod(m_creature->GetOrientation() + M_PI, 2*M_PI), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 2*HOUR*IN_MILLISECONDS); + m_creature->SummonCreature(NPC_RAGNAROS, pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), fmod(m_creature->GetOrientation() + M_PI, 2 * M_PI), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 2 * HOUR * IN_MILLISECONDS); ++m_uiSpeech; m_uiSpeechTimer = 8700; break; @@ -424,14 +424,14 @@ bool GossipHello_boss_majordomo(Player* pPlayer, Creature* pCreature) { if (pInstance->GetData(TYPE_RAGNAROS) == NOT_STARTED || pInstance->GetData(TYPE_RAGNAROS) == FAIL) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SUMMON_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SUMMON_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SUMMON_1, pCreature->GetObjectGuid()); } } return true; } -bool GossipSelect_boss_majordomo(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 uiAction) +bool GossipSelect_boss_majordomo(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) { switch (uiAction) { @@ -453,7 +453,7 @@ bool GossipSelect_boss_majordomo(Player* pPlayer, Creature* pCreature, uint32 se return true; } -bool EffectDummyCreature_spell_boss_majordomo(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_spell_boss_majordomo(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiSpellId != SPELL_TELEPORT_SELF || uiEffIndex != EFFECT_INDEX_0) return false; diff --git a/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp b/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp index 0fd7b609a..1998250b6 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_ragnaros.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Boss_Ragnaros -SD%Complete: 60 +SD%Complete: 70 SDComment: Melee/ Range Combat behavior is not correct(any enemy in melee range, not only getVictim), Some abilities are missing SDCategory: Molten Core EndScriptData */ @@ -26,8 +26,7 @@ EndScriptData */ /* There have been quite some bugs about his spells, keep this as reference untill all finished * Missing features (based on wowwiki) - * Lava Splash - Localized Damage - * Melt Weapon - Proc Aura missing in DBC, or hack missing + * Lava Burst - this spell is handled by Go 178088 which is summoned by spells 21886, 21900 - 21907 */ enum @@ -43,7 +42,7 @@ enum SPELL_WRATH_OF_RAGNAROS = 20566, SPELL_ELEMENTAL_FIRE = 20564, SPELL_MAGMA_BLAST = 20565, // Ranged attack if nobody is in melee range - SPELL_MELT_WEAPON = 21388, // Passive aura was spell 21387, TODO need some hack.. + SPELL_MELT_WEAPON = 21387, SPELL_RAGNA_SUBMERGE = 21107, // Stealth aura SPELL_RAGNA_EMERGE = 20568, // Emerge from lava SPELL_ELEMENTAL_FIRE_KILL = 19773, @@ -55,7 +54,7 @@ enum NPC_FLAME_OF_RAGNAROS = 13148, }; -struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI +struct boss_ragnarosAI : public Scripted_NoMovementAI { boss_ragnarosAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -81,14 +80,14 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI bool m_bHasSubmergedOnce; bool m_bIsSubmerged; - void Reset() + void Reset() override { m_uiWrathOfRagnarosTimer = 30000; // TODO Research more, according to wowwiki 25s, but timers up to 34s confirmed m_uiHammerTimer = 11000; // TODO wowwiki states 20-30s timer, but ~11s confirmed m_uiMagmaBlastTimer = 2000; m_uiElementalFireTimer = 3000; - m_uiSubmergeTimer = 3*MINUTE*IN_MILLISECONDS; - m_uiAttackTimer = 90*IN_MILLISECONDS; + m_uiSubmergeTimer = 3 * MINUTE * IN_MILLISECONDS; + m_uiAttackTimer = 90 * IN_MILLISECONDS; m_uiAddCount = 0; m_bHasYelledMagmaBurst = false; @@ -96,7 +95,7 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI m_bIsSubmerged = false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -107,22 +106,24 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI DoScriptText(SAY_KILL, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_RAGNAROS, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_MAJORDOMO) return; + DoCastSpellIfCan(m_creature, SPELL_MELT_WEAPON); + if (m_pInstance) m_pInstance->SetData(TYPE_RAGNAROS, IN_PROGRESS); } - void EnterEvadeMode() + void EnterEvadeMode() override { if (m_pInstance) m_pInstance->SetData(TYPE_RAGNAROS, FAIL); @@ -134,7 +135,7 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI ScriptedAI::EnterEvadeMode(); } - void SummonedCreatureJustDied(Creature* pSummmoned) + void SummonedCreatureJustDied(Creature* pSummmoned) override { // If all Sons of Flame are dead, trigger emerge if (pSummmoned->GetEntry() == NPC_SON_OF_FLAME) @@ -147,7 +148,7 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SON_OF_FLAME) { @@ -160,14 +161,14 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI pSummoned->CastSpell(pSummoned, SPELL_INTENSE_HEAT, true, NULL, NULL, m_creature->GetObjectGuid()); } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { // As Majordomo is now killed, the last timer (until attacking) must be handled with ragnaros script if (pSpell->Id == SPELL_ELEMENTAL_FIRE_KILL && pTarget->GetTypeId() == TYPEID_UNIT && pTarget->GetEntry() == NPC_MAJORDOMO) m_uiEnterCombatTimer = 10000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiEnterCombatTimer) { @@ -209,7 +210,7 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI // Become emerged again DoCastSpellIfCan(m_creature, SPELL_RAGNA_EMERGE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_uiSubmergeTimer = 3*MINUTE*IN_MILLISECONDS; + m_uiSubmergeTimer = 3 * MINUTE * IN_MILLISECONDS; m_uiMagmaBlastTimer = 3000; // Delay the magma blast after emerge m_bIsSubmerged = false; } @@ -265,20 +266,20 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI DoCastSpellIfCan(m_creature, SPELL_RAGNA_SUBMERGE, CAST_INTERRUPT_PREVIOUS); m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); m_bIsSubmerged = true; - m_uiAttackTimer = 90*IN_MILLISECONDS; + m_uiAttackTimer = 90 * IN_MILLISECONDS; m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); // Say dependend if first time or not DoScriptText(!m_bHasSubmergedOnce ? SAY_REINFORCEMENTS_1 : SAY_REINFORCEMENTS_2, m_creature); - m_bHasSubmergedOnce = false; + m_bHasSubmergedOnce = true; // Summon 8 elementals at random points around the boss float fX, fY, fZ; - for(uint8 i = 0; i < MAX_ADDS_IN_SUBMERGE; ++i) + for (uint8 i = 0; i < MAX_ADDS_IN_SUBMERGE; ++i) { m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 30.0f, fX, fY, fZ); - m_creature->SummonCreature(NPC_SON_OF_FLAME, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + m_creature->SummonCreature(NPC_SON_OF_FLAME, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 1000); } return; @@ -316,7 +317,7 @@ struct MANGOS_DLL_DECL boss_ragnarosAI : public Scripted_NoMovementAI DoScriptText(SAY_MAGMABURST, m_creature); m_bHasYelledMagmaBurst = true; } - m_uiMagmaBlastTimer = 1000; // Spamm this! + m_uiMagmaBlastTimer = 1000; // Spamm this! } } } diff --git a/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp b/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp index 3429bbf17..b126805dc 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_shazzrah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -33,7 +33,7 @@ enum SPELL_GATE_OF_SHAZZRAH = 23138 // effect spell: 23139 }; -struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI +struct boss_shazzrahAI : public ScriptedAI { boss_shazzrahAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -49,7 +49,7 @@ struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI uint32 m_uiCounterspellTimer; uint32 m_uiBlinkTimer; - void Reset() + void Reset() override { m_uiArcaneExplosionTimer = 6000; m_uiShazzrahCurseTimer = 10000; @@ -58,25 +58,25 @@ struct MANGOS_DLL_DECL boss_shazzrahAI : public ScriptedAI m_uiBlinkTimer = 30000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SHAZZRAH, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SHAZZRAH, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SHAZZRAH, NOT_STARTED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp b/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp index 107a81115..3301ed31b 100644 --- a/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp +++ b/scripts/eastern_kingdoms/molten_core/boss_sulfuron_harbinger.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ enum SPELL_IMMOLATE = 20294 }; -struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI +struct boss_sulfuronAI : public ScriptedAI { boss_sulfuronAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -54,7 +54,7 @@ struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI uint32 m_uiKnockdownTimer; uint32 m_uiFlamespearTimer; - void Reset() + void Reset() override { m_uiDarkstrikeTimer = 10000; m_uiDemoralizingShoutTimer = 15000; @@ -63,25 +63,25 @@ struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI m_uiFlamespearTimer = 2000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SULFURON, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SULFURON, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SULFURON, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -103,7 +103,7 @@ struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI if (!pList.empty()) { std::list::iterator i = pList.begin(); - advance(i, (rand()%pList.size())); + advance(i, (rand() % pList.size())); pTarget = (*i); } @@ -150,7 +150,7 @@ struct MANGOS_DLL_DECL boss_sulfuronAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_flamewaker_priestAI : public ScriptedAI +struct mob_flamewaker_priestAI : public ScriptedAI { mob_flamewaker_priestAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -164,14 +164,14 @@ struct MANGOS_DLL_DECL mob_flamewaker_priestAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() + void Reset() override { m_uiHealTimer = urand(15000, 30000); m_uiShadowWordPainTimer = 2000; m_uiImmolateTimer = 8000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp b/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp index f6684abca..7d0ed35f5 100644 --- a/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp +++ b/scripts/eastern_kingdoms/molten_core/instance_molten_core.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,6 +24,18 @@ EndScriptData */ #include "precompiled.h" #include "molten_core.h" +static sSpawnLocation m_aBosspawnLocs[MAX_MAJORDOMO_ADDS] = +{ + {NPC_FLAMEWAKER_ELITE, 737.945f, -1156.48f, -118.945f, 4.46804f}, + {NPC_FLAMEWAKER_ELITE, 752.520f, -1191.02f, -118.218f, 2.49582f}, + {NPC_FLAMEWAKER_ELITE, 752.953f, -1163.94f, -118.869f, 3.70010f}, + {NPC_FLAMEWAKER_ELITE, 738.814f, -1197.40f, -118.018f, 1.83260f}, + {NPC_FLAMEWAKER_HEALER, 746.939f, -1194.87f, -118.016f, 2.21657f}, + {NPC_FLAMEWAKER_HEALER, 747.132f, -1158.87f, -118.897f, 4.03171f}, + {NPC_FLAMEWAKER_HEALER, 757.116f, -1170.12f, -118.793f, 3.40339f}, + {NPC_FLAMEWAKER_HEALER, 755.910f, -1184.46f, -118.449f, 2.80998f} +}; + instance_molten_core::instance_molten_core(Map* pMap) : ScriptedInstance(pMap) { Initialize(); @@ -45,7 +57,7 @@ bool instance_molten_core::IsEncounterInProgress() const return false; } -void instance_molten_core::OnPlayerEnter(Player* pPlayer) +void instance_molten_core::OnPlayerEnter(Player* /*pPlayer*/) { // Summon Majordomo if can DoSpawnMajordomoIfCan(true); @@ -55,7 +67,7 @@ void instance_molten_core::OnCreatureCreate(Creature* pCreature) { switch (pCreature->GetEntry()) { - // Bosses + // Bosses case NPC_GARR: case NPC_SULFURON: case NPC_MAJORDOMO: @@ -66,9 +78,9 @@ void instance_molten_core::OnCreatureCreate(Creature* pCreature) void instance_molten_core::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - // Runes + // Runes case GO_RUNE_KRESS: case GO_RUNE_MOHN: case GO_RUNE_BLAZ: @@ -77,9 +89,9 @@ void instance_molten_core::OnObjectCreate(GameObject* pGo) case GO_RUNE_THERI: case GO_RUNE_KORO: - // Majordomo event chest + // Majordomo event chest case GO_CACHE_OF_THE_FIRE_LORD: - // Ragnaros GOs + // Ragnaros GOs case GO_LAVA_STEAM: case GO_LAVA_SPLASH: m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); @@ -89,7 +101,7 @@ void instance_molten_core::OnObjectCreate(GameObject* pGo) void instance_molten_core::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_LUCIFRON: m_auiEncounter[uiType] = uiData; @@ -149,9 +161,9 @@ void instance_molten_core::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9]; m_strInstData = saveStream.str(); @@ -160,7 +172,7 @@ void instance_molten_core::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_molten_core::GetData(uint32 uiType) +uint32 instance_molten_core::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -180,7 +192,7 @@ void instance_molten_core::DoSpawnMajordomoIfCan(bool bByPlayerEnter) return; // Check if all rune bosses are done - for(uint8 i = TYPE_MAGMADAR; i < TYPE_MAJORDOMO; ++i) + for (uint8 i = TYPE_MAGMADAR; i < TYPE_MAJORDOMO; ++i) { if (m_auiEncounter[i] != DONE) return; @@ -193,11 +205,11 @@ void instance_molten_core::DoSpawnMajordomoIfCan(bool bByPlayerEnter) // Summon Majordomo // If Majordomo encounter isn't done, summon at encounter place, else near Ragnaros uint8 uiSummonPos = m_auiEncounter[TYPE_MAJORDOMO] == DONE ? 1 : 0; - if (Creature* pMajordomo = pPlayer->SummonCreature(m_aMajordomoLocations[uiSummonPos].m_uiEntry, m_aMajordomoLocations[uiSummonPos].m_fX, m_aMajordomoLocations[uiSummonPos].m_fY, m_aMajordomoLocations[uiSummonPos].m_fZ, m_aMajordomoLocations[uiSummonPos].m_fO, TEMPSUMMON_MANUAL_DESPAWN, 2*HOUR*IN_MILLISECONDS)) + if (Creature* pMajordomo = pPlayer->SummonCreature(m_aMajordomoLocations[uiSummonPos].m_uiEntry, m_aMajordomoLocations[uiSummonPos].m_fX, m_aMajordomoLocations[uiSummonPos].m_fY, m_aMajordomoLocations[uiSummonPos].m_fZ, m_aMajordomoLocations[uiSummonPos].m_fO, TEMPSUMMON_MANUAL_DESPAWN, 2 * HOUR * IN_MILLISECONDS)) { if (uiSummonPos) // Majordomo encounter already done, set faction { - pMajordomo->setFaction(FACTION_MAJORDOMO_FRIENDLY); + pMajordomo->SetFactionTemporary(FACTION_MAJORDOMO_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); pMajordomo->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); pMajordomo->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } @@ -207,7 +219,7 @@ void instance_molten_core::DoSpawnMajordomoIfCan(bool bByPlayerEnter) DoScriptText(SAY_MAJORDOMO_SPAWN, pMajordomo); for (uint8 i = 0; i < MAX_MAJORDOMO_ADDS; ++i) - pMajordomo->SummonCreature(m_aBosspawnLocs[i].m_uiEntry, m_aBosspawnLocs[i].m_fX, m_aBosspawnLocs[i].m_fY, m_aBosspawnLocs[i].m_fZ, m_aBosspawnLocs[i].m_fO, TEMPSUMMON_MANUAL_DESPAWN, DAY*IN_MILLISECONDS); + pMajordomo->SummonCreature(m_aBosspawnLocs[i].m_uiEntry, m_aBosspawnLocs[i].m_fX, m_aBosspawnLocs[i].m_fY, m_aBosspawnLocs[i].m_fZ, m_aBosspawnLocs[i].m_fO, TEMPSUMMON_MANUAL_DESPAWN, DAY * IN_MILLISECONDS); } } } @@ -225,10 +237,10 @@ void instance_molten_core::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/eastern_kingdoms/molten_core/molten_core.cpp b/scripts/eastern_kingdoms/molten_core/molten_core.cpp index 7145b2038..8dc81290c 100644 --- a/scripts/eastern_kingdoms/molten_core/molten_core.cpp +++ b/scripts/eastern_kingdoms/molten_core/molten_core.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/eastern_kingdoms/molten_core/molten_core.h b/scripts/eastern_kingdoms/molten_core/molten_core.h index d3cd6e408..ce47e02bb 100644 --- a/scripts/eastern_kingdoms/molten_core/molten_core.h +++ b/scripts/eastern_kingdoms/molten_core/molten_core.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -63,42 +63,30 @@ struct sSpawnLocation float m_fX, m_fY, m_fZ, m_fO; }; -static sSpawnLocation m_aBosspawnLocs[MAX_MAJORDOMO_ADDS] = -{ - {NPC_FLAMEWAKER_ELITE, 737.945f, -1156.48f, -118.945f, 4.46804f}, - {NPC_FLAMEWAKER_ELITE, 752.520f, -1191.02f, -118.218f, 2.49582f}, - {NPC_FLAMEWAKER_ELITE, 752.953f, -1163.94f, -118.869f, 3.70010f}, - {NPC_FLAMEWAKER_ELITE, 738.814f, -1197.40f, -118.018f, 1.83260f}, - {NPC_FLAMEWAKER_HEALER, 746.939f, -1194.87f, -118.016f, 2.21657f}, - {NPC_FLAMEWAKER_HEALER, 747.132f, -1158.87f, -118.897f, 4.03171f}, - {NPC_FLAMEWAKER_HEALER, 757.116f, -1170.12f, -118.793f, 3.40339f}, - {NPC_FLAMEWAKER_HEALER, 755.910f, -1184.46f, -118.449f, 2.80998f} -}; - static sSpawnLocation m_aMajordomoLocations[2] = { {NPC_MAJORDOMO, 758.089f, -1176.71f, -118.640f, 3.12414f}, // Summon fight position - {NPC_MAJORDOMO, 847.103f, -816.153f, -229.775f, 4.344f} // Summon and teleport location (near Ragnaros) + {NPC_MAJORDOMO, 847.103f, -816.153f, -229.775f, 4.344f} // Summon and teleport location (near Ragnaros) }; -class MANGOS_DLL_DECL instance_molten_core : public ScriptedInstance +class instance_molten_core : public ScriptedInstance { public: instance_molten_core(Map* pMap); ~instance_molten_core() {} - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); - void OnPlayerEnter(Player* pPlayer); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnPlayerEnter(Player* pPlayer) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: void DoSpawnMajordomoIfCan(bool bByPlayerEnter); diff --git a/scripts/eastern_kingdoms/redridge_mountains.cpp b/scripts/eastern_kingdoms/redridge_mountains.cpp index 23b2bb86e..472063f77 100644 --- a/scripts/eastern_kingdoms/redridge_mountains.cpp +++ b/scripts/eastern_kingdoms/redridge_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -45,42 +45,52 @@ enum SAY_CORPORAL_KEESHAN_5 = -1000565, }; -struct MANGOS_DLL_DECL npc_corporal_keeshan_escortAI : public npc_escortAI +struct npc_corporal_keeshan_escortAI : public npc_escortAI { npc_corporal_keeshan_escortAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } uint32 m_uiMockingBlowTimer; uint32 m_uiShieldBashTimer; - void Reset() + void Reset() override { m_uiMockingBlowTimer = 5000; m_uiShieldBashTimer = 8000; } - void WaypointStart(uint32 uiWP) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_CORPORAL_KEESHAN_1, m_creature); + m_creature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } + } + + void WaypointStart(uint32 uiWP) override { switch (uiWP) { - case 27: //break outside + case 27: // break outside DoScriptText(SAY_CORPORAL_KEESHAN_3, m_creature); m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; - case 54: //say goodbye + case 54: // say goodbye DoScriptText(SAY_CORPORAL_KEESHAN_5, m_creature); break; } } - void WaypointReached(uint32 uiWP) + void WaypointReached(uint32 uiWP) override { switch (uiWP) { - case 26: //break outside + case 26: // break outside m_creature->SetStandState(UNIT_STAND_STATE_SIT); DoScriptText(SAY_CORPORAL_KEESHAN_2, m_creature); break; - case 53: //quest_complete + case 53: // quest_complete DoScriptText(SAY_CORPORAL_KEESHAN_4, m_creature); if (Player* pPlayer = GetPlayerForEscort()) pPlayer->GroupEventHappens(QUEST_MISSING_IN_ACTION, m_creature); @@ -88,9 +98,9 @@ struct MANGOS_DLL_DECL npc_corporal_keeshan_escortAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { - //Combat check + // Combat check if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -122,13 +132,7 @@ CreatureAI* GetAI_npc_corporal_keeshan(Creature* pCreature) bool QuestAccept_npc_corporal_keeshan(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_MISSING_IN_ACTION) - { - if (npc_corporal_keeshan_escortAI* pEscortAI = dynamic_cast(pCreature->AI())) - { - DoScriptText(SAY_CORPORAL_KEESHAN_1, pCreature); - pEscortAI->Start(false, pPlayer, pQuest); - } - } + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); return true; } diff --git a/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp b/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp index 69d1b45cb..8e02df738 100644 --- a/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp +++ b/scripts/eastern_kingdoms/scarlet_enclave/ebon_hold.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Ebon_Hold -SD%Complete: 80 -SDComment: Quest support: 12848, 12733, 12739(and 12742 to 12750), 12727 +SD%Complete: 95 +SDComment: Quest support: 12641, 12687, 12698, 12733, 12739(and 12742 to 12750), 12754, 12801, 12848 SDCategory: Ebon Hold EndScriptData */ @@ -27,10 +27,19 @@ npc_death_knight_initiate npc_unworthy_initiate_anchor npc_unworthy_initiate go_acherus_soul_prison +npc_eye_of_acherus +npc_scarlet_ghoul +npc_highlord_darion_mograine +npc_fellow_death_knight +npc_acherus_deathcharger +npc_scarlet_courier EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "world_map_ebon_hold.h" +#include "pet_ai.h" +#include "TemporarySummon.h" /*###### ## npc_a_special_surprise @@ -96,15 +105,15 @@ enum SpecialSurprise NPC_PLAGUEFIST = 29053 }; -struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI +struct npc_a_special_surpriseAI : public ScriptedAI { - npc_a_special_surpriseAI(Creature *pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_a_special_surpriseAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiExecuteSpeech_Timer; uint32 m_uiExecuteSpeech_Counter; ObjectGuid m_playerGuid; - void Reset() + void Reset() override { m_uiExecuteSpeech_Timer = 0; m_uiExecuteSpeech_Counter = 0; @@ -113,7 +122,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI bool MeetQuestCondition(Player* pPlayer) { - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case 29061: // Ellen Stanbridge if (pPlayer->GetQuestStatus(12742) == QUEST_STATUS_INCOMPLETE) @@ -160,7 +169,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI return false; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (m_playerGuid || pWho->GetTypeId() != TYPEID_PLAYER || !pWho->IsWithinDist(m_creature, INTERACTION_DISTANCE)) return; @@ -169,7 +178,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI m_playerGuid = pWho->GetObjectGuid(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_playerGuid && !m_creature->getVictim() && m_creature->isAlive()) { @@ -183,12 +192,12 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI return; } - //TODO: simplify text's selection + // TODO: simplify text's selection - switch(pPlayer->getRace()) + switch (pPlayer->getRace()) { case RACE_HUMAN: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -216,7 +225,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_ORC: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -244,7 +253,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_DWARF: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_2, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -272,7 +281,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_NIGHTELF: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -300,7 +309,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_UNDEAD: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -328,7 +337,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_TAUREN: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -356,7 +365,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_GNOME: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -384,7 +393,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_TROLL: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_3, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -412,14 +421,14 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_BLOODELF: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; case 2: DoScriptText(SAY_EXEC_PROG_1, m_creature, pPlayer); break; case 3: DoScriptText(SAY_EXEC_NAME_1, m_creature, pPlayer); break; case 4: DoScriptText(SAY_EXEC_RECOG_1, m_creature, pPlayer); break; - //case 5: //unknown + // case 5: // unknown case 6: DoScriptText(SAY_EXEC_THINK_3, m_creature, pPlayer); break; case 7: DoScriptText(SAY_EXEC_LISTEN_1, m_creature, pPlayer); break; case 8: @@ -440,7 +449,7 @@ struct MANGOS_DLL_DECL npc_a_special_surpriseAI : public ScriptedAI } break; case RACE_DRAENEI: - switch(m_uiExecuteSpeech_Counter) + switch (m_uiExecuteSpeech_Counter) { case 0: DoScriptText(SAY_EXEC_START_1, m_creature, pPlayer); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_STAND); break; @@ -503,11 +512,27 @@ enum SAY_DUEL_H = -1609023, SAY_DUEL_I = -1609024, + EMOTE_DUEL_BEGIN = -1001137, + EMOTE_DUEL_BEGIN_3 = -1001138, + EMOTE_DUEL_BEGIN_2 = -1001139, + EMOTE_DUEL_BEGIN_1 = -1001140, + + GOSSIP_ITEM_ACCEPT_DUEL = -3609000, + GOSSIP_TEXT_ID_DUEL = 13433, + SPELL_DUEL = 52996, SPELL_DUEL_TRIGGERED = 52990, SPELL_DUEL_VICTORY = 52994, SPELL_DUEL_FLAG = 52991, + // generic DK spells. used in many scripts here + SPELL_BLOOD_STRIKE = 52374, + SPELL_DEATH_COIL = 52375, + SPELL_ICY_TOUCH = 52372, + SPELL_PLAGUE_STRIKE = 52373, + + GO_DUEL_FLAG = 191126, + QUEST_DEATH_CHALLENGE = 12733, FACTION_HOSTILE = 2068 }; @@ -517,82 +542,160 @@ int32 m_auiRandomSay[] = SAY_DUEL_A, SAY_DUEL_B, SAY_DUEL_C, SAY_DUEL_D, SAY_DUEL_E, SAY_DUEL_F, SAY_DUEL_G, SAY_DUEL_H, SAY_DUEL_I }; -#define GOSSIP_ACCEPT_DUEL "I challenge you, death knight!" - -struct MANGOS_DLL_DECL npc_death_knight_initiateAI : public ScriptedAI +struct npc_death_knight_initiateAI : public ScriptedAI { npc_death_knight_initiateAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } ObjectGuid m_duelerGuid; + uint8 m_uiDuelStartStage; uint32 m_uiDuelTimer; - bool m_bIsDuelInProgress; + uint32 m_uiBloodStrikeTimer; + uint32 m_uiDeathCoilTimer; + uint32 m_uiIcyTouchTimer; + uint32 m_uiPlagueStrikeTimer; - void Reset() - { - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); + bool m_bIsDuelComplete; + void Reset() override + { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15); - m_duelerGuid.Clear(); - m_uiDuelTimer = 5000; - m_bIsDuelInProgress = false; + + m_uiDuelStartStage = 0; + m_uiDuelTimer = 0; + m_bIsDuelComplete = false; + + m_uiBloodStrikeTimer = 4000; + m_uiDeathCoilTimer = 6000; + m_uiIcyTouchTimer = 2000; + m_uiPlagueStrikeTimer = 5000; } - void AttackedBy(Unit* pAttacker) + void JustReachedHome() override { - if (m_creature->getVictim()) - return; - - if (m_creature->IsFriendlyTo(pAttacker)) - return; + // reset encounter + if (GameObject* pFlag = GetClosestGameObjectWithEntry(m_creature, GO_DUEL_FLAG, 30.0f)) + pFlag->SetLootState(GO_JUST_DEACTIVATED); - AttackStart(pAttacker); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override { - if (!m_bIsDuelInProgress && pSpell->Id == SPELL_DUEL_TRIGGERED && pCaster->GetTypeId() == TYPEID_PLAYER) + // start duel + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetTypeId() == TYPEID_PLAYER) { - m_duelerGuid = pCaster->GetObjectGuid(); - m_bIsDuelInProgress = true; + m_duelerGuid = pInvoker->GetObjectGuid(); + m_uiDuelStartStage = 0; + m_uiDuelTimer = 5000; } } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (m_bIsDuelInProgress && uiDamage > m_creature->GetHealth()) + if (uiDamage >= m_creature->GetHealth()) { uiDamage = 0; - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_duelerGuid)) - m_creature->CastSpell(pPlayer, SPELL_DUEL_VICTORY, true); + if (!m_bIsDuelComplete) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_duelerGuid)) + { + m_creature->CastSpell(pPlayer, SPELL_DUEL_VICTORY, true); + m_creature->SetFacingToObject(pPlayer); + } + + // complete duel and evade (without home movemnet) + m_bIsDuelComplete = true; + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + + // remove duel flag + if (GameObject* pFlag = GetClosestGameObjectWithEntry(m_creature, GO_DUEL_FLAG, 30.0f)) + pFlag->SetLootState(GO_JUST_DEACTIVATED); - //possibly not evade, but instead have end sequenze - EnterEvadeMode(); + m_creature->HandleEmoteCommand(EMOTE_ONESHOT_BEG); + m_creature->ForcedDespawn(10000); + } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_uiDuelTimer) { - if (m_bIsDuelInProgress) + if (m_uiDuelTimer <= uiDiff) { - if (m_uiDuelTimer < uiDiff) - { - m_creature->setFaction(FACTION_HOSTILE); + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_duelerGuid); + if (!pPlayer) + return; - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_duelerGuid)) + switch (m_uiDuelStartStage) + { + case 0: + DoScriptText(EMOTE_DUEL_BEGIN, m_creature, pPlayer); + m_uiDuelTimer = 1000; + break; + case 1: + DoScriptText(EMOTE_DUEL_BEGIN_3, m_creature, pPlayer); + m_uiDuelTimer = 1000; + break; + case 2: + DoScriptText(EMOTE_DUEL_BEGIN_2, m_creature, pPlayer); + m_uiDuelTimer = 1000; + break; + case 3: + DoScriptText(EMOTE_DUEL_BEGIN_1, m_creature, pPlayer); + m_uiDuelTimer = 1000; + break; + case 4: + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN); AttackStart(pPlayer); + m_uiDuelTimer = 0; + break; } - else - m_uiDuelTimer -= uiDiff; + ++m_uiDuelStartStage; } + else + m_uiDuelTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + + if (m_uiBloodStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLOOD_STRIKE) == CAST_OK) + m_uiBloodStrikeTimer = 9000; + } + else + m_uiBloodStrikeTimer -= uiDiff; + + if (m_uiDeathCoilTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_COIL) == CAST_OK) + m_uiDeathCoilTimer = 8000; + } + else + m_uiDeathCoilTimer -= uiDiff; + + if (m_uiIcyTouchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICY_TOUCH) == CAST_OK) + m_uiIcyTouchTimer = 8000; } + else + m_uiIcyTouchTimer -= uiDiff; - // TODO: spells + if (m_uiPlagueStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE) == CAST_OK) + m_uiPlagueStrikeTimer = 8000; + } + else + m_uiPlagueStrikeTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -607,220 +710,44 @@ bool GossipHello_npc_death_knight_initiate(Player* pPlayer, Creature* pCreature) { if (pPlayer->GetQuestStatus(QUEST_DEATH_CHALLENGE) == QUEST_STATUS_INCOMPLETE) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ACCEPT_DUEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(13433, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ACCEPT_DUEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_DUEL, pCreature->GetObjectGuid()); return true; } return false; } -bool GossipSelect_npc_death_knight_initiate(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_death_knight_initiate(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->CLOSE_GOSSIP_MENU(); - if (npc_death_knight_initiateAI* pInitiateAI = dynamic_cast(pCreature->AI())) - { - if (pInitiateAI->m_bIsDuelInProgress) - return true; - } - + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_15); + pCreature->SetFacingToObject(pPlayer); - int32 uiSayId = rand()% (sizeof(m_auiRandomSay)/sizeof(int32)); - DoScriptText(m_auiRandomSay[uiSayId], pCreature, pPlayer); + DoScriptText(m_auiRandomSay[urand(0, countof(m_auiRandomSay) - 1)], pCreature, pPlayer); - pCreature->CastSpell(pPlayer, SPELL_DUEL, false); + pCreature->CastSpell(pPlayer, SPELL_DUEL, true); pCreature->CastSpell(pPlayer, SPELL_DUEL_FLAG, true); } return true; } -/*###### -## npc_koltira_deathweaver -######*/ - -enum eKoltira -{ - SAY_BREAKOUT1 = -1609079, - SAY_BREAKOUT2 = -1609080, - SAY_BREAKOUT3 = -1609081, - SAY_BREAKOUT4 = -1609082, - SAY_BREAKOUT5 = -1609083, - SAY_BREAKOUT6 = -1609084, - SAY_BREAKOUT7 = -1609085, - SAY_BREAKOUT8 = -1609086, - SAY_BREAKOUT9 = -1609087, - SAY_BREAKOUT10 = -1609088, - - SPELL_KOLTIRA_TRANSFORM = 52899, - SPELL_ANTI_MAGIC_ZONE = 52894, - - QUEST_BREAKOUT = 12727, - - NPC_CRIMSON_ACOLYTE = 29007, - NPC_HIGH_INQUISITOR_VALROTH = 29001, - NPC_KOLTIRA_ALT = 28447, - - //not sure about this id - //NPC_DEATH_KNIGHT_MOUNT = 29201, - MODEL_DEATH_KNIGHT_MOUNT = 25278 -}; - -struct MANGOS_DLL_DECL npc_koltira_deathweaverAI : public npc_escortAI +bool EffectDummyCreature_npc_death_knight_initiate(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - npc_koltira_deathweaverAI(Creature *pCreature) : npc_escortAI(pCreature) { Reset(); } - - uint32 m_uiWave; - uint32 m_uiWave_Timer; - ObjectGuid m_valrothGuid; - - void Reset() + if (uiSpellId == SPELL_DUEL_TRIGGERED && uiEffIndex == EFFECT_INDEX_0) { - if (!HasEscortState(STATE_ESCORT_ESCORTING)) - { - m_uiWave = 0; - m_uiWave_Timer = 3000; - m_valrothGuid.Clear(); - } - } - - void WaypointReached(uint32 uiPointId) - { - switch(uiPointId) - { - case 0: - DoScriptText(SAY_BREAKOUT1, m_creature); - break; - case 1: - m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); - break; - case 2: - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - //m_creature->UpdateEntry(NPC_KOLTIRA_ALT); //unclear if we must update or not - DoCastSpellIfCan(m_creature, SPELL_KOLTIRA_TRANSFORM); - break; - case 3: - SetEscortPaused(true); - m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); - DoScriptText(SAY_BREAKOUT2, m_creature); - DoCastSpellIfCan(m_creature, SPELL_ANTI_MAGIC_ZONE); // cast again that makes bubble up - break; - case 4: - SetRun(true); - break; - case 9: - m_creature->Mount(MODEL_DEATH_KNIGHT_MOUNT); - break; - case 10: - m_creature->Unmount(); - break; - } - } - - void JustSummoned(Creature* pSummoned) - { - if (Player* pPlayer = GetPlayerForEscort()) - pSummoned->AI()->AttackStart(pPlayer); - - if (pSummoned->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH) - m_valrothGuid = pSummoned->GetObjectGuid(); - } - - void SummonAcolyte(uint32 uiAmount) - { - for(uint32 i = 0; i < uiAmount; ++i) - m_creature->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - } - - void UpdateEscortAI(const uint32 uiDiff) - { - if (HasEscortState(STATE_ESCORT_PAUSED)) - { - if (m_uiWave_Timer < uiDiff) - { - switch(m_uiWave) - { - case 0: - DoScriptText(SAY_BREAKOUT3, m_creature); - SummonAcolyte(3); - m_uiWave_Timer = 20000; - break; - case 1: - DoScriptText(SAY_BREAKOUT4, m_creature); - SummonAcolyte(3); - m_uiWave_Timer = 20000; - break; - case 2: - DoScriptText(SAY_BREAKOUT5, m_creature); - SummonAcolyte(4); - m_uiWave_Timer = 20000; - break; - case 3: - DoScriptText(SAY_BREAKOUT6, m_creature); - m_creature->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); - m_uiWave_Timer = 1000; - break; - case 4: - { - Creature* pTemp = m_creature->GetMap()->GetCreature(m_valrothGuid); - - if (!pTemp || !pTemp->isAlive()) - { - DoScriptText(SAY_BREAKOUT8, m_creature); - m_uiWave_Timer = 5000; - } - else - { - m_uiWave_Timer = 2500; - return; //return, we don't want m_uiWave to increment now - } - break; - } - case 5: - DoScriptText(SAY_BREAKOUT9, m_creature); - m_creature->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE); - m_uiWave_Timer = 2500; - break; - case 6: - DoScriptText(SAY_BREAKOUT10, m_creature); - SetEscortPaused(false); - break; - } - - ++m_uiWave; - } - else - m_uiWave_Timer -= uiDiff; - } - - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_START_EVENT, pCaster, pCreatureTarget); + return true; } -}; - -CreatureAI* GetAI_npc_koltira_deathweaver(Creature* pCreature) -{ - return new npc_koltira_deathweaverAI(pCreature); -} - -bool QuestAccept_npc_koltira_deathweaver(Player* pPlayer, Creature* pCreature, const Quest* pQuest) -{ - if (pQuest->GetQuestId() == QUEST_BREAKOUT) - { - pCreature->SetStandState(UNIT_STAND_STATE_STAND); - if (npc_koltira_deathweaverAI* pEscortAI = dynamic_cast(pCreature->AI())) - pEscortAI->Start(false, pPlayer, pQuest); - } - return true; + return false; } /*###### -## +## npc_unworthy_initiate_anchor ######*/ enum @@ -828,17 +755,12 @@ enum SAY_START = -1609000, // 8 texts in total, GetTextId() generates random with this as base SAY_AGGRO = -1609008, // 8 texts in total, GetTextId() generates random with this as base - //SPELL_CHAINED_PESANT_LH = 54602, // not used. possible it determine side, where to go get "weapon" - //SPELL_CHAINED_PESANT_RH = 54610, + // SPELL_CHAINED_PESANT_LH = 54602, // not used. possible it determine side, where to go get "weapon" + // SPELL_CHAINED_PESANT_RH = 54610, SPELL_CHAINED_PESANT_CHEST = 54612, SPELL_CHAINED_PESANT_BREATH = 54613, SPELL_INITIATE_VISUAL = 51519, - SPELL_BLOOD_STRIKE = 52374, - SPELL_DEATH_COIL = 52375, - SPELL_ICY_TOUCH = 52372, - SPELL_PLAGUE_STRIKE = 52373, - NPC_ANCHOR = 29521, FACTION_MONSTER = 16, @@ -847,48 +769,14 @@ enum PHASE_ACTIVATE = 2 }; -struct DisplayToSpell -{ - uint32 m_uiDisplayId; - uint32 m_uiSpellToNewDisplay; -}; - -DisplayToSpell m_aDisplayToSpell[] = -{ - {25354, 51520}, // human M - {25355, 51534}, // human F - {25356, 51538}, // dwarf M - {25357, 51541}, // draenei M - {25358, 51535}, // nelf M - {25359, 51539}, // gnome M - {25360, 51536}, // nelf F - {25361, 51537}, // dwarf F - {25362, 51540}, // gnome F - {25363, 51542}, // draenei F - {25364, 51543}, // orc M - {25365, 51546}, // troll M - {25366, 51547}, // tauren M - {25367, 51549}, // forsaken M - {25368, 51544}, // orc F - {25369, 51552}, // belf F - {25370, 51545}, // troll F - {25371, 51548}, // tauren F - {25372, 51550}, // forsaken F - {25373, 51551} // belf M -}; - -/*###### -## npc_unworthy_initiate_anchor -######*/ - -struct MANGOS_DLL_DECL npc_unworthy_initiate_anchorAI : public ScriptedAI +struct npc_unworthy_initiate_anchorAI : public ScriptedAI { npc_unworthy_initiate_anchorAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } ObjectGuid m_myInitiateGuid; ObjectGuid m_myPrisonGuid; - void Reset() {} + void Reset() override {} void NotifyMe(Unit* pSource, GameObject* pGo) { @@ -898,7 +786,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiate_anchorAI : public ScriptedAI if (pInitiate && pSource) { pInitiate->SetLootRecipient(pSource); - m_creature->CastSpell(pInitiate,SPELL_CHAINED_PESANT_BREATH,true); + m_creature->CastSpell(pInitiate, SPELL_CHAINED_PESANT_BREATH, true); } } @@ -923,32 +811,14 @@ CreatureAI* GetAI_npc_unworthy_initiate_anchor(Creature* pCreature) ## npc_unworthy_initiate ######*/ -struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI +struct npc_unworthy_initiateAI : public ScriptedAI { npc_unworthy_initiateAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pToTransform = NULL; - - uint32 uiDisplayCount = sizeof(m_aDisplayToSpell)/sizeof(DisplayToSpell); - - for (uint8 i=0; iGetDisplayId()) - { - m_pToTransform = &m_aDisplayToSpell[i]; - break; - } - } - - m_uiNormFaction = pCreature->getFaction(); Reset(); } - DisplayToSpell* m_pToTransform; - ObjectGuid m_myAnchorGuid; - uint32 m_uiNormFaction; uint32 m_uiAnchorCheckTimer; uint32 m_uiPhase; uint32 m_uiPhaseTimer; @@ -957,11 +827,8 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI uint32 m_uiIcyTouch_Timer; uint32 m_uiPlagueStrike_Timer; - void Reset() + void Reset() override { - if (m_creature->getFaction() != m_uiNormFaction) - m_creature->setFaction(m_uiNormFaction); - m_uiAnchorCheckTimer = 5000; m_uiPhase = PHASE_INACTIVE_OR_COMBAT; m_uiPhaseTimer = 7500; @@ -971,7 +838,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI m_uiPlagueStrike_Timer = 5000; } - void JustReachedHome() + void JustReachedHome() override { SetAnchor(); @@ -982,7 +849,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI } } - void JustRespawned() + void JustRespawned() override { if (Creature* pAnchor = GetAnchor()) { @@ -995,7 +862,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI int32 GetTextId() { - return m_uiPhase == PHASE_DRESSUP ? SAY_START-rand()%8 : SAY_AGGRO-rand()%8; + return m_uiPhase == PHASE_DRESSUP ? SAY_START - urand(0, 7) : SAY_AGGRO - urand(0, 7); } Creature* GetAnchor() @@ -1003,7 +870,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if (m_myAnchorGuid) return m_creature->GetMap()->GetCreature(m_myAnchorGuid); else - return GetClosestCreatureWithEntry(m_creature, NPC_ANCHOR, INTERACTION_DISTANCE*2); + return GetClosestCreatureWithEntry(m_creature, NPC_ANCHOR, INTERACTION_DISTANCE * 2); } void SetAnchor() @@ -1023,7 +890,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI m_uiAnchorCheckTimer = 5000; } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_CHAINED_PESANT_BREATH) { @@ -1037,7 +904,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiAnchorCheckTimer) { @@ -1054,7 +921,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if (m_uiBloodStrike_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BLOOD_STRIKE); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLOOD_STRIKE); m_uiBloodStrike_Timer = 9000; } else @@ -1062,7 +929,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if (m_uiDeathCoil_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_DEATH_COIL); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_COIL); m_uiDeathCoil_Timer = 8000; } else @@ -1070,7 +937,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if (m_uiIcyTouch_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ICY_TOUCH); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICY_TOUCH); m_uiIcyTouch_Timer = 8000; } else @@ -1078,7 +945,7 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI if (m_uiPlagueStrike_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_PLAGUE_STRIKE); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE); m_uiPlagueStrike_Timer = 8000; } else @@ -1092,19 +959,13 @@ struct MANGOS_DLL_DECL npc_unworthy_initiateAI : public ScriptedAI { if (m_uiPhase == PHASE_DRESSUP) { - if (m_pToTransform) - { - m_creature->CastSpell(m_creature, m_pToTransform->m_uiSpellToNewDisplay, true); - m_creature->CastSpell(m_creature, SPELL_INITIATE_VISUAL, false); - } - else - error_log("SD2: npc_unworthy_initiate does not have any spell associated with model"); + m_creature->CastSpell(m_creature, SPELL_INITIATE_VISUAL, false); m_uiPhase = PHASE_ACTIVATE; } else { - m_creature->setFaction(FACTION_MONSTER); + m_creature->SetFactionTemporary(FACTION_MONSTER, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN); m_uiPhase = PHASE_INACTIVE_OR_COMBAT; @@ -1143,40 +1004,2018 @@ bool GOUse_go_acherus_soul_prison(Player* pPlayer, GameObject* pGo) return false; } -void AddSC_ebon_hold() +/*###### +## npc_eye_of_acherus +######*/ + +enum { - Script* pNewScript; + SPELL_EYE_CONTROL = 51852, // player control aura + SPELL_EYE_VISUAL = 51892, + SPELL_EYE_FLIGHT = 51890, // player flight control + SPELL_EYE_FLIGHT_BOOST = 51923, // flight boost to reach new avalon - pNewScript = new Script; - pNewScript->Name = "npc_a_special_surprise"; - pNewScript->GetAI = &GetAI_npc_a_special_surprise; - pNewScript->RegisterSelf(); + EMOTE_DESTIANTION = -1609089, + EMOTE_CONTROL = -1609090, - pNewScript = new Script; - pNewScript->Name = "npc_death_knight_initiate"; - pNewScript->GetAI = &GetAI_npc_death_knight_initiate; - pNewScript->pGossipHello = &GossipHello_npc_death_knight_initiate; - pNewScript->pGossipSelect = &GossipSelect_npc_death_knight_initiate; - pNewScript->RegisterSelf(); + POINT_EYE_DESTINATION = 0 +}; - pNewScript = new Script; - pNewScript->Name = "npc_koltira_deathweaver"; - pNewScript->GetAI = &GetAI_npc_koltira_deathweaver; - pNewScript->pQuestAcceptNPC = &QuestAccept_npc_koltira_deathweaver; - pNewScript->RegisterSelf(); +// movement destination coords +static const float aEyeDestination[3] = {1750.8276f, -5873.788f, 147.2266f}; - pNewScript = new Script; - pNewScript->Name = "npc_unworthy_initiate"; - pNewScript->GetAI = &GetAI_npc_unworthy_initiate; - pNewScript->RegisterSelf(); +struct npc_eye_of_acherusAI : public ScriptedAI +{ + npc_eye_of_acherusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsInitialized = false; + m_creature->SetPhaseMask(3, true); // HACK as mangos cannot handle auras proberly, also HACK below + Reset(); + } - pNewScript = new Script; - pNewScript->Name = "npc_unworthy_initiate_anchor"; - pNewScript->GetAI = &GetAI_npc_unworthy_initiate_anchor; - pNewScript->RegisterSelf(); + bool m_bIsInitialized; - pNewScript = new Script; - pNewScript->Name = "go_acherus_soul_prison"; - pNewScript->pGOUse = &GOUse_go_acherus_soul_prison; + void Reset() override {} + + void JustDied(Unit* /*pKiller*/) override + { + m_creature->CastSpell(m_creature, 52694, true); // HACK - Remove this when mangos supports proper spell casting + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || uiPointId != POINT_EYE_DESTINATION) + return; + + if (Player* pPlayer = m_creature->GetCharmerOrOwnerPlayerOrPlayerItself()) + DoScriptText(EMOTE_CONTROL, m_creature, pPlayer); + + DoCastSpellIfCan(m_creature, SPELL_EYE_FLIGHT, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override {} + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (m_bIsInitialized) + return; + + if (Player* pPlayer = m_creature->GetCharmerOrOwnerPlayerOrPlayerItself()) + { + m_creature->SetDisplayId(26320); // HACK remove when correct modelid will be taken by core + m_creature->SetPhaseMask(2, true); // HACK remove when summon spells and auras are implemented properly in mangos + + DoScriptText(EMOTE_DESTIANTION, m_creature, pPlayer); + + DoCastSpellIfCan(m_creature, SPELL_EYE_VISUAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_EYE_FLIGHT_BOOST, CAST_TRIGGERED); + // Update Speed for Eye + m_creature->UpdateSpeed(MOVE_FLIGHT, true, pPlayer->GetSpeed(MOVE_FLIGHT)); + + //m_creature->RemoveSplineFlag(SPLINEFLAG_WALKMODE); + m_creature->GetMotionMaster()->MovePoint(POINT_EYE_DESTINATION, aEyeDestination[0], aEyeDestination[1], aEyeDestination[2]); + + m_bIsInitialized = true; + } + else + m_creature->ForcedDespawn(); + } +}; + +CreatureAI* GetAI_npc_eye_of_acherus(Creature* pCreature) +{ + return new npc_eye_of_acherusAI(pCreature); +} + +/*###### +## npc_scarlet_ghoul +######*/ + +enum +{ + SAY_GHUL_SPAWN_1 = -1609091, + SAY_GHUL_SPAWN_2 = -1609092, + SAY_GHUL_SPAWN_3 = -1609093, + SAY_GHUL_SPAWN_4 = -1609094, + SAY_GHUL_SPAWN_5 = -1609095, + SAY_GOTHIK_THROW_IN_PIT = -1609096, // TODO: Unclear if there exist more texts + + SPELL_GHOUL_SUMMONED = 52500, + SPELL_GOTHIK_GHOUL_PING = 52514, + SPELL_QUEST_CREDIT = 52517, + SPELL_GHOUL_UNSUMMON = 52555, + + NPC_GOTHIK = 28658, +}; + +static const float aPitPosition[3] = {2380.13f, -5783.06f, 151.367f}; + +struct npc_scarlet_ghoulAI : public ScriptedPetAI +{ + npc_scarlet_ghoulAI(Creature* pCreature) : ScriptedPetAI(pCreature) + { + m_bGotHit = false; + m_bIsJumping = false; + m_bDidInitText = false; + m_uiUnsummonTimer = 0; + DoCastSpellIfCan(m_creature, SPELL_GHOUL_SUMMONED); + + if (m_creature->GetCharmInfo()) + m_creature->GetCharmInfo()->SetReactState(REACT_DEFENSIVE); + + Reset(); + } + + bool m_bGotHit; + bool m_bIsJumping; + bool m_bDidInitText; + uint32 m_uiUnsummonTimer; + + void Reset() override {} + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType == EFFECT_MOTION_TYPE && uiPointId == 1) + { + m_uiUnsummonTimer = 1000; + DoCastSpellIfCan(m_creature, SPELL_GHOUL_UNSUMMON); + m_creature->GetMotionMaster()->MoveIdle(); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_GHOUL_UNSUMMON, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bDidInitText) + { + Unit* pOwner = m_creature->GetCharmerOrOwner(); + DoScriptText(SAY_GHUL_SPAWN_1 - urand(0, 4), m_creature, pOwner); + + m_bDidInitText = true; + } + + if (m_uiUnsummonTimer) + { + if (m_uiUnsummonTimer <= uiDiff) + { + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (m_creature->IsPet()) + ((Pet*)m_creature)->Unsummon(PET_SAVE_AS_DELETED); + return; + } + else + m_uiUnsummonTimer -= uiDiff; + } + + if (m_bIsJumping) + return; + + ScriptedPetAI::UpdateAI(uiDiff); + } +}; + +bool EffectDummyCreature_npc_scarlet_ghoul(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_GOTHIK_GHOUL_PING && uiEffIndex == EFFECT_INDEX_0) + { + if (npc_scarlet_ghoulAI* pGhoulAi = dynamic_cast(pCreatureTarget->AI())) + { + if (!pGhoulAi->m_bGotHit) // First hit + { + pCreatureTarget->CastSpell(pCreatureTarget, 52517, false); + pGhoulAi->m_bGotHit = true; + } + else // Second hit + { + world_map_ebon_hold* pInstance = static_cast(pCreatureTarget->GetInstanceData()); + if (pCaster && pInstance && pInstance->CanAndToggleGothikYell()) + DoScriptText(SAY_GOTHIK_THROW_IN_PIT, pCaster); + + float fX, fY, fZ; + pCreatureTarget->GetRandomPoint(aPitPosition[0], aPitPosition[1], aPitPosition[2], 10.0f, fX, fY, fZ); + pGhoulAi->m_bIsJumping = true; + pCreatureTarget->GetMotionMaster()->MoveJump(fX, fY, fZ, 24.21229f, 6.0f, 1); + } + } + return true; + } + + return false; +} + +CreatureAI* GetAI_npc_scarlet_ghoul(Creature* pCreature) +{ + return new npc_scarlet_ghoulAI(pCreature); +} + +/*###### +## npc_highlord_darion_mograine +######*/ + +enum LightOfDawn +{ + // yells + SAY_LIGHT_OF_DAWN_INTRO_1 = -1609201, // Highlord Darion Mograine + SAY_LIGHT_OF_DAWN_INTRO_2 = -1609202, + + SAY_LIGHT_OF_DAWN_PREPARE_1 = -1609203, + SAY_LIGHT_OF_DAWN_PREPARE_2 = -1609204, + SAY_LIGHT_OF_DAWN_PREPARE_3 = -1609205, + SAY_LIGHT_OF_DAWN_PREPARE_4 = -1609206, + + SAY_LIGHT_OF_DAWN_STAND_1 = -1609207, // Korfax + SAY_LIGHT_OF_DAWN_STAND_2 = -1609208, // Lord Maxwell Tyrosus + + SAY_LIGHT_OF_DAWN_BATTLE_1 = -1609209, // Highlord Darion Mograine + SAY_LIGHT_OF_DAWN_BATTLE_2 = -1609210, + SAY_LIGHT_OF_DAWN_BATTLE_3 = -1609211, + SAY_LIGHT_OF_DAWN_BATTLE_4 = -1609212, + SAY_LIGHT_OF_DAWN_BATTLE_5 = -1609213, + SAY_LIGHT_OF_DAWN_BATTLE_6 = -1609214, + SAY_LIGHT_OF_DAWN_BATTLE_7 = -1609215, + SAY_LIGHT_OF_DAWN_BATTLE_8 = -1609216, + SAY_LIGHT_OF_DAWN_BATTLE_9 = -1609224, + + SAY_LIGHT_OF_DAWN_BATTLE_10 = -1609217, // Battle end yells + SAY_LIGHT_OF_DAWN_BATTLE_11 = -1609218, + SAY_LIGHT_OF_DAWN_BATTLE_12 = -1609219, + SAY_LIGHT_OF_DAWN_BATTLE_13 = -1609220, + SAY_LIGHT_OF_DAWN_BATTLE_14 = -1609221, + SAY_LIGHT_OF_DAWN_BATTLE_15 = -1609222, + SAY_LIGHT_OF_DAWN_BATTLE_16 = -1609223, + + SAY_LIGHT_OF_DAWN_OUTRO_1 = -1609225, // Highlord Tirion Fordring + SAY_LIGHT_OF_DAWN_OUTRO_2 = -1609226, + SAY_LIGHT_OF_DAWN_OUTRO_3 = -1609227, // Highlord Darion Mograine + SAY_LIGHT_OF_DAWN_OUTRO_4 = -1609228, // Highlord Tirion Fordring + SAY_LIGHT_OF_DAWN_OUTRO_5 = -1609229, + SAY_LIGHT_OF_DAWN_OUTRO_6 = -1609230, + SAY_LIGHT_OF_DAWN_OUTRO_7 = -1609231, // Highlord Darion Mograine + + SAY_LIGHT_OF_DAWN_VISION_1 = -1609232, // Highlord Alexandros Mograine + SAY_LIGHT_OF_DAWN_VISION_2 = -1609233, // Highlord Darion Mograine + SAY_LIGHT_OF_DAWN_VISION_3 = -1609234, + SAY_LIGHT_OF_DAWN_VISION_4 = -1609235, // Darion Mograine + SAY_LIGHT_OF_DAWN_VISION_5 = -1609236, + SAY_LIGHT_OF_DAWN_VISION_6 = -1609237, // Highlord Alexandros Mograine + SAY_LIGHT_OF_DAWN_VISION_7 = -1609238, // Darion Mograine + SAY_LIGHT_OF_DAWN_VISION_8 = -1609239, // Highlord Alexandros Mograine + SAY_LIGHT_OF_DAWN_VISION_9 = -1609240, // Darion Mograine + SAY_LIGHT_OF_DAWN_VISION_10 = -1609241, // Highlord Alexandros Mograine + SAY_LIGHT_OF_DAWN_VISION_11 = -1609242, + + SAY_LIGHT_OF_DAWN_KING_VISIT_1 = -1609243, // The Lich King + SAY_LIGHT_OF_DAWN_KING_VISIT_2 = -1609245, + SAY_LIGHT_OF_DAWN_KING_VISIT_3 = -1609244, // Highlord Darion Mograine + SAY_LIGHT_OF_DAWN_KING_VISIT_4 = -1609246, // The Lich King + SAY_LIGHT_OF_DAWN_KING_VISIT_5 = -1609247, // Highlord Tirion Fordring + SAY_LIGHT_OF_DAWN_KING_VISIT_6 = -1609248, // The Lich King + SAY_LIGHT_OF_DAWN_KING_VISIT_7 = -1609249, + SAY_LIGHT_OF_DAWN_KING_VISIT_8 = -1609250, // Lord Maxwell Tyrosus + SAY_LIGHT_OF_DAWN_KING_VISIT_9 = -1609251, // The Lich King + SAY_LIGHT_OF_DAWN_KING_VISIT_10 = -1609252, // Highlord Darion Mograine + SAY_LIGHT_OF_DAWN_KING_VISIT_11 = -1609253, + SAY_LIGHT_OF_DAWN_KING_VISIT_12 = -1609254, // Highlord Tirion Fordring + SAY_LIGHT_OF_DAWN_KING_VISIT_13 = -1609255, // The Lich King + SAY_LIGHT_OF_DAWN_KING_VISIT_14 = -1609256, // Highlord Tirion Fordring + SAY_LIGHT_OF_DAWN_KING_VISIT_15 = -1609257, // The Lich King + SAY_LIGHT_OF_DAWN_KING_VISIT_16 = -1609258, + SAY_LIGHT_OF_DAWN_KING_VISIT_17 = -1609259, + + SAY_LIGHT_OF_DAWN_EPILOGUE_1 = -1609260, // Highlord Tirion Fordring + SAY_LIGHT_OF_DAWN_EPILOGUE_2 = -1609261, + SAY_LIGHT_OF_DAWN_EPILOGUE_3 = -1609262, + SAY_LIGHT_OF_DAWN_EPILOGUE_4 = -1609263, + SAY_LIGHT_OF_DAWN_EPILOGUE_5 = -1609264, + SAY_LIGHT_OF_DAWN_EPILOGUE_6 = -1609265, + SAY_LIGHT_OF_DAWN_EPILOGUE_7 = -1609266, + SAY_LIGHT_OF_DAWN_EPILOGUE_8 = -1609267, + SAY_LIGHT_OF_DAWN_EPILOGUE_9 = -1609268, // Highlord Darion Mograine + + // Emotes + EMOTE_LIGHT_OF_DAWN_ARMY_RISE = -1609269, // Emotes + EMOTE_LIGHT_OF_DAWN_ARMY_MARCH = -1609270, + EMOTE_LIGHT_OF_DAWN_TIRION = -1609271, + EMOTE_LIGHT_OF_DAWN_FLEE = -1609272, + EMOTE_LIGHT_OF_DAWN_KNEEL = -1609273, + EMOTE_LIGHT_OF_DAWN_ALEXANDROS = -1609274, + EMOTE_LIGHT_OF_DAWN_SHADE = -1609275, + EMOTE_LIGHT_OF_DAWN_HUG = -1609276, + EMOTE_LIGHT_OF_DAWN_LICH_KING = -1609277, + EMOTE_LIGHT_OF_DAWN_ANGRY = -1609278, + EMOTE_LIGHT_OF_DAWN_CAST_SPELL = -1609279, + EMOTE_LIGHT_OF_DAWN_GRASP = -1609280, + EMOTE_LIGHT_OF_DAWN_POWERFULL = -1609281, + EMOTE_LIGHT_OF_DAWN_ASHBRINGER = -1609282, + EMOTE_LIGHT_OF_DAWN_COLAPSE = -1609283, + EMOTE_LIGHT_OF_DAWN_CHARGE = -1609284, + EMOTE_LIGHT_OF_DAWN_KING_LEAVE = -1609285, + EMOTE_LIGHT_OF_DAWN_LIGHT = -1609286, + + // Spells + // Highlord Darion Mograine + SPELL_HERO_AGGRO_AURA = 53627, + SPELL_SCOURGE_AGGRO_AURA = 53624, + SPELL_ANTI_MAGIC_ZONE_DARION = 52893, + SPELL_DEATH_STRIKE = 53639, + SPELL_DEATH_EMBRACE = 53635, + SPELL_ICY_TOUCH_DARION = 49723, + SPELL_PLAGUE_STRIKE_KNIGHTS = 50688, + SPELL_THE_MIGHT_OF_MOGRAINE = 53642, // on players when battle begins + SPELL_UNHOLY_BLIGHT = 53640, + + SPELL_BIRTH = 53603, // ground shake + SPELL_THE_LIGHT_OF_DAWN_DUMMY = 53658, // light globe + SPELL_THE_LIGHT_OF_DAWN_DAMAGE_LOSS = 53645, // cast by the scourge units + SPELL_ALEXANDROS_MOGRAINE_SPAWN = 53667, // spawn effect for Alexandros + SPELL_MOGRAINE_CHARGE = 53679, // charge to the Lich King + SPELL_ASHBRINGER = 53701, // throw Ashbringer to Tirion + SPELL_THE_LIGHT_OF_DAWN_CREDIT = 53606, // quest credit + + // Lich King spells + SPELL_APOCALYPSE = 53210, // knocks back all enemies + SPELL_APOCALYPSE_STUN = 53745, // stuns all enemies + SPELL_POST_APOCALYPSE = 53211, // after apocalypse - not sure where to use it + SPELL_TELEPORT_VISUAL = 52233, // on leave + SPELL_SOUL_FEAST_ALEX = 53677, // on Alexandros + SPELL_SOUL_FEAST_TIRION = 53685, // on Tirion + SPELL_ICEBOUND_VISAGE = 53274, // ice effect + SPELL_REBUKE = 53680, // knockback + + // Highlord Tirion Fordring + //EQUIP_HIGHLORD_TIRION_FORDRING = 13262, + SPELL_LAY_ON_HANDS = 53778, // heal effect + SPELL_REBIRTH_OF_THE_ASHBRINGER = 53702, // globe sphere + SPELL_TIRION_CHARGE = 53705, // on the lich king + + POINT_MOVE_CHAPEL = 100, // Use high entries to not conflict with escortAI waypoints + POINT_MOVE_OTHER = 101, + POINT_MOVE_RETURN_BATTLE = 102, + + // others + QUEST_ID_LIGHT_OF_DAWN = 12801, + + GOSSIP_ITEM_READY = -3609001, + GOSSIP_TEXT_ID_READY = 13485, +}; + +struct npc_highlord_darion_mograineAI : public npc_escortAI +{ + npc_highlord_darion_mograineAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (world_map_ebon_hold*)pCreature->GetInstanceData(); + Reset(); + } + + world_map_ebon_hold* m_pInstance; + + // event timers + uint8 m_uiIntroYell; + uint32 m_uiPrepareTimer; + + uint32 m_uiEventStep; + uint32 m_uiEventTimer; + uint32 m_uiFightTimer; + + bool m_bIsBattleEnd; + + uint8 m_uiLightWarriorsDead; + uint8 m_uiScourgeWarriorsDead; + + // spell timers + uint32 m_uiAntimagicZoneTimer; + uint32 m_uiDeathStrikeTimer; + uint32 m_uiDeathEmbraceTimer; + uint32 m_uiIcyTouchTimer; + uint32 m_uiUnholyBlightTimer; + uint32 m_uiFightSpeechTimer; + + uint32 m_uiSpawncheck; + uint32 m_uiTargetcheck; + + // others + GuidList m_lDefendersGUIDs; // light of dawn defenders + GuidList m_lAttackersGUIDs; // scourge attackers + + void Reset() override + { + // reset only when event is not in progress + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiIntroYell = 0; + m_uiPrepareTimer = 5 * MINUTE * IN_MILLISECONDS; + + m_uiEventStep = 0; + m_uiEventTimer = 3000; + m_uiFightTimer = 0; + + m_bIsBattleEnd = false; + + m_uiLightWarriorsDead = 0; + m_uiScourgeWarriorsDead = 0; + + m_uiAntimagicZoneTimer = urand(1000, 5000); + m_uiDeathStrikeTimer = urand(5000, 10000); + m_uiDeathEmbraceTimer = urand(5000, 10000); + m_uiIcyTouchTimer = urand(5000, 10000); + m_uiUnholyBlightTimer = urand(5000, 10000); + m_uiFightSpeechTimer = 15000; + } + } + + void GetAIInformation(ChatHandler& reader) override + { + npc_escortAI::GetAIInformation(reader); + + if (m_pInstance) + reader.PSendSysMessage("Current state for TYPE_BATTLE: %u", m_pInstance->GetData(TYPE_BATTLE)); + + reader.PSendSysMessage("Current Event step: %u (%s)", m_uiEventStep, m_uiEventStep == 0 ? "Not-Started" : m_uiEventStep < 7 ? "Intro" : m_uiEventStep < 10 ? "Battle" : "Outro"); + reader.PSendSysMessage("Event-processing is %s, Fighting is %s", reader.GetOnOffStr(m_uiEventTimer), reader.GetOnOffStr(m_uiFightTimer)); + } + + void Aggro(Unit* /*pWho*/) override + { + // cast aggro aura + DoCastSpellIfCan(m_creature, SPELL_HERO_AGGRO_AURA); + } + + void JustSummoned(Creature* pSummoned) override + { + // store summoned guid for easy handle + switch (pSummoned->GetEntry()) + { + case NPC_VOLATILE_GHOUL: + pSummoned->CastSpell(pSummoned, SPELL_BIRTH, true); + // no break; + case NPC_WARRIOR_OF_THE_FROZEN_WASTES: + m_lAttackersGUIDs.push_back(pSummoned->GetObjectGuid()); + // make the scourge attack only during the battle + if (m_creature->isInCombat()) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + break; + case NPC_DEFENDER_OF_THE_LIGHT: + m_lDefendersGUIDs.push_back(pSummoned->GetObjectGuid()); + break; + } + + // set respawn delay + pSummoned->SetRespawnDelay(DAY); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // if battle has ended return + if (m_pInstance->GetData(TYPE_BATTLE) != IN_PROGRESS) + return; + + // should we count the 2 behemots and 5 abominations as well? + switch (pSummoned->GetEntry()) + { + case NPC_VOLATILE_GHOUL: + case NPC_WARRIOR_OF_THE_FROZEN_WASTES: + ++m_uiScourgeWarriorsDead; + m_lAttackersGUIDs.remove(pSummoned->GetObjectGuid()); + + if (m_pInstance) + m_pInstance->DoUpdateBattleWorldState(WORLD_STATE_FORCES_SCOURGE, MAX_FORCES_SCOURGE - m_uiScourgeWarriorsDead); + + // if 5 soldiers are dead summon others + if (m_uiScourgeWarriorsDead % MAX_WARRIORS_SUMMONED_PER_TURN == 0) + { + float fX, fY, fZ; + // Actually this is some sort of cheat - but so many scourge numbers fall (currently), that I think it is ok to increase the summon amount + for (uint8 i = 0; i < MAX_WARRIORS_SUMMONED_PER_TURN + 1; ++i) + { + uint32 uiSummonEntry = urand(0, 1) ? NPC_VOLATILE_GHOUL : NPC_WARRIOR_OF_THE_FROZEN_WASTES; + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + m_creature->SummonCreature(uiSummonEntry, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 5000); + } + } + break; + case NPC_DEFENDER_OF_THE_LIGHT: + ++m_uiLightWarriorsDead; + m_lDefendersGUIDs.remove(pSummoned->GetObjectGuid()); + + if (m_pInstance) + m_pInstance->DoUpdateBattleWorldState(WORLD_STATE_FORCES_LIGHT, MAX_FORCES_LIGHT - m_uiLightWarriorsDead); + + // if 5 light soldiers are dead summon others + if (m_uiLightWarriorsDead % MAX_WARRIORS_SUMMONED_PER_TURN == 0) + { + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_WARRIORS_SUMMONED_PER_TURN; i++) + { + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_DEFENDER_OF_THE_LIGHT, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 5000); + } + } + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || uiPointId != POINT_MOVE_CHAPEL) + return; + + if (!m_pInstance) + return; + + switch (pSummoned->GetEntry()) + { + // hug father + case NPC_DARION_MOGRAINE: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + DoScriptText(EMOTE_LIGHT_OF_DAWN_HUG, pSummoned, pAlexandros); + break; + case NPC_HIGHLORD_TIRION_FORDRING: + // tirions stops the battle and brings the DK in front of the chapel + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_2, pSummoned); + m_pInstance->SetData(TYPE_BATTLE, DONE); + + // scourge fighters die, if not already dead + for (GuidList::const_iterator itr = m_lAttackersGUIDs.begin(); itr != m_lAttackersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + + // light fighters despawn + for (GuidList::const_iterator itr = m_lDefendersGUIDs.begin(); itr != m_lDefendersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->ForcedDespawn(); + } + + // despawn big units + m_pInstance->DoDespawnArmy(); + + // facing and mount + pSummoned->Unmount(); + pSummoned->SetFacingTo(aEventLocations[1].m_fO); + + m_creature->Unmount(); + m_bIsBattleEnd = false; + + if (!HasEscortState(STATE_ESCORT_PAUSED)) + { + SetEscortPaused(true); // In case something didn't go as expected + SetCurrentWaypoint(5); + m_uiEventTimer = 60000; // Another failsafe + } + + SetEscortPaused(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + SetRun(false); + m_creature->AI()->EnterEvadeMode(); + + DoCastSpellIfCan(m_creature, SPELL_THE_LIGHT_OF_DAWN_DUMMY); + + // death knights are defeated + if (Creature* pKoltira = m_pInstance->GetSingleCreatureFromStorage(NPC_KOLTIRA_DEATHWEAVER)) + pKoltira->AI()->EnterEvadeMode(); + if (Creature* pThassarian = m_pInstance->GetSingleCreatureFromStorage(NPC_THASSARIAN)) + pThassarian->AI()->EnterEvadeMode(); + // Orbaz flees -> despawn + if (Creature* pOrbaz = m_pInstance->GetSingleCreatureFromStorage(NPC_ORBAZ_BLOODBANE)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_FLEE, pOrbaz); + pOrbaz->AI()->EnterEvadeMode(); + pOrbaz->ForcedDespawn(30000); + } + + // ligth champs evade to their summon points + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[i].m_uiEntry)) + { + // normally it shouldn't happen + if (!pTemp->isAlive()) + pTemp->Respawn(); + else + pTemp->AI()->EnterEvadeMode(); + + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + } + } + + // clear defenders list + m_lDefendersGUIDs.clear(); + + // spawn soldiers + for (uint8 i = 0; i < MAX_LIGHT_GUARDS; ++i) + { + if (Creature* pGuard = m_creature->SummonCreature(NPC_DEFENDER_OF_THE_LIGHT, aGuardsSpawnLoc[i].m_fX, aGuardsSpawnLoc[i].m_fY, aGuardsSpawnLoc[i].m_fZ, aGuardsSpawnLoc[i].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + // make guard passive and with weapon + pGuard->SetFacingToObject(m_creature); + // should be 2 handed when the DB data is correct + pGuard->HandleEmoteCommand(EMOTE_STATE_READY2H); + pGuard->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pGuard->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + + break; + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) + { + if (uiPointId < POINT_MOVE_CHAPEL || uiPointId > 10 * POINT_MOVE_RETURN_BATTLE) + { + npc_escortAI::MovementInform(uiMotionType, uiPointId); + return; + } + + if (uiMotionType == POINT_MOTION_TYPE && uiPointId == POINT_MOVE_RETURN_BATTLE) + { + SetCombatMovement(false); + DoStartMovement(m_creature->getVictim()); + } + } + + void JustRespawned() override + { + m_creature->SetActiveObjectState(false); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BATTLE, NOT_STARTED); + + npc_escortAI::JustRespawned(); + } + + void WaypointReached(uint32 uiPoint) override + { + if (!m_pInstance) + return; + + switch (uiPoint) + { + case 0: + // summon light champions + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + m_creature->SummonCreature(aLightArmySpawnLoc[i].m_uiEntry, aLightArmySpawnLoc[i].m_fX, aLightArmySpawnLoc[i].m_fY, aLightArmySpawnLoc[i].m_fZ, aLightArmySpawnLoc[i].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS); + + // summon light soldiers + float fX, fY, fZ; + for (uint8 i = 0; i < 5 * MAX_WARRIORS_SUMMONED_PER_TURN; ++i) + { + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_DEFENDER_OF_THE_LIGHT, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 5000); + } + break; + case 2: + // yell dawn 1 + if (Creature* pKorfax = m_pInstance->GetSingleCreatureFromStorage(NPC_KORFAX_CHAMPION_OF_THE_LIGHT)) + DoScriptText(SAY_LIGHT_OF_DAWN_STAND_1, pKorfax); + break; + case 3: + // yell dawn 2 + if (Creature* pMaxwell = m_pInstance->GetSingleCreatureFromStorage(NPC_LORD_MAXWELL_TYROSUS)) + DoScriptText(SAY_LIGHT_OF_DAWN_STAND_2, pMaxwell); + + DoCastSpellIfCan(m_creature, SPELL_THE_MIGHT_OF_MOGRAINE); + // max fight timer + m_uiFightTimer = 5 * MINUTE * IN_MILLISECONDS; + break; + case 4: + // start the battle + SetEscortPaused(true); + + // start attacking someone + if (Creature* pChamp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[urand(0, MAX_LIGHT_CHAMPIONS - 1)].m_uiEntry)) + m_creature->AI()->AttackStart(pChamp); + + // make army attack + for (GuidList::const_iterator itr = m_lAttackersGUIDs.begin(); itr != m_lAttackersGUIDs.end(); ++itr) + { + Creature* pAttacker = m_creature->GetMap()->GetCreature(*itr); + Creature* pChamp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[urand(0, MAX_LIGHT_CHAMPIONS - 1)].m_uiEntry); + if (pAttacker && pChamp) + pAttacker->AI()->AttackStart(pChamp); + } + + // need to make sure that all defenders attack + for (GuidList::const_iterator itr = m_lDefendersGUIDs.begin(); itr != m_lDefendersGUIDs.end(); ++itr) + { + if (Creature* pDefender = m_creature->GetMap()->GetCreature(*itr)) + pDefender->AI()->AttackStart(m_creature); + } + break; + case 5: + // battle finished - remove light of dawn aura + DoScriptText(EMOTE_LIGHT_OF_DAWN_KNEEL, m_creature); + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_3, m_creature); + + if (m_creature->HasAura(SPELL_THE_LIGHT_OF_DAWN_DUMMY)) + m_creature->RemoveAurasDueToSpell(SPELL_THE_LIGHT_OF_DAWN_DUMMY); + + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + m_creature->SetFacingToObject(pTirion); + + // update guards facing + for (GuidList::const_iterator itr = m_lDefendersGUIDs.begin(); itr != m_lDefendersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->SetFacingToObject(m_creature); + } + + // escort paused and start cinematic + m_uiEventTimer = 10000; + SetEscortPaused(true); + break; + } + } + + // override evade function to always check for targets while in battle + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + // if evade while the battle is in progress start attacking another target + if (m_pInstance->GetData(TYPE_BATTLE) == IN_PROGRESS) + { + // attack random champion + if (Creature* pChamp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[urand(0, MAX_LIGHT_CHAMPIONS - 1)].m_uiEntry)) + m_creature->AI()->AttackStart(pChamp); + } + else + npc_escortAI::EnterEvadeMode(); + } + + void DoSendQuestCredit() + { + Map::PlayerList const& PlayerList = m_creature->GetMap()->GetPlayers(); + + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + { + Player* pPlayer = itr->getSource(); + if (pPlayer && pPlayer->GetQuestStatus(QUEST_ID_LIGHT_OF_DAWN) == QUEST_STATUS_INCOMPLETE && pPlayer->isAlive() && m_creature->IsWithinDistInMap(pPlayer, 50.0f)) + pPlayer->CastSpell(pPlayer, SPELL_THE_LIGHT_OF_DAWN_CREDIT, true); + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (m_pInstance->GetData(TYPE_BATTLE) == SPECIAL) + { + // intro event and battle timer + if (m_uiIntroYell == 0 && m_uiPrepareTimer < 3 * MINUTE * IN_MILLISECONDS) + { + DoScriptText(SAY_LIGHT_OF_DAWN_INTRO_1, m_creature); + ++m_uiIntroYell; + } + else if (m_uiIntroYell == 1 && m_uiPrepareTimer < 2 * MINUTE * IN_MILLISECONDS) + { + DoScriptText(SAY_LIGHT_OF_DAWN_INTRO_2, m_creature); + ++m_uiIntroYell; + } + + // battle prepare timer + if (m_uiPrepareTimer < uiDiff) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BATTLE, IN_PROGRESS); + } + else + { + m_uiPrepareTimer -= uiDiff; + + if (m_uiPrepareTimer / IN_MILLISECONDS % 60 == 0) + { + if (m_pInstance) + m_pInstance->DoUpdateBattleWorldState(WORLD_STATE_BATTLE_TIMER_TIME, m_uiPrepareTimer / (MINUTE * IN_MILLISECONDS)); + } + } + } + else if (m_pInstance->GetData(TYPE_BATTLE) == IN_PROGRESS || m_pInstance->GetData(TYPE_BATTLE) == DONE) + { + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + if (!m_pInstance) + return; + + switch (m_uiEventStep) + { + case 0: + DoScriptText(SAY_LIGHT_OF_DAWN_PREPARE_1, m_creature); + m_uiEventTimer = 5000; + break; + case 1: + DoScriptText(SAY_LIGHT_OF_DAWN_PREPARE_2, m_creature); + m_uiEventTimer = 10000; + break; + case 2: + DoScriptText(SAY_LIGHT_OF_DAWN_PREPARE_3, m_creature); + m_uiEventTimer = 3000; + break; + case 3: + DoScriptText(EMOTE_LIGHT_OF_DAWN_ARMY_RISE, m_creature); + case 4: + case 5: + { + // summon army takes about 20 secs and it's done on a few stages; no break between them + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_WARRIORS_SUMMONED_PER_TURN; ++i) + { + uint32 uiSummonEntry = urand(0, 1) ? NPC_VOLATILE_GHOUL : NPC_WARRIOR_OF_THE_FROZEN_WASTES; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 50.0f, fX, fY, fZ); + m_creature->SummonCreature(uiSummonEntry, fX, fY, fZ, 4.7f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + m_uiEventTimer = 6000; + break; + } + case 6: + DoScriptText(SAY_LIGHT_OF_DAWN_PREPARE_4, m_creature); + m_uiEventTimer = 2000; + break; + case 7: + // send army emote + for (GuidList::const_iterator itr = m_lAttackersGUIDs.begin(); itr != m_lAttackersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->HandleEmoteCommand(EMOTE_ONESHOT_BATTLEROAR); + } + m_uiEventTimer = 6000; + break; + case 8: + // start attack (escort) + DoScriptText(EMOTE_LIGHT_OF_DAWN_ARMY_MARCH, m_creature); + m_creature->SetActiveObjectState(true); + Start(true); + + // move the companions as well + float fX, fY, fZ; + if (Creature* pKoltira = m_pInstance->GetSingleCreatureFromStorage(NPC_KOLTIRA_DEATHWEAVER)) + { + pKoltira->SetWalk(false); + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + pKoltira->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + if (Creature* pThassarian = m_pInstance->GetSingleCreatureFromStorage(NPC_THASSARIAN)) + { + pThassarian->SetWalk(false); + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + pThassarian->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + if (Creature* pOrbaz = m_pInstance->GetSingleCreatureFromStorage(NPC_ORBAZ_BLOODBANE)) + { + pOrbaz->SetWalk(false); + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + pOrbaz->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + + // move army + for (GuidList::const_iterator itr = m_lAttackersGUIDs.begin(); itr != m_lAttackersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + pTemp->SetWalk(false); + m_creature->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + // move big units + m_pInstance->DoMoveArmy(); + m_uiEventTimer = 0; + break; + case 9: + // after the battle + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_4, pTirion); + m_uiEventTimer = 21000; + break; + case 10: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_5, pTirion); + m_uiEventTimer = 13000; + break; + case 11: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_6, pTirion); + m_uiEventTimer = 13000; + break; + case 12: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_7, m_creature); + m_uiEventTimer = 7000; + break; + case 13: + // start Alexandros vision + if (Creature* pAlexandros = m_creature->SummonCreature(NPC_HIGHLORD_ALEXANDROS_MOGRAINE, aEventLocations[4].m_fX, aEventLocations[4].m_fY, aEventLocations[4].m_fZ, aEventLocations[4].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_ALEXANDROS, pAlexandros); + pAlexandros->CastSpell(pAlexandros, SPELL_ALEXANDROS_MOGRAINE_SPAWN, true); + } + m_uiEventTimer = 4000; + break; + case 14: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + { + pAlexandros->GetMotionMaster()->MovePoint(POINT_MOVE_OTHER, aEventLocations[5].m_fX, aEventLocations[5].m_fY, aEventLocations[5].m_fZ); + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_1, pAlexandros); + m_creature->SetFacingToObject(pAlexandros); + } + m_uiEventTimer = 2000; + break; + case 15: + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_2, m_creature); + m_uiEventTimer = 4000; + break; + case 16: + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_3, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + // summon young Darion for 1 min + if (Creature* pDarion = m_creature->SummonCreature(NPC_DARION_MOGRAINE, aEventLocations[6].m_fX, aEventLocations[6].m_fY, aEventLocations[6].m_fZ, aEventLocations[6].m_fO, TEMPSUMMON_TIMED_DESPAWN, 1 * MINUTE * IN_MILLISECONDS)) + DoScriptText(EMOTE_LIGHT_OF_DAWN_SHADE, pDarion); + m_uiEventTimer = 3000; + break; + case 17: + if (Creature* pDarion = m_pInstance->GetSingleCreatureFromStorage(NPC_DARION_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_4, pDarion); + m_uiEventTimer = 3000; + break; + case 18: + // young darion runs to father + if (Creature* pDarion = m_pInstance->GetSingleCreatureFromStorage(NPC_DARION_MOGRAINE)) + { + pDarion->SetWalk(false); + pDarion->GetMotionMaster()->MovePoint(POINT_MOVE_CHAPEL, aEventLocations[7].m_fX, aEventLocations[7].m_fY, aEventLocations[7].m_fZ); + } + m_uiEventTimer = 5000; + break; + case 19: + if (Creature* pDarion = m_pInstance->GetSingleCreatureFromStorage(NPC_DARION_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_5, pDarion); + m_uiEventTimer = 5000; + break; + case 20: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_6, pAlexandros); + m_uiEventTimer = 8000; + break; + case 21: + if (Creature* pDarion = m_pInstance->GetSingleCreatureFromStorage(NPC_DARION_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_7, pDarion); + m_uiEventTimer = 8000; + break; + case 22: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_8, pAlexandros); + + // move Tirion to the point where the light of dawn is + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + pTirion->SetWalk(true); + if (GameObject* pLight = m_pInstance->GetSingleGameObjectFromStorage(GO_LIGHT_OF_DAWN)) + pTirion->GetMotionMaster()->MovePoint(POINT_MOVE_OTHER, pLight->GetPositionX(), pLight->GetPositionY(), pLight->GetPositionZ()); + } + m_uiEventTimer = 15000; + break; + case 23: + if (Creature* pDarion = m_pInstance->GetSingleCreatureFromStorage(NPC_DARION_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_9, pDarion); + m_uiEventTimer = 11000; + break; + case 24: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_10, pAlexandros); + m_uiEventTimer = 29000; + break; + case 25: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + DoScriptText(SAY_LIGHT_OF_DAWN_VISION_11, pAlexandros); + m_uiEventTimer = 6000; + break; + case 26: + // Lich king visit + if (Creature* pLichKing = m_creature->SummonCreature(NPC_THE_LICH_KING, aEventLocations[8].m_fX, aEventLocations[8].m_fY, aEventLocations[8].m_fZ, aEventLocations[8].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 5000)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_1, pLichKing); + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + DoScriptText(EMOTE_LIGHT_OF_DAWN_LICH_KING, pAlexandros); + m_uiEventTimer = 2000; + break; + case 27: + // the LK feasts on Alexandros + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_2, pLichKing); + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + pLichKing->CastSpell(pAlexandros, SPELL_SOUL_FEAST_ALEX, false); + } + m_uiEventTimer = 2000; + break; + case 28: + if (Creature* pAlexandros = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_ALEXANDROS_MOGRAINE)) + pAlexandros->ForcedDespawn(); + m_uiEventTimer = 2000; + break; + case 29: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoScriptText(EMOTE_LIGHT_OF_DAWN_ANGRY, m_creature); + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_3, m_creature); + m_uiEventTimer = 3000; + break; + case 30: + // the LK moves forward + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + pLichKing->CastSpell(pLichKing, SPELL_ICEBOUND_VISAGE, true); + pLichKing->GetMotionMaster()->MovePoint(POINT_MOVE_CHAPEL, aEventLocations[9].m_fX, aEventLocations[9].m_fY, aEventLocations[9].m_fZ); + } + m_uiEventTimer = 5000; + break; + case 31: + // darion charges + DoCastSpellIfCan(m_creature, SPELL_MOGRAINE_CHARGE); + m_uiEventTimer = 3000; + break; + case 32: + // the LK kicks darion + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_4, pLichKing); + // Note: this should be cast by the LK - spell bug + m_creature->CastSpell(m_creature, SPELL_REBUKE, true); + } + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + m_uiEventTimer = 4000; + break; + case 33: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + m_creature->SetFacingToObject(pLichKing); + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_5, pTirion); + m_uiEventTimer = 8000; + break; + case 34: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_6, pLichKing); + m_uiEventTimer = 15000; + break; + case 35: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_7, pLichKing); + m_uiEventTimer = 17000; + break; + case 36: + // the LK feasts on tirion + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_CAST_SPELL, pLichKing); + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_GRASP, pTirion); + pLichKing->CastSpell(pTirion, SPELL_SOUL_FEAST_TIRION, false); + pLichKing->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + m_uiEventTimer = 2000; + break; + case 37: + // the light champions attack the LK + if (Creature* pMaxwell = m_pInstance->GetSingleCreatureFromStorage(NPC_LORD_MAXWELL_TYROSUS)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_8, pMaxwell); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + float fX, fY, fZ; + pLichKing->GetContactPoint(m_creature, fX, fY, fZ); + for (GuidList::const_iterator itr = m_lDefendersGUIDs.begin(); itr != m_lDefendersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->SetWalk(false); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + // attack gives us some issues + //pTemp->AI()->AttackStart(pLichKing); + } + } + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[i].m_uiEntry)) + { + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->SetWalk(false); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + // attack gives us some issues + //pTemp->AI()->AttackStart(pLichKing); + } + } + } + m_uiEventTimer = 6000; + break; + case 38: + // the LK throws away all the attackers + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_POWERFULL, pLichKing); + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_9, pLichKing); + pLichKing->CastSpell(pLichKing, SPELL_APOCALYPSE, true); + } + m_uiEventTimer = 1000; + break; + case 39: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + pLichKing->CastSpell(pLichKing, SPELL_POST_APOCALYPSE, true); + + // despawn guards + for (GuidList::const_iterator itr = m_lDefendersGUIDs.begin(); itr != m_lDefendersGUIDs.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + // workaround for the light champions - spell doesn't work right + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[i].m_uiEntry)) + { + pTemp->SetStandState(UNIT_STAND_STATE_DEAD); + pTemp->KnockBackFrom(pLichKing, 50, float(urand(44, 87)) / 10); + } + } + } + m_uiEventTimer = 5000; + break; + case 40: + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_10, m_creature); + m_uiEventTimer = 5000; + break; + case 41: + // darion throws the ashbringer to tirion + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_11, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiEventTimer = 1000; + break; + case 42: + DoScriptText(EMOTE_LIGHT_OF_DAWN_ASHBRINGER, m_creature); + DoCastSpellIfCan(m_creature, SPELL_ASHBRINGER); + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + m_uiEventTimer = 5000; + break; + case 43: + // darion colapses while tirion is engulfed in light + DoScriptText(EMOTE_LIGHT_OF_DAWN_COLAPSE, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + pTirion->CastSpell(pTirion, SPELL_REBIRTH_OF_THE_ASHBRINGER, true); + m_pInstance->DoRespawnGameObject(GO_LIGHT_OF_DAWN, 5 * MINUTE); + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + pLichKing->InterruptNonMeleeSpells(false); + m_uiEventTimer = 2000; + break; + case 44: + // rebirth of the ashbringer + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + if (pTirion->HasAura(SPELL_REBIRTH_OF_THE_ASHBRINGER)) + pTirion->RemoveAurasDueToSpell(SPELL_REBIRTH_OF_THE_ASHBRINGER); + pTirion->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + } + m_uiEventTimer = 2500; + break; + case 45: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_12, pTirion); + m_uiEventTimer = 4000; + break; + case 46: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_13, pLichKing); + m_uiEventTimer = 5000; + break; + case 47: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_14, pTirion); + m_uiEventTimer = 1000; + break; + case 48: + // tirion charges to the LK + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_CHARGE, pTirion); + pTirion->CastSpell(pTirion, SPELL_TIRION_CHARGE, true); + } + m_uiEventTimer = 2000; + break; + case 49: + // move the LK back in front of tirion; + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_15, pLichKing); + pLichKing->GetMotionMaster()->MovePoint(POINT_MOVE_CHAPEL, aEventLocations[8].m_fX, aEventLocations[8].m_fY, aEventLocations[8].m_fZ); + } + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + pTirion->DeleteThreatList(); + m_uiEventTimer = 1000; + break; + case 50: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + pLichKing->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL); + m_uiEventTimer = 3000; + break; + case 51: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_16, pLichKing); + m_uiEventTimer = 10000; + break; + case 52: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + DoScriptText(SAY_LIGHT_OF_DAWN_KING_VISIT_17, pLichKing); + m_uiEventTimer = 10000; + break; + case 53: + // the lich king teleports to leave + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + pLichKing->CastSpell(pLichKing, SPELL_TELEPORT_VISUAL, false); + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + float fX, fY, fZ; + pTirion->SetWalk(false); + m_creature->GetContactPoint(pTirion, fX, fY, fZ, INTERACTION_DISTANCE); + pTirion->GetMotionMaster()->MovePoint(POINT_MOVE_OTHER, fX, fY, fZ); + } + // make champions stand + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[i].m_uiEntry)) + { + pTemp->SetStandState(UNIT_STAND_STATE_STAND); + pTemp->SetFacingToObject(m_creature); + } + } + m_uiEventTimer = 2000; + break; + case 54: + // the lich king leaves + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_THE_LICH_KING)) + { + DoScriptText(EMOTE_LIGHT_OF_DAWN_KING_LEAVE, pLichKing); + pLichKing->ForcedDespawn(); + } + m_uiEventTimer = 7000; + break; + case 55: + // tirion reaches darion and starts the epilogue + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + pTirion->CastSpell(m_creature, SPELL_LAY_ON_HANDS, true); + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_1, pTirion); + } + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_uiEventTimer = 3000; + break; + case 56: + // tirion moves near the light of dawn object + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + pTirion->SetWalk(true); + pTirion->GetMotionMaster()->MovePoint(POINT_MOVE_OTHER, aEventLocations[10].m_fX, aEventLocations[10].m_fY, aEventLocations[10].m_fZ); + } + m_uiEventTimer = 5000; + break; + case 57: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + { + pTirion->SetFacingToObject(m_creature); + m_creature->SetFacingToObject(pTirion); + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_2, pTirion); + } + m_uiEventTimer = 15000; + break; + case 58: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_3, pTirion); + m_uiEventTimer = 7000; + break; + case 59: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_4, pTirion); + m_uiEventTimer = 10000; + break; + case 60: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_5, pTirion); + m_uiEventTimer = 11000; + break; + case 61: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_6, pTirion); + m_uiEventTimer = 10000; + break; + case 62: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_7, pTirion); + m_uiEventTimer = 8000; + break; + case 63: + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_8, pTirion); + m_uiEventTimer = 10000; + break; + case 64: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoScriptText(SAY_LIGHT_OF_DAWN_EPILOGUE_9, m_creature); + m_uiEventTimer = 10000; + break; + case 65: + // send credit then in 5 min reset + DoSendQuestCredit(); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_uiEventTimer = 5 * MINUTE * IN_MILLISECONDS; + break; + case 66: + m_pInstance->SetData(TYPE_BATTLE, NOT_STARTED); + if (Creature* pKoltira = m_pInstance->GetSingleCreatureFromStorage(NPC_KOLTIRA_DEATHWEAVER)) + pKoltira->ForcedDespawn(); + if (Creature* pThassarian = m_pInstance->GetSingleCreatureFromStorage(NPC_THASSARIAN)) + pThassarian->ForcedDespawn(); + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + pTirion->ForcedDespawn(); + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + { + if (Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(aLightArmySpawnLoc[i].m_uiEntry)) + pTemp->ForcedDespawn(); + } + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + } + + ++m_uiEventStep; + } + else + m_uiEventTimer -= uiDiff; + } + + // Battle end yells + if (m_bIsBattleEnd) + { + if (m_uiFightSpeechTimer < uiDiff) + { + switch (urand(0, 6)) + { + case 0: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_10, m_creature); break; + case 1: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_11, m_creature); break; + case 2: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_12, m_creature); break; + case 3: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_13, m_creature); break; + case 4: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_14, m_creature); break; + case 5: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_15, m_creature); break; + case 6: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_16, m_creature); break; + } + m_uiFightSpeechTimer = urand(5000, 7000); + } + else + m_uiFightSpeechTimer -= uiDiff; + } + + // Handle battle events + if (m_uiFightTimer) + { + // on blizz the battle takes about 4 min, time in which about 100 light warriors die + if (m_uiFightTimer <= uiDiff || m_uiLightWarriorsDead >= 100) + { + // summon Tirion and move him to the chapel + if (Creature* pTirion = m_creature->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING, aEventLocations[0].m_fX, aEventLocations[0].m_fY, aEventLocations[0].m_fZ, aEventLocations[0].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 5000, true)) + { + // decrease Darion's damage + DoCastSpellIfCan(m_creature, SPELL_THE_LIGHT_OF_DAWN_DAMAGE_LOSS, CAST_TRIGGERED); + + // Damage the scourge army + if (m_pInstance) + m_pInstance->DoEnableHolyTraps(); + + DoScriptText(SAY_LIGHT_OF_DAWN_OUTRO_1, pTirion); + DoScriptText(EMOTE_LIGHT_OF_DAWN_TIRION, pTirion); + + pTirion->SetWalk(false); + pTirion->GetMotionMaster()->MovePoint(POINT_MOVE_CHAPEL, aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ); + + m_uiFightTimer = 0; + m_uiFightSpeechTimer = 1000; + m_bIsBattleEnd = true; + } + } + else + m_uiFightTimer -= uiDiff; + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // battle sounds + if (m_uiFightSpeechTimer < uiDiff) + { + switch (urand(0, 8)) + { + case 0: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_1, m_creature); break; + case 1: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_2, m_creature); break; + case 2: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_3, m_creature); break; + case 3: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_4, m_creature); break; + case 4: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_5, m_creature); break; + case 5: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_6, m_creature); break; + case 6: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_7, m_creature); break; + case 7: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_8, m_creature); break; + case 8: DoScriptText(SAY_LIGHT_OF_DAWN_BATTLE_9, m_creature); break; + } + m_uiFightSpeechTimer = urand(15000, 20000); + } + else + m_uiFightSpeechTimer -= uiDiff; + + // make sure that darion always stays in the area + if (!m_creature->IsWithinDist2d(aEventLocations[1].m_fX, aEventLocations[1].m_fY, 50.0f)) + { + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(POINT_MOVE_RETURN_BATTLE, aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ); + } + + // Darion spells + if (m_uiAntimagicZoneTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ANTI_MAGIC_ZONE_DARION) == CAST_OK) + m_uiAntimagicZoneTimer = urand(85000, 90000); + } + else + m_uiAntimagicZoneTimer -= uiDiff; + + if (m_uiDeathStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_STRIKE) == CAST_OK) + m_uiDeathStrikeTimer = urand(5000, 10000); + } + else + m_uiDeathStrikeTimer -= uiDiff; + + if (m_uiDeathEmbraceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_EMBRACE) == CAST_OK) + m_uiDeathEmbraceTimer = urand(5000, 10000); + } + else + m_uiDeathEmbraceTimer -= uiDiff; + + if (m_uiIcyTouchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICY_TOUCH_DARION) == CAST_OK) + m_uiIcyTouchTimer = urand(5000, 10000); + } + else + m_uiIcyTouchTimer -= uiDiff; + + if (m_uiUnholyBlightTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_UNHOLY_BLIGHT) == CAST_OK) + m_uiUnholyBlightTimer = urand(5000, 10000); + } + else + m_uiUnholyBlightTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + } + } +}; + +bool GossipHello_npc_highlord_darion_mograine(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + // Only allow start battle after reset + if (world_map_ebon_hold* pInstance = (world_map_ebon_hold*)pCreature->GetInstanceData()) + { + if (pPlayer->GetQuestStatus(QUEST_ID_LIGHT_OF_DAWN) == QUEST_STATUS_INCOMPLETE && pInstance->GetData(TYPE_BATTLE) == NOT_STARTED) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_READY, pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_highlord_darion_mograine(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + if (world_map_ebon_hold* pInstance = (world_map_ebon_hold*)pCreature->GetInstanceData()) + { + // set data to special in order to start the event + pInstance->SetData(TYPE_BATTLE, SPECIAL); + pPlayer->CLOSE_GOSSIP_MENU(); + + return true; + } + } + pPlayer->CLOSE_GOSSIP_MENU(); + + return false; +} + +CreatureAI* GetAI_npc_highlord_darion_mograine(Creature* pCreature) +{ + return new npc_highlord_darion_mograineAI(pCreature); +} + +struct npc_fellow_death_knightAI : public ScriptedAI +{ + npc_fellow_death_knightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (world_map_ebon_hold*)pCreature->GetInstanceData(); + Reset(); + } + + world_map_ebon_hold* m_pInstance; + + uint32 m_uiIcyTouchTimer; + uint32 m_uiBloodStrikeTimer; + uint32 m_uiPlagueStrikeTimer; + + void Reset() override + { + m_uiBloodStrikeTimer = urand(5000, 10000); + m_uiIcyTouchTimer = urand(5000, 10000); + m_uiPlagueStrikeTimer = urand(5000, 10000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_HERO_AGGRO_AURA); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || uiPointId != POINT_MOVE_CHAPEL) + return; + + // make the death knights kneel + if (m_creature->HasAura(SPELL_THE_LIGHT_OF_DAWN_DUMMY)) + m_creature->RemoveAurasDueToSpell(SPELL_THE_LIGHT_OF_DAWN_DUMMY); + + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + + if (Creature* pTirion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + m_creature->SetFacingToObject(pTirion); + } + + void EnterEvadeMode() override + { + if (!m_creature->isAlive()) + return; + + if (!m_pInstance) + return; + + // if evade while the battle is in progress start attacking another target + if (m_pInstance->GetData(TYPE_BATTLE) == IN_PROGRESS) + { + if (Creature* pDarion = m_pInstance->GetSingleCreatureFromStorage(NPC_HIGHLORD_DARION_MOGRAINE)) + { + if (Unit* pTarget = pDarion->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->AI()->AttackStart(pTarget); + } + } + else if (m_pInstance->GetData(TYPE_BATTLE) == DONE) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + m_creature->SetLootRecipient(NULL); + + Reset(); + + if (m_creature->GetEntry() != NPC_ORBAZ_BLOODBANE) + { + // cast light of dawn + if (DoCastSpellIfCan(m_creature, SPELL_THE_LIGHT_OF_DAWN_DUMMY, CAST_TRIGGERED) == CAST_OK) + { + m_creature->Unmount(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + + // move to chapel points + switch (m_creature->GetEntry()) + { + case NPC_THASSARIAN: + m_creature->GetMotionMaster()->MovePoint(POINT_MOVE_CHAPEL, aEventLocations[3].m_fX, aEventLocations[3].m_fY, aEventLocations[3].m_fZ); + break; + case NPC_KOLTIRA_DEATHWEAVER: + m_creature->GetMotionMaster()->MovePoint(POINT_MOVE_CHAPEL, aEventLocations[2].m_fX, aEventLocations[2].m_fY, aEventLocations[2].m_fZ); + break; + case NPC_ORBAZ_BLOODBANE: + m_creature->GetMotionMaster()->MoveTargetedHome(); + break; + } + } + else + ScriptedAI::EnterEvadeMode(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPlagueStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE_KNIGHTS) == CAST_OK) + m_uiPlagueStrikeTimer = urand(5000, 10000); + } + else + m_uiPlagueStrikeTimer -= uiDiff; + + if (m_uiIcyTouchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ICY_TOUCH_DARION) == CAST_OK) + m_uiIcyTouchTimer = urand(5000, 10000); + } + else + m_uiIcyTouchTimer -= uiDiff; + + if (m_uiBloodStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLOOD_STRIKE) == CAST_OK) + m_uiBloodStrikeTimer = urand(5000, 10000); + } + else + m_uiBloodStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_fellow_death_knight(Creature* pCreature) +{ + return new npc_fellow_death_knightAI(pCreature); +} + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_lich_king_light_dawnAI : public ScriptedAI +{ + npc_lich_king_light_dawnAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_lich_king_light_dawn(Creature* pCreature) +{ + return new npc_lich_king_light_dawnAI(pCreature); +} + +/*###### +## npc_acherus_deathcharger +######*/ + +enum +{ + EMOTE_HORSE_READY = -1609097, + SAY_RACE_FINISHED = -1609098, + + SPELL_HORSEMAN_SLAIN = 52692, + SPELL_RACE_COMPLETE = 52361, + + NPC_DARK_RIDER_OF_ACHERUS = 28768, + NPC_SALANAR_THE_HORSEMAN = 28788, + + FACTION_FRIENDLY = 35, +}; + +struct npc_acherus_deathchargerAI : public ScriptedAI +{ + npc_acherus_deathchargerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bIsRiderDead; + + uint8 m_uiQuestEndStage; + uint32 m_uiQuestEndTimer; + + ObjectGuid m_salaranGuid; + + void Reset() override + { + m_bIsRiderDead = false; + m_uiQuestEndStage = 0; + m_uiQuestEndTimer = 0; + + SetCombatMovement(true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void EnterEvadeMode() override + { + if (m_bIsRiderDead) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + m_creature->SetLootRecipient(NULL); + + // Stop movemnet + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + + // Prepare to be mounted + SetCombatMovement(false); + DoScriptText(EMOTE_HORSE_READY, m_creature); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + } + else + ScriptedAI::EnterEvadeMode(); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SALANAR_THE_HORSEMAN) + { + float fX, fY, fZ; + m_creature->GetContactPoint(pSummoned, fX, fY, fZ, INTERACTION_DISTANCE); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + + m_salaranGuid = pSummoned->GetObjectGuid(); + m_uiQuestEndTimer = 4000; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // Initial vehicle rider - handled in DB + if (pSummoned->GetEntry() == NPC_DARK_RIDER_OF_ACHERUS) + { + m_bIsRiderDead = true; + DoCastSpellIfCan(m_creature, SPELL_HORSEMAN_SLAIN, CAST_TRIGGERED); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiQuestEndTimer) + { + if (m_uiQuestEndTimer <= uiDiff) + { + switch (m_uiQuestEndStage) + { + case 0: + if (Creature* pSalaran = m_creature->GetMap()->GetCreature(m_salaranGuid)) + DoScriptText(SAY_RACE_FINISHED, pSalaran); + + m_uiQuestEndTimer = 5000; + break; + case 1: + // Cast completion spell on player + Creature* pSalaran = m_creature->GetMap()->GetCreature(m_salaranGuid); + Player* pPlayer = m_creature->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!pPlayer || !pSalaran) + return; + + pSalaran->CastSpell(pPlayer, SPELL_RACE_COMPLETE, true); + pSalaran->ForcedDespawn(1000); + m_creature->ForcedDespawn(1000); + m_uiQuestEndTimer = 0; + break; + } + ++m_uiQuestEndStage; + } + else + m_uiQuestEndTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_acherus_deathcharger(Creature* pCreature) +{ + return new npc_acherus_deathchargerAI(pCreature); +} + +bool EffectDummyCreature_npc_acherus_deathcharger(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_HORSEMAN_SLAIN && uiEffIndex == EFFECT_INDEX_0) + { + // Make horse evade + pCreatureTarget->AI()->EnterEvadeMode(); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_scarlet_courier +######*/ + +enum +{ + SAY_TREE_1 = -1609079, + SAY_TREE_2 = -1609080, + + GO_TREE = 191144, +}; + +struct npc_scarlet_courierAI : public ScriptedAI +{ + npc_scarlet_courierAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiInitTimer; + uint32 m_uiCombatTimer; + uint8 m_uiCombatStage; + + void Reset() override + { + m_uiInitTimer = 2000; + m_uiCombatTimer = 0; + m_uiCombatStage = 0; + } + + void AttackedBy(Unit* /*pAttacker*/) override + { + m_creature->Unmount(); + } + + void JustReachedHome() override + { + m_creature->ForcedDespawn(); + DoDespawnTree(); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoDespawnTree(); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + m_uiCombatTimer = 5000; + } + + // Wrapper function that despawns the tree + void DoDespawnTree() + { + if (GameObject* pTree = GetClosestGameObjectWithEntry(m_creature, GO_TREE, 30.0f)) + pTree->SetLootState(GO_JUST_DEACTIVATED); + } + + void UpdateAI(const uint32 uiDiff) override + { + // walk to the tree + if (m_uiInitTimer) + { + if (m_uiInitTimer <= uiDiff) + { + DoScriptText(SAY_TREE_1, m_creature); + + float fX, fY, fZ; + if (GameObject* pTree = GetClosestGameObjectWithEntry(m_creature, GO_TREE, 30.0f)) + { + pTree->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + + m_uiInitTimer = 0; + } + else + m_uiInitTimer -= uiDiff; + } + + // despawn tree and start combat + if (m_uiCombatTimer) + { + if (m_uiCombatTimer <= uiDiff) + { + switch (m_uiCombatStage) + { + case 0: + DoScriptText(SAY_TREE_2, m_creature); + m_creature->Unmount(); + DoDespawnTree(); + + m_uiCombatTimer = 3000; + break; + case 1: + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + m_creature->AI()->AttackStart(pSummoner); + } + + m_uiCombatTimer = 0; + break; + } + ++m_uiCombatStage; + } + else + m_uiCombatTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_scarlet_courier(Creature* pCreature) +{ + return new npc_scarlet_courierAI(pCreature); +} + +void AddSC_ebon_hold() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_a_special_surprise"; + pNewScript->GetAI = &GetAI_npc_a_special_surprise; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_death_knight_initiate"; + pNewScript->GetAI = &GetAI_npc_death_knight_initiate; + pNewScript->pGossipHello = &GossipHello_npc_death_knight_initiate; + pNewScript->pGossipSelect = &GossipSelect_npc_death_knight_initiate; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_death_knight_initiate; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_unworthy_initiate"; + pNewScript->GetAI = &GetAI_npc_unworthy_initiate; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_unworthy_initiate_anchor"; + pNewScript->GetAI = &GetAI_npc_unworthy_initiate_anchor; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_acherus_soul_prison"; + pNewScript->pGOUse = &GOUse_go_acherus_soul_prison; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_eye_of_acherus"; + pNewScript->GetAI = &GetAI_npc_eye_of_acherus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scarlet_ghoul"; + pNewScript->GetAI = &GetAI_npc_scarlet_ghoul; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_scarlet_ghoul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_highlord_darion_mograine"; + pNewScript->GetAI = &GetAI_npc_highlord_darion_mograine; + pNewScript->pGossipHello = &GossipHello_npc_highlord_darion_mograine; + pNewScript->pGossipSelect = &GossipSelect_npc_highlord_darion_mograine; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_fellow_death_knight"; + pNewScript->GetAI = &GetAI_npc_fellow_death_knight; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_lich_king_light_dawn"; + pNewScript->GetAI = &GetAI_npc_lich_king_light_dawn; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_acherus_deathcharger"; + pNewScript->GetAI = &GetAI_npc_acherus_deathcharger; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_acherus_deathcharger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scarlet_courier"; + pNewScript->GetAI = &GetAI_npc_scarlet_courier; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.cpp b/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.cpp new file mode 100644 index 000000000..ca9c581fb --- /dev/null +++ b/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.cpp @@ -0,0 +1,294 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: world_map_ebon_hold +SD%Complete: 0 +SDComment: +SDCategory: Ebon Hold +EndScriptData */ + +#include "precompiled.h" +#include "world_map_ebon_hold.h" + +world_map_ebon_hold::world_map_ebon_hold(Map* pMap) : ScriptedInstance(pMap), + m_uiGothikYellTimer(0), + m_uiBattleEncounter(0) +{ + Initialize(); +} + +void world_map_ebon_hold::Initialize() {} + +void world_map_ebon_hold::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_HIGHLORD_DARION_MOGRAINE: + case NPC_KOLTIRA_DEATHWEAVER: + case NPC_ORBAZ_BLOODBANE: + case NPC_THASSARIAN: + + case NPC_HIGHLORD_TIRION_FORDRING: + case NPC_KORFAX_CHAMPION_OF_THE_LIGHT: + case NPC_LORD_MAXWELL_TYROSUS: + case NPC_LEONID_BARTHALOMEW_THE_REVERED: + case NPC_DUKE_NICHOLAS_ZVERENHOFF: + case NPC_COMMANDER_ELIGOR_DAWNBRINGER: + case NPC_RIMBLAT_EARTHSHATTER: + case NPC_RAYNE: + + case NPC_THE_LICH_KING: + case NPC_HIGHLORD_ALEXANDROS_MOGRAINE: + case NPC_DARION_MOGRAINE: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + // Behemots and abominations are spawned by default on the map so they need to be handled here + case NPC_FLESH_BEHEMOTH: + case NPC_RAMPAGING_ABOMINATION: + m_lArmyGuids.push_back(pCreature->GetObjectGuid()); + break; + } +} + +void world_map_ebon_hold::OnCreatureDeath(Creature* pCreature) +{ + if (GetData(TYPE_BATTLE) != IN_PROGRESS) + return; + + switch (pCreature->GetEntry()) + { + // resummon the behemots or abominations if they die + case NPC_FLESH_BEHEMOTH: + case NPC_RAMPAGING_ABOMINATION: + m_lArmyGuids.remove(pCreature->GetObjectGuid());// if remove respawning on reset won't work! (are there any spawned by default?) ?? - unclear related to ResetBattle() + if (Creature* pTemp = pCreature->SummonCreature(pCreature->GetEntry(), pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ(), pCreature->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + // the new summoned mob should attack + Creature* pDarion = GetSingleCreatureFromStorage(NPC_HIGHLORD_DARION_MOGRAINE); + if (pDarion && pDarion->getVictim()) + pTemp->AI()->AttackStart(pDarion->getVictim()); + } + pCreature->ForcedDespawn(1000); + break; + } +} + +void world_map_ebon_hold::OnCreatureEvade(Creature* pCreature) +{ + if (GetData(TYPE_BATTLE) != IN_PROGRESS) + return; + + switch (pCreature->GetEntry()) + { + // don't let the scourge evade while the battle is running + case NPC_FLESH_BEHEMOTH: + case NPC_RAMPAGING_ABOMINATION: + case NPC_VOLATILE_GHOUL: + case NPC_WARRIOR_OF_THE_FROZEN_WASTES: + if (Creature* pDarion = GetSingleCreatureFromStorage(NPC_HIGHLORD_DARION_MOGRAINE)) + { + if (!pDarion->isInCombat()) + return; + + if (Unit* pTarget = pDarion->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pCreature->AI()->AttackStart(pTarget); + } + case NPC_KORFAX_CHAMPION_OF_THE_LIGHT: + case NPC_LORD_MAXWELL_TYROSUS: + case NPC_COMMANDER_ELIGOR_DAWNBRINGER: + case NPC_LEONID_BARTHALOMEW_THE_REVERED: + case NPC_DUKE_NICHOLAS_ZVERENHOFF: + case NPC_RIMBLAT_EARTHSHATTER: + case NPC_RAYNE: + case NPC_DEFENDER_OF_THE_LIGHT: + if (Creature* pDarion = GetSingleCreatureFromStorage(NPC_HIGHLORD_DARION_MOGRAINE)) + pCreature->AI()->AttackStart(pDarion); + break; + } +} + +void world_map_ebon_hold::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_LIGHT_OF_DAWN: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + case GO_HOLY_LIGHTNING_1: + case GO_HOLY_LIGHTNING_2: + m_lLightTrapsGuids.push_back(pGo->GetObjectGuid()); + break; + } +} + +void world_map_ebon_hold::SetData(uint32 uiType, uint32 uiData) +{ + if (uiType == TYPE_BATTLE) + { + switch (uiData) + { + case NOT_STARTED: + // update world states to default + DoUpdateBattleWorldState(WORLD_STATE_FORCES_SHOW, 1); + DoUpdateBattleWorldState(WORLD_STATE_FORCES_LIGHT, MAX_FORCES_LIGHT); + DoUpdateBattleWorldState(WORLD_STATE_FORCES_SCOURGE, MAX_FORCES_SCOURGE); + + DoUpdateBattleWorldState(WORLD_STATE_BATTLE_TIMER_SHOW, 0); + DoUpdateBattleWorldState(WORLD_STATE_BATTLE_BEGIN, 0); + + DoResetBattle(); + break; + case SPECIAL: + // display timer + DoUpdateBattleWorldState(WORLD_STATE_BATTLE_TIMER_SHOW, 1); + DoUpdateBattleWorldState(WORLD_STATE_BATTLE_TIMER_TIME, MAX_BATTLE_INTRO_TIMER); + + // update world states to also show the army + DoUpdateBattleWorldState(WORLD_STATE_FORCES_SHOW, 1); + DoUpdateBattleWorldState(WORLD_STATE_FORCES_LIGHT, MAX_FORCES_LIGHT); + DoUpdateBattleWorldState(WORLD_STATE_FORCES_SCOURGE, MAX_FORCES_SCOURGE); + break; + case IN_PROGRESS: + DoUpdateBattleWorldState(WORLD_STATE_BATTLE_TIMER_SHOW, 0); + DoUpdateBattleWorldState(WORLD_STATE_BATTLE_BEGIN, 1); + break; + } + + m_uiBattleEncounter = uiData; + } +} + +uint32 world_map_ebon_hold::GetData(uint32 uiType) const +{ + if (uiType == TYPE_BATTLE) + return m_uiBattleEncounter; + + return 0; +} + +void world_map_ebon_hold::DoUpdateBattleWorldState(uint32 uiStateId, uint32 uiStateData) +{ + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + { + // we need to manually check the phase mask because the value from DBC is not used yet + if (pPlayer->HasAura(SPELL_CHAPTER_IV) || pPlayer->isGameMaster()) + pPlayer->SendUpdateWorldState(uiStateId, uiStateData); + } + } +} + +void world_map_ebon_hold::DoResetBattle() +{ + // reset all npcs to the original state + if (Creature* pKoltira = GetSingleCreatureFromStorage(NPC_KOLTIRA_DEATHWEAVER)) + pKoltira->Respawn(); + if (Creature* pThassarian = GetSingleCreatureFromStorage(NPC_THASSARIAN)) + pThassarian->Respawn(); + if (Creature* pOrbaz = GetSingleCreatureFromStorage(NPC_ORBAZ_BLOODBANE)) + pOrbaz->Respawn(); + + // respawn all abominations + for (GuidList::const_iterator itr = m_lArmyGuids.begin(); itr != m_lArmyGuids.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->Respawn(); + } + + // despawn the argent dawn + for (uint8 i = 0; i < MAX_LIGHT_CHAMPIONS; i++) + { + if (Creature* pTemp = GetSingleCreatureFromStorage(aLightArmySpawnLoc[i].m_uiEntry)) + pTemp->ForcedDespawn(); + } + + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_HIGHLORD_TIRION_FORDRING)) + pTirion->ForcedDespawn(); +} + +void world_map_ebon_hold::DoMoveArmy() +{ + // move all the army to the chapel + float fX, fY, fZ; + for (GuidList::const_iterator itr = m_lArmyGuids.begin(); itr != m_lArmyGuids.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + { + pTemp->SetWalk(false); + pTemp->GetRandomPoint(aEventLocations[1].m_fX, aEventLocations[1].m_fY, aEventLocations[1].m_fZ, 30.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } +} + +void world_map_ebon_hold::DoDespawnArmy() +{ + // despawn all army units when the battle is finished + for (GuidList::const_iterator itr = m_lArmyGuids.begin(); itr != m_lArmyGuids.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + { + if (pTemp->isAlive()) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } +} + +void world_map_ebon_hold::DoEnableHolyTraps() +{ + for (GuidList::const_iterator itr = m_lLightTrapsGuids.begin(); itr != m_lLightTrapsGuids.end(); ++itr) + DoRespawnGameObject(*itr, 25); +} + +void world_map_ebon_hold::Update(uint32 uiDiff) +{ + if (m_uiGothikYellTimer) + { + if (m_uiGothikYellTimer <= uiDiff) + m_uiGothikYellTimer = 0; + else + m_uiGothikYellTimer -= uiDiff; + } +} + +bool world_map_ebon_hold::CanAndToggleGothikYell() +{ + if (m_uiGothikYellTimer) + return false; + + m_uiGothikYellTimer = 2000; + return true; +} + +InstanceData* GetInstance_world_map_ebon_hold(Map* pMap) +{ + return new world_map_ebon_hold(pMap); +} + +void AddSC_world_map_ebon_hold() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "world_map_ebon_hold"; + pNewScript->GetInstanceData = &GetInstance_world_map_ebon_hold; + pNewScript->RegisterSelf(); +} diff --git a/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.h b/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.h new file mode 100644 index 000000000..261f4142c --- /dev/null +++ b/scripts/eastern_kingdoms/scarlet_enclave/world_map_ebon_hold.h @@ -0,0 +1,153 @@ +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_EBON_HOLD_H +#define DEF_EBON_HOLD_H + +enum +{ + TYPE_BATTLE = 0, + + // npcs + // death knights + NPC_HIGHLORD_DARION_MOGRAINE = 29173, + NPC_KOLTIRA_DEATHWEAVER = 29199, + NPC_ORBAZ_BLOODBANE = 29204, + NPC_THASSARIAN = 29200, + + // scourge warriors - summond during the event + NPC_FLESH_BEHEMOTH = 29190, + NPC_RAMPAGING_ABOMINATION = 29186, + NPC_VOLATILE_GHOUL = 29219, + NPC_WARRIOR_OF_THE_FROZEN_WASTES = 29206, + + // argent dawn commanders + NPC_HIGHLORD_TIRION_FORDRING = 29175, + NPC_KORFAX_CHAMPION_OF_THE_LIGHT = 29176, + NPC_LORD_MAXWELL_TYROSUS = 29178, + NPC_COMMANDER_ELIGOR_DAWNBRINGER = 29177, + NPC_LEONID_BARTHALOMEW_THE_REVERED = 29179, + NPC_DUKE_NICHOLAS_ZVERENHOFF = 29180, + NPC_RIMBLAT_EARTHSHATTER = 29182, + NPC_RAYNE = 29181, + + // argent warriors + NPC_DEFENDER_OF_THE_LIGHT = 29174, + + // cinematic + NPC_THE_LICH_KING = 29183, + NPC_HIGHLORD_ALEXANDROS_MOGRAINE = 29227, + NPC_DARION_MOGRAINE = 29228, + + // object + GO_LIGHT_OF_DAWN = 191330, + GO_HOLY_LIGHTNING_1 = 191301, + GO_HOLY_LIGHTNING_2 = 191302, + + // spells + SPELL_CHAPTER_IV = 53405, // phase aura + + // variables + MAX_LIGHT_CHAMPIONS = 7, // the number of the light champions + MAX_WARRIORS_SUMMONED_PER_TURN = 5, // summoned warriors (light and death) per turn + MAX_LIGHT_GUARDS = 4, // guards summond for the outro + + // event variables + MAX_BATTLE_INTRO_TIMER = 5, + MAX_FORCES_LIGHT = 300, + MAX_FORCES_SCOURGE = 10000, + + // world states + // basically world states should be shown to all players with phase mask = 128 as stated in DBC + // because we don't have the possibility to do that we'll just iterate through the players and set the phase mask manually based on the battle status + WORLD_STATE_FORCES_SHOW = 3592, // show the remaining units + WORLD_STATE_FORCES_SCOURGE = 3591, + WORLD_STATE_FORCES_LIGHT = 3590, + WORLD_STATE_BATTLE_TIMER_SHOW = 3603, // countdown timer + WORLD_STATE_BATTLE_TIMER_TIME = 3604, + WORLD_STATE_BATTLE_BEGIN = 3605, // battle has begun +}; + +struct sSpawnLocation +{ + float m_fX, m_fY, m_fZ, m_fO; + uint32 m_uiEntry; +}; + +// light champions +static sSpawnLocation aLightArmySpawnLoc[MAX_LIGHT_CHAMPIONS] = +{ + {2285.80f, -5308.82f, 87.04f, 1.67f, NPC_KORFAX_CHAMPION_OF_THE_LIGHT}, + {2276.96f, -5309.36f, 86.66f, 1.61f, NPC_LORD_MAXWELL_TYROSUS}, + {2279.82f, -5322.61f, 88.95f, 1.54f, NPC_LEONID_BARTHALOMEW_THE_REVERED}, + {2287.96f, -5313.96f, 88.27f, 1.63f, NPC_DUKE_NICHOLAS_ZVERENHOFF}, + {2276.84f, -5313.78f, 87.62f, 1.61f, NPC_COMMANDER_ELIGOR_DAWNBRINGER}, + {2275.80f, -5322.51f, 88.62f, 1.68f, NPC_RAYNE}, + {2282.47f, -5319.84f, 88.83f, 1.74f, NPC_RIMBLAT_EARTHSHATTER} +}; + +// four guards spawned for the outro +static sSpawnLocation aGuardsSpawnLoc[MAX_LIGHT_GUARDS] = +{ + {2287.581f, -5284.991f, 82.535f, 2.60f}, + {2287.856f, -5281.127f, 82.225f, 3.44f}, + {2275.964f, -5282.389f, 82.301f, 5.80f}, + {2275.471f, -5277.668f, 82.058f, 5.79f} +}; + +// Tirion is spawned at the edge of the battle and runs toward the chapel +// When he reach the chapel he cast some powerfull light spell and the battle ends +static sSpawnLocation aEventLocations[] = +{ + {2165.711f, -5266.124f, 95.50f, 0.13f}, // 0 Tirion spawn location + {2281.390f, -5299.98f, 85.07f, 1.61f}, // 1 Tirion move location + {2289.259f, -5280.350f, 82.11f, 0.0f}, // 2 Koltira chapel loc + {2273.289f, -5273.675f, 81.70f, 0.0f}, // 3 Thassarian chapel loc + {2280.159f, -5263.561f, 81.15f, 4.70f}, // 4 Alexandros summon location + {2279.927f, -5265.84f, 81.39f, 0.0f}, // 5 Alexandros move loc + {2280.538f, -5280.103f, 82.41f, 1.60f}, // 6 Young Darion spawn + {2279.895f, -5269.334f, 81.73f, 0.0f}, // 7 Young Darion move + {2280.304f, -5257.205f, 80.09f, 4.62f}, // 8 Lich King spawn + {2281.523f, -5261.058f, 80.87f, 0.0f}, // 9 Lich King move + {2273.071f, -5293.428f, 83.06f, 0.0f}, // 10 Tirion final point +}; + +class world_map_ebon_hold : public ScriptedInstance +{ + public: + world_map_ebon_hold(Map* pMap); + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void Update(uint32 uiDiff) override; + + bool CanAndToggleGothikYell(); + + void DoUpdateBattleWorldState(uint32 uiStateId, uint32 uiStateData); + + void DoEnableHolyTraps(); + + // Move the behemots and abominations and make them attack + void DoMoveArmy(); + void DoDespawnArmy(); + + protected: + void DoResetBattle(); + + uint32 m_uiGothikYellTimer; // Timer to check if Gothik can yell (related q 12698) + uint32 m_uiBattleEncounter; // Store state of the battle around "The Light of Dawn" + + GuidList m_lArmyGuids; + GuidList m_lLightTrapsGuids; +}; + +#endif diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp index a34091dc7..f1f725424 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp +++ b/scripts/eastern_kingdoms/scarlet_monastery/boss_arcanist_doan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,7 +35,7 @@ enum SPELL_ARCANE_BUBBLE = 9438, }; -struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI +struct boss_arcanist_doanAI : public ScriptedAI { boss_arcanist_doanAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -45,21 +45,21 @@ struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI uint32 m_uiDetonationTimer; bool bShielded; - void Reset() + void Reset() override { m_uiPolymorphTimer = 15000; - m_uiSilenceTimer = 18000; - m_uiArcaneExplosionTimer = 3000; + m_uiSilenceTimer = 7500; + m_uiArcaneExplosionTimer = urand(1000, 3000); m_uiDetonationTimer = 0; - bShielded = false; + bShielded = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -107,7 +107,7 @@ struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI if (m_uiSilenceTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SILENCE) == CAST_OK) - m_uiSilenceTimer = urand(15000, 20000); + m_uiSilenceTimer = urand(15000, 22000); } else m_uiSilenceTimer -= uiDiff; @@ -116,7 +116,7 @@ struct MANGOS_DLL_DECL boss_arcanist_doanAI : public ScriptedAI if (m_uiArcaneExplosionTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) - m_uiArcaneExplosionTimer = 8000; + m_uiArcaneExplosionTimer = urand(2500, 8500); } else m_uiArcaneExplosionTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp deleted file mode 100644 index 22b51f82e..000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_azshir_the_sleepless.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Azshir_the_Sleepless -SD%Complete: 80 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_CALLOFTHEGRAVE 17831 -#define SPELL_TERRIFY 7399 -#define SPELL_SOULSIPHON 7290 - -struct MANGOS_DLL_DECL boss_azshir_the_sleeplessAI : public ScriptedAI -{ - boss_azshir_the_sleeplessAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 SoulSiphon_Timer; - uint32 CallOftheGrave_Timer; - uint32 Terrify_Timer; - - void Reset() - { - SoulSiphon_Timer = 1; - CallOftheGrave_Timer = 30000; - Terrify_Timer = 20000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //If we are <50% hp cast Soul Siphon rank 1 - if (m_creature->GetHealthPercent() <= 50.0f && !m_creature->IsNonMeleeSpellCasted(false)) - { - //SoulSiphon_Timer - if (SoulSiphon_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SOULSIPHON); - // return; // Why was this return here? - - SoulSiphon_Timer = 20000; - }else SoulSiphon_Timer -= diff; - } - - //CallOfTheGrave_Timer - if (CallOftheGrave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CALLOFTHEGRAVE); - CallOftheGrave_Timer = 30000; - }else CallOftheGrave_Timer -= diff; - - //Terrify_Timer - if (Terrify_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_TERRIFY); - Terrify_Timer = 20000; - }else Terrify_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_azshir_the_sleepless(Creature* pCreature) -{ - return new boss_azshir_the_sleeplessAI(pCreature); -} - -void AddSC_boss_azshir_the_sleepless() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_azshir_the_sleepless"; - pNewScript->GetAI = &GetAI_boss_azshir_the_sleepless; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp deleted file mode 100644 index ca9758243..000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_bloodmage_thalnos.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Bloodmage_Thalnos -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SAY_AGGRO = -1189016, - SAY_HEALTH = -1189017, - SAY_KILL = -1189018, - - SPELL_FLAMESHOCK = 8053, - SPELL_SHADOWBOLT = 1106, - SPELL_FLAMESPIKE = 8814, - SPELL_FIRENOVA = 16079, -}; - -struct MANGOS_DLL_DECL boss_bloodmage_thalnosAI : public ScriptedAI -{ - boss_bloodmage_thalnosAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - bool HpYell; - uint32 FlameShock_Timer; - uint32 ShadowBolt_Timer; - uint32 FlameSpike_Timer; - uint32 FireNova_Timer; - - void Reset() - { - HpYell = false; - FlameShock_Timer = 10000; - ShadowBolt_Timer = 2000; - FlameSpike_Timer = 8000; - FireNova_Timer = 40000; - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - void KilledUnit(Unit* Victim) - { - DoScriptText(SAY_KILL, m_creature); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //If we are <35% hp - if (!HpYell && m_creature->GetHealthPercent() <= 35.0f) - { - DoScriptText(SAY_HEALTH, m_creature); - HpYell = true; - } - - //FlameShock_Timer - if (FlameShock_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FLAMESHOCK); - FlameShock_Timer = urand(10000, 15000); - }else FlameShock_Timer -= diff; - - //FlameSpike_Timer - if (FlameSpike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FLAMESPIKE); - FlameSpike_Timer = 30000; - }else FlameSpike_Timer -= diff; - - //FireNova_Timer - if (FireNova_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FIRENOVA); - FireNova_Timer = 40000; - }else FireNova_Timer -= diff; - - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWBOLT); - ShadowBolt_Timer = 2000; - }else ShadowBolt_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_bloodmage_thalnos(Creature* pCreature) -{ - return new boss_bloodmage_thalnosAI(pCreature); -} - -void AddSC_boss_bloodmage_thalnos() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_bloodmage_thalnos"; - pNewScript->GetAI = &GetAI_boss_bloodmage_thalnos; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp index a44b98924..0a1defd41 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp +++ b/scripts/eastern_kingdoms/scarlet_monastery/boss_headless_horseman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,61 +16,329 @@ /* ScriptData SDName: boss_headless_horseman -SD%Complete: 0 -SDComment: Place Holder +SD%Complete: 90 +SDComment: Intro and epilog are handled by DB. Script might require some fine-tune. SDCategory: Scarlet Monastery EndScriptData */ #include "precompiled.h" +#include "TemporarySummon.h" enum { - SAY_ENTRANCE = -1189022, - SAY_REJOINED = -1189023, - SAY_BODY_DEFEAT = -1189024, - SAY_LOST_HEAD = -1189025, - SAY_CONFLAGRATION = -1189026, - SAY_SPROUTING_PUMPKINS = -1189027, - SAY_SLAY = -1189028, - SAY_DEATH = -1189029, - - EMOTE_LAUGH = -1189030, - - SAY_PLAYER1 = -1189031, - SAY_PLAYER2 = -1189032, - SAY_PLAYER3 = -1189033, - SAY_PLAYER4 = -1189034 + // horseman yells + SAY_REJOINED = -1189023, + SAY_BODY_DEFEAT = -1189024, + SAY_LOST_HEAD = -1189025, + SAY_CONFLAGRATION = -1189026, + SAY_SPROUTING_PUMPKINS = -1189027, + SAY_SLAY = -1189028, + SAY_DEATH = -1189029, + + // event start yells - handled by dbscripts + // SAY_ENTRANCE = -1189022, + // EMOTE_LAUGH = -1189030, + // SAY_PLAYER1 = -1189031, + // SAY_PLAYER2 = -1189032, + // SAY_PLAYER3 = -1189033, + // SAY_PLAYER4 = -1189034, + + // normal phase spells + SPELL_BODY_HEAD_VISUAL = 42413, // head visual + SPELL_JACK_LANTERNED = 44185, // on killed player + SPELL_HORSEMAN_CLEAVE = 42587, + SPELL_CONFLAGRATION = 42380, // triggers 42381 + SPELL_SUMMON_PUMPKIN = 52236, // triggers 42394 + SPELL_HORSEMAN_SUMMON = 42394, // triggered spell - used to do the text + SPELL_CONFLAGRATION_SOUND = 48149, + SPELL_BODY_STAGE_1 = 42547, // phase control spells + SPELL_BODY_STAGE_2 = 42548, + SPELL_BODY_STAGE_3 = 42549, + + // headless body spells + SPELL_SEND_HEAD = 42399, // send event 15394 - toss head + SPELL_WHIRLWIND = 43116, // triggers 43118 + SPELL_BODY_REGEN_PROC = 42556, // procs 42587; also adds immunity + SPELL_BODY_REGEN = 42403, // change model to headless + SPELL_BODY_REGEN_CONFUSE = 43105, // confuse spell + + // head spells + SPELL_HEAD_VISUAL = 44241, + SPELL_HEAL_BODY = 43306, // heal body to 100% on rejoin + SPELL_REQUEST_BODY = 43101, + SPELL_HORSEMAN_HEAD_LANDS = 42400, // head land visual + // SPELL_HEAD_INVISIBLE = 44312, // purpose unk + // SPELL_HEADS_BREATH = 43207, // purpose unk + + // pumpkin spells + SPELL_PUMPKIN_LIFE_CYCLE = 42280, // visual root aura + SPELL_PUMPKIN_AURA = 42294, // visual green aura + SPELL_SPROUTING = 42281, // sprout delay + SPELL_PUMPKIN_DEATH = 42291, // visual on sprout + SPELL_SPROUT_BODY = 42285, // visual moving aura + SPELL_SQUASH_SOUL = 42514, + + // event end spells + SPELL_HEAD_IS_DEAD = 42428, // send event 15407; triggers 42566 + SPELL_BODY_DEAD = 42429, // send event 15331 + SPELL_BODY_LEAVE_COMBAT = 43805, // send event 15407; trigger spell 42556 + + // spells used for the intro or epilog (handled by DB) + // SPELL_LAUGH = 43881, // play sound 11965 + // SPELL_LAUGH_MANIACAL = 43885, // play sound 11975 + // SPELL_LAUGH_LOW = 43894, // play sound 11976 + // SPELL_RHYME_SHAKE_MEDIUM = 42909, // shake effect on event start + // SPELL_RHYME_SHAKE_SMALL = 42910, + // SPELL_WISP_ESCAPE_MISSILE = 43034, + // SPELL_WISP_FLIGHT_MISSILE = 42821, // triggers 42818 + // SPELL_WISP_INVISIBLE = 42823, + // SPELL_ON_KILL_PROC = 43877, // procs 13567 - use unk + // SPELL_ENRAGE_VISUAL = 42438, // use unk + + // creatures + NPC_HEADLESS_HORSEMAN = 23682, + NPC_HEAD_OF_HORSEMAN = 23775, + NPC_PULSING_PUMPKIN = 23694, // summoned by spell 42277 + // NPC_HORSEMAN_WISP_INV = 24034, // probably used for the epilog }; -struct MANGOS_DLL_DECL boss_headless_horsemanAI : public ScriptedAI +enum HorsemanPhase { - boss_headless_horsemanAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + PHASE_HORSEMAN = 1, + PHASE_CONFLAGRATION = 2, + PHASE_PUMPKINS = 3, + PHASE_HEAD_TOSS = 4, +}; - void Reset() +struct boss_headless_horsemanAI : public ScriptedAI +{ + boss_headless_horsemanAI(Creature* pCreature) : ScriptedAI(pCreature) { + m_creature->SetWalk(false); + m_creature->SetLevitate(true); + + m_bHorsemanLanded = false; + Reset(); } - void Aggro(Unit* pWho) + bool m_bHorsemanLanded; + bool m_bHeadRequested; + + HorsemanPhase m_fightPhase; + + ObjectGuid m_headGuid; + + uint32 m_uiCleaveTimer; + uint32 m_uiConflagrationTimer; + uint32 m_uiPumpkinTimer; + + void Reset() override { - m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_BODY_STAGE_1, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_BODY_HEAD_VISUAL, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + m_fightPhase = PHASE_HORSEMAN; + m_uiCleaveTimer = 3000; + m_uiConflagrationTimer = urand(20000, 25000); + m_uiPumpkinTimer = urand(35000, 40000); + m_bHeadRequested = false; } - void KilledUnit(Unit* pVictim) + void MoveInLineOfSight(Unit* pWho) override { - DoScriptText(SAY_SLAY, m_creature); + if (m_bHorsemanLanded) + ScriptedAI::MoveInLineOfSight(pWho); } - void JustDied(Unit* pKiller) + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + DoCastSpellIfCan(pVictim, SPELL_JACK_LANTERNED, CAST_TRIGGERED); + DoScriptText(SAY_SLAY, m_creature); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_HEAD_OF_HORSEMAN) + m_headGuid = pSummoned->GetObjectGuid(); + else if (pSummoned->GetEntry() == NPC_PULSING_PUMPKIN) + { + pSummoned->CastSpell(pSummoned, SPELL_SPROUTING, false); + pSummoned->CastSpell(pSummoned, SPELL_PUMPKIN_AURA, true); + pSummoned->CastSpell(pSummoned, SPELL_PUMPKIN_LIFE_CYCLE, true); + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (m_fightPhase != PHASE_HEAD_TOSS && uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + DoTossHead(); + } + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_HORSEMAN_SUMMON) + DoScriptText(SAY_SPROUTING_PUMPKINS, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + // cleanup + m_creature->ForcedDespawn(); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + // allow attacking + if (uiType == WAYPOINT_MOTION_TYPE && uiPointId == 15) + { + m_bHorsemanLanded = true; + m_creature->SetLevitate(false); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // rejoin head on request + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_HEAD_OF_HORSEMAN) + { + DoRejoinHead(); + pInvoker->CastSpell(m_creature, SPELL_SEND_HEAD, true); + } + } + + // function to handle toss head phase + void DoTossHead() + { + // in the first transition; spawn the head + if (m_creature->HasAura(SPELL_BODY_STAGE_1)) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 15.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_HEAD_OF_HORSEMAN, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + // make head available + if (Creature* pHead = m_creature->GetMap()->GetCreature(m_headGuid)) + DoCastSpellIfCan(pHead, SPELL_SEND_HEAD, CAST_TRIGGERED); + + // only from second transition we start whirlwind + if (m_creature->HasAura(SPELL_BODY_STAGE_2) || m_creature->HasAura(SPELL_BODY_STAGE_3)) + DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND, CAST_TRIGGERED); + + // remove head visual and set transition phase auras + m_creature->RemoveAurasDueToSpell(SPELL_HEAD_VISUAL); + DoCastSpellIfCan(m_creature, SPELL_BODY_REGEN_PROC, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_BODY_REGEN, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_BODY_REGEN_CONFUSE, CAST_TRIGGERED); + + m_fightPhase = PHASE_HEAD_TOSS; + m_bHeadRequested = false; + } + + // function to handle the head rejoin + void DoRejoinHead() + { + // remove transition auras and set the head visual + m_creature->RemoveAurasDueToSpell(SPELL_BODY_REGEN_CONFUSE); + m_creature->RemoveAurasDueToSpell(SPELL_BODY_REGEN); + m_creature->RemoveAurasDueToSpell(SPELL_BODY_REGEN_PROC); + m_creature->RemoveAurasDueToSpell(SPELL_WHIRLWIND); + + DoScriptText(SAY_REJOINED, m_creature); + DoCastSpellIfCan(m_creature, SPELL_BODY_HEAD_VISUAL, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + // switch from phase 1 to phase 2 + if (m_creature->HasAura(SPELL_BODY_STAGE_1)) + { + m_fightPhase = PHASE_CONFLAGRATION; + m_creature->RemoveAurasDueToSpell(SPELL_BODY_STAGE_1); + DoCastSpellIfCan(m_creature, SPELL_BODY_STAGE_2, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + // switch from phase 2 to phase 3 or repeat phase 3 + else if (m_creature->HasAura(SPELL_BODY_STAGE_2) || m_creature->HasAura(SPELL_BODY_STAGE_3)) + { + m_fightPhase = PHASE_PUMPKINS; + m_creature->RemoveAurasDueToSpell(SPELL_BODY_STAGE_2); + DoCastSpellIfCan(m_creature, SPELL_BODY_STAGE_3, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_PUMPKIN, CAST_TRIGGERED); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); + switch (m_fightPhase) + { + case PHASE_PUMPKINS: + + if (m_uiPumpkinTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_PUMPKIN) == CAST_OK) + m_uiPumpkinTimer = urand(35000, 40000); + } + else + m_uiPumpkinTimer -= uiDiff; + + // no break; + case PHASE_CONFLAGRATION: + + // conflagration not happening during pumpkin phase + if (m_fightPhase != PHASE_PUMPKINS) + { + if (m_uiConflagrationTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CONFLAGRATION) == CAST_OK) + { + DoScriptText(SAY_CONFLAGRATION, m_creature); + m_uiConflagrationTimer = urand(15000, 20000); + } + } + } + else + m_uiConflagrationTimer -= uiDiff; + } + + // no break; + case PHASE_HORSEMAN: + + // cleave - all phases + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HORSEMAN_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 5000; + } + else + m_uiCleaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + case PHASE_HEAD_TOSS: + // rejoin head by force at 100% hp + if (!m_bHeadRequested && m_creature->GetHealthPercent() == 100.0f) + { + if (Creature* pHead = m_creature->GetMap()->GetCreature(m_headGuid)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pHead); + + m_bHeadRequested = true; + } + break; + } } }; @@ -79,6 +347,125 @@ CreatureAI* GetAI_boss_headless_horseman(Creature* pCreature) return new boss_headless_horsemanAI(pCreature); } +bool EffectScriptEffectCreature_boss_headless_horseman(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_REQUEST_BODY && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_HEADLESS_HORSEMAN) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + + return true; + } + + return false; +} + +struct boss_head_of_horsemanAI : public ScriptedAI +{ + boss_head_of_horsemanAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_uiHeadPhase = 1; + Reset(); + } + + uint8 m_uiHeadPhase; + + void Reset() override { } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_HEAD_IS_DEAD, CAST_TRIGGERED); + + // end the event + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Unit* pHorseman = m_creature->GetMap()->GetUnit(pTemporary->GetSummonerGuid())) + { + pHorseman->CastSpell(pHorseman, SPELL_BODY_LEAVE_COMBAT, true); + pHorseman->CastSpell(pHorseman, SPELL_BODY_DEAD, true); + } + } + } + + void DamageTaken(Unit* /*pDealer*/, uint32& /*uiDamage*/) override + { + // allow him to die the last phase + if (m_uiHeadPhase >= 3) + return; + + // rejoin and switch to next phase + if (m_creature->GetHealthPercent() < float(100 - m_uiHeadPhase * 33.3f)) + { + DoRejoinHead(false); + ++m_uiHeadPhase; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (pInvoker->GetEntry() != NPC_HEADLESS_HORSEMAN) + return; + + // toss head + if (eventType == AI_EVENT_CUSTOM_A) + { + // make visible + DoScriptText(SAY_LOST_HEAD, m_creature); + DoCastSpellIfCan(m_creature, SPELL_HORSEMAN_HEAD_LANDS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_HEAD_VISUAL, CAST_TRIGGERED); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // run around the graveyard + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MoveRandomAroundPoint(pInvoker->GetPositionX(), pInvoker->GetPositionY(), pInvoker->GetPositionZ(), 40.0f); + } + // rejoin head by force - body healed + else if (eventType == AI_EVENT_CUSTOM_B) + DoRejoinHead(true); + } + + // rejoin the head with the body + void DoRejoinHead(bool bForced) + { + // script targets on body + m_creature->RemoveAllAurasOnEvade(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCastSpellIfCan(m_creature, SPELL_REQUEST_BODY, CAST_TRIGGERED); + + // heal body only if head is not requested by force (Horseman healed) + if (!bForced) + DoCastSpellIfCan(m_creature, SPELL_HEAL_BODY, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override { } +}; + +CreatureAI* GetAI_boss_head_of_horseman(Creature* pCreature) +{ + return new boss_head_of_horsemanAI(pCreature); +} + +bool EffectScriptEffectCreature_boss_head_of_horseman(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_SEND_HEAD && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_HEAD_OF_HORSEMAN) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + + return true; + } + + return false; +} + void AddSC_boss_headless_horseman() { Script* pNewScript; @@ -86,5 +473,12 @@ void AddSC_boss_headless_horseman() pNewScript = new Script; pNewScript->Name = "boss_headless_horseman"; pNewScript->GetAI = GetAI_boss_headless_horseman; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_boss_headless_horseman; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_head_of_horseman"; + pNewScript->GetAI = GetAI_boss_head_of_horseman; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_boss_head_of_horseman; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp index 34d7cce90..e02d3afc3 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp +++ b/scripts/eastern_kingdoms/scarlet_monastery/boss_herod.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -42,7 +42,7 @@ enum NPC_SCARLET_TRAINEE = 6575 }; -struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI +struct boss_herodAI : public ScriptedAI { boss_herodAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -52,16 +52,16 @@ struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI uint32 m_uiCleaveTimer; uint32 m_uiWhirlwindTimer; - void Reset() + void Reset() override { m_bTraineeSay = false; m_bEnrage = false; - m_uiCleaveTimer = 12000; - m_uiWhirlwindTimer = 45000; + m_uiCleaveTimer = 7500; + m_uiWhirlwindTimer = 14500; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); DoCastSpellIfCan(m_creature, SPELL_RUSHINGCHARGE); @@ -75,21 +75,20 @@ struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI DoScriptText(SAY_TRAINEE_SPAWN, pSummoned); m_bTraineeSay = true; } - } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_KILL, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - for(uint8 i = 0; i < 20; ++i) - m_creature->SummonCreature(NPC_SCARLET_TRAINEE, 1939.18f, -431.58f, 17.09f, 6.22f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); + for (uint8 i = 0; i < 20; ++i) + m_creature->SummonCreature(NPC_SCARLET_TRAINEE, 1939.18f, -431.58f, 17.09f, 6.22f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -109,7 +108,7 @@ struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI if (m_uiCleaveTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 12000; + m_uiCleaveTimer = urand(7500, 17500); } else m_uiCleaveTimer -= uiDiff; @@ -119,7 +118,7 @@ struct MANGOS_DLL_DECL boss_herodAI : public ScriptedAI if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_WHIRLWIND) == CAST_OK) { DoScriptText(SAY_WHIRLWIND, m_creature); - m_uiWhirlwindTimer = 30000; + m_uiWhirlwindTimer = urand(15000, 25000); } } else @@ -134,7 +133,7 @@ CreatureAI* GetAI_boss_herod(Creature* pCreature) return new boss_herodAI(pCreature); } -struct MANGOS_DLL_DECL mob_scarlet_traineeAI : public npc_escortAI +struct mob_scarlet_traineeAI : public npc_escortAI { mob_scarlet_traineeAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -144,10 +143,10 @@ struct MANGOS_DLL_DECL mob_scarlet_traineeAI : public npc_escortAI uint32 m_uiStartTimer; - void Reset() { } - void WaypointReached(uint32 /*uiPointId*/) {} + void Reset() override { } + void WaypointReached(uint32 /*uiPointId*/) override {} - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_uiStartTimer) { diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp deleted file mode 100644 index f3573b1f2..000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_high_inquisitor_fairbanks.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_High_Inquisitor_Fairbanks -SD%Complete: 100 -SDComment: TODO: if this guy not involved in some special event, remove (and let ACID script) -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_CURSEOFBLOOD = 8282, - SPELL_DISPELMAGIC = 15090, - SPELL_FEAR = 12096, - SPELL_HEAL = 12039, - SPELL_POWERWORDSHIELD = 11647, - SPELL_SLEEP = 8399 -}; - -struct MANGOS_DLL_DECL boss_high_inquisitor_fairbanksAI : public ScriptedAI -{ - boss_high_inquisitor_fairbanksAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 CurseOfBlood_Timer; - uint32 DispelMagic_Timer; - uint32 Fear_Timer; - uint32 Heal_Timer; - uint32 Sleep_Timer; - uint32 Dispel_Timer; - bool PowerWordShield; - - void Reset() - { - CurseOfBlood_Timer = 10000; - DispelMagic_Timer = 30000; - Fear_Timer = 40000; - Heal_Timer = 30000; - Sleep_Timer = 30000; - Dispel_Timer = 20000; - PowerWordShield = false; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //If we are <25% hp cast Heal - if (m_creature->GetHealthPercent() <= 25.0f && !m_creature->IsNonMeleeSpellCasted(false) && Heal_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_HEAL); - Heal_Timer = 30000; - }else Heal_Timer -= diff; - - //Fear_Timer - if (Fear_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target,SPELL_FEAR); - - Fear_Timer = 40000; - }else Fear_Timer -= diff; - - //Sleep_Timer - if (Sleep_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO,0)) - DoCastSpellIfCan(target,SPELL_SLEEP); - - Sleep_Timer = 30000; - }else Sleep_Timer -= diff; - - //PowerWordShield_Timer - if (!PowerWordShield && m_creature->GetHealthPercent() <= 25.0f) - { - DoCastSpellIfCan(m_creature,SPELL_POWERWORDSHIELD); - PowerWordShield = true; - } - - //Dispel_Timer - if (Dispel_Timer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_DISPELMAGIC); - - DispelMagic_Timer = 30000; - }else DispelMagic_Timer -= diff; - - //CurseOfBlood_Timer - if (CurseOfBlood_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFBLOOD); - CurseOfBlood_Timer = 25000; - }else CurseOfBlood_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_high_inquisitor_fairbanks(Creature* pCreature) -{ - return new boss_high_inquisitor_fairbanksAI(pCreature); -} - -void AddSC_boss_high_inquisitor_fairbanks() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_high_inquisitor_fairbanks"; - pNewScript->GetAI = &GetAI_boss_high_inquisitor_fairbanks; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp deleted file mode 100644 index 7f6a02beb..000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_houndmaster_loksey.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Houndmaster_Loksey -SD%Complete: 100 -SDComment: TODO: if this guy not involved in some special event, remove (and let ACID script) -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SAY_AGGRO = -1189021, - SPELL_SUMMONSCARLETHOUND = 17164, - SPELL_BLOODLUST = 6742 -}; - -struct MANGOS_DLL_DECL boss_houndmaster_lokseyAI : public ScriptedAI -{ - boss_houndmaster_lokseyAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 BloodLust_Timer; - - void Reset() - { - BloodLust_Timer = 20000; - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO, m_creature); - DoCastSpellIfCan(m_creature,SPELL_SUMMONSCARLETHOUND); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (BloodLust_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_BLOODLUST); - BloodLust_Timer = 20000; - }else BloodLust_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_houndmaster_loksey(Creature* pCreature) -{ - return new boss_houndmaster_lokseyAI(pCreature); -} - -void AddSC_boss_houndmaster_loksey() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_houndmaster_loksey"; - pNewScript->GetAI = &GetAI_boss_houndmaster_loksey; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp deleted file mode 100644 index 68eae58cf..000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_interrogator_vishas.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Interrogator_Vishas -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" -#include "scarlet_monastery.h" - -enum -{ - SAY_AGGRO = -1189011, - SAY_HEALTH1 = -1189012, - SAY_HEALTH2 = -1189013, - SAY_KILL = -1189014, - - SPELL_SHADOWWORDPAIN = 2767, -}; - -struct MANGOS_DLL_DECL boss_interrogator_vishasAI : public ScriptedAI -{ - boss_interrogator_vishasAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - bool Yell30; - bool Yell60; - uint32 ShadowWordPain_Timer; - - void Reset() - { - Yell30 = false; - Yell60 = false; - ShadowWordPain_Timer = 5000; - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - void KilledUnit(Unit* Victim) - { - DoScriptText(SAY_KILL, m_creature); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //If we are low on hp Do sayings - if (!Yell60 && m_creature->GetHealthPercent() <= 60.0f) - { - DoScriptText(SAY_HEALTH1, m_creature); - Yell60 = true; - } - - if (!Yell30 && m_creature->GetHealthPercent() <= 30.0f) - { - DoScriptText(SAY_HEALTH2, m_creature); - Yell30 = true; - } - - //ShadowWordPain_Timer - if (ShadowWordPain_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWWORDPAIN); - ShadowWordPain_Timer = urand(5000, 15000); - }else ShadowWordPain_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_interrogator_vishas(Creature* pCreature) -{ - return new boss_interrogator_vishasAI(pCreature); -} - -void AddSC_boss_interrogator_vishas() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_interrogator_vishas"; - pNewScript->GetAI = &GetAI_boss_interrogator_vishas; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp index 29b86e412..a6d79f7b8 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp +++ b/scripts/eastern_kingdoms/scarlet_monastery/boss_mograine_and_whitemane.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,23 +26,23 @@ EndScriptData */ enum { - //Mograine says + // Mograine says SAY_MO_AGGRO = -1189005, SAY_MO_KILL = -1189006, SAY_MO_RESSURECTED = -1189007, - //Whitemane says + // Whitemane says SAY_WH_INTRO = -1189008, SAY_WH_KILL = -1189009, SAY_WH_RESSURECT = -1189010, - //Mograine Spells + // Mograine Spells SPELL_CRUSADERSTRIKE = 14518, SPELL_HAMMEROFJUSTICE = 5589, SPELL_LAYONHANDS = 9257, SPELL_RETRIBUTIONAURA = 8990, - //Whitemanes Spells + // Whitemanes Spells SPELL_DEEPSLEEP = 9256, SPELL_SCARLETRESURRECTION = 9232, SPELL_DOMINATEMIND = 14515, @@ -51,7 +51,7 @@ enum SPELL_POWERWORDSHIELD = 22187 }; -struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI +struct boss_scarlet_commander_mograineAI : public ScriptedAI { boss_scarlet_commander_mograineAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -68,44 +68,45 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI bool m_bHeal; bool m_bFakeDeath; - void Reset() + void Reset() override { - m_uiCrusaderStrike_Timer = 10000; - m_uiHammerOfJustice_Timer = 10000; + m_uiCrusaderStrike_Timer = 8400; + m_uiHammerOfJustice_Timer = 9600; - //Incase wipe during phase that mograine fake death + m_bHasDied = false; + m_bHeal = false; + m_bFakeDeath = false; + + // Incase wipe during phase that mograine fake death m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetStandState(UNIT_STAND_STATE_STAND); - - m_bHasDied = false; - m_bHeal = false; - m_bFakeDeath = false; - - if (!m_pInstance) - return; - - if (Creature* pWhitemane = m_pInstance->GetSingleCreatureFromStorage(NPC_WHITEMANE)) - { - if (m_creature->isAlive() && !pWhitemane->isAlive()) - pWhitemane->Respawn(); - } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_MO_AGGRO, m_creature); - DoCastSpellIfCan(m_creature,SPELL_RETRIBUTIONAURA); + DoCastSpellIfCan(m_creature, SPELL_RETRIBUTIONAURA); m_creature->CallForHelp(VISIBLE_RANGE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_MO_KILL, m_creature); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void JustReachedHome() override + { + if (!m_pInstance) + return; + + Creature* pWhitemane = m_pInstance->GetSingleCreatureFromStorage(NPC_WHITEMANE); + if (pWhitemane && !pWhitemane->isAlive()) + pWhitemane->Respawn(); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth() || m_bHasDied) return; @@ -113,7 +114,7 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI if (!m_pInstance) return; - //On first death, fake death and open door, as well as initiate whitemane if exist + // On first death, fake death and open door, as well as initiate whitemane if exist if (Creature* pWhitemane = m_pInstance->GetSingleCreatureFromStorage(NPC_WHITEMANE)) { m_pInstance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); @@ -129,10 +130,11 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI m_creature->InterruptNonMeleeSpells(false); m_creature->ClearComboPointHolders(); - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnDeath(); m_creature->ClearAllReactives(); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->SetStandState(UNIT_STAND_STATE_DEAD); m_bHasDied = true; @@ -142,9 +144,9 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI } } - void SpellHit(Unit* pWho, const SpellEntry* pSpell) + void SpellHit(Unit* /*pWho*/, const SpellEntry* pSpell) override { - //When hit with ressurection say text + // When hit with ressurection say text if (pSpell->Id == SPELL_SCARLETRESURRECTION) { DoScriptText(SAY_MO_RESSURECTED, m_creature); @@ -155,48 +157,47 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_bHasDied && !m_bHeal && m_pInstance && m_pInstance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) { - //On ressurection, stop fake death and heal whitemane and resume fight - if (Creature* pWhitemane = m_pInstance->GetSingleCreatureFromStorage(NPC_WHITEMANE)) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - DoCastSpellIfCan(pWhitemane, SPELL_LAYONHANDS); + // On ressurection, stop fake death and heal whitemane and resume fight + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + // spell has script target on Whitemane + DoCastSpellIfCan(m_creature, SPELL_LAYONHANDS); - m_uiCrusaderStrike_Timer = 10000; - m_uiHammerOfJustice_Timer = 10000; + m_uiCrusaderStrike_Timer = 8400; + m_uiHammerOfJustice_Timer = 9600; - if (m_creature->getVictim()) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_bHeal = true; - } + m_bHeal = true; } - //This if-check to make sure mograine does not attack while fake death + // This if-check to make sure mograine does not attack while fake death if (m_bFakeDeath) return; - //m_uiCrusaderStrike_Timer + // m_uiCrusaderStrike_Timer if (m_uiCrusaderStrike_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); - m_uiCrusaderStrike_Timer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSADERSTRIKE) == CAST_OK) + m_uiCrusaderStrike_Timer = urand(6000, 15000); } else m_uiCrusaderStrike_Timer -= uiDiff; - //m_uiHammerOfJustice_Timer + // m_uiHammerOfJustice_Timer if (m_uiHammerOfJustice_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HAMMEROFJUSTICE); - m_uiHammerOfJustice_Timer = 60000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMEROFJUSTICE) == CAST_OK) + m_uiHammerOfJustice_Timer = urand(7000, 18500); } else m_uiHammerOfJustice_Timer -= uiDiff; @@ -205,7 +206,7 @@ struct MANGOS_DLL_DECL boss_scarlet_commander_mograineAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI +struct boss_high_inquisitor_whitemaneAI : public ScriptedAI { boss_high_inquisitor_whitemaneAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -223,15 +224,15 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI bool m_bCanResurrectCheck; bool m_bCanResurrect; - void Reset() + void Reset() override { - m_uiWait_Timer = 7000; - m_uiHeal_Timer = 10000; + m_uiWait_Timer = 7000; + m_uiHeal_Timer = 10000; m_uiPowerWordShield_Timer = 15000; - m_uiHolySmite_Timer = 6000; + m_uiHolySmite_Timer = 4000; - m_bCanResurrectCheck = false; - m_bCanResurrect = false; + m_bCanResurrectCheck = false; + m_bCanResurrect = false; if (!m_pInstance) return; @@ -243,7 +244,7 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -252,12 +253,12 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* /*pWho*/) override { - //This needs to be empty because Whitemane should NOT aggro while fighting Mograine. Mograine will give us a target. + // This needs to be empty because Whitemane should NOT aggro while fighting Mograine. Mograine will give us a target. } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; @@ -265,11 +266,12 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI if (!m_bCanResurrectCheck || m_bCanResurrect) { // prevent killing blow before rezzing commander - m_creature->SetHealth(uiDamage+1); + m_creature->SetHealth(uiDamage + 1); + uiDamage = 0; } } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_pInstance && (m_pInstance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED || m_pInstance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == FAIL)) return; @@ -277,92 +279,74 @@ struct MANGOS_DLL_DECL boss_high_inquisitor_whitemaneAI : public ScriptedAI ScriptedAI::AttackStart(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_WH_INTRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_WH_KILL, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_bCanResurrect) { - //When casting resuruction make sure to delay so on rez when reinstate battle deepsleep runs out - if (m_pInstance && m_uiWait_Timer < uiDiff) + // When casting resuruction make sure to delay so on rez when reinstate battle deepsleep runs out + if (m_uiWait_Timer < uiDiff) { - if (Creature* pMograine = m_pInstance->GetSingleCreatureFromStorage(NPC_MOGRAINE)) - { - DoCastSpellIfCan(pMograine, SPELL_SCARLETRESURRECTION); - DoScriptText(SAY_WH_RESSURECT, m_creature); - m_bCanResurrect = false; - } + // spell has script target on Mograine + DoCastSpellIfCan(m_creature, SPELL_SCARLETRESURRECTION); + DoScriptText(SAY_WH_RESSURECT, m_creature); + m_bCanResurrect = false; } else m_uiWait_Timer -= uiDiff; } - //Cast Deep sleep when health is less than 50% + // Cast Deep sleep when health is less than 50% if (!m_bCanResurrectCheck && m_creature->GetHealthPercent() <= 50.0f) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEEPSLEEP); + DoCastSpellIfCan(m_creature, SPELL_DEEPSLEEP, CAST_INTERRUPT_PREVIOUS); m_bCanResurrectCheck = true; m_bCanResurrect = true; return; } - //while in "resurrect-mode", don't do anything + // while in "resurrect-mode", don't do anything if (m_bCanResurrect) return; - //If we are <75% hp cast healing spells at self or Mograine + // If we are <75% hp cast healing spells at self or Mograine if (m_uiHeal_Timer < uiDiff) { - Creature* pTarget = NULL; - - if (m_creature->GetHealthPercent() <= 75.0f) - pTarget = m_creature; - - if (m_pInstance) + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - if (Creature* pMograine = m_pInstance->GetSingleCreatureFromStorage(NPC_MOGRAINE)) - { - if (pMograine->isAlive() && pMograine->GetHealthPercent() <= 75.0f) - pTarget = pMograine; - } + if (DoCastSpellIfCan(pTarget, SPELL_HEAL) == CAST_OK) + m_uiHeal_Timer = 13000; } - - if (pTarget) - DoCastSpellIfCan(pTarget, SPELL_HEAL); - - m_uiHeal_Timer = 13000; } else m_uiHeal_Timer -= uiDiff; - //m_uiPowerWordShield_Timer + // m_uiPowerWordShield_Timer if (m_uiPowerWordShield_Timer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_POWERWORDSHIELD); - m_uiPowerWordShield_Timer = 15000; + if (DoCastSpellIfCan(m_creature, SPELL_POWERWORDSHIELD) == CAST_OK) + m_uiPowerWordShield_Timer = urand(22000, 45000); } else m_uiPowerWordShield_Timer -= uiDiff; - //m_uiHolySmite_Timer + // m_uiHolySmite_Timer if (m_uiHolySmite_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HOLYSMITE); - m_uiHolySmite_Timer = 6000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLYSMITE) == CAST_OK) + m_uiHolySmite_Timer = urand(3500, 5000); } else m_uiHolySmite_Timer -= uiDiff; diff --git a/scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp b/scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp deleted file mode 100644 index 4afda0bf0..000000000 --- a/scripts/eastern_kingdoms/scarlet_monastery/boss_scorn.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Scorn -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_LICHSLAP 28873 -#define SPELL_FROSTBOLTVOLLEY 8398 -#define SPELL_MINDFLAY 17313 -#define SPELL_FROSTNOVA 15531 - -struct MANGOS_DLL_DECL boss_scornAI : public ScriptedAI -{ - boss_scornAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 LichSlap_Timer; - uint32 FrostboltVolley_Timer; - uint32 MindFlay_Timer; - uint32 FrostNova_Timer; - - void Reset() - { - LichSlap_Timer = 45000; - FrostboltVolley_Timer = 30000; - MindFlay_Timer = 30000; - FrostNova_Timer = 30000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //LichSlap_Timer - if (LichSlap_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_LICHSLAP); - LichSlap_Timer = 45000; - }else LichSlap_Timer -= diff; - - //FrostboltVolley_Timer - if (FrostboltVolley_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLTVOLLEY); - FrostboltVolley_Timer = 20000; - }else FrostboltVolley_Timer -= diff; - - //MindFlay_Timer - if (MindFlay_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MINDFLAY); - MindFlay_Timer = 20000; - }else MindFlay_Timer -= diff; - - //FrostNova_Timer - if (FrostNova_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTNOVA); - FrostNova_Timer = 15000; - }else FrostNova_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_scorn(Creature* pCreature) -{ - return new boss_scornAI(pCreature); -} - -void AddSC_boss_scorn() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_scorn"; - pNewScript->GetAI = &GetAI_boss_scorn; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp b/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp index 21de1d1a3..21d36f580 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp +++ b/scripts/eastern_kingdoms/scarlet_monastery/instance_scarlet_monastery.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -36,7 +36,7 @@ void instance_scarlet_monastery::Initialize() void instance_scarlet_monastery::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_MOGRAINE: case NPC_WHITEMANE: @@ -75,7 +75,7 @@ void instance_scarlet_monastery::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_scarlet_monastery::GetData(uint32 uiData) +uint32 instance_scarlet_monastery::GetData(uint32 uiData) const { if (uiData == TYPE_MOGRAINE_AND_WHITE_EVENT) return m_auiEncounter[0]; diff --git a/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h b/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h index f13806402..2e1c41ad8 100644 --- a/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h +++ b/scripts/eastern_kingdoms/scarlet_monastery/scarlet_monastery.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -21,19 +21,19 @@ enum SAY_TRIGGER_VORREL = -1189015, }; -class MANGOS_DLL_DECL instance_scarlet_monastery : public ScriptedInstance +class instance_scarlet_monastery : public ScriptedInstance { public: instance_scarlet_monastery(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiData) const override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp b/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp index 65ba208cb..3d4a62ffb 100644 --- a/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp +++ b/scripts/eastern_kingdoms/scholomance/boss_darkmaster_gandling.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -32,7 +32,7 @@ enum SPELL_SHADOW_PORTAL = 17950 }; -struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI +struct boss_darkmaster_gandlingAI : public ScriptedAI { boss_darkmaster_gandlingAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -47,7 +47,7 @@ struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI uint32 m_uiCurseTimer; uint32 m_uiTeleportTimer; - void Reset() + void Reset() override { m_uiArcaneMissilesTimer = 4500; m_uiShadowShieldTimer = 12000; @@ -55,7 +55,7 @@ struct MANGOS_DLL_DECL boss_darkmaster_gandlingAI : public ScriptedAI m_uiTeleportTimer = 16000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp b/scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp deleted file mode 100644 index 6b70cd4fc..000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_death_knight_darkreaver.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Death_knight_darkreaver -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" - -struct MANGOS_DLL_DECL boss_death_knight_darkreaverAI : public ScriptedAI -{ - boss_death_knight_darkreaverAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (m_creature->GetHealth() <= damage) - { - m_creature->CastSpell(m_creature,23261,true); //Summon Darkreaver's Fallen Charger - } - } -}; - -CreatureAI* GetAI_boss_death_knight_darkreaver(Creature* pCreature) -{ - return new boss_death_knight_darkreaverAI(pCreature); -} - -void AddSC_boss_death_knight_darkreaver() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_death_knight_darkreaver"; - pNewScript->GetAI = &GetAI_boss_death_knight_darkreaver; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp b/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp index e0d19b395..742aa1f38 100644 --- a/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp +++ b/scripts/eastern_kingdoms/scholomance/boss_jandice_barov.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -28,12 +28,9 @@ enum SPELL_CURSE_OF_BLOOD = 16098, SPELL_SUMMON_ILLUSIONS = 17773, SPELL_BANISH = 8994, - - //Spells of Illusion of Jandice Barov - SPELL_CLEAVE = 15584, }; -struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI +struct boss_jandicebarovAI : public ScriptedAI { boss_jandicebarovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -41,14 +38,14 @@ struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI uint32 m_uiIllusionTimer; uint32 m_uiBanishTimer; - void Reset() + void Reset() override { m_uiCurseOfBloodTimer = 5000; m_uiIllusionTimer = 15000; m_uiBanishTimer = urand(9000, 13000); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); @@ -56,7 +53,7 @@ struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI pSummoned->AI()->AttackStart(pTarget); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -96,46 +93,11 @@ struct MANGOS_DLL_DECL boss_jandicebarovAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_illusionofjandicebarovAI : public ScriptedAI -{ - mob_illusionofjandicebarovAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiCleaveTimer; - - void Reset() - { - m_uiCleaveTimer = urand(2000, 8000); - } - - void UpdateAI(const uint32 diff) - { - // Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Cleave_Timer - if (m_uiCleaveTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = urand(5000, 8000); - } - else - m_uiCleaveTimer -= diff; - - DoMeleeAttackIfReady(); - } -}; - CreatureAI* GetAI_boss_jandicebarov(Creature* pCreature) { return new boss_jandicebarovAI(pCreature); } -CreatureAI* GetAI_mob_illusionofjandicebarov(Creature* pCreature) -{ - return new mob_illusionofjandicebarovAI(pCreature); -} - void AddSC_boss_jandicebarov() { Script* pNewScript; @@ -144,9 +106,4 @@ void AddSC_boss_jandicebarov() pNewScript->Name = "boss_jandice_barov"; pNewScript->GetAI = &GetAI_boss_jandicebarov; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_illusionofjandicebarov"; - pNewScript->GetAI = &GetAI_mob_illusionofjandicebarov; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/scholomance/boss_kormok.cpp b/scripts/eastern_kingdoms/scholomance/boss_kormok.cpp deleted file mode 100644 index 342d5969d..000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_kormok.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Kormok -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" - -enum -{ - EMOTE_GENERIC_FRENZY = -1000002, - - SPELL_SHADOWBOLT_VOLLEY = 20741, - SPELL_BONE_SHIELD = 27688, - SPELL_BLOODLUST = 27689, - SPELL_SUMMON_BONE_MAGES = 27695, // triggers 27696, 27697, 27698, 27699 - SPELL_SUMMON_BONE_MINIONS = 27687, // triggers 27690, 27691, 27692, 27693 (spells were removed after vanilla) - SPELL_FRENZY = 8269, -}; - -struct MANGOS_DLL_DECL boss_kormokAI : public ScriptedAI -{ - boss_kormokAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiShadowVolleyTimer; - uint32 m_uiBoneShieldTimer; - uint32 m_uiMinionTimer; - uint32 m_uiBloodlustTimer; - bool m_bHasMages; - bool m_bIsFrenzy; - - void Reset() - { - m_uiShadowVolleyTimer = urand(10000, 12000); - m_uiMinionTimer = 15000; - m_uiBloodlustTimer = urand(20000, 25000); - m_bHasMages = false; - m_bIsFrenzy = false; - - // the boss casts this on spawn because he is summoned - DoCastSpellIfCan(m_creature, SPELL_BONE_SHIELD); - } - - void Aggro(Unit* pWho) - { - DoCastSpellIfCan(m_creature, SPELL_BONE_SHIELD, CAST_AURA_NOT_PRESENT); - } - - void JustSummoned(Creature* pSummoned) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // ShadowVolley_Timer - if (m_uiShadowVolleyTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_SHADOWBOLT_VOLLEY) == CAST_OK) - m_uiShadowVolleyTimer = 15000; - } - else - m_uiShadowVolleyTimer -= uiDiff; - - // Minion_Timer - if (m_uiMinionTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_BONE_MINIONS) == CAST_OK) - m_uiMinionTimer = urand(12000, 15000); - } - else - m_uiMinionTimer -= uiDiff; - - // Bloodlust - if (m_uiBloodlustTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_BLOODLUST) == CAST_OK) - m_uiBloodlustTimer = urand(25000, 30000); - } - else - m_uiBloodlustTimer -= uiDiff; - - // Summon Bone Mages - if (!m_bHasMages && m_creature->GetHealthPercent() < 26.0f) - { - if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_BONE_MAGES) == CAST_OK) - m_bHasMages = true; - } - - // Frenzy - if (!m_bIsFrenzy && m_creature->GetHealthPercent() < 20.0f) - { - if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) - { - DoScriptText(EMOTE_GENERIC_FRENZY, m_creature); - m_bIsFrenzy = true; - } - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_kormok(Creature* pCreature) -{ - return new boss_kormokAI(pCreature); -} - -void AddSC_boss_kormok() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_kormok"; - pNewScript->GetAI = &GetAI_boss_kormok; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp b/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp deleted file mode 100644 index cd236d22f..000000000 --- a/scripts/eastern_kingdoms/scholomance/boss_vectus.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Vectus -SD%Complete: 60 -SDComment: event not implemented -SDCategory: Scholomance -EndScriptData */ - -#include "precompiled.h" - -enum -{ - //EMOTE_GENERIC_FRENZY_KILL = -1000001, - - SPELL_FLAMESTRIKE = 18399, - SPELL_BLAST_WAVE = 16046 - //SPELL_FRENZY = 28371 //spell is used by Gluth, confirm this is for this boss too - //SPELL_FIRE_SHIELD = 0 //should supposedly have some aura, but proper spell not found -}; - -struct MANGOS_DLL_DECL boss_vectusAI : public ScriptedAI -{ - boss_vectusAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiFlameStrike_Timer; - uint32 m_uiBlastWave_Timer; - uint32 m_uiFrenzy_Timer; - - void Reset() - { - m_uiFlameStrike_Timer = 2000; - m_uiBlastWave_Timer = 14000; - m_uiFrenzy_Timer = 0; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //m_uiFlameStrike_Timer - if (m_uiFlameStrike_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAMESTRIKE); - m_uiFlameStrike_Timer = 30000; - } - else - m_uiFlameStrike_Timer -= uiDiff; - - //BlastWave_Timer - if (m_uiBlastWave_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLAST_WAVE); - m_uiBlastWave_Timer = 12000; - } - else - m_uiBlastWave_Timer -= uiDiff; - - //Frenzy_Timer - /*if (m_creature->GetHealthPercent() < 25.0f) - { - if (m_uiFrenzy_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FRENZY); - DoScriptText(EMOTE_GENERIC_FRENZY_KILL, m_creature); - m_uiFrenzy_Timer = 24000; - } - else - m_uiFrenzy_Timer -= uiDiff; - }*/ - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_vectus(Creature* pCreature) -{ - return new boss_vectusAI(pCreature); -} - -void AddSC_boss_vectus() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_vectus"; - pNewScript->GetAI = &GetAI_boss_vectus; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp b/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp index 155975a94..8478b5649 100644 --- a/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp +++ b/scripts/eastern_kingdoms/scholomance/instance_scholomance.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ void instance_scholomance::Initialize() m_mGandlingData[aGandlingEvents[i]] = GandlingEventData(); } -void instance_scholomance::OnPlayerEnter(Player* pPlayer) +void instance_scholomance::OnPlayerEnter(Player* /*pPlayer*/) { // Summon Gandling if can DoSpawnGandlingIfCan(true); @@ -61,7 +61,7 @@ void instance_scholomance::OnCreatureCreate(Creature* pCreature) void instance_scholomance::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_GATE_KIRTONOS: case GO_GATE_RAS: @@ -86,7 +86,7 @@ void instance_scholomance::OnObjectCreate(GameObject* pGo) void instance_scholomance::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_KIRTONOS: // This door is initially closed by DB-scripts, so only use it in case of FAIL, DONE, or on aggro after wipe @@ -143,8 +143,8 @@ void instance_scholomance::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " << m_auiEncounter[9]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " << m_auiEncounter[9]; m_strInstData = saveStream.str(); @@ -169,7 +169,7 @@ void instance_scholomance::DoSpawnGandlingIfCan(bool bByPlayerEnter) // Check if all the six bosses are done first if (m_auiEncounter[TYPE_MALICIA] == DONE && m_auiEncounter[TYPE_THEOLEN] == DONE && m_auiEncounter[TYPE_POLKELT] == DONE && - m_auiEncounter[TYPE_RAVENIAN] == DONE && m_auiEncounter[TYPE_ALEXEI_BAROV] == DONE && m_auiEncounter[TYPE_ILLUCIA_BAROV] == DONE) + m_auiEncounter[TYPE_RAVENIAN] == DONE && m_auiEncounter[TYPE_ALEXEI_BAROV] == DONE && m_auiEncounter[TYPE_ILLUCIA_BAROV] == DONE) { if (Creature* pGandling = pPlayer->SummonCreature(NPC_DARKMASTER_GANDLING, aGandlingSpawnLocs[0].m_fX, aGandlingSpawnLocs[0].m_fY, aGandlingSpawnLocs[0].m_fZ, aGandlingSpawnLocs[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) { @@ -200,9 +200,9 @@ void instance_scholomance::HandlePortalEvent(uint32 uiEventId, uint32 uiData) // Toggle door and event state in case of state-switch else { - if (uiData == IN_PROGRESS && !find->second.m_bIsActive || - uiData == FAIL && find->second.m_bIsActive || - uiData == DONE && find->second.m_bIsActive) + if ((uiData == IN_PROGRESS && !find->second.m_bIsActive) || + (uiData == FAIL && find->second.m_bIsActive) || + (uiData == DONE && find->second.m_bIsActive)) { find->second.m_bIsActive = !find->second.m_bIsActive; DoUseDoorOrButton(find->second.m_doorGuid); @@ -210,7 +210,7 @@ void instance_scholomance::HandlePortalEvent(uint32 uiEventId, uint32 uiData) } } -uint32 instance_scholomance::GetData(uint32 uiType) +uint32 instance_scholomance::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -232,7 +232,7 @@ void instance_scholomance::Load(const char* chrIn) loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8] >> m_auiEncounter[9]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -349,7 +349,7 @@ InstanceData* GetInstanceData_instance_scholomance(Map* pMap) return new instance_scholomance(pMap); } -bool ProcessEventId_event_spell_gandling_shadow_portal(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_spell_gandling_shadow_portal(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) { if (pSource->GetTypeId() == TYPEID_UNIT) { diff --git a/scripts/eastern_kingdoms/scholomance/scholomance.h b/scripts/eastern_kingdoms/scholomance/scholomance.h index 967d9f125..4637dd02b 100644 --- a/scripts/eastern_kingdoms/scholomance/scholomance.h +++ b/scripts/eastern_kingdoms/scholomance/scholomance.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -78,29 +78,29 @@ static const uint32 aGandlingEvents[MAX_EVENTS] = {EVENT_ID_POLKELT, EVENT_ID_TH typedef std::map GandlingEventMap; -class MANGOS_DLL_DECL instance_scholomance : public ScriptedInstance +class instance_scholomance : public ScriptedInstance { public: instance_scholomance(Map* pMap); ~instance_scholomance() {} - void Initialize(); + void Initialize() override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); - void OnPlayerEnter(Player* pPlayer); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnPlayerEnter(Player* pPlayer) override; void HandlePortalEvent(uint32 uiEventId, uint32 uiData); - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: void DoSpawnGandlingIfCan(bool bByPlayerEnter); diff --git a/scripts/eastern_kingdoms/searing_gorge.cpp b/scripts/eastern_kingdoms/searing_gorge.cpp index b723081ff..c0dbe9139 100644 --- a/scripts/eastern_kingdoms/searing_gorge.cpp +++ b/scripts/eastern_kingdoms/searing_gorge.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,20 +16,115 @@ /* ScriptData SDName: Searing_Gorge -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 80 +SDComment: Quest support: 3367. SDCategory: Searing Gorge EndScriptData */ /* ContentData +npc_dorius_stonetender EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### -## +## npc_dorius_stonetender ######*/ +enum +{ + SAY_DORIUS_AGGRO_1 = -1000993, + SAY_DORIUS_AGGRO_2 = -1000994, + + NPC_DARK_IRON_STEELSHIFTER = 8337, + MAX_STEELSHIFTERS = 4, + + QUEST_ID_SUNTARA_STONES = 3367, +}; + +struct npc_dorius_stonetenderAI : public npc_escortAI +{ + npc_dorius_stonetenderAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + void Reset() override { } + + void Aggro(Unit* pWho) override + { + DoScriptText(urand(0, 1) ? SAY_DORIUS_AGGRO_1 : SAY_DORIUS_AGGRO_2, m_creature, pWho); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + // ToDo: research if there is any text here + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue), true); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 20: + // ToDo: research if there is any text here! + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_STEELSHIFTERS; ++i) + { + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 15.0f, i * M_PI_F / 2); + m_creature->SummonCreature(NPC_DARK_IRON_STEELSHIFTER, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + } + break; + case 33: + // ToDo: research if there is any event and text here! + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_SUNTARA_STONES, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DARK_IRON_STEELSHIFTER) + pSummoned->AI()->AttackStart(m_creature); + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_dorius_stonetender(Creature* pCreature) +{ + return new npc_dorius_stonetenderAI(pCreature); +} + +bool QuestAccept_npc_dorius_stonetender(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_SUNTARA_STONES) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + void AddSC_searing_gorge() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_dorius_stonetender"; + pNewScript->GetAI = &GetAI_npc_dorius_stonetender; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_dorius_stonetender; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/shadowfang_keep/boss_hummel.cpp b/scripts/eastern_kingdoms/shadowfang_keep/boss_hummel.cpp index d06459181..265e7d19f 100644 --- a/scripts/eastern_kingdoms/shadowfang_keep/boss_hummel.cpp +++ b/scripts/eastern_kingdoms/shadowfang_keep/boss_hummel.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -54,7 +54,7 @@ static const DialogueEntry aIntroDialogue[] = {0, 0, 0}, }; -struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private DialogueHelper +struct npc_valentine_boss_managerAI : public ScriptedAI, private DialogueHelper { npc_valentine_boss_managerAI(Creature* pCreature) : ScriptedAI(pCreature), DialogueHelper(aIntroDialogue) @@ -70,12 +70,12 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private ObjectGuid m_EventStarterGuid; - void Reset() + void Reset() override { m_uiCrazedApothecaryTimer = 30000; } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { if (!m_pInstance) return; @@ -136,7 +136,7 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NCP_CRAZED_APOTHECARY) { @@ -171,7 +171,7 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private // I'm not sure if this unit flag should be used, but it's clear that the NPC shouldn't be attacked until the dialogue is finished pHummel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // WARNING: workaround -> faction should be set here - FIX THIS after the aura bug in core is fixed - //pHummel->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + // pHummel->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); } StartNextDialogueText(QUEST_BEEN_SERVED); @@ -181,7 +181,7 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private { pBaxter->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // WARNING: workaround -> faction should be set here - FIX THIS after the aura bug in core is fixed - //pBaxter->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + // pBaxter->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); if (GameObject* pVials = m_pInstance->GetSingleGameObjectFromStorage(GO_APOTHECARE_VIALS)) { @@ -191,7 +191,7 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private pBaxter->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else - error_log("SD2: Gameobject %u couldn't be found or something really bad happened.", GO_APOTHECARE_VIALS); + script_error_log("Gameobject %u couldn't be found or something really bad happened.", GO_APOTHECARE_VIALS); } // Move Frye to position @@ -199,7 +199,7 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private { pFrye->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // WARNING: workaround -> faction should be set here - FIX THIS after the aura bug in core is fixed - //pFrye->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + // pFrye->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); if (GameObject* pChemistry = m_pInstance->GetSingleGameObjectFromStorage(GO_CHEMISTRY_SET)) { @@ -209,11 +209,11 @@ struct MANGOS_DLL_DECL npc_valentine_boss_managerAI : public ScriptedAI, private pFrye->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else - error_log("SD2: Gameobject %u couldn't be found or something really bad happened.", GO_CHEMISTRY_SET); + script_error_log("Gameobject %u couldn't be found or something really bad happened.", GO_CHEMISTRY_SET); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); diff --git a/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp b/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp index ff9d81524..544f78cdb 100644 --- a/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp +++ b/scripts/eastern_kingdoms/shadowfang_keep/instance_shadowfang_keep.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,7 +37,7 @@ void instance_shadowfang_keep::Initialize() void instance_shadowfang_keep::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ASH: case NPC_ADA: @@ -62,14 +62,14 @@ void instance_shadowfang_keep::OnCreatureCreate(Creature* pCreature) void instance_shadowfang_keep::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_COURTYARD_DOOR: if (m_auiEncounter[0] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - // For this we ignore voidwalkers, because if the server restarts - // They won't be there, but Fenrus is dead so the door can't be opened! + // For this we ignore voidwalkers, because if the server restarts + // They won't be there, but Fenrus is dead so the door can't be opened! case GO_SORCERER_DOOR: if (m_auiEncounter[2] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); @@ -91,10 +91,10 @@ void instance_shadowfang_keep::OnObjectCreate(GameObject* pGo) void instance_shadowfang_keep::OnCreatureDeath(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - // Remove lootable flag from Hummel - // Instance data is set to SPECIAL because the encounter depends on multiple bosses + // Remove lootable flag from Hummel + // Instance data is set to SPECIAL because the encounter depends on multiple bosses case NPC_HUMMEL: pCreature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); DoScriptText(SAY_HUMMEL_DEATH, pCreature); @@ -108,7 +108,7 @@ void instance_shadowfang_keep::OnCreatureDeath(Creature* pCreature) void instance_shadowfang_keep::OnCreatureEvade(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_HUMMEL: case NPC_FRYE: @@ -125,14 +125,14 @@ void instance_shadowfang_keep::DoSpeech() if (pAda && pAda->isAlive() && pAsh && pAsh->isAlive()) { - DoScriptText(SAY_BOSS_DIE_AD,pAda); - DoScriptText(SAY_BOSS_DIE_AS,pAsh); + DoScriptText(SAY_BOSS_DIE_AD, pAda); + DoScriptText(SAY_BOSS_DIE_AS, pAsh); } } void instance_shadowfang_keep::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_FREE_NPC: if (uiData == DONE) @@ -197,7 +197,7 @@ void instance_shadowfang_keep::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] - << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6]; + << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6]; m_strInstData = saveStream.str(); @@ -206,9 +206,9 @@ void instance_shadowfang_keep::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_shadowfang_keep::GetData(uint32 uiType) +uint32 instance_shadowfang_keep::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_FREE_NPC: return m_auiEncounter[0]; case TYPE_RETHILGORE: return m_auiEncounter[1]; @@ -234,9 +234,9 @@ void instance_shadowfang_keep::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp b/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp index 322fbe0e1..3c23e8b9e 100644 --- a/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp +++ b/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -55,7 +55,7 @@ enum GOSSIP_ITEM_DOOR = -3033000 }; -struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI +struct npc_shadowfang_prisonerAI : public npc_escortAI { npc_shadowfang_prisonerAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -67,9 +67,9 @@ struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI ScriptedInstance* m_pInstance; uint32 m_uiNpcEntry; - void WaypointReached(uint32 uiPoint) + void WaypointReached(uint32 uiPoint) override { - switch(uiPoint) + switch (uiPoint) { case 0: if (m_uiNpcEntry == NPC_ASH) @@ -118,11 +118,11 @@ struct MANGOS_DLL_DECL npc_shadowfang_prisonerAI : public npc_escortAI } } - void Reset() {} + void Reset() override {} // Let's prevent Adamant from charging into Ashcrombe's cell // And beating the crap out of him and vice versa XD - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (pWho) { @@ -144,7 +144,7 @@ bool GossipHello_npc_shadowfang_prisoner(Player* pPlayer, Creature* pCreature) ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); if (pInstance && pInstance->GetData(TYPE_FREE_NPC) != DONE && pInstance->GetData(TYPE_RETHILGORE) == DONE) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DOOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DOOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; @@ -152,7 +152,7 @@ bool GossipHello_npc_shadowfang_prisoner(Player* pPlayer, Creature* pCreature) bool GossipSelect_npc_shadowfang_prisoner(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->CLOSE_GOSSIP_MENU(); @@ -172,21 +172,21 @@ struct Waypoint }; // Cordinates for voidwalker spawns -static const Waypoint VWWaypoints[]= +static const Waypoint VWWaypoints[] = { - {-146.06f, 2172.84f, 127.953f}, // This is the initial location, in the middle of the room - {-159.547f, 2178.11f, 128.944f}, // When they come back up, they hit this point then walk back down - {-171.113f, 2182.69f, 129.255f}, - {-177.613f, 2175.59f, 128.161f}, - {-185.396f, 2178.35f, 126.413f}, - {-184.004f, 2188.31f, 124.122f}, - {-172.781f, 2188.71f, 121.611f}, - {-173.245f, 2176.93f, 119.085f}, - {-183.145f, 2176.04f, 116.995f}, - {-185.551f, 2185.77f, 114.784f}, - {-177.502f, 2190.75f, 112.681f}, - {-171.218f, 2182.61f, 110.314f}, - {-173.857f, 2175.1f, 109.255f} + { -146.06f, 2172.84f, 127.953f}, // This is the initial location, in the middle of the room + { -159.547f, 2178.11f, 128.944f}, // When they come back up, they hit this point then walk back down + { -171.113f, 2182.69f, 129.255f}, + { -177.613f, 2175.59f, 128.161f}, + { -185.396f, 2178.35f, 126.413f}, + { -184.004f, 2188.31f, 124.122f}, + { -172.781f, 2188.71f, 121.611f}, + { -173.245f, 2176.93f, 119.085f}, + { -183.145f, 2176.04f, 116.995f}, + { -185.551f, 2185.77f, 114.784f}, + { -177.502f, 2190.75f, 112.681f}, + { -171.218f, 2182.61f, 110.314f}, + { -173.857f, 2175.1f, 109.255f} }; enum @@ -198,7 +198,7 @@ enum SPELL_DARK_OFFERING = 7154 }; -struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI +struct mob_arugal_voidwalkerAI : public ScriptedAI { mob_arugal_voidwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -214,7 +214,7 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsLeader, m_bReverse, m_bWPDone; - void Reset() + void Reset() override { m_creature->SetWalk(true); m_uiDarkOffering = urand(4400, 12500); @@ -223,7 +223,7 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI Creature* pLeader = m_creature->GetMap()->GetCreature(m_leaderGuid); if (pLeader && pLeader->isAlive()) { - m_creature->GetMotionMaster()->MoveFollow(pLeader, 1.0f, M_PI/2*m_uiPosition); + m_creature->GetMotionMaster()->MoveFollow(pLeader, 1.0f, M_PI / 2 * m_uiPosition); } else { @@ -231,7 +231,7 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI Creature* pNewLeader = NULL; uint8 uiHighestPosition = 0; GetCreatureListWithEntryInGrid(lVoidwalkerList, m_creature, NPC_VOIDWALKER, 50.0f); - for(std::list::iterator itr = lVoidwalkerList.begin(); itr != lVoidwalkerList.end(); ++itr) + for (std::list::iterator itr = lVoidwalkerList.begin(); itr != lVoidwalkerList.end(); ++itr) { if ((*itr)->isAlive()) { @@ -256,7 +256,7 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI m_bWPDone = true; } else - m_creature->GetMotionMaster()->MoveFollow(pNewLeader, 1.0f, M_PI/2*m_uiPosition); + m_creature->GetMotionMaster()->MoveFollow(pNewLeader, 1.0f, M_PI / 2 * m_uiPosition); } else { @@ -267,12 +267,12 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bIsLeader && m_bWPDone) { m_creature->GetMotionMaster()->MovePoint(m_uiCurrentPoint, VWWaypoints[m_uiCurrentPoint].fX, - VWWaypoints[m_uiCurrentPoint].fY, VWWaypoints[m_uiCurrentPoint].fZ); + VWWaypoints[m_uiCurrentPoint].fY, VWWaypoints[m_uiCurrentPoint].fZ); m_bWPDone = false; } @@ -296,12 +296,12 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI DoMeleeAttackIfReady(); } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || !m_bIsLeader) return; - switch(uiPointId) + switch (uiPointId) { case 1: if (m_bReverse) @@ -323,10 +323,10 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI SendWaypoint(); } - void JustDied(Unit* /*pKiller*/) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) - m_pInstance->SetData(TYPE_VOIDWALKER,DONE); + m_pInstance->SetData(TYPE_VOIDWALKER, DONE); } void SetPosition(uint8 uiPosition, Creature* pLeader) @@ -355,7 +355,7 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI { std::list lVoidwalkerList; GetCreatureListWithEntryInGrid(lVoidwalkerList, m_creature, NPC_VOIDWALKER, 50.0f); - for(std::list::iterator itr = lVoidwalkerList.begin(); itr != lVoidwalkerList.end(); ++itr) + for (std::list::iterator itr = lVoidwalkerList.begin(); itr != lVoidwalkerList.end(); ++itr) { if ((*itr)->isAlive()) if (mob_arugal_voidwalkerAI* pVoidwalkerAI = dynamic_cast((*itr)->AI())) @@ -369,9 +369,9 @@ struct MANGOS_DLL_DECL mob_arugal_voidwalkerAI : public ScriptedAI m_bReverse = bReverse; } - void EnterEvadeMode() + void EnterEvadeMode() override { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->LoadCreatureAddon(true); @@ -419,20 +419,20 @@ struct SpawnPoint }; // Cordinates for voidwalker spawns -static const SpawnPoint VWSpawns[]= +static const SpawnPoint VWSpawns[] = { - //fX fY fZ fO - {-155.352f, 2172.780f, 128.448f, 4.679f}, - {-147.059f, 2163.193f, 128.696f, 0.128f}, - {-148.869f, 2180.859f, 128.448f, 1.814f}, - {-140.203f, 2175.263f, 128.448f, 0.373f} + // fX fY fZ fO + { -155.352f, 2172.780f, 128.448f, 4.679f}, + { -147.059f, 2163.193f, 128.696f, 0.128f}, + { -148.869f, 2180.859f, 128.448f, 1.814f}, + { -140.203f, 2175.263f, 128.448f, 0.373f} }; // Roughly the height of Fenrus' room, // Used to tell how he should behave const float HEIGHT_FENRUS_ROOM = 140.0f; -struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI +struct boss_arugalAI : public ScriptedAI { boss_arugalAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -456,7 +456,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI uint8 m_uiSpeechStep; bool m_bAttacking, m_bEventMode; - void Reset() + void Reset() override { m_uiTeleportTimer = urand(22000, 26000); m_uiCurseTimer = urand(20000, 30000); @@ -467,19 +467,19 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI m_uiSpeechStep = 1; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoScriptText(YELL_AGGRO, m_creature); DoCastSpellIfCan(pWho, SPELL_VOID_BOLT); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) DoScriptText(YELL_KILLED_PLAYER, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bEventMode) { @@ -488,7 +488,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI if (m_uiSpeechTimer < uiDiff) { - switch(m_uiSpeechStep) + switch (m_uiSpeechStep) { case 1: DoScriptText(YELL_FENRUS, m_creature); @@ -518,7 +518,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI for (uint8 i = 0; i < 4; ++i) { pVoidwalker = m_creature->SummonCreature(NPC_VOIDWALKER, VWSpawns[i].fX, - VWSpawns[i].fY, VWSpawns[i].fZ, VWSpawns[i].fO, TEMPSUMMON_DEAD_DESPAWN, 1); + VWSpawns[i].fY, VWSpawns[i].fZ, VWSpawns[i].fO, TEMPSUMMON_DEAD_DESPAWN, 1); if (!pVoidwalker) continue; @@ -622,7 +622,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI if (m_creature->IsNonMeleeSpellCasted(false)) m_creature->InterruptNonMeleeSpells(false); - switch(posNewPosition) + switch (posNewPosition) { case POSITION_SPAWN_LEDGE: DoCastSpellIfCan(m_creature, SPELL_SHADOW_PORT_SPAWN_LEDGE, true); @@ -660,7 +660,7 @@ struct MANGOS_DLL_DECL boss_arugalAI : public ScriptedAI DoMeleeAttackIfReady(); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!m_bEventMode) ScriptedAI::AttackStart(pWho); @@ -722,7 +722,7 @@ enum SPELL_SPAWN = 7741, }; -struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI +struct npc_arugalAI : public ScriptedAI { npc_arugalAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -734,7 +734,7 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI uint8 m_uiSpeechStep; ScriptedInstance* m_pInstance; - void Reset() + void Reset() override { m_uiSpeechTimer = 0; m_uiSpeechStep = 0; @@ -745,14 +745,14 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI m_uiSpeechStep = 1; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_uiSpeechStep) return; if (m_uiSpeechTimer < uiDiff) { - switch(m_uiSpeechStep) + switch (m_uiSpeechStep) { case 1: m_creature->SetVisibility(VISIBILITY_ON); @@ -764,7 +764,7 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI break; case 3: // Make him die - if (Creature* pVincent = GetClosestCreatureWithEntry(m_creature,NPC_VINCENT,20.0f)) + if (Creature* pVincent = GetClosestCreatureWithEntry(m_creature, NPC_VINCENT, 20.0f)) pVincent->SetStandState(UNIT_STAND_STATE_DEAD); m_uiSpeechTimer = 10000; @@ -805,7 +805,7 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI break; case 12: if (m_pInstance) - m_pInstance->SetData(TYPE_INTRO,DONE); + m_pInstance->SetData(TYPE_INTRO, DONE); m_creature->SetVisibility(VISIBILITY_OFF); m_uiSpeechStep = 0; @@ -820,7 +820,7 @@ struct MANGOS_DLL_DECL npc_arugalAI : public ScriptedAI m_uiSpeechTimer -= uiDiff; } - void AttackStart(Unit* /*who*/) { } + void AttackStart(Unit* /*who*/) override { } }; CreatureAI* GetAI_npc_arugal(Creature* pCreature) @@ -839,7 +839,7 @@ enum FACTION_FRIENDLY = 35 }; -struct MANGOS_DLL_DECL npc_deathstalker_vincentAI : public ScriptedAI +struct npc_deathstalker_vincentAI : public ScriptedAI { npc_deathstalker_vincentAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -849,13 +849,13 @@ struct MANGOS_DLL_DECL npc_deathstalker_vincentAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() + void Reset() override { if (m_pInstance && m_pInstance->GetData(TYPE_INTRO) == DONE && !m_creature->GetByteValue(UNIT_FIELD_BYTES_1, 0)) m_creature->SetStandState(UNIT_STAND_STATE_DEAD); } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { if (pDoneBy) { @@ -869,13 +869,13 @@ struct MANGOS_DLL_DECL npc_deathstalker_vincentAI : public ScriptedAI if (uiDamage >= m_creature->GetHealth()) { m_creature->GetHealth() > 1 ? uiDamage = m_creature->GetHealth() - 1 : uiDamage = 0; - m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_NONE); EnterEvadeMode(); DoScriptText(SAY_VINCENT_DIE, m_creature); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_creature->isInCombat() && m_creature->getFaction() == FACTION_FRIENDLY) EnterEvadeMode(); @@ -883,7 +883,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_vincentAI : public ScriptedAI ScriptedAI::UpdateAI(uiDiff); } - void EnterEvadeMode() + void EnterEvadeMode() override { m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); diff --git a/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h b/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h index 6acda8f2e..bc39e8b90 100644 --- a/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h +++ b/scripts/eastern_kingdoms/shadowfang_keep/shadowfang_keep.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -22,21 +22,21 @@ enum NPC_ASH = 3850, NPC_ADA = 3849, - // NPC_ARUGAL = 10000, //"Arugal" says intro text, not used + // NPC_ARUGAL = 10000, //"Arugal" says intro text, not used NPC_ARCHMAGE_ARUGAL = 4275, //"Archmage Arugal" does Fenrus event - NPC_FENRUS = 4274, //used to summon Arugal in Fenrus event - NPC_VINCENT = 4444, //Vincent should be "dead" is Arugal is done the intro already + NPC_FENRUS = 4274, // used to summon Arugal in Fenrus event + NPC_VINCENT = 4444, // Vincent should be "dead" is Arugal is done the intro already NPC_HUMMEL = 36296, // Love is in the Air event NPC_FRYE = 36272, NPC_BAXTER = 36565, NPC_VALENTINE_BOSS_MGR = 36643, // controller npc for the apothecary event - NPC_APOTHECARY_GENERATOR= 36212, // the npc which summons the crazed apothecary + NPC_APOTHECARY_GENERATOR = 36212, // the npc which summons the crazed apothecary - GO_COURTYARD_DOOR = 18895, //door to open when talking to NPC's - GO_SORCERER_DOOR = 18972, //door to open when Fenrus the Devourer - GO_ARUGAL_DOOR = 18971, //door to open when Wolf Master Nandos - GO_ARUGAL_FOCUS = 18973, //this generates the lightning visual in the Fenrus event + GO_COURTYARD_DOOR = 18895, // door to open when talking to NPC's + GO_SORCERER_DOOR = 18972, // door to open when Fenrus the Devourer + GO_ARUGAL_DOOR = 18971, // door to open when Wolf Master Nandos + GO_ARUGAL_FOCUS = 18973, // this generates the lightning visual in the Fenrus event GO_APOTHECARE_VIALS = 190678, // move position for Baxter GO_CHEMISTRY_SET = 200335, // move position for Frye @@ -46,25 +46,25 @@ enum MAX_APOTHECARY = 3, }; -class MANGOS_DLL_DECL instance_shadowfang_keep : public ScriptedInstance +class instance_shadowfang_keep : public ScriptedInstance { public: instance_shadowfang_keep(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; void DoSpeech(); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/eastern_kingdoms/silvermoon_city.cpp b/scripts/eastern_kingdoms/silvermoon_city.cpp index eb6284bac..e4fc3fcef 100644 --- a/scripts/eastern_kingdoms/silvermoon_city.cpp +++ b/scripts/eastern_kingdoms/silvermoon_city.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,85 +16,16 @@ /* ScriptData SDName: Silvermoon_City -SD%Complete: 100 -SDComment: Quest support: 9685 +SD%Complete: 0 +SDComment: Placeholder SDCategory: Silvermoon City EndScriptData */ /* ContentData -npc_blood_knight_stillblade EndContentData */ #include "precompiled.h" -/*####### -# npc_blood_knight_stillblade -#######*/ - -enum -{ - QUEST_REDEEMING_THE_DEAD = 9685, - - SAY_HEAL = -1000193, - SPELL_SHIMMERING_VESSEL = 31225, - SPELL_REVIVE_SELF = 32343, -}; - -struct MANGOS_DLL_DECL npc_blood_knight_stillbladeAI : public ScriptedAI -{ - npc_blood_knight_stillbladeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 m_uiLifeTimer; - bool m_bSpellHit; - - void Reset() - { - m_uiLifeTimer = 120000; - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - m_bSpellHit = false; - } - - void MoveInLineOfSight(Unit* pWho) {} - - void UpdateAI(const uint32 uiDiff) - { - if (m_creature->IsStandState()) - { - if (m_uiLifeTimer < uiDiff) - m_creature->AI()->EnterEvadeMode(); - else - m_uiLifeTimer -= uiDiff; - } - } - - void SpellHit(Unit* pCaster, const SpellEntry* pSpellInfo) - { - if ((pSpellInfo->Id == SPELL_SHIMMERING_VESSEL) && !m_bSpellHit && - (pCaster->GetTypeId() == TYPEID_PLAYER) && (((Player*)pCaster)->IsActiveQuest(QUEST_REDEEMING_THE_DEAD))) - { - ((Player*)pCaster)->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); - DoCastSpellIfCan(m_creature, SPELL_REVIVE_SELF); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0); - //m_creature->RemoveAllAuras(); - DoScriptText(SAY_HEAL, m_creature, pCaster); - m_bSpellHit = true; - } - } -}; - -CreatureAI* GetAI_npc_blood_knight_stillblade(Creature* pCreature) -{ - return new npc_blood_knight_stillbladeAI(pCreature); -} - void AddSC_silvermoon_city() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "npc_blood_knight_stillblade"; - pNewScript->GetAI = &GetAI_npc_blood_knight_stillblade; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/silverpine_forest.cpp b/scripts/eastern_kingdoms/silverpine_forest.cpp index 361491d86..aa2783b4b 100644 --- a/scripts/eastern_kingdoms/silverpine_forest.cpp +++ b/scripts/eastern_kingdoms/silverpine_forest.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -54,18 +54,18 @@ enum NPC_QUINN = 1951 }; -struct MANGOS_DLL_DECL npc_deathstalker_erlandAI : public npc_escortAI +struct npc_deathstalker_erlandAI : public npc_escortAI { npc_deathstalker_erlandAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 i) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(i) + switch (i) { case 0: DoScriptText(SAY_START_2, m_creature, pPlayer); @@ -97,11 +97,11 @@ struct MANGOS_DLL_DECL npc_deathstalker_erlandAI : public npc_escortAI } } - void Reset() {} + void Reset() override {} - void Aggro(Unit* who) + void Aggro(Unit* who) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature, who); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature, who); break; @@ -166,18 +166,18 @@ struct SpawnPoint SpawnPoint SpawnPoints[] = { - {-397.45f, 1509.56f, 18.87f, 4.73f}, - {-398.35f, 1510.75f, 18.87f, 4.76f}, - {-396.41f, 1511.06f, 18.87f, 4.74f} + { -397.45f, 1509.56f, 18.87f, 4.73f}, + { -398.35f, 1510.75f, 18.87f, 4.76f}, + { -396.41f, 1511.06f, 18.87f, 4.74f} }; -static float m_afMoveCoords[] = {-410.69f, 1498.04f, 19.77f}; +static float m_afMoveCoords[] = { -410.69f, 1498.04f, 19.77f}; -struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI +struct npc_deathstalker_faerleiaAI : public ScriptedAI { npc_deathstalker_faerleiaAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} ObjectGuid m_playerGuid; uint32 m_uiWaveTimer; @@ -203,7 +203,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) pPlayer->SendQuestFailed(QUEST_PYREWOOD_AMBUSH); @@ -211,7 +211,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI FinishEvent(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { ++m_uiSummonCount; @@ -221,7 +221,7 @@ struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); } - void SummonedCreatureJustDied(Creature* pKilled) + void SummonedCreatureJustDied(Creature* /*pKilled*/) override { --m_uiSummonCount; @@ -242,13 +242,13 @@ struct MANGOS_DLL_DECL npc_deathstalker_faerleiaAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bEventStarted && !m_uiSummonCount) { if (m_uiWaveTimer < uiDiff) { - switch(m_uiWaveCount) + switch (m_uiWaveCount) { case 0: m_creature->SummonCreature(NPC_COUNCILMAN_SMITHERS, SpawnPoints[1].fX, SpawnPoints[1].fY, SpawnPoints[1].fZ, SpawnPoints[1].fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000); diff --git a/scripts/eastern_kingdoms/stormwind_city.cpp b/scripts/eastern_kingdoms/stormwind_city.cpp index 02f9407bf..662600d17 100644 --- a/scripts/eastern_kingdoms/stormwind_city.cpp +++ b/scripts/eastern_kingdoms/stormwind_city.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Stormwind_City SD%Complete: 100 -SDComment: Quest support: 1640, 1447, 4185 +SDComment: Quest support: 1640, 1447, 4185, 6402, 6403. SDCategory: Stormwind City EndScriptData */ @@ -25,9 +25,13 @@ EndScriptData */ npc_bartleby npc_dashel_stonefist npc_lady_katrana_prestor +npc_squire_rowe +npc_reginald_windsor EndContentData */ #include "precompiled.h" +#include "../world/world_map_scripts.h" +#include "escort_ai.h" /*###### ## npc_bartleby @@ -39,23 +43,16 @@ enum QUEST_BEAT = 1640 }; -struct MANGOS_DLL_DECL npc_bartlebyAI : public ScriptedAI +struct npc_bartlebyAI : public ScriptedAI { npc_bartlebyAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiNormalFaction = pCreature->getFaction(); Reset(); } - uint32 m_uiNormalFaction; + void Reset() override {} - void Reset() - { - if (m_creature->getFaction() != m_uiNormalFaction) - m_creature->setFaction(m_uiNormalFaction); - } - - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -66,9 +63,9 @@ struct MANGOS_DLL_DECL npc_bartlebyAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { - if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() < 15)) + if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage) * 100 / m_creature->GetMaxHealth() < 15)) { uiDamage = 0; @@ -84,7 +81,7 @@ bool QuestAccept_npc_bartleby(Player* pPlayer, Creature* pCreature, const Quest* { if (pQuest->GetQuestId() == QUEST_BEAT) { - pCreature->setFaction(FACTION_ENEMY); + pCreature->SetFactionTemporary(FACTION_ENEMY, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_COMBAT_STOP); pCreature->AI()->AttackStart(pPlayer); } return true; @@ -105,23 +102,16 @@ enum FACTION_HOSTILE = 168 }; -struct MANGOS_DLL_DECL npc_dashel_stonefistAI : public ScriptedAI +struct npc_dashel_stonefistAI : public ScriptedAI { npc_dashel_stonefistAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiNormalFaction = pCreature->getFaction(); Reset(); } - uint32 m_uiNormalFaction; - - void Reset() - { - if (m_creature->getFaction() != m_uiNormalFaction) - m_creature->setFaction(m_uiNormalFaction); - } + void Reset() override {} - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -132,9 +122,9 @@ struct MANGOS_DLL_DECL npc_dashel_stonefistAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { - if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() < 15)) + if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage) * 100 / m_creature->GetMaxHealth() < 15)) { uiDamage = 0; @@ -150,7 +140,7 @@ bool QuestAccept_npc_dashel_stonefist(Player* pPlayer, Creature* pCreature, cons { if (pQuest->GetQuestId() == QUEST_MISSING_DIPLO_PT8) { - pCreature->setFaction(FACTION_HOSTILE); + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN); pCreature->AI()->AttackStart(pPlayer); } return true; @@ -183,9 +173,9 @@ bool GossipHello_npc_lady_katrana_prestor(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_lady_katrana_prestor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_lady_katrana_prestor(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); @@ -207,6 +197,859 @@ bool GossipSelect_npc_lady_katrana_prestor(Player* pPlayer, Creature* pCreature, return true; } +/*###### +## npc_squire_rowe +######*/ + +enum +{ + SAY_SIGNAL_SENT = -1000822, + SAY_DISMOUNT = -1000823, + SAY_WELCOME = -1000824, + + GOSSIP_ITEM_WINDSOR = -3000106, + + GOSSIP_TEXT_ID_DEFAULT = 9063, + GOSSIP_TEXT_ID_PROGRESS = 9064, + GOSSIP_TEXT_ID_START = 9065, + + NPC_WINDSOR_MOUNT = 12581, + + QUEST_STORMWIND_RENDEZVOUS = 6402, + QUEST_THE_GREAT_MASQUERADE = 6403, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {NPC_WINDSOR, 0, 3000}, // wait + {NPC_WINDSOR_MOUNT, 0, 1000}, // summon horse + {SAY_DISMOUNT, NPC_WINDSOR, 2000}, + {QUEST_STORMWIND_RENDEZVOUS, 0, 2000}, // face player + {QUEST_THE_GREAT_MASQUERADE, 0, 0}, // say intro to player + {0, 0, 0}, +}; + +static const float aWindsorSpawnLoc[3] = { -9145.68f, 373.79f, 90.64f}; +static const float aWindsorMoveLoc[3] = { -9050.39f, 443.55f, 93.05f}; + +struct npc_squire_roweAI : public npc_escortAI, private DialogueHelper +{ + npc_squire_roweAI(Creature* m_creature) : npc_escortAI(m_creature), + DialogueHelper(aIntroDialogue) + { + m_bIsEventInProgress = false; + Reset(); + } + + bool m_bIsEventInProgress; + + ObjectGuid m_windsorGuid; + ObjectGuid m_horseGuid; + + void Reset() override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_WINDSOR) + { + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, aWindsorMoveLoc[0], aWindsorMoveLoc[1], aWindsorMoveLoc[2]); + + m_windsorGuid = pSummoned->GetObjectGuid(); + m_bIsEventInProgress = true; + } + else if (pSummoned->GetEntry() == NPC_WINDSOR_MOUNT) + m_horseGuid = pSummoned->GetObjectGuid(); + } + + void SummonedCreatureDespawn(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_WINDSOR) + { + m_windsorGuid.Clear(); + m_bIsEventInProgress = false; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId || pSummoned->GetEntry() != NPC_WINDSOR) + return; + + // Summoned npc has escort and this can trigger twice if escort state is not checked + if (uiPointId && HasEscortState(STATE_ESCORT_PAUSED)) + StartNextDialogueText(NPC_WINDSOR); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case 3: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SummonCreature(NPC_WINDSOR, aWindsorSpawnLoc[0], aWindsorSpawnLoc[1], aWindsorSpawnLoc[2], 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + case 6: + DoScriptText(SAY_SIGNAL_SENT, m_creature); + m_creature->SetFacingTo(2.15f); + SetEscortPaused(true); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case NPC_WINDSOR_MOUNT: + { + if (Creature* pWindsor = m_creature->GetMap()->GetCreature(m_windsorGuid)) + { + pWindsor->Unmount(); + m_creature->SummonCreature(NPC_WINDSOR_MOUNT, pWindsor->GetPositionX() - 1.0f, pWindsor->GetPositionY() + 1.0f, pWindsor->GetPositionZ(), pWindsor->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 30000); + } + break; + } + case SAY_DISMOUNT: + { + if (Creature* pHorse = m_creature->GetMap()->GetCreature(m_horseGuid)) + { + pHorse->SetWalk(false); + pHorse->GetMotionMaster()->MovePoint(1, aWindsorSpawnLoc[0], aWindsorSpawnLoc[1], aWindsorSpawnLoc[2]); + } + break; + } + case QUEST_STORMWIND_RENDEZVOUS: + { + Creature* pWindsor = m_creature->GetMap()->GetCreature(m_windsorGuid); + Player* pPlayer = GetPlayerForEscort(); + if (!pWindsor || !pPlayer) + break; + + pWindsor->SetFacingToObject(pPlayer); + break; + } + case QUEST_THE_GREAT_MASQUERADE: + { + Creature* pWindsor = m_creature->GetMap()->GetCreature(m_windsorGuid); + Player* pPlayer = GetPlayerForEscort(); + if (!pWindsor || !pPlayer) + break; + + DoScriptText(SAY_WELCOME, pWindsor, pPlayer); + // Allow players to finish quest and also finish the escort + pWindsor->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + SetEscortPaused(false); + break; + } + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_WINDSOR) + return m_creature->GetMap()->GetCreature(m_windsorGuid); + + return NULL; + } + + // Check if the event is already running + bool IsStormwindQuestActive() { return m_bIsEventInProgress; } + + void UpdateEscortAI(const uint32 uiDiff) { DialogueUpdate(uiDiff); } +}; + +CreatureAI* GetAI_npc_squire_rowe(Creature* pCreature) +{ + return new npc_squire_roweAI(pCreature); +} + +bool GossipHello_npc_squire_rowe(Player* pPlayer, Creature* pCreature) +{ + // Allow gossip if quest 6402 is completed but not yet rewarded or 6402 is rewarded but 6403 isn't yet completed + if ((pPlayer->GetQuestStatus(QUEST_STORMWIND_RENDEZVOUS) == QUEST_STATUS_COMPLETE && !pPlayer->GetQuestRewardStatus(QUEST_STORMWIND_RENDEZVOUS)) || + (pPlayer->GetQuestRewardStatus(QUEST_STORMWIND_RENDEZVOUS) && pPlayer->GetQuestStatus(QUEST_THE_GREAT_MASQUERADE) != QUEST_STATUS_COMPLETE)) + { + bool bIsEventInProgress = true; + + // Check if event is already in progress + if (npc_squire_roweAI* pRoweAI = dynamic_cast(pCreature->AI())) + bIsEventInProgress = pRoweAI->IsStormwindQuestActive(); + + // If event is already in progress, then inform the player to wait + if (bIsEventInProgress) + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_PROGRESS, pCreature->GetObjectGuid()); + else + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WINDSOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_START, pCreature->GetObjectGuid()); + } + } + else + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_DEFAULT, pCreature->GetObjectGuid()); + + return true; +} + +bool GossipSelect_npc_squire_rowe(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + if (npc_squire_roweAI* pRoweAI = dynamic_cast(pCreature->AI())) + pRoweAI->Start(true, pPlayer, 0, true, false); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## npc_reginald_windsor +######*/ + +enum +{ + SAY_WINDSOR_QUEST_ACCEPT = -1000825, + SAY_WINDSOR_GET_READY = -1000826, + SAY_PRESTOR_SIEZE = -1000827, + + SAY_JON_DIALOGUE_1 = -1000828, + SAY_WINDSOR_DIALOGUE_2 = -1000829, + SAY_WINDSOR_DIALOGUE_3 = -1000830, + SAY_JON_DIALOGUE_4 = -1000832, + SAY_JON_DIALOGUE_5 = -1000833, + SAY_WINDSOR_DIALOGUE_6 = -1000834, + SAY_WINDSOR_DIALOGUE_7 = -1000835, + SAY_JON_DIALOGUE_8 = -1000836, + SAY_JON_DIALOGUE_9 = -1000837, + SAY_JON_DIALOGUE_10 = -1000838, + SAY_JON_DIALOGUE_11 = -1000839, + SAY_WINDSOR_DIALOGUE_12 = -1000840, + SAY_WINDSOR_DIALOGUE_13 = -1000841, + + SAY_WINDSOR_BEFORE_KEEP = -1000849, + SAY_WINDSOR_TO_KEEP = -1000850, + + SAY_WINDSOR_KEEP_1 = -1000851, + SAY_BOLVAR_KEEP_2 = -1000852, + SAY_WINDSOR_KEEP_3 = -1000853, + SAY_PRESTOR_KEEP_4 = -1000855, + SAY_PRESTOR_KEEP_5 = -1000856, + SAY_WINDSOR_KEEP_6 = -1000857, + SAY_WINDSOR_KEEP_7 = -1000859, + SAY_WINDSOR_KEEP_8 = -1000860, + SAY_PRESTOR_KEEP_9 = -1000863, + SAY_BOLVAR_KEEP_10 = -1000864, + SAY_PRESTOR_KEEP_11 = -1000865, + SAY_WINDSOR_KEEP_12 = -1000866, + SAY_PRESTOR_KEEP_13 = -1000867, + SAY_PRESTOR_KEEP_14 = -1000868, + SAY_BOLVAR_KEEP_15 = -1000869, + SAY_WINDSOR_KEEP_16 = -1000870, + + EMOTE_CONTEMPLATION = -1000831, + EMOTE_PRESTOR_LAUGH = -1000854, + EMOTE_WINDSOR_TABLETS = -1000858, + EMOTE_WINDSOR_READ = -1000861, + EMOTE_BOLVAR_GASP = -1000862, + EMOTE_WINDSOR_DIE = -1000871, + EMOTE_GUARD_TRANSFORM = -1000872, + + GOSSIP_ITEM_REGINALD = -3000107, + + GOSSIP_TEXT_ID_MASQUERADE = 5633, + + // SPELL_ONYXIA_TRANSFORM = 20409, // removed from DBC + SPELL_WINDSOR_READ = 20358, + SPELL_WINDSOR_DEATH = 20465, + SPELL_ONYXIA_DESPAWN = 20466, + + // combat spells + SPELL_HAMMER_OF_JUSTICE = 10308, + SPELL_SHIELD_WALL = 871, + SPELL_STRONG_CLEAVE = 8255, + + NPC_GUARD_ROYAL = 1756, + NPC_GUARD_CITY = 68, + NPC_GUARD_PATROLLER = 1976, + NPC_GUARD_ONYXIA = 12739, + NPC_LADY_ONYXIA = 12756, + + MAX_ROYAL_GUARDS = 6, + MAX_GUARD_SALUTES = 7, +}; + +static const float aGuardLocations[MAX_ROYAL_GUARDS][4] = +{ + { -8968.510f, 512.556f, 96.352f, 3.849f}, // guard right - left + { -8969.780f, 515.012f, 96.593f, 3.955f}, // guard right - middle + { -8972.410f, 518.228f, 96.594f, 4.281f}, // guard right - right + { -8965.170f, 508.565f, 96.352f, 3.825f}, // guard left - right + { -8962.960f, 506.583f, 96.593f, 3.802f}, // guard left - middle + { -8961.080f, 503.828f, 96.593f, 3.465f}, // guard left - left +}; + +static const float aMoveLocations[10][3] = +{ + { -8967.960f, 510.008f, 96.351f}, // Jonathan move + { -8959.440f, 505.424f, 96.595f}, // Guard Left - Middle kneel + { -8957.670f, 507.056f, 96.595f}, // Guard Left - Right kneel + { -8970.680f, 519.252f, 96.595f}, // Guard Right - Middle kneel + { -8969.100f, 520.395f, 96.595f}, // Guard Right - Left kneel + { -8974.590f, 516.213f, 96.590f}, // Jonathan kneel + { -8505.770f, 338.312f, 120.886f}, // Wrynn safe + { -8448.690f, 337.074f, 121.330f}, // Bolvar help + { -8448.279f, 338.398f, 121.329f} // Bolvar kneel +}; + +static const DialogueEntry aMasqueradeDialogue[] = +{ + {SAY_WINDSOR_QUEST_ACCEPT, NPC_WINDSOR, 7000}, + {SAY_WINDSOR_GET_READY, NPC_WINDSOR, 6000}, + {SAY_PRESTOR_SIEZE, NPC_PRESTOR, 0}, + + {SAY_JON_DIALOGUE_1, NPC_JONATHAN, 5000}, + {SAY_WINDSOR_DIALOGUE_2, NPC_WINDSOR, 6000}, + {SAY_WINDSOR_DIALOGUE_3, NPC_WINDSOR, 5000}, + {EMOTE_CONTEMPLATION, NPC_JONATHAN, 3000}, + {SAY_JON_DIALOGUE_4, NPC_JONATHAN, 6000}, + {SAY_JON_DIALOGUE_5, NPC_JONATHAN, 7000}, + {SAY_WINDSOR_DIALOGUE_6, NPC_WINDSOR, 8000}, + {SAY_WINDSOR_DIALOGUE_7, NPC_WINDSOR, 6000}, + {SAY_JON_DIALOGUE_8, NPC_JONATHAN, 7000}, + {SAY_JON_DIALOGUE_9, NPC_JONATHAN, 6000}, + {SAY_JON_DIALOGUE_10, NPC_JONATHAN, 5000}, + {EMOTE_ONESHOT_SALUTE, 0, 4000}, + {SAY_JON_DIALOGUE_11, NPC_JONATHAN, 3000}, + {NPC_JONATHAN, 0, 2000}, + {EMOTE_ONESHOT_KNEEL, 0, 3000}, + {SAY_WINDSOR_DIALOGUE_12, NPC_WINDSOR, 5000}, + {SAY_WINDSOR_DIALOGUE_13, NPC_WINDSOR, 3000}, + {EMOTE_ONESHOT_POINT, 0, 3000}, + {NPC_WINDSOR, 0, 0}, + + {NPC_GUARD_ROYAL, 0, 3000}, + {SAY_WINDSOR_BEFORE_KEEP, NPC_WINDSOR, 0}, + {SAY_WINDSOR_TO_KEEP, NPC_WINDSOR, 4000}, + {NPC_GUARD_CITY, 0, 0}, + + {NPC_WRYNN, 0, 3000}, + {SAY_WINDSOR_KEEP_1, NPC_WINDSOR, 3000}, + {SAY_BOLVAR_KEEP_2, NPC_BOLVAR, 2000}, + {SAY_WINDSOR_KEEP_3, NPC_WINDSOR, 4000}, + {EMOTE_PRESTOR_LAUGH, NPC_PRESTOR, 4000}, + {SAY_PRESTOR_KEEP_4, NPC_PRESTOR, 9000}, + {SAY_PRESTOR_KEEP_5, NPC_PRESTOR, 7000}, + {SAY_WINDSOR_KEEP_6, NPC_WINDSOR, 6000}, + {EMOTE_WINDSOR_TABLETS, NPC_WINDSOR, 6000}, + {SAY_WINDSOR_KEEP_7, NPC_WINDSOR, 4000}, + {SAY_WINDSOR_KEEP_8, NPC_WINDSOR, 5000}, + {EMOTE_WINDSOR_READ, NPC_WINDSOR, 3000}, + {SPELL_WINDSOR_READ, 0, 10000}, + {EMOTE_BOLVAR_GASP, NPC_BOLVAR, 3000}, + {SAY_PRESTOR_KEEP_9, NPC_PRESTOR, 4000}, + {SAY_BOLVAR_KEEP_10, NPC_BOLVAR, 3000}, + {SAY_PRESTOR_KEEP_11, NPC_PRESTOR, 2000}, + {SPELL_WINDSOR_DEATH, 0, 1500}, + {SAY_WINDSOR_KEEP_12, NPC_WINDSOR, 4000}, + {SAY_PRESTOR_KEEP_14, NPC_PRESTOR, 0}, + + {NPC_GUARD_ONYXIA, 0, 14000}, + {NPC_BOLVAR, 0, 2000}, + {SAY_BOLVAR_KEEP_15, NPC_BOLVAR, 8000}, + {NPC_GUARD_PATROLLER, 0, 0}, + {0, 0, 0}, +}; + +static const int32 aGuardSalute[MAX_GUARD_SALUTES] = { -1000842, -1000843, -1000844, -1000845, -1000846, -1000847, -1000848}; + +struct npc_reginald_windsorAI : public npc_escortAI, private DialogueHelper +{ + npc_reginald_windsorAI(Creature* m_creature) : npc_escortAI(m_creature), + DialogueHelper(aMasqueradeDialogue) + { + m_pScriptedMap = (ScriptedMap*)m_creature->GetInstanceData(); + // Npc flag is controlled by script + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + InitializeDialogueHelper(m_pScriptedMap); + Reset(); + } + + ScriptedMap* m_pScriptedMap; + + uint32 m_uiGuardCheckTimer; + uint8 m_uiOnyxiaGuardCount; + + uint32 m_uiHammerTimer; + uint32 m_uiCleaveTimer; + + bool m_bIsKeepReady; + bool m_bCanGuardSalute; + + ObjectGuid m_playerGuid; + ObjectGuid m_guardsGuid[MAX_ROYAL_GUARDS]; + + GuidList m_lRoyalGuardsGuidList; + GuidSet m_sGuardsSalutedGuidSet; + + void Reset() override + { + m_uiGuardCheckTimer = 0; + m_bIsKeepReady = false; + m_bCanGuardSalute = false; + + m_uiHammerTimer = urand(0, 1000); + m_uiCleaveTimer = urand(1000, 3000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_SHIELD_WALL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // Note: this implementation is not the best; It should be better handled by the guard script + if (m_bCanGuardSalute && (pWho->GetEntry() == NPC_GUARD_CITY || pWho->GetEntry() == NPC_GUARD_ROYAL || + pWho->GetEntry() == NPC_GUARD_PATROLLER) && pWho->IsWithinDistInMap(m_creature, 15.0f) && + m_sGuardsSalutedGuidSet.find(pWho->GetObjectGuid()) == m_sGuardsSalutedGuidSet.end() && pWho->IsWithinLOSInMap(m_creature)) + { + DoScriptText(aGuardSalute[urand(0, MAX_GUARD_SALUTES - 1)], pWho); + m_sGuardsSalutedGuidSet.insert(pWho->GetObjectGuid()); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + if (!m_pScriptedMap) + break; + // Prepare Jonathan for the first event + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + { + // Summon 3 guards on each side and move Jonathan in the middle + for (uint8 i = 0; i < MAX_ROYAL_GUARDS; ++i) + { + if (Creature* pTemp = m_creature->SummonCreature(NPC_GUARD_ROYAL, aGuardLocations[i][0], aGuardLocations[i][1], aGuardLocations[i][2], aGuardLocations[i][3], TEMPSUMMON_TIMED_DESPAWN, 180000)) + m_guardsGuid[i] = pTemp->GetObjectGuid(); + } + + pJonathan->SetWalk(false); + pJonathan->Unmount(); + pJonathan->GetMotionMaster()->MovePoint(0, aMoveLocations[0][0], aMoveLocations[0][1], aMoveLocations[0][2]); + } + break; + case 1: + StartNextDialogueText(SAY_JON_DIALOGUE_1); + SetEscortPaused(true); + break; + case 3: + m_bCanGuardSalute = true; + break; + case 11: + if (!m_pScriptedMap) + break; + // We can reset Jonathan now + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + { + pJonathan->SetWalk(true); + pJonathan->SetStandState(UNIT_STAND_STATE_STAND); + pJonathan->GetMotionMaster()->MoveTargetedHome(); + } + break; + case 22: + SetEscortPaused(true); + m_creature->SetFacingTo(5.41f); + StartNextDialogueText(NPC_GUARD_ROYAL); + break; + case 24: + m_bCanGuardSalute = false; + break; + case 25: + StartNextDialogueText(NPC_WRYNN); + SetEscortPaused(true); + m_bCanGuardSalute = false; + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId || pSummoned->GetEntry() != NPC_GUARD_ROYAL) + return; + + // Handle city gates royal guards + switch (uiPointId) + { + case 1: + case 2: + pSummoned->SetFacingTo(2.234f); + pSummoned->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case 3: + case 4: + pSummoned->SetFacingTo(5.375f); + pSummoned->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pScriptedMap) + return; + + switch (iEntry) + { + // Set orientation and prepare the npcs for the next event + case SAY_WINDSOR_GET_READY: + m_creature->SetFacingTo(0.6f); + break; + case SAY_PRESTOR_SIEZE: + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + Start(false, pPlayer); + break; + case SAY_JON_DIALOGUE_8: + // Turn left and move the guards + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + pJonathan->SetFacingTo(5.375f); + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardsGuid[5])) + { + pGuard->SetFacingTo(2.234f); + pGuard->SetStandState(UNIT_STAND_STATE_KNEEL); + } + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardsGuid[4])) + pGuard->GetMotionMaster()->MovePoint(1, aMoveLocations[1][0], aMoveLocations[1][1], aMoveLocations[1][2]); + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardsGuid[3])) + pGuard->GetMotionMaster()->MovePoint(2, aMoveLocations[2][0], aMoveLocations[2][1], aMoveLocations[2][2]); + break; + case SAY_JON_DIALOGUE_9: + // Turn right and move the guards + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + pJonathan->SetFacingTo(2.234f); + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardsGuid[2])) + { + pGuard->SetFacingTo(5.375f); + pGuard->SetStandState(UNIT_STAND_STATE_KNEEL); + } + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardsGuid[1])) + pGuard->GetMotionMaster()->MovePoint(3, aMoveLocations[3][0], aMoveLocations[3][1], aMoveLocations[3][2]); + if (Creature* pGuard = m_creature->GetMap()->GetCreature(m_guardsGuid[0])) + pGuard->GetMotionMaster()->MovePoint(4, aMoveLocations[4][0], aMoveLocations[4][1], aMoveLocations[4][2]); + break; + case SAY_JON_DIALOGUE_10: + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + pJonathan->SetFacingToObject(m_creature); + break; + case EMOTE_ONESHOT_SALUTE: + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + pJonathan->HandleEmote(EMOTE_ONESHOT_SALUTE); + break; + case NPC_JONATHAN: + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + { + pJonathan->SetWalk(true); + pJonathan->GetMotionMaster()->MovePoint(0, aMoveLocations[5][0], aMoveLocations[5][1], aMoveLocations[5][2]); + } + break; + case EMOTE_ONESHOT_KNEEL: + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + { + pJonathan->SetFacingToObject(m_creature); + pJonathan->SetStandState(UNIT_STAND_STATE_KNEEL); + } + break; + case SAY_WINDSOR_DIALOGUE_12: + if (Creature* pJonathan = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_JONATHAN)) + m_creature->SetFacingToObject(pJonathan); + break; + case SAY_WINDSOR_DIALOGUE_13: + m_creature->SetFacingTo(0.6f); + break; + case EMOTE_ONESHOT_POINT: + m_creature->HandleEmote(EMOTE_ONESHOT_POINT); + break; + case NPC_WINDSOR: + SetEscortPaused(false); + break; + case SAY_WINDSOR_BEFORE_KEEP: + m_bIsKeepReady = true; + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + case NPC_GUARD_CITY: + SetEscortPaused(false); + break; + case NPC_WRYNN: + // Remove npc flags during the event + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + pOnyxia->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + if (Creature* pWrynn = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_WRYNN)) + pWrynn->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + pBolvar->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + break; + case SAY_BOLVAR_KEEP_2: + if (Creature* pWrynn = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_WRYNN)) + { + pWrynn->SetWalk(false); + pWrynn->ForcedDespawn(15000); + pWrynn->GetMotionMaster()->MovePoint(0, aMoveLocations[6][0], aMoveLocations[6][1], aMoveLocations[6][2]); + + // Store all the nearby guards, in order to transform them into Onyxia guards + std::list lGuardsList; + GetCreatureListWithEntryInGrid(lGuardsList, pWrynn, NPC_GUARD_ROYAL, 25.0f); + + for (std::list::const_iterator itr = lGuardsList.begin(); itr != lGuardsList.end(); ++itr) + m_lRoyalGuardsGuidList.push_back((*itr)->GetObjectGuid()); + } + break; + case SPELL_WINDSOR_READ: + DoCastSpellIfCan(m_creature, SPELL_WINDSOR_READ); + break; + case EMOTE_BOLVAR_GASP: + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + { + pOnyxia->UpdateEntry(NPC_LADY_ONYXIA); + + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + pBolvar->SetFacingToObject(pOnyxia); + } + break; + case SAY_PRESTOR_KEEP_9: + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + { + pBolvar->SetWalk(false); + pBolvar->GetMotionMaster()->MovePoint(0, aMoveLocations[7][0], aMoveLocations[7][1], aMoveLocations[7][2]); + } + break; + case SAY_BOLVAR_KEEP_10: + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + { + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + { + pBolvar->SetFacingToObject(pOnyxia); + DoScriptText(EMOTE_PRESTOR_LAUGH, pOnyxia); + } + } + break; + case SAY_PRESTOR_KEEP_11: + for (GuidList::const_iterator itr = m_lRoyalGuardsGuidList.begin(); itr != m_lRoyalGuardsGuidList.end(); ++itr) + { + if (Creature* pGuard = m_creature->GetMap()->GetCreature(*itr)) + { + if (!pGuard->isAlive()) + continue; + + pGuard->UpdateEntry(NPC_GUARD_ONYXIA); + DoScriptText(EMOTE_GUARD_TRANSFORM, pGuard); + + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + pGuard->AI()->AttackStart(pBolvar); + } + } + m_uiGuardCheckTimer = 1000; + break; + case SPELL_WINDSOR_DEATH: + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + pOnyxia->CastSpell(m_creature, SPELL_WINDSOR_DEATH, false); + break; + case SAY_WINDSOR_KEEP_12: + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + DoScriptText(SAY_PRESTOR_KEEP_13, pOnyxia); + + // Fake death + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(0); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + break; + case SAY_PRESTOR_KEEP_14: + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + { + pOnyxia->ForcedDespawn(1000); + pOnyxia->HandleEmote(EMOTE_ONESHOT_LIFTOFF); + pOnyxia->CastSpell(pOnyxia, SPELL_ONYXIA_DESPAWN, false); + } + break; + case NPC_GUARD_ONYXIA: + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + pBolvar->GetMotionMaster()->MovePoint(0, aMoveLocations[7][0], aMoveLocations[7][1], aMoveLocations[7][2]); + break; + case NPC_BOLVAR: + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + { + pBolvar->SetWalk(true); + pBolvar->GetMotionMaster()->MovePoint(0, aMoveLocations[8][0], aMoveLocations[8][1], aMoveLocations[8][2]); + } + break; + case SAY_BOLVAR_KEEP_15: + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + pBolvar->SetStandState(UNIT_STAND_STATE_KNEEL); + + DoScriptText(SAY_WINDSOR_KEEP_16, m_creature); + DoScriptText(EMOTE_WINDSOR_DIE, m_creature); + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->GroupEventHappens(QUEST_THE_GREAT_MASQUERADE, m_creature); + break; + case NPC_GUARD_PATROLLER: + // Reset Bolvar and Wrynn + if (Creature* pBolvar = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_BOLVAR)) + { + pBolvar->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + pBolvar->SetStandState(UNIT_STAND_STATE_STAND); + pBolvar->GetMotionMaster()->MoveTargetedHome(); + } + if (Creature* pWrynn = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_WRYNN)) + { + pWrynn->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + pWrynn->Respawn(); + pWrynn->SetWalk(true); + pWrynn->GetMotionMaster()->MoveTargetedHome(); + } + // Onyxia will respawn by herself in about 30 min, so just reset flags + if (Creature* pOnyxia = m_pScriptedMap->GetSingleCreatureFromStorage(NPC_PRESTOR)) + pOnyxia->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + // Allow creature to despawn + SetEscortPaused(false); + break; + } + } + + void DoStartKeepEvent() + { + StartNextDialogueText(SAY_WINDSOR_TO_KEEP); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + void DoStartEscort(Player* pPlayer) + { + StartNextDialogueText(SAY_WINDSOR_QUEST_ACCEPT); + m_playerGuid = pPlayer->GetObjectGuid(); + } + + bool IsKeepEventReady() { return m_bIsKeepReady; } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + // Check if all Onyxia guards are dead + if (m_uiGuardCheckTimer) + { + if (m_uiGuardCheckTimer <= uiDiff) + { + uint8 uiDeadGuardsCount = 0; + for (GuidList::const_iterator itr = m_lRoyalGuardsGuidList.begin(); itr != m_lRoyalGuardsGuidList.end(); ++itr) + { + if (Creature* pGuard = m_creature->GetMap()->GetCreature(*itr)) + { + if (!pGuard->isAlive() && pGuard->GetEntry() == NPC_GUARD_ONYXIA) + ++uiDeadGuardsCount; + } + } + if (uiDeadGuardsCount == m_lRoyalGuardsGuidList.size()) + { + StartNextDialogueText(NPC_GUARD_ONYXIA); + m_uiGuardCheckTimer = 0; + } + else + m_uiGuardCheckTimer = 1000; + } + else + m_uiGuardCheckTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHammerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE) == CAST_OK) + m_uiHammerTimer = 60000; + } + else + m_uiHammerTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRONG_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(1000, 5000); + } + else + m_uiCleaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_reginald_windsor(Creature* pCreature) +{ + return new npc_reginald_windsorAI(pCreature); +} + +bool QuestAccept_npc_reginald_windsor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_THE_GREAT_MASQUERADE) + { + if (npc_reginald_windsorAI* pReginaldAI = dynamic_cast(pCreature->AI())) + pReginaldAI->DoStartEscort(pPlayer); + } + + return true; +} + +bool GossipHello_npc_reginald_windsor(Player* pPlayer, Creature* pCreature) +{ + bool bIsEventReady = false; + + if (npc_reginald_windsorAI* pReginaldAI = dynamic_cast(pCreature->AI())) + bIsEventReady = pReginaldAI->IsKeepEventReady(); + + // Check if event is possible and also check the status of the quests + if (bIsEventReady && pPlayer->GetQuestStatus(QUEST_THE_GREAT_MASQUERADE) != QUEST_STATUS_COMPLETE && pPlayer->GetQuestRewardStatus(QUEST_STORMWIND_RENDEZVOUS)) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_REGINALD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_MASQUERADE, pCreature->GetObjectGuid()); + } + else + { + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetObjectGuid()); + } + + return true; +} + +bool GossipSelect_npc_reginald_windsor(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + if (npc_reginald_windsorAI* pReginaldAI = dynamic_cast(pCreature->AI())) + pReginaldAI->DoStartKeepEvent(); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + void AddSC_stormwind_city() { Script* pNewScript; @@ -228,4 +1071,19 @@ void AddSC_stormwind_city() pNewScript->pGossipHello = &GossipHello_npc_lady_katrana_prestor; pNewScript->pGossipSelect = &GossipSelect_npc_lady_katrana_prestor; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_squire_rowe"; + pNewScript->GetAI = &GetAI_npc_squire_rowe; + pNewScript->pGossipHello = &GossipHello_npc_squire_rowe; + pNewScript->pGossipSelect = &GossipSelect_npc_squire_rowe; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_reginald_windsor"; + pNewScript->GetAI = &GetAI_npc_reginald_windsor; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_reginald_windsor; + pNewScript->pGossipHello = &GossipHello_npc_reginald_windsor; + pNewScript->pGossipSelect = &GossipSelect_npc_reginald_windsor; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/stranglethorn_vale.cpp b/scripts/eastern_kingdoms/stranglethorn_vale.cpp index e7bd3dce9..cd48a1a4e 100644 --- a/scripts/eastern_kingdoms/stranglethorn_vale.cpp +++ b/scripts/eastern_kingdoms/stranglethorn_vale.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,65 +31,77 @@ EndContentData */ ## mob_yenniku ######*/ -struct MANGOS_DLL_DECL mob_yennikuAI : public ScriptedAI +enum { - mob_yennikuAI(Creature *c) : ScriptedAI(c) - { - bReset = false; - Reset(); - } + SPELL_YENNIKUS_RELEASE = 3607, - uint32 Reset_Timer; - bool bReset; + QUEST_ID_SAVING_YENNIKU = 592, - void Reset() - { - Reset_Timer = 0; - m_creature->HandleEmote(EMOTE_STATE_NONE); - } + FACTION_ID_HORDE_GENERIC = 83, // Note: faction may not be correct! +}; - void SpellHit(Unit *caster, const SpellEntry *spell) +struct mob_yennikuAI : public ScriptedAI +{ + mob_yennikuAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiResetTimer; + + void Reset() override { m_uiResetTimer = 0; } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (caster->GetTypeId() == TYPEID_PLAYER) + if (pSpell->Id == SPELL_YENNIKUS_RELEASE && pCaster->GetTypeId() == TYPEID_PLAYER) { - //Yenniku's Release - if (!bReset && ((Player*)caster)->GetQuestStatus(592) == QUEST_STATUS_INCOMPLETE && spell->Id == 3607) + if (!m_uiResetTimer && ((Player*)pCaster)->GetQuestStatus(QUEST_ID_SAVING_YENNIKU) == QUEST_STATUS_INCOMPLETE) { - m_creature->HandleEmote(EMOTE_STATE_STUN); - m_creature->CombatStop(); //stop combat - m_creature->DeleteThreatList(); //unsure of this - m_creature->setFaction(83); //horde generic - - bReset = true; - Reset_Timer = 60000; + m_uiResetTimer = 60000; + EnterEvadeMode(); } } - return; } - void Aggro(Unit *who) {} + void EnterEvadeMode() override + { + if (m_uiResetTimer) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); - void UpdateAI(const uint32 diff) + m_creature->HandleEmote(EMOTE_STATE_STUN); + m_creature->SetFactionTemporary(FACTION_ID_HORDE_GENERIC, TEMPFACTION_RESTORE_REACH_HOME); + } + else + ScriptedAI::EnterEvadeMode(); + } + + void UpdateAI(const uint32 uiDiff) override { - if (bReset) - if (Reset_Timer < diff) + if (m_uiResetTimer) { - EnterEvadeMode(); - bReset = false; - m_creature->setFaction(28); //troll, bloodscalp + if (m_uiResetTimer <= uiDiff) + { + m_creature->HandleEmote(EMOTE_STATE_NONE); + m_uiResetTimer = 0; + EnterEvadeMode(); + } + else + m_uiResetTimer -= uiDiff; } - else Reset_Timer -= diff; - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_mob_yenniku(Creature *_Creature) + +CreatureAI* GetAI_mob_yenniku(Creature* _Creature) { - return new mob_yennikuAI (_Creature); + return new mob_yennikuAI(_Creature); } /*###### diff --git a/scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp b/scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp deleted file mode 100644 index 553a93edc..000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_baron_rivendare.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Baron_Rivendare -SD%Complete: 70 -SDComment: aura applied/defined in database -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" -#include "stratholme.h" - -enum -{ - SPELL_SHADOW_BOLT = 17393, - SPELL_CLEAVE = 15284, - SPELL_MORTAL_STRIKE = 15708, - - SPELL_RAISE_DEAD = 17473, //triggers death pact (17471) - - SPELL_RAISE_DEAD_1 = 17475, - SPELL_RAISE_DEAD_2 = 17476, - SPELL_RAISE_DEAD_3 = 17477, - SPELL_RAISE_DEAD_4 = 17478, - SPELL_RAISE_DEAD_5 = 17479, - SPELL_RAISE_DEAD_6 = 17480 -}; - -struct MANGOS_DLL_DECL boss_baron_rivendareAI : public ScriptedAI -{ - boss_baron_rivendareAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiShadowBoltTimer; - uint32 m_uiCleaveTimer; - uint32 m_uiMortalStrikeTimer; - uint32 m_uiRaiseDeadTimer; - - void Reset() - { - m_uiShadowBoltTimer = 5000; - m_uiCleaveTimer = 8000; - m_uiMortalStrikeTimer = 12000; - m_uiRaiseDeadTimer = 30000; - } - - void JustSummoned(Creature* pSummoned) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); - } - - void SpellHit(Unit* pWho, const SpellEntry* pSpell) - { - if (pSpell->Id == SPELL_RAISE_DEAD) - { - DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD_1, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD_2, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD_3, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD_4, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD_5, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD_6, CAST_TRIGGERED); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // ShadowBolt - if (m_uiShadowBoltTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_BOLT) == CAST_OK) - m_uiShadowBoltTimer = 10000; - } - } - else - m_uiShadowBoltTimer -= uiDiff; - - // Cleave - if (m_uiCleaveTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) - m_uiCleaveTimer = urand(7000, 17000); - } - else - m_uiCleaveTimer -= uiDiff; - - // MortalStrike - if (m_uiMortalStrikeTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) - m_uiMortalStrikeTimer = urand(10000, 25000); - } - else - m_uiMortalStrikeTimer -= uiDiff; - - // RaiseDead - if (m_uiRaiseDeadTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD) == CAST_OK) - m_uiRaiseDeadTimer = 45000; - } - else - m_uiRaiseDeadTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_baron_rivendare(Creature* pCreature) -{ - return new boss_baron_rivendareAI(pCreature); -} - -void AddSC_boss_baron_rivendare() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_baron_rivendare"; - pNewScript->GetAI = &GetAI_boss_baron_rivendare; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp b/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp index b396245d9..5690d5c4b 100644 --- a/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp +++ b/scripts/eastern_kingdoms/stratholme/boss_baroness_anastari.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Baroness_Anastari -SD%Complete: 75 -SDComment: Possess event NYI +SD%Complete: 100 +SDComment: SDCategory: Stratholme EndScriptData */ @@ -29,10 +29,11 @@ enum SPELL_BANSHEE_CURSE = 16867, SPELL_SILENCE = 18327, SPELL_POSSESS = 17244, + SPELL_POSSESSED = 17246, SPELL_POSSESS_INV = 17250, // baroness becomes invisible while possessing a target }; -struct MANGOS_DLL_DECL boss_baroness_anastariAI : public ScriptedAI +struct boss_baroness_anastariAI : public ScriptedAI { boss_baroness_anastariAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -40,17 +41,67 @@ struct MANGOS_DLL_DECL boss_baroness_anastariAI : public ScriptedAI uint32 m_uiBansheeCurseTimer; uint32 m_uiSilenceTimer; uint32 m_uiPossessTimer; + uint32 m_uiPossessEndTimer; - void Reset() + ObjectGuid m_possessedPlayer; + + void Reset() override { m_uiBansheeWailTimer = 0; m_uiBansheeCurseTimer = 10000; m_uiSilenceTimer = 25000; m_uiPossessTimer = 15000; + m_uiPossessEndTimer = 0; + } + + void EnterEvadeMode() override + { + // If it's invisible don't evade + if (m_uiPossessEndTimer) + return; + + ScriptedAI::EnterEvadeMode(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (m_uiPossessEndTimer) + { + // Check if the possessed player has been damaged + if (m_uiPossessEndTimer <= uiDiff) + { + // If aura has expired, return to fight + if (!m_creature->HasAura(SPELL_POSSESS_INV)) + { + m_uiPossessEndTimer = 0; + return; + } + + // Check for possessed player + Player* pPlayer = m_creature->GetMap()->GetPlayer(m_possessedPlayer); + if (!pPlayer || !pPlayer->isAlive()) + { + m_creature->RemoveAurasDueToSpell(SPELL_POSSESS_INV); + m_uiPossessEndTimer = 0; + return; + } + + // If possessed player has less than 50% health + if (pPlayer->GetHealth() <= pPlayer->GetMaxHealth() * .5f) + { + m_creature->RemoveAurasDueToSpell(SPELL_POSSESS_INV); + pPlayer->RemoveAurasDueToSpell(SPELL_POSSESSED); + pPlayer->RemoveAurasDueToSpell(SPELL_POSSESS); + m_uiPossessEndTimer = 0; + return; + } + + m_uiPossessEndTimer = 1000; + } + else + m_uiPossessEndTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -88,20 +139,23 @@ struct MANGOS_DLL_DECL boss_baroness_anastariAI : public ScriptedAI m_uiSilenceTimer -= uiDiff; // Possess - // ToDo: uncomment this when the event is properly implemented - /*if (m_uiPossessTimer < uiDiff) + if (m_uiPossessTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_POSSESS, SELECT_FLAG_PLAYER)) { if (DoCastSpellIfCan(pTarget, SPELL_POSSESS) == CAST_OK) { + DoCastSpellIfCan(pTarget, SPELL_POSSESSED, CAST_TRIGGERED); DoCastSpellIfCan(m_creature, SPELL_POSSESS_INV, CAST_TRIGGERED); + + m_possessedPlayer = pTarget->GetObjectGuid(); + m_uiPossessEndTimer = 1000; m_uiPossessTimer = 30000; } } } else - m_uiPossessTimer -= uiDiff;*/ + m_uiPossessTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp b/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp index 2e610cc9a..07f08fe74 100644 --- a/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp +++ b/scripts/eastern_kingdoms/stratholme/boss_cannon_master_willey.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_SUMMON_RIFLEMAN = 17279, // spell needs script target }; -struct MANGOS_DLL_DECL boss_cannon_master_willeyAI : public ScriptedAI +struct boss_cannon_master_willeyAI : public ScriptedAI { boss_cannon_master_willeyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -40,7 +40,7 @@ struct MANGOS_DLL_DECL boss_cannon_master_willeyAI : public ScriptedAI uint32 m_uiShootTimer; uint32 m_uiSummonRiflemanTimer; - void Reset() + void Reset() override { m_uiShootTimer = 1000; m_uiPummelTimer = 7000; @@ -48,15 +48,15 @@ struct MANGOS_DLL_DECL boss_cannon_master_willeyAI : public ScriptedAI m_uiSummonRiflemanTimer = 15000; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (m_creature->getVictim()) pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp b/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp index ad749dd9b..960cb4e26 100644 --- a/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp +++ b/scripts/eastern_kingdoms/stratholme/boss_dathrohan_balnazzar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,15 +29,15 @@ enum SAY_TRANSFORM = -1329017, SAY_DEATH = -1329018, - //Dathrohan spells - SPELL_CRUSADERSHAMMER = 17286, //AOE stun + // Dathrohan spells + SPELL_CRUSADERSHAMMER = 17286, // AOE stun SPELL_CRUSADERSTRIKE = 17281, - SPELL_HOLYSTRIKE = 17284, //weapon dmg +3 + SPELL_HOLYSTRIKE = 17284, // weapon dmg +3 - //Transform - SPELL_BALNAZZARTRANSFORM = 17288, //restore full HP/mana, trigger spell Balnazzar Transform Stun + // Transform + SPELL_BALNAZZARTRANSFORM = 17288, // restore full HP/mana, trigger spell Balnazzar Transform Stun - //Balnazzar spells + // Balnazzar spells SPELL_SHADOWSHOCK = 17399, SPELL_MINDBLAST = 17287, SPELL_PSYCHICSCREAM = 13704, @@ -56,7 +56,7 @@ struct SummonDef float m_fX, m_fY, m_fZ, m_fOrient; }; -SummonDef m_aSummonPoint[]= +SummonDef m_aSummonPoint[] = { {NPC_SKELETAL_BERSERKER, 3460.356f, -3070.572f, 135.086f, 0.332f}, {NPC_SKELETAL_BERSERKER, 3465.289f, -3069.987f, 135.086f, 5.480f}, @@ -73,7 +73,7 @@ SummonDef m_aSummonPoint[]= {NPC_SKELETAL_GUARDIAN, 3518.825f, -3060.926f, 135.080f, 3.944f} }; -struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI +struct boss_dathrohan_balnazzarAI : public ScriptedAI { boss_dathrohan_balnazzarAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -87,7 +87,7 @@ struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI uint32 m_uiMindControl_Timer; bool m_bTransformed; - void Reset() + void Reset() override { m_uiCrusadersHammer_Timer = 8000; m_uiCrusaderStrike_Timer = 12000; @@ -101,66 +101,67 @@ struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI if (m_creature->GetEntry() == NPC_BALNAZZAR) m_creature->UpdateEntry(NPC_DATHROHAN); - } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* Victim) + void JustDied(Unit* /*Victim*/) override { DoScriptText(SAY_DEATH, m_creature); - static uint32 uiCount = sizeof(m_aSummonPoint)/sizeof(SummonDef); - - for (uint32 i = 0; i < uiCount; ++i) + for (uint32 i = 0; i < countof(m_aSummonPoint); ++i) m_creature->SummonCreature(m_aSummonPoint[i].m_uiEntry, - m_aSummonPoint[i].m_fX, m_aSummonPoint[i].m_fY, m_aSummonPoint[i].m_fZ, m_aSummonPoint[i].m_fOrient, - TEMPSUMMON_TIMED_DESPAWN, HOUR*IN_MILLISECONDS); + m_aSummonPoint[i].m_fX, m_aSummonPoint[i].m_fY, m_aSummonPoint[i].m_fZ, m_aSummonPoint[i].m_fOrient, + TEMPSUMMON_TIMED_DESPAWN, HOUR * IN_MILLISECONDS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //START NOT TRANSFORMED + // START NOT TRANSFORMED if (!m_bTransformed) { - //MindBlast + // MindBlast if (m_uiMindBlast_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MINDBLAST); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MINDBLAST); m_uiMindBlast_Timer = urand(15000, 20000); - }else m_uiMindBlast_Timer -= uiDiff; + } + else m_uiMindBlast_Timer -= uiDiff; - //CrusadersHammer + // CrusadersHammer if (m_uiCrusadersHammer_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CRUSADERSHAMMER); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSADERSHAMMER); m_uiCrusadersHammer_Timer = 12000; - }else m_uiCrusadersHammer_Timer -= uiDiff; + } + else m_uiCrusadersHammer_Timer -= uiDiff; - //CrusaderStrike + // CrusaderStrike if (m_uiCrusaderStrike_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CRUSADERSTRIKE); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSADERSTRIKE); m_uiCrusaderStrike_Timer = 15000; - }else m_uiCrusaderStrike_Timer -= uiDiff; + } + else m_uiCrusaderStrike_Timer -= uiDiff; - //HolyStrike + // HolyStrike if (m_uiHolyStrike_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HOLYSTRIKE); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLYSTRIKE); m_uiHolyStrike_Timer = 15000; - }else m_uiHolyStrike_Timer -= uiDiff; + } + else m_uiHolyStrike_Timer -= uiDiff; - //BalnazzarTransform + // BalnazzarTransform if (m_creature->GetHealthPercent() < 40.0f) { - //restore hp, mana and stun + // restore hp, mana and stun if (DoCastSpellIfCan(m_creature, SPELL_BALNAZZARTRANSFORM) == CAST_OK) { m_creature->UpdateEntry(NPC_BALNAZZAR); @@ -171,44 +172,49 @@ struct MANGOS_DLL_DECL boss_dathrohan_balnazzarAI : public ScriptedAI } else { - //MindBlast + // MindBlast if (m_uiMindBlast_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MINDBLAST); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MINDBLAST); m_uiMindBlast_Timer = urand(15000, 20000); - }else m_uiMindBlast_Timer -= uiDiff; + } + else m_uiMindBlast_Timer -= uiDiff; - //ShadowShock + // ShadowShock if (m_uiShadowShock_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWSHOCK); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWSHOCK); m_uiShadowShock_Timer = 11000; - }else m_uiShadowShock_Timer -= uiDiff; + } + else m_uiShadowShock_Timer -= uiDiff; - //PsychicScream + // PsychicScream if (m_uiPsychicScream_Timer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget,SPELL_PSYCHICSCREAM); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_PSYCHICSCREAM); m_uiPsychicScream_Timer = 20000; - }else m_uiPsychicScream_Timer -= uiDiff; + } + else m_uiPsychicScream_Timer -= uiDiff; - //DeepSleep + // DeepSleep if (m_uiDeepSleep_Timer < uiDiff) { - if (Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget,SPELL_SLEEP); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_SLEEP); m_uiDeepSleep_Timer = 15000; - }else m_uiDeepSleep_Timer -= uiDiff; + } + else m_uiDeepSleep_Timer -= uiDiff; - //MindControl + // MindControl if (m_uiMindControl_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MINDCONTROL); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MINDCONTROL); m_uiMindControl_Timer = 15000; - }else m_uiMindControl_Timer -= uiDiff; + } + else m_uiMindControl_Timer -= uiDiff; } DoMeleeAttackIfReady(); diff --git a/scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp b/scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp deleted file mode 100644 index 81335ccd2..000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_magistrate_barthilas.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Magistrate_Barthilas -SD%Complete: 70 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_DRAINING_BLOW = 16793, - SPELL_CROWD_PUMMEL = 10887, - SPELL_MIGHTY_BLOW = 14099, - SPELL_FURIOUS_ANGER = 16792, - - MODEL_HUMAN = 3637 -}; - -struct MANGOS_DLL_DECL boss_magistrate_barthilasAI : public ScriptedAI -{ - boss_magistrate_barthilasAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 m_uiDrainingBlowTimer; - uint32 m_uiCrowdPummelTimer; - uint32 m_uiMightyBlowTimer; - - void Reset() - { - m_uiDrainingBlowTimer = 20000; - m_uiCrowdPummelTimer = 15000; - m_uiMightyBlowTimer = 10000; - } - - void Aggro(Unit* pWho) - { - DoCastSpellIfCan(m_creature, SPELL_FURIOUS_ANGER); - } - - void JustDied(Unit* pKiller) - { - m_creature->SetDisplayId(MODEL_HUMAN); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // DrainingBlow - if (m_uiDrainingBlowTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DRAINING_BLOW) == CAST_OK) - m_uiDrainingBlowTimer = 15000; - } - else - m_uiDrainingBlowTimer -= uiDiff; - - // CrowdPummel - if (m_uiCrowdPummelTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_CROWD_PUMMEL) == CAST_OK) - m_uiCrowdPummelTimer = 15000; - } - else - m_uiCrowdPummelTimer -= uiDiff; - - // MightyBlow - if (m_uiMightyBlowTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTY_BLOW) == CAST_OK) - m_uiMightyBlowTimer = 20000; - } - else - m_uiMightyBlowTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_magistrate_barthilas(Creature* pCreature) -{ - return new boss_magistrate_barthilasAI(pCreature); -} - -void AddSC_boss_magistrate_barthilas() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_magistrate_barthilas"; - pNewScript->GetAI = &GetAI_boss_magistrate_barthilas; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp b/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp index c53fdade4..ed2b6051c 100644 --- a/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp +++ b/scripts/eastern_kingdoms/stratholme/boss_maleki_the_pallid.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_ICE_TOMB = 16869 }; -struct MANGOS_DLL_DECL boss_maleki_the_pallidAI : public ScriptedAI +struct boss_maleki_the_pallidAI : public ScriptedAI { boss_maleki_the_pallidAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -40,7 +40,7 @@ struct MANGOS_DLL_DECL boss_maleki_the_pallidAI : public ScriptedAI uint32 m_uiIceTombTimer; uint32 m_uiDrainLifeTimer; - void Reset() + void Reset() override { m_uiDrainManaTimer = 30000; m_uiFrostboltTimer = 0; @@ -48,7 +48,7 @@ struct MANGOS_DLL_DECL boss_maleki_the_pallidAI : public ScriptedAI m_uiDrainLifeTimer = 20000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp b/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp deleted file mode 100644 index 8687f598c..000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_nerubenkan.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Nerubenkan -SD%Complete: 70 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -enum -{ - SPELL_ENCASING_WEBS = 4962, - SPELL_PIERCE_ARMOR = 6016, - SPELL_CRYPT_SCARABS = 31602, - SPELL_RAISE_UNDEAD_SCARAB = 17235 -}; - -struct MANGOS_DLL_DECL boss_nerubenkanAI : public ScriptedAI -{ - boss_nerubenkanAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 m_uiEncasingWebsTimer; - uint32 m_uiPierceArmorTimer; - uint32 m_uiCryptScarabsTimer; - uint32 m_uiRaiseUndeadScarabTimer; - - void Reset() - { - m_uiCryptScarabsTimer = 3000; - m_uiEncasingWebsTimer = 7000; - m_uiPierceArmorTimer = 19000; - m_uiRaiseUndeadScarabTimer = 3000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // EncasingWebs - if (m_uiEncasingWebsTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - { - if (DoCastSpellIfCan(pTarget, SPELL_ENCASING_WEBS) == CAST_OK) - m_uiEncasingWebsTimer = 30000; - } - } - else - m_uiEncasingWebsTimer -= uiDiff; - - // PierceArmor - if (m_uiPierceArmorTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PIERCE_ARMOR) == CAST_OK) - m_uiPierceArmorTimer = 35000; - } - else - m_uiPierceArmorTimer -= uiDiff; - - // CryptScarabs - if (m_uiCryptScarabsTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(pTarget, SPELL_CRYPT_SCARABS) == CAST_OK) - m_uiCryptScarabsTimer = 16000; - } - } - else - m_uiCryptScarabsTimer -= uiDiff; - - // RaiseUndeadScarab - if (m_uiRaiseUndeadScarabTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_RAISE_UNDEAD_SCARAB) == CAST_OK) - m_uiRaiseUndeadScarabTimer = 18000; - } - else - m_uiRaiseUndeadScarabTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_nerubenkan(Creature* pCreature) -{ - return new boss_nerubenkanAI(pCreature); -} - -void AddSC_boss_nerubenkan() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_nerubenkan"; - pNewScript->GetAI = &GetAI_boss_nerubenkan; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp b/scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp index 9c2b51eb1..227f772ab 100644 --- a/scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp +++ b/scripts/eastern_kingdoms/stratholme/boss_order_of_silver_hand.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -70,12 +70,12 @@ static SilverHandAbilityStruct m_aSilverHandAbility[8] = {NPC_VICAR_HYERONIMUS, SPELL_BLESSING, TARGET_TYPE_FRIENDLY, 2000, 13000}, {NPC_VICAR_HYERONIMUS, SPELL_HOLY_LIGHT, TARGET_TYPE_FRIENDLY, 5000, 9000}, }; -struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI +struct boss_silver_hand_bossesAI : public ScriptedAI { boss_silver_hand_bossesAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_stratholme*)pCreature->GetInstanceData(); - for (uint8 i = 0; i < sizeof(m_aSilverHandAbility); ++i) + for (uint8 i = 0; i < countof(m_aSilverHandAbility); ++i) { if (m_aSilverHandAbility[i].m_uiCreatureEntry == m_creature->GetEntry()) m_mSpellTimers[i] = m_aSilverHandAbility[i].m_uiInitialTimer; @@ -87,13 +87,13 @@ struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI UNORDERED_MAP m_mSpellTimers; - void Reset() + void Reset() override { for (UNORDERED_MAP::iterator itr = m_mSpellTimers.begin(); itr != m_mSpellTimers.end(); ++itr) itr->second = m_aSilverHandAbility[itr->first].m_uiInitialTimer; } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (m_pInstance) { @@ -116,7 +116,7 @@ struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI { Unit* pTarget = NULL; - switch(m_aSilverHandAbility[uiIndex].m_uiTargetType) + switch (m_aSilverHandAbility[uiIndex].m_uiTargetType) { case TARGET_TYPE_SELF: pTarget = m_creature; @@ -141,9 +141,9 @@ struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -163,7 +163,6 @@ struct MANGOS_DLL_DECL boss_silver_hand_bossesAI : public ScriptedAI DoMeleeAttackIfReady(); } - }; CreatureAI* GetAI_boss_silver_hand_bossesAI(Creature* pCreature) diff --git a/scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp b/scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp deleted file mode 100644 index f11809ab7..000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_postmaster_malown.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: boss_postmaster_malown -SD%Complete: 50 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -//Spell ID to summon this guy is 24627 "Summon Postmaster Malown" -//He should be spawned along with three other elites once the third postbox has been opened - -#define SAY_MALOWNED "You just got MALOWNED!" - -#define SPELL_WAILINGDEAD 7713 -#define SPELL_BACKHAND 6253 -#define SPELL_CURSEOFWEAKNESS 8552 -#define SPELL_CURSEOFTONGUES 12889 -#define SPELL_CALLOFTHEGRAVE 17831 - -struct MANGOS_DLL_DECL boss_postmaster_malownAI : public ScriptedAI -{ - boss_postmaster_malownAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 WailingDead_Timer; - uint32 Backhand_Timer; - uint32 CurseOfWeakness_Timer; - uint32 CurseOfTongues_Timer; - uint32 CallOfTheGrave_Timer; - bool HasYelled; - - void Reset() - { - WailingDead_Timer = 19000; //lasts 6 sec - Backhand_Timer = 8000; //2 sec stun - CurseOfWeakness_Timer = 20000; //lasts 2 mins - CurseOfTongues_Timer = 22000; - CallOfTheGrave_Timer = 25000; - HasYelled = false; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //WailingDead - if (WailingDead_Timer < diff) - { - //Cast - if (rand()%100 < 65) //65% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_WAILINGDEAD); - } - //19 seconds until we should cast this again - WailingDead_Timer = 19000; - }else WailingDead_Timer -= diff; - - //Backhand - if (Backhand_Timer < diff) - { - //Cast - if (rand()%100 < 45) //45% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_BACKHAND); - } - //8 seconds until we should cast this again - Backhand_Timer = 8000; - }else Backhand_Timer -= diff; - - //CurseOfWeakness - if (CurseOfWeakness_Timer < diff) - { - //Cast - if (rand()%100 < 3) //3% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFWEAKNESS); - } - //20 seconds until we should cast this again - CurseOfWeakness_Timer = 20000; - }else CurseOfWeakness_Timer -= diff; - - //CurseOfTongues - if (CurseOfTongues_Timer < diff) - { - //Cast - if (rand()%100 < 3) //3% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CURSEOFTONGUES); - } - //22 seconds until we should cast this again - CurseOfTongues_Timer = 22000; - }else CurseOfTongues_Timer -= diff; - - //CallOfTheGrave - if (CallOfTheGrave_Timer < diff) - { - //Cast - if (rand()%100 < 5) //5% chance to cast - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CALLOFTHEGRAVE); - } - //25 seconds until we should cast this again - CallOfTheGrave_Timer = 25000; - }else CallOfTheGrave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_postmaster_malown(Creature* pCreature) -{ - return new boss_postmaster_malownAI(pCreature); -} - -void AddSC_boss_postmaster_malown() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_postmaster_malown"; - pNewScript->GetAI = &GetAI_boss_postmaster_malown; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp b/scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp deleted file mode 100644 index ebdeac2bf..000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_ramstein_the_gorger.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Ramstein_the_Gorger -SD%Complete: 70 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" -#include "stratholme.h" - -#define SPELL_TRAMPLE 5568 -#define SPELL_KNOCKOUT 17307 - -struct MANGOS_DLL_DECL boss_ramstein_the_gorgerAI : public ScriptedAI -{ - boss_ramstein_the_gorgerAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 Trample_Timer; - uint32 Knockout_Timer; - - void Reset() - { - Trample_Timer = 3000; - Knockout_Timer = 12000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Trample - if (Trample_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_TRAMPLE); - Trample_Timer = 7000; - }else Trample_Timer -= diff; - - //Knockout - if (Knockout_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKOUT); - Knockout_Timer = 10000; - }else Knockout_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ramstein_the_gorger(Creature* pCreature) -{ - return new boss_ramstein_the_gorgerAI(pCreature); -} - -void AddSC_boss_ramstein_the_gorger() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_ramstein_the_gorger"; - pNewScript->GetAI = &GetAI_boss_ramstein_the_gorger; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp b/scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp deleted file mode 100644 index 9a6fa8cca..000000000 --- a/scripts/eastern_kingdoms/stratholme/boss_timmy_the_cruel.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: boss_timmy_the_cruel -SD%Complete: 100 -SDComment: -SDCategory: Stratholme -EndScriptData */ - -#include "precompiled.h" - -#define SAY_SPAWN "TIMMY!" - -#define SPELL_RAVENOUSCLAW 17470 - -struct MANGOS_DLL_DECL boss_timmy_the_cruelAI : public ScriptedAI -{ - boss_timmy_the_cruelAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 RavenousClaw_Timer; - - void Reset() - { - RavenousClaw_Timer = 10000; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //RavenousClaw - if (RavenousClaw_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_RAVENOUSCLAW); - RavenousClaw_Timer = 15000; - }else RavenousClaw_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_timmy_the_cruel(Creature* pCreature) -{ - return new boss_timmy_the_cruelAI(pCreature); -} - -void AddSC_boss_timmy_the_cruel() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_timmy_the_cruel"; - pNewScript->GetAI = &GetAI_boss_timmy_the_cruel; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp b/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp index 14552b452..5b79d4359 100644 --- a/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp +++ b/scripts/eastern_kingdoms/stratholme/instance_stratholme.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -61,7 +61,7 @@ bool instance_stratholme::StartSlaugtherSquare() void instance_stratholme::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_BARON: case NPC_YSIDA_TRIGGER: @@ -93,13 +93,13 @@ void instance_stratholme::OnCreatureCreate(Creature* pCreature) void instance_stratholme::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_SERVICE_ENTRANCE: break; case GO_GAUNTLET_GATE1: // TODO - //weird, but unless flag is set, client will not respond as expected. DB bug? + // weird, but unless flag is set, client will not respond as expected. DB bug? pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); break; @@ -152,10 +152,10 @@ void instance_stratholme::OnObjectCreate(GameObject* pGo) void instance_stratholme::SetData(uint32 uiType, uint32 uiData) { // TODO: Remove the hard-coded indexes from array accessing - switch(uiType) + switch (uiType) { case TYPE_BARON_RUN: - switch(uiData) + switch (uiData) { case IN_PROGRESS: if (m_auiEncounter[uiType] == IN_PROGRESS || m_auiEncounter[uiType] == FAIL) @@ -163,11 +163,11 @@ void instance_stratholme::SetData(uint32 uiType, uint32 uiData) DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_START, NPC_BARON); - m_uiBaronRunTimer = 45*MINUTE*IN_MILLISECONDS; + m_uiBaronRunTimer = 45 * MINUTE * IN_MILLISECONDS; debug_log("SD2: Instance Stratholme: Baron run in progress."); break; case FAIL: - //may add code to remove aura from players, but in theory the time should be up already and removed. + // may add code to remove aura from players, but in theory the time should be up already and removed. break; case DONE: m_uiBaronRunTimer = 0; @@ -197,7 +197,7 @@ void instance_stratholme::SetData(uint32 uiType, uint32 uiData) } uint32 uiCount = m_sAbomnationGUID.size(); - for(GUIDSet::iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end();) + for (GuidSet::iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end();) { if (Creature* pAbom = instance->GetCreature(*itr)) { @@ -249,7 +249,7 @@ void instance_stratholme::SetData(uint32 uiType, uint32 uiData) // Summon 5 guards if (Creature* pBaron = GetSingleCreatureFromStorage(NPC_BARON)) { - for(uint8 i = 0; i < 5; ++i) + for (uint8 i = 0; i < 5; ++i) { float fX, fY, fZ; pBaron->GetRandomPoint(aStratholmeLocation[6].m_fX, aStratholmeLocation[6].m_fY, aStratholmeLocation[6].m_fZ, 5.0f, fX, fY, fZ); @@ -267,7 +267,7 @@ void instance_stratholme::SetData(uint32 uiType, uint32 uiData) m_uiSlaugtherSquareTimer = 0; // Let already moving Abomnations stop - for (GUIDSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr) + for (GuidSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr) { Creature* pAbom = instance->GetCreature(*itr); if (pAbom && pAbom->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) @@ -294,7 +294,7 @@ void instance_stratholme::SetData(uint32 uiType, uint32 uiData) { Map::PlayerList const& players = instance->GetPlayers(); - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if (Player* pPlayer = itr->getSource()) { @@ -394,7 +394,7 @@ void instance_stratholme::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6]; m_strInstData = saveStream.str(); @@ -415,7 +415,7 @@ void instance_stratholme::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { @@ -434,9 +434,9 @@ void instance_stratholme::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_stratholme::GetData(uint32 uiType) +uint32 instance_stratholme::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_BARON_RUN: case TYPE_BARONESS: @@ -464,7 +464,7 @@ void instance_stratholme::DoSortZiggurats() return; std::list lAcolytes; // Valid pointers, only used locally - for (GUIDList::const_iterator itr = m_luiAcolyteGUIDs.begin(); itr != m_luiAcolyteGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiAcolyteGUIDs.begin(); itr != m_luiAcolyteGUIDs.end(); ++itr) { if (Creature* pAcolyte = instance->GetCreature(*itr)) lAcolytes.push_back(pAcolyte); @@ -483,7 +483,7 @@ void instance_stratholme::DoSortZiggurats() } // Sort Acolytes - for (std::list::iterator itr = lAcolytes.begin(); itr != lAcolytes.end(); ) + for (std::list::iterator itr = lAcolytes.begin(); itr != lAcolytes.end();) { bool bAlreadyIterated = false; for (uint8 i = 0; i < MAX_ZIGGURATS; ++i) @@ -509,7 +509,7 @@ void instance_stratholme::DoSortZiggurats() m_luiAcolyteGUIDs.push_back((*itr)->GetObjectGuid()); // Sort Crystal - for (GUIDList::iterator itr = m_luiCrystalGUIDs.begin(); itr != m_luiCrystalGUIDs.end(); ) + for (GuidList::iterator itr = m_luiCrystalGUIDs.begin(); itr != m_luiCrystalGUIDs.end();) { Creature* pCrystal = instance->GetCreature(*itr); if (!pCrystal) @@ -546,7 +546,7 @@ void instance_stratholme::OnCreatureEnterCombat(Creature* pCreature) case NPC_MALEKI_THE_PALLID: SetData(TYPE_PALLID, IN_PROGRESS); break; case NPC_NERUBENKAN: SetData(TYPE_NERUB, IN_PROGRESS); break; case NPC_RAMSTEIN: SetData(TYPE_RAMSTEIN, IN_PROGRESS); break; - // TODO - uncomment when proper working within core! case NPC_BARON: SetData(TYPE_BARON, IN_PROGRESS); break; + // TODO - uncomment when proper working within core! case NPC_BARON: SetData(TYPE_BARON, IN_PROGRESS); break; case NPC_ABOM_BILE: case NPC_ABOM_VENOM: @@ -570,7 +570,7 @@ void instance_stratholme::OnCreatureEvade(Creature* pCreature) case NPC_MALEKI_THE_PALLID: SetData(TYPE_PALLID, FAIL); break; case NPC_NERUBENKAN: SetData(TYPE_NERUB, FAIL); break; case NPC_RAMSTEIN: SetData(TYPE_RAMSTEIN, FAIL); break; - // TODO - uncomment when proper working within core! case NPC_BARON: SetData(TYPE_BARON, FAIL); break; + // TODO - uncomment when proper working within core! case NPC_BARON: SetData(TYPE_BARON, FAIL); break; case NPC_ABOM_BILE: case NPC_ABOM_VENOM: @@ -610,7 +610,7 @@ void instance_stratholme::OnCreatureDeath(Creature* pCreature) if (m_luiUndeadGUIDs.empty()) { // Let the black Guards move out of the citadel - for (GUIDList::const_iterator itr = m_luiGuardGUIDs.begin(); itr != m_luiGuardGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiGuardGUIDs.begin(); itr != m_luiGuardGUIDs.end(); ++itr) { Creature* pGuard = instance->GetCreature(*itr); if (pGuard && pGuard->isAlive() && !pGuard->isInCombat()) @@ -629,7 +629,7 @@ void instance_stratholme::OnCreatureDeath(Creature* pCreature) break; - // Timmy spawn support + // Timmy spawn support case NPC_CRIMSON_INITIATE: case NPC_CRIMSON_GALLANT: case NPC_CRIMSON_GUARDSMAN: @@ -693,12 +693,12 @@ void instance_stratholme::Update(uint32 uiDiff) if (m_uiBaronRunTimer) { - if (m_uiYellCounter == 0 && m_uiBaronRunTimer <= 10*MINUTE*IN_MILLISECONDS) + if (m_uiYellCounter == 0 && m_uiBaronRunTimer <= 10 * MINUTE * IN_MILLISECONDS) { DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_10_MIN, NPC_BARON); ++m_uiYellCounter; } - else if (m_uiYellCounter == 1 && m_uiBaronRunTimer <= 5*MINUTE*IN_MILLISECONDS) + else if (m_uiYellCounter == 1 && m_uiBaronRunTimer <= 5 * MINUTE * IN_MILLISECONDS) { DoOrSimulateScriptTextForThisInstance(SAY_ANNOUNCE_RUN_5_MIN, NPC_BARON); ++m_uiYellCounter; @@ -749,7 +749,7 @@ void instance_stratholme::Update(uint32 uiDiff) if (m_uiSlaugtherSquareTimer <= uiDiff) { // Call next Abomnations - for (GUIDSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr) + for (GuidSet::const_iterator itr = m_sAbomnationGUID.begin(); itr != m_sAbomnationGUID.end(); ++itr) { Creature* pAbom = instance->GetCreature(*itr); // Skip killed and already walking Abomnations diff --git a/scripts/eastern_kingdoms/stratholme/stratholme.cpp b/scripts/eastern_kingdoms/stratholme/stratholme.cpp index d98345f53..54ec3f428 100644 --- a/scripts/eastern_kingdoms/stratholme/stratholme.cpp +++ b/scripts/eastern_kingdoms/stratholme/stratholme.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,7 +25,6 @@ EndScriptData */ go_service_gate go_gauntlet_gate go_stratholme_postbox -mob_freed_soul mob_restless_soul mobs_spectral_ghostly_citizen EndContentData */ @@ -37,7 +36,7 @@ EndContentData */ ## go_service_gate ######*/ -bool GOUse_go_service_gate(Player* pPlayer, GameObject* pGo) +bool GOUse_go_service_gate(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); @@ -66,9 +65,9 @@ bool GOUse_go_gauntlet_gate(Player* pPlayer, GameObject* pGo) if (pInstance->GetData(TYPE_BARON_RUN) != NOT_STARTED) return false; - if (Group *pGroup = pPlayer->GetGroup()) + if (Group* pGroup = pPlayer->GetGroup()) { - for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) + for (GroupReference* itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* pGroupie = itr->getSource(); if (!pGroupie) @@ -123,45 +122,17 @@ bool GOUse_go_stratholme_postbox(Player* pPlayer, GameObject* pGo) } /*###### -## mob_freed_soul +## mob_restless_soul ######*/ -// Possibly more of these quotes around. enum { + // Possibly more of these quotes around. SAY_ZAPPED0 = -1329000, SAY_ZAPPED1 = -1329001, SAY_ZAPPED2 = -1329002, SAY_ZAPPED3 = -1329003, -}; - -struct MANGOS_DLL_DECL mob_freed_soulAI : public ScriptedAI -{ - mob_freed_soulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - void Reset() - { - switch(urand(0, 3)) - { - case 0: DoScriptText(SAY_ZAPPED0, m_creature); break; - case 1: DoScriptText(SAY_ZAPPED1, m_creature); break; - case 2: DoScriptText(SAY_ZAPPED2, m_creature); break; - case 3: DoScriptText(SAY_ZAPPED3, m_creature); break; - } - } -}; -CreatureAI* GetAI_mob_freed_soul(Creature* pCreature) -{ - return new mob_freed_soulAI(pCreature); -} - -/*###### -## mob_restless_soul -######*/ - -enum -{ QUEST_RESTLESS_SOUL = 5282, SPELL_EGAN_BLASTER = 17368, @@ -172,7 +143,7 @@ enum }; // TODO - likely entirely not needed workaround -struct MANGOS_DLL_DECL mob_restless_soulAI : public ScriptedAI +struct mob_restless_soulAI : public ScriptedAI { mob_restless_soulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -180,14 +151,14 @@ struct MANGOS_DLL_DECL mob_restless_soulAI : public ScriptedAI uint32 m_uiDieTimer; bool m_bIsTagged; - void Reset() + void Reset() override { m_taggerGuid.Clear(); m_uiDieTimer = 5000; m_bIsTagged = false; } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pCaster->GetTypeId() == TYPEID_PLAYER) { @@ -199,18 +170,29 @@ struct MANGOS_DLL_DECL mob_restless_soulAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - pSummoned->CastSpell(pSummoned, SPELL_SOUL_FREED, false); + if (pSummoned->GetEntry() == NPC_FREED_SOUL) + { + pSummoned->CastSpell(pSummoned, SPELL_SOUL_FREED, false); + + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_ZAPPED0, pSummoned); break; + case 1: DoScriptText(SAY_ZAPPED1, pSummoned); break; + case 2: DoScriptText(SAY_ZAPPED2, pSummoned); break; + case 3: DoScriptText(SAY_ZAPPED3, pSummoned); break; + } + } } - void JustDied(Unit* Killer) + void JustDied(Unit* /*Killer*/) override { if (m_bIsTagged) m_creature->SummonCreature(NPC_FREED_SOUL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 300000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bIsTagged) { @@ -240,30 +222,30 @@ enum SPELL_SLAP = 6754 }; -struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI +struct mobs_spectral_ghostly_citizenAI : public ScriptedAI { mobs_spectral_ghostly_citizenAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint32 m_uiDieTimer; bool m_bIsTagged; - void Reset() + void Reset() override { m_uiDieTimer = 5000; m_bIsTagged = false; } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (!m_bIsTagged && pSpell->Id == SPELL_EGAN_BLASTER) m_bIsTagged = true; } - void JustDied(Unit* Killer) + void JustDied(Unit* /*Killer*/) override { if (m_bIsTagged) { - for(uint32 i = 0; i < 4; ++i) + for (uint32 i = 0; i < 4; ++i) { float x, y, z; m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, x, y, z); @@ -276,7 +258,7 @@ struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bIsTagged) { @@ -294,9 +276,9 @@ struct MANGOS_DLL_DECL mobs_spectral_ghostly_citizenAI : public ScriptedAI DoMeleeAttackIfReady(); } - void ReceiveEmote(Player* pPlayer, uint32 uiEmote) + void ReceiveEmote(Player* pPlayer, uint32 uiEmote) override { - switch(uiEmote) + switch (uiEmote) { case TEXTEMOTE_DANCE: EnterEvadeMode(); @@ -344,11 +326,6 @@ void AddSC_stratholme() pNewScript->pGOUse = &GOUse_go_stratholme_postbox; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "mob_freed_soul"; - pNewScript->GetAI = &GetAI_mob_freed_soul; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "mob_restless_soul"; pNewScript->GetAI = &GetAI_mob_restless_soul; diff --git a/scripts/eastern_kingdoms/stratholme/stratholme.h b/scripts/eastern_kingdoms/stratholme/stratholme.h index ab0443d21..ccfe73351 100644 --- a/scripts/eastern_kingdoms/stratholme/stratholme.h +++ b/scripts/eastern_kingdoms/stratholme/stratholme.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -108,36 +108,36 @@ struct ZigguratStore { ObjectGuid m_doorGuid; ObjectGuid m_crystalGuid; - GUIDList m_lZigguratAcolyteGuid; + GuidList m_lZigguratAcolyteGuid; }; -class MANGOS_DLL_DECL instance_stratholme : public ScriptedInstance +class instance_stratholme : public ScriptedInstance { public: instance_stratholme(Map* pMap); ~instance_stratholme() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; protected: bool StartSlaugtherSquare(); void DoSortZiggurats(); - void ThazudinAcolyteJustDied( Creature* pCreature ); + void ThazudinAcolyteJustDied(Creature* pCreature); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; @@ -155,11 +155,11 @@ class MANGOS_DLL_DECL instance_stratholme : public ScriptedInstance ZigguratStore m_zigguratStorage[MAX_ZIGGURATS]; std::set m_suiCrimsonLowGuids; - GUIDList m_luiCrystalGUIDs; - GUIDSet m_sAbomnationGUID; - GUIDList m_luiAcolyteGUIDs; - GUIDList m_luiUndeadGUIDs; - GUIDList m_luiGuardGUIDs; + GuidList m_luiCrystalGUIDs; + GuidSet m_sAbomnationGUID; + GuidList m_luiAcolyteGUIDs; + GuidList m_luiUndeadGUIDs; + GuidList m_luiGuardGUIDs; }; #endif diff --git a/scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp b/scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp index f77708088..a0541e1f8 100644 --- a/scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp +++ b/scripts/eastern_kingdoms/sunken_temple/instance_sunken_temple.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,13 +25,13 @@ EndScriptData */ #include "sunken_temple.h" instance_sunken_temple::instance_sunken_temple(Map* pMap) : ScriptedInstance(pMap), + m_uiProtectorsRemaining(0), m_uiStatueCounter(0), + m_uiFlameCounter(0), m_uiAvatarSummonTimer(0), m_uiSupressorTimer(0), - m_uiFlameCounter(0), - m_uiProtectorsRemaining(0), - m_bCanSummonBloodkeeper(false), - m_bIsFirstHakkarWave(false) + m_bIsFirstHakkarWave(false), + m_bCanSummonBloodkeeper(false) { Initialize(); } @@ -43,7 +43,7 @@ void instance_sunken_temple::Initialize() void instance_sunken_temple::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_JAMMALAN_BARRIER: if (m_auiEncounter[TYPE_PROTECTORS] == DONE) @@ -75,7 +75,7 @@ void instance_sunken_temple::OnObjectCreate(GameObject* pGo) void instance_sunken_temple::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ZOLO: case NPC_GASHER: @@ -87,6 +87,7 @@ void instance_sunken_temple::OnCreatureCreate(Creature* pCreature) break; case NPC_JAMMALAN: case NPC_ATALARION: + case NPC_SHADE_OF_ERANIKUS: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; } @@ -96,13 +97,17 @@ void instance_sunken_temple::OnCreatureEvade(Creature* pCreature) { switch (pCreature->GetEntry()) { - // Hakkar Event Mobs: On Wipe set as failed! + // Hakkar Event Mobs: On Wipe set as failed! case NPC_BLOODKEEPER: case NPC_HAKKARI_MINION: case NPC_SUPPRESSOR: case NPC_AVATAR_OF_HAKKAR: SetData(TYPE_AVATAR, FAIL); break; + // Shade of Eranikus: prevent it to become unattackable after a wipe + case NPC_SHADE_OF_ERANIKUS: + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + break; } } @@ -118,7 +123,7 @@ void instance_sunken_temple::OnCreatureDeath(Creature* pCreature) m_bCanSummonBloodkeeper = true; break; - // Jammalain mini-bosses + // Jammalain mini-bosses case NPC_ZOLO: case NPC_GASHER: case NPC_LORO: @@ -132,7 +137,7 @@ void instance_sunken_temple::OnCreatureDeath(Creature* pCreature) void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ATALARION: if (uiData == SPECIAL) @@ -153,6 +158,11 @@ void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData) } break; case TYPE_JAMMALAN: + if (uiData == DONE) + { + if (Creature* pEranikus = GetSingleCreatureFromStorage(NPC_SHADE_OF_ERANIKUS)) + pEranikus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } m_auiEncounter[uiType] = uiData; break; case TYPE_AVATAR: @@ -166,12 +176,12 @@ void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData) switch (m_uiFlameCounter) { - // Yells on each flame - // TODO It might be possible that these yells should be ordered randomly, however this is the seen state + // Yells on each flame + // TODO It might be possible that these yells should be ordered randomly, however this is the seen state case 1: DoScriptText(SAY_AVATAR_BRAZIER_1, pShade); break; case 2: DoScriptText(SAY_AVATAR_BRAZIER_2, pShade); break; case 3: DoScriptText(SAY_AVATAR_BRAZIER_3, pShade); break; - // Summon the avatar of all flames are used + // Summon the avatar of all flames are used case MAX_FLAMES: DoScriptText(SAY_AVATAR_BRAZIER_4, pShade); pShade->CastSpell(pShade, SPELL_SUMMON_AVATAR, true); @@ -213,8 +223,8 @@ void instance_sunken_temple::SetData(uint32 uiType, uint32 uiData) } // Respawn circles - for (GUIDVector::const_iterator itr = m_vuiCircleGUIDs.begin(); itr != m_vuiCircleGUIDs.end(); ++itr) - DoRespawnGameObject(*itr, 30*MINUTE); + for (GuidVector::const_iterator itr = m_vuiCircleGUIDs.begin(); itr != m_vuiCircleGUIDs.end(); ++itr) + DoRespawnGameObject(*itr, 30 * MINUTE); } else if (uiData == FAIL) { @@ -270,8 +280,8 @@ void instance_sunken_temple::DoSpawnAtalarionIfCan() DoRespawnGameObject(GO_IDOL_OF_HAKKAR, 30 * MINUTE); // Spawn the big green lights - for (GUIDList::const_iterator itr = m_luiBigLightGUIDs.begin(); itr != m_luiBigLightGUIDs.end(); ++itr) - DoRespawnGameObject(*itr, 30*MINUTE); + for (GuidList::const_iterator itr = m_luiBigLightGUIDs.begin(); itr != m_luiBigLightGUIDs.end(); ++itr) + DoRespawnGameObject(*itr, 30 * MINUTE); } bool instance_sunken_temple::ProcessStatueEvent(uint32 uiEventId) @@ -303,7 +313,7 @@ bool instance_sunken_temple::ProcessStatueEvent(uint32 uiEventId) void instance_sunken_temple::DoUpdateFlamesFlags(bool bRestore) { - for (GUIDList::const_iterator itr = m_luiFlameGUIDs.begin(); itr != m_luiFlameGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiFlameGUIDs.begin(); itr != m_luiFlameGUIDs.end(); ++itr) DoToggleGameObjectFlags(*itr, GO_FLAG_NO_INTERACT, bRestore); } @@ -320,7 +330,7 @@ void instance_sunken_temple::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { // Here a bit custom, to have proper mechanics for the statue events if (m_auiEncounter[i] != DONE) @@ -330,7 +340,7 @@ void instance_sunken_temple::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_sunken_temple::GetData(uint32 uiType) +uint32 instance_sunken_temple::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -359,7 +369,7 @@ void instance_sunken_temple::Update(uint32 uiDiff) if (m_bIsFirstHakkarWave) // First wave summoned { // Summon at all circles - for (GUIDVector::const_iterator itr = m_vuiCircleGUIDs.begin(); itr != m_vuiCircleGUIDs.end(); ++itr) + for (GuidVector::const_iterator itr = m_vuiCircleGUIDs.begin(); itr != m_vuiCircleGUIDs.end(); ++itr) { if (GameObject* pCircle = instance->GetGameObject(*itr)) pShade->SummonCreature(NPC_HAKKARI_MINION, pCircle->GetPositionX(), pCircle->GetPositionY(), pCircle->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); diff --git a/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp b/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp index 2784307b7..1556cd6ee 100644 --- a/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp +++ b/scripts/eastern_kingdoms/sunken_temple/sunken_temple.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,14 +39,14 @@ enum QUEST_ERANIKUS_TYRANT_OF_DREAMS = 8733 }; -bool AreaTrigger_at_shade_of_eranikus(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_shade_of_eranikus(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) { // Only do stuff, if the player has finished the PreQuest if (pPlayer->GetQuestRewardStatus(QUEST_THE_CHARGE_OF_DRAGONFLIGHTS) && - !pPlayer->GetQuestRewardStatus(QUEST_ERANIKUS_TYRANT_OF_DREAMS) && - pPlayer->GetQuestStatus(QUEST_ERANIKUS_TYRANT_OF_DREAMS) != QUEST_STATUS_COMPLETE) + !pPlayer->GetQuestRewardStatus(QUEST_ERANIKUS_TYRANT_OF_DREAMS) && + pPlayer->GetQuestStatus(QUEST_ERANIKUS_TYRANT_OF_DREAMS) != QUEST_STATUS_COMPLETE) { if (pInstance->GetData(TYPE_MALFURION) != DONE) { @@ -73,21 +73,26 @@ enum MAX_MALFURION_TEMPLE_SPEECHES = 6 }; -struct MANGOS_DLL_DECL npc_malfurionAI : public ScriptedAI +struct npc_malfurionAI : public ScriptedAI { npc_malfurionAI(Creature* pCreature) : ScriptedAI(pCreature) { - DoScriptText(EMOTE_MALFURION1, m_creature); - m_uiSpeech = 0; - m_uiSayTimer = 3000; + // Only in Sunken Temple + if (m_creature->GetMap()->IsDungeon()) + { + DoScriptText(EMOTE_MALFURION1, m_creature); + m_uiSpeech = 0; + m_uiSayTimer = 3000; + } + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } uint32 m_uiSayTimer; uint32 m_uiSpeech; - void Reset() {} - void UpdateAI(const uint32 uiDiff) + void Reset() override {} + void UpdateAI(const uint32 uiDiff) override { // We are in Sunken Temple if (m_creature->GetMap()->IsDungeon()) @@ -143,7 +148,7 @@ CreatureAI* GetAI_npc_malfurion(Creature* pCreature) ## event_antalarion_statues ######*/ -bool ProcessEventId_event_antalarion_statue_activation(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_antalarion_statue_activation(uint32 uiEventId, Object* pSource, Object* pTarget, bool /*bIsStart*/) { if (pSource->GetTypeId() == TYPEID_PLAYER && pTarget->GetTypeId() == TYPEID_GAMEOBJECT) { @@ -181,7 +186,7 @@ bool ProcessEventId_event_antalarion_statue_activation(uint32 uiEventId, Object* /*###### ## event_avatar_of_hakkar ######*/ -bool ProcessEventId_event_avatar_of_hakkar(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_avatar_of_hakkar(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) { if (pSource->GetTypeId() == TYPEID_PLAYER) { @@ -202,7 +207,7 @@ bool ProcessEventId_event_avatar_of_hakkar(uint32 uiEventId, Object* pSource, Ob /*###### ## go_eternal_flame ######*/ -bool GOUse_go_eternal_flame(Player* pPlayer, GameObject* pGo) +bool GOUse_go_eternal_flame(Player* /*pPlayer*/, GameObject* pGo) { instance_sunken_temple* pInstance = (instance_sunken_temple*)pGo->GetInstanceData(); @@ -222,7 +227,7 @@ bool GOUse_go_eternal_flame(Player* pPlayer, GameObject* pGo) /*###### ## effectDummy_summon_hakkar ######*/ -bool EffectDummyCreature_summon_hakkar(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_summon_hakkar(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* /*pCreatureTarget*/, ObjectGuid /*originalCasterGuid*/) { // Always check spellid and effectindex if (uiSpellId == SPELL_SUMMON_AVATAR && uiEffIndex == EFFECT_INDEX_0) diff --git a/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h b/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h index a21a41fdc..9195b076c 100644 --- a/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h +++ b/scripts/eastern_kingdoms/sunken_temple/sunken_temple.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -90,41 +90,41 @@ struct SummonLocations static const SummonLocations aSunkenTempleLocation[] = { - {-466.5130f, 95.19820f, -189.646f, 0.0349f}, // Atalarion summon loc - {-466.8673f,272.31204f, -90.7441f, 3.5255f}, // Shade of hakkar summon loc - {-660.5277f, -16.7117f, -90.8357f, 1.6055f} // Malfurion summon loc + { -466.5130f, 95.19820f, -189.646f, 0.0349f}, // Atalarion summon loc + { -466.8673f, 272.31204f, -90.7441f, 3.5255f}, // Shade of hakkar summon loc + { -660.5277f, -16.7117f, -90.8357f, 1.6055f} // Malfurion summon loc }; // Summon location for the suppressors static const SummonLocations aHakkariDoorLocations[2] = { - {-420.629f, 276.682f, -90.827f}, - {-512.015f, 276.134f, -90.827f} + { -420.629f, 276.682f, -90.827f, 0.0f}, + { -512.015f, 276.134f, -90.827f, 0.0f} }; -class MANGOS_DLL_DECL instance_sunken_temple : public ScriptedInstance +class instance_sunken_temple : public ScriptedInstance { public: instance_sunken_temple(Map* pMap); ~instance_sunken_temple() {} - void Initialize(); + void Initialize() override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; bool ProcessStatueEvent(uint32 uiEventId); - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: void DoSpawnAtalarionIfCan(); @@ -141,9 +141,9 @@ class MANGOS_DLL_DECL instance_sunken_temple : public ScriptedInstance bool m_bIsFirstHakkarWave; bool m_bCanSummonBloodkeeper; - GUIDList m_luiFlameGUIDs; - GUIDList m_luiBigLightGUIDs; - GUIDVector m_vuiCircleGUIDs; + GuidList m_luiFlameGUIDs; + GuidList m_luiBigLightGUIDs; + GuidVector m_vuiCircleGUIDs; }; #endif diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp index 876995dac..c626b6509 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_brutallus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -68,7 +68,8 @@ enum SPELL_FROST_BREATH = 45065, SPELL_ENCAPSULATE = 44883, SPELL_FEL_FIREBALL = 44844, // Brutallus' spells - SPELL_FLAME_RING = 44873, // this spell should have a fire explosion when removed + SPELL_CLEAR_DEBUFFS = 34098, + SPELL_FLAME_RING = 44874, // this spell should have a fire explosion when removed SPELL_CHARGE = 44884, SPELL_BREAK_ICE = 46637, // Break the ice, open the door - dummy spell for 46638 and 47030 @@ -96,7 +97,11 @@ static const DialogueEntry aIntroDialogue[] = {0, 0, 0}, }; -struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHelper +/*###### +## boss_brutallus +######*/ + +struct boss_brutallusAI : public ScriptedAI, private DialogueHelper { boss_brutallusAI(Creature* pCreature) : ScriptedAI(pCreature), DialogueHelper(aIntroDialogue) @@ -119,12 +124,12 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel bool m_bCanDoMeleeAttack; bool m_bIsIntroInProgress; - void Reset() + void Reset() override { m_uiSlashTimer = 11000; m_uiStompTimer = 30000; m_uiBurnTimer = 20000; - m_uiBerserkTimer = 6*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 6 * MINUTE * IN_MILLISECONDS; m_uiLoveTimer = urand(10000, 17000); m_uiMadrigosaSpellTimer = 0; @@ -133,7 +138,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel m_bIsIntroInProgress = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { // Don't aggro when attacking Madrigosa if (pWho->GetEntry() == NPC_MADRIGOSA) @@ -145,13 +150,13 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel m_pInstance->SetData(TYPE_BRUTALLUS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { // Don't yell for Madrigosa if (pVictim->GetEntry() == NPC_MADRIGOSA) return; - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(YELL_KILL1, m_creature); break; case 1: DoScriptText(YELL_KILL2, m_creature); break; @@ -159,7 +164,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(YELL_DEATH, m_creature); DoCastSpellIfCan(m_creature, SPELL_SUMMON_DEATH_CLOUD, CAST_TRIGGERED); @@ -168,7 +173,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel m_pInstance->SetData(TYPE_BRUTALLUS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -180,7 +185,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel } } - void GetAIInformation(ChatHandler& reader) + void GetAIInformation(ChatHandler& reader) override { if (m_pInstance) { @@ -197,33 +202,33 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { // Error log if Madrigosa dies if (pSummoned->GetEntry() == NPC_MADRIGOSA) - error_log("SD2: Npc %u, %s, died unexpectedly. Felmyst won't be summoned anymore.", pSummoned->GetEntry(), pSummoned->GetName()); + script_error_log("Npc %u, %s, died unexpectedly. Felmyst won't be summoned anymore.", pSummoned->GetEntry(), pSummoned->GetName()); } - void SummonedCreatureDespawn(Creature* pSummoned) + void SummonedCreatureDespawn(Creature* pSummoned) override { // Yell of Madrigosa on death if (pSummoned->GetEntry() == NPC_MADRIGOSA) pSummoned->CastSpell(pSummoned, SPELL_SUMMON_FELBLAZE, true); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_MADRIGOSA) { pSummoned->SetWalk(false); pSummoned->SetLevitate(true); - pSummoned->GetMotionMaster()->MovePoint(0, aMadrigosaFlyLoc[0], aMadrigosaFlyLoc[1], aMadrigosaFlyLoc[2]); + pSummoned->GetMotionMaster()->MovePoint(0, aMadrigosaLoc[1].m_fX, aMadrigosaLoc[1].m_fY, aMadrigosaLoc[1].m_fZ, false); } else if (pSummoned->GetEntry() == NPC_BRUTALLUS_DEATH_CLOUD) pSummoned->CastSpell(pSummoned, SPELL_BRUTALLUS_DEATH_CLOUD, true); } - void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_MADRIGOSA) return; @@ -232,7 +237,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel pSummoned->SetLevitate(false); } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { // Fake death Madrigosa when charged if (pTarget->GetEntry() == NPC_MADRIGOSA && pSpell->Id == SPELL_CHARGE) @@ -256,7 +261,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel } } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { if (!m_pInstance) return; @@ -270,11 +275,11 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel break; case YELL_MADR_ICE_BARRIER: if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) - pMadrigosa->CastSpell(pMadrigosa, SPELL_FREEZE, true); + pMadrigosa->CastSpell(pMadrigosa, SPELL_FREEZE, false); break; case YELL_MADR_INTRO: if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) - pMadrigosa->GetMotionMaster()->MovePoint(POINT_MOVE_GROUND, aMadrigosaGroundLoc[0], aMadrigosaGroundLoc[1], aMadrigosaGroundLoc[2]); + pMadrigosa->GetMotionMaster()->MovePoint(POINT_MOVE_GROUND, aMadrigosaLoc[0].m_fX, aMadrigosaLoc[0].m_fY, aMadrigosaLoc[0].m_fZ); break; case YELL_INTRO: if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) @@ -283,7 +288,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel case SPELL_FROST_BREATH: if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) { - pMadrigosa->CastSpell(m_creature, SPELL_FROST_BREATH, true); + pMadrigosa->CastSpell(m_creature, SPELL_FROST_BREATH, false); pMadrigosa->GetMotionMaster()->MoveIdle(); } break; @@ -291,7 +296,8 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel m_bCanDoMeleeAttack = false; if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) { - pMadrigosa->GetMotionMaster()->MovePoint(POINT_MOVE_ICE_BLOCK, aMadrigosaFlyLoc[0], aMadrigosaFlyLoc[1], aMadrigosaFlyLoc[2]); + pMadrigosa->GetMotionMaster()->MovePoint(POINT_MOVE_ICE_BLOCK, aMadrigosaLoc[1].m_fX, aMadrigosaLoc[1].m_fY, aMadrigosaLoc[1].m_fZ); + pMadrigosa->HandleEmote(EMOTE_ONESHOT_LIFTOFF); pMadrigosa->SetLevitate(true); } // Temporary! This will make Brutallus not follow Madrigosa through the air until mmaps are implemented @@ -303,6 +309,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel m_uiMadrigosaSpellTimer = 2000; break; case SPELL_FLAME_RING: + DoCastSpellIfCan(m_creature, SPELL_CLEAR_DEBUFFS, CAST_TRIGGERED); DoCastSpellIfCan(m_creature, SPELL_FLAME_RING, CAST_TRIGGERED); break; case YELL_INTRO_BREAK_ICE: @@ -314,7 +321,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel break; case POINT_MOVE_GROUND: if (Creature* pMadrigosa = m_pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) - pMadrigosa->GetMotionMaster()->MovePoint(POINT_MOVE_GROUND, aMadrigosaGroundLoc[0], aMadrigosaGroundLoc[1], aMadrigosaGroundLoc[2]); + pMadrigosa->GetMotionMaster()->MovePoint(POINT_MOVE_GROUND, aMadrigosaLoc[0].m_fX, aMadrigosaLoc[0].m_fY, aMadrigosaLoc[0].m_fZ); m_uiMadrigosaSpellTimer = 0; break; case YELL_MADR_TRAP: @@ -375,10 +382,10 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel DoMeleeAttackIfReady(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Update only the intro related stuff - if (m_pInstance->GetData(TYPE_BRUTALLUS) == SPECIAL) + if (m_pInstance && m_pInstance->GetData(TYPE_BRUTALLUS) == SPECIAL) { UpdateIntroEvent(uiDiff); return; @@ -389,7 +396,7 @@ struct MANGOS_DLL_DECL boss_brutallusAI : public ScriptedAI, private DialogueHel if (m_uiLoveTimer < uiDiff) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(YELL_LOVE1, m_creature); break; case 1: DoScriptText(YELL_LOVE2, m_creature); break; @@ -450,6 +457,10 @@ CreatureAI* GetAI_boss_brutallus(Creature* pCreature) return new boss_brutallusAI(pCreature); } +/*###### +## spell_aura_dummy_npc_brutallus_cloud +######*/ + bool EffectAuraDummy_spell_aura_dummy_npc_brutallus_cloud(const Aura* pAura, bool bApply) { // On Aura removal start Felmyst summon visuals @@ -461,6 +472,9 @@ bool EffectAuraDummy_spell_aura_dummy_npc_brutallus_cloud(const Aura* pAura, boo { if (Creature* pMadrigosa = pInstance->GetSingleCreatureFromStorage(NPC_MADRIGOSA)) { + // Set respawn pos to current pos + pMadrigosa->SetRespawnCoord(pMadrigosa->GetPositionX(), pMadrigosa->GetPositionY(), pMadrigosa->GetPositionZ(), pMadrigosa->GetOrientation()); + pMadrigosa->CastSpell(pMadrigosa, SPELL_FELBLAZE_PREVIZUAL, true); pMadrigosa->ForcedDespawn(10000); } @@ -470,12 +484,16 @@ bool EffectAuraDummy_spell_aura_dummy_npc_brutallus_cloud(const Aura* pAura, boo return true; } -bool AreaTrigger_at_madrigosa(Player* pPlayer, AreaTriggerEntry const* pAt) +/*###### +## at_madrigosa +######*/ + +bool AreaTrigger_at_madrigosa(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) { - //this simply set encounter state, and trigger ice barrier become active - //bosses can start pre-event based on this new state + // this simply set encounter state, and trigger ice barrier become active + // bosses can start pre-event based on this new state if (pInstance->GetData(TYPE_BRUTALLUS) == NOT_STARTED) { pInstance->SetData(TYPE_BRUTALLUS, SPECIAL); diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp index 5b5987f86..501ccda52 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_eredar_twins.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -55,7 +55,7 @@ enum SPELL_DARK_FLAME = 45345, // Sacrolash spells - SPELL_DARK_TOUCHED = 45347, // TODO NYI - Player debuff; removed by shadow damage + SPELL_DARK_TOUCHED = 45347, // Player debuff; removed by shadow damage SPELL_SHADOW_BLADES = 45248, // 10 secs SPELL_DARK_STRIKE = 45271, SPELL_SHADOW_NOVA = 45329, // 30-35 secs @@ -69,7 +69,7 @@ enum // Alythess spells SPELL_PYROGENICS = 45230, // Self buff; 15secs - SPELL_FLAME_TOUCHED = 45348, // TODO NYI - Player debuff; removed by shadow damage + SPELL_FLAME_TOUCHED = 45348, // Player debuff; removed by shadow damage SPELL_CONFLAGRATION = 45342, // 30-35 secs SPELL_BLAZE = 45235, // On main target every 3 secs; should trigger 45236 which leaves a fire on the ground SPELL_FLAME_SEAR = 46771, // A few random targets debuff @@ -89,7 +89,11 @@ static const DialogueEntry aIntroDialogue[] = {0, 0, 0}, }; -struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI +/*###### +## boss_alythess +######*/ + +struct boss_alythessAI : public ScriptedAI { boss_alythessAI(Creature* pCreature) : ScriptedAI(pCreature), m_introDialogue(aIntroDialogue) @@ -104,24 +108,22 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI uint32 m_uiEnrageTimer; uint32 m_uiPyrogenicsTimer; - uint32 m_uiFlameTouchedTimer; uint32 m_uiConflagrationTimer; uint32 m_uiBlazeTimer; uint32 m_uiFlameSearTimer; bool m_bDidIntro; - void Reset() + void Reset() override { - m_uiEnrageTimer = 6*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; m_uiPyrogenicsTimer = 20000; - m_uiFlameTouchedTimer = 30000; m_uiConflagrationTimer = urand(25000, 30000); m_uiBlazeTimer = 1000; m_uiFlameSearTimer = 5000; m_bDidIntro = false; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -137,7 +139,7 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) { @@ -146,7 +148,7 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI } } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, false)) { @@ -159,12 +161,12 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_ALYTHESS_KILL_1 : SAY_ALYTHESS_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) { @@ -187,7 +189,34 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + if (pTarget->HasAura(SPELL_DARK_FLAME)) + return; + + if (pSpell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) + { + if (pTarget->HasAura(SPELL_DARK_TOUCHED)) + { + pTarget->RemoveAurasDueToSpell(SPELL_DARK_TOUCHED); + pTarget->CastSpell(pTarget, SPELL_DARK_FLAME, true); + } + else + pTarget->CastSpell(pTarget, SPELL_FLAME_TOUCHED, true); + } + else if (pSpell->SchoolMask == SPELL_SCHOOL_MASK_SHADOW) + { + if (pTarget->HasAura(SPELL_FLAME_TOUCHED)) + { + pTarget->RemoveAurasDueToSpell(SPELL_FLAME_TOUCHED); + pTarget->CastSpell(pTarget, SPELL_DARK_FLAME, true); + } + else + pTarget->CastSpell(pTarget, SPELL_DARK_TOUCHED, true); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (m_pInstance && m_pInstance->GetData(TYPE_EREDAR_TWINS) == SPECIAL) { @@ -207,7 +236,7 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, SPELL_TWINS_ENRAGE) == CAST_OK) { DoScriptText(SAY_ALYTHESS_BERSERK, m_creature); - m_uiEnrageTimer = 6*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; } } else @@ -221,16 +250,6 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI else m_uiPyrogenicsTimer -= uiDiff; - /* // Spell needs research of fix; it shoudn't be cast on self - if (m_uiFlameTouchedTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_FLAME_TOUCHED) == CAST_OK) - m_uiFlameTouchedTimer = urand(10000, 13000); - } - else - m_uiFlameTouchedTimer -= uiDiff; - */ - if (m_uiConflagrationTimer < uiDiff) { Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 3); @@ -268,7 +287,11 @@ struct MANGOS_DLL_DECL boss_alythessAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI +/*###### +## boss_sacrolash +######*/ + +struct boss_sacrolashAI : public ScriptedAI { boss_sacrolashAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -279,23 +302,21 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI ScriptedInstance* m_pInstance; uint32 m_uiEnrageTimer; - uint32 m_uiDarkTouchedTimer; uint32 m_uiShadowNovaTimer; uint32 m_uiConfoundingBlowTimer; uint32 m_uiShadowBladesTimer; uint32 m_uiSummonShadowImage; - void Reset() + void Reset() override { - m_uiEnrageTimer = 6*MINUTE*IN_MILLISECONDS; - m_uiDarkTouchedTimer = 30000; + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; m_uiShadowNovaTimer = 15000; m_uiConfoundingBlowTimer = 30000; m_uiShadowBladesTimer = 15000; m_uiSummonShadowImage = 10000; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -311,7 +332,7 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) { @@ -320,12 +341,12 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SACROLASH_KILL_1 : SAY_SACROLASH_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) { @@ -348,13 +369,40 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI } } + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + if (pTarget->HasAura(SPELL_DARK_FLAME)) + return; + + if (pSpell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) + { + if (pTarget->HasAura(SPELL_DARK_TOUCHED)) + { + pTarget->RemoveAurasDueToSpell(SPELL_DARK_TOUCHED); + pTarget->CastSpell(pTarget, SPELL_DARK_FLAME, true); + } + else + pTarget->CastSpell(pTarget, SPELL_FLAME_TOUCHED, true); + } + else if (pSpell->SchoolMask == SPELL_SCHOOL_MASK_SHADOW) + { + if (pTarget->HasAura(SPELL_FLAME_TOUCHED)) + { + pTarget->RemoveAurasDueToSpell(SPELL_FLAME_TOUCHED); + pTarget->CastSpell(pTarget, SPELL_DARK_FLAME, true); + } + else + pTarget->CastSpell(pTarget, SPELL_DARK_TOUCHED, true); + } + } + // Return a random target which it's not in range of 10 yards of boss Unit* GetRandomTargetAtDist(float fDist) { std::vector m_vRangeTargets; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator iter = tList.begin();iter != tList.end(); ++iter) + for (ThreatList::const_iterator iter = tList.begin(); iter != tList.end(); ++iter) { if (Unit* pTempTarget = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid())) { @@ -369,7 +417,7 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SHADOW_IMAGE) { @@ -380,7 +428,7 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -390,22 +438,12 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, SPELL_TWINS_ENRAGE) == CAST_OK) { DoScriptText(SAY_SACROLASH_BERSERK, m_creature); - m_uiEnrageTimer = 6*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 6 * MINUTE * IN_MILLISECONDS; } } else m_uiEnrageTimer -= uiDiff; - /* // Spell needs research of fix; it shoudn't be cast on self - if (m_uiDarkTouchedTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_DARK_TOUCHED) == CAST_OK) - m_uiDarkTouchedTimer = urand(10000, 13000); - } - else - m_uiDarkTouchedTimer -= uiDiff; - */ - if (m_uiShadowBladesTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_BLADES) == CAST_OK) @@ -450,7 +488,7 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI if (m_uiSummonShadowImage < uiDiff) { // Summon 3 shadow images at the boss position - for(uint8 i = 0; i < 3; ++i) + for (uint8 i = 0; i < 3; ++i) m_creature->SummonCreature(NPC_SHADOW_IMAGE, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000); m_uiSummonShadowImage = urand(10000, 12000); @@ -473,7 +511,11 @@ struct MANGOS_DLL_DECL boss_sacrolashAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL npc_shadow_imageAI : public ScriptedAI +/*###### +## npc_shadow_image +######*/ + +struct npc_shadow_imageAI : public ScriptedAI { npc_shadow_imageAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -482,7 +524,7 @@ struct MANGOS_DLL_DECL npc_shadow_imageAI : public ScriptedAI uint32 m_uiAbilityTimer; uint8 m_uiDarkStrikes; - void Reset() + void Reset() override { // Choose only one spell for attack m_uiChosenAbility = urand(0, 1) ? SPELL_DARK_STRIKE : SPELL_SHADOWFURY; @@ -491,7 +533,7 @@ struct MANGOS_DLL_DECL npc_shadow_imageAI : public ScriptedAI m_uiSuicideTimer = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -547,17 +589,17 @@ struct MANGOS_DLL_DECL npc_shadow_imageAI : public ScriptedAI CreatureAI* GetAI_boss_alythess(Creature* pCreature) { - return new boss_alythessAI (pCreature); + return new boss_alythessAI(pCreature); } CreatureAI* GetAI_boss_sacrolash(Creature* pCreature) { - return new boss_sacrolashAI (pCreature); + return new boss_sacrolashAI(pCreature); } CreatureAI* GetAI_npc_shadow_image(Creature* pCreature) { - return new npc_shadow_imageAI (pCreature); + return new npc_shadow_imageAI(pCreature); } void AddSC_boss_eredar_twins() diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp index b3ce4619b..47ccc140c 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_felmyst.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,14 @@ /* ScriptData SDName: boss_felmyst -SD%Complete: 50% -SDComment: Only ground phase spells +SD%Complete: 90% +SDComment: Intro movement NYI; Event cleanup (despawn & resummon) NYI; Breath phase spells could use some improvements. SDCategory: Sunwell Plateau EndScriptData */ #include "precompiled.h" #include "sunwell_plateau.h" +#include "TemporarySummon.h" enum { @@ -33,9 +34,11 @@ enum SAY_TAKEOFF = -1580040, SAY_BREATH = -1580039, SAY_BERSERK = -1580041, + EMOTE_DEEP_BREATH = -1580107, SPELL_FELBLAZE_VISUAL = 45068, // Visual transform aura SPELL_NOXIOUS_FUMES = 47002, + SPELL_SOUL_SEVER = 45918, // kills all charmed targets at wipe - script effect for 45917 SPELL_BERSERK = 26662, // ground phase @@ -46,36 +49,50 @@ enum SPELL_ENCAPSULATE_CHANNEL = 45661, // flight phase - SPELL_DEMONIC_VAPOR = 45399, - SPELL_VAPOR_BEAM_VISUAL = 45389, - SPELL_FOG_CORRUPTION = 45582, - SPELL_SOUL_SEVER = 45918, // kills all charmed targets at wipe - script effect for 45917 SPELL_SUMMON_VAPOR = 45391, - SPELL_SUMMON_VAPOR_TRIAL = 45410, - SPELL_SUMMON_BLAZING_DEAD = 45400, + SPELL_VAPOR_SPAWN_TRIGGER = 45388, + SPELL_SPEED_BURST = 45495, // spell needs to be confirmed + SPELL_FOG_CORRUPTION = 45582, + + // demonic vapor spells + SPELL_DEMONIC_VAPOR_PER = 45411, + SPELL_DEMONIC_VAPOR = 45399, + // SPELL_SUMMON_BLAZING_DEAD = 45400, // npcs - NPC_UNYELDING_DEAD = 25268, // spawned during flight phase - NPC_DEMONIC_VAPOR = 25265, + // NPC_UNYELDING_DEAD = 25268, // spawned during flight phase + NPC_DEMONIC_VAPOR = 25265, // npc which follows the player NPC_DEMONIC_VAPOR_TRAIL = 25267, // phases PHASE_GROUND = 1, PHASE_AIR = 2, + PHASE_TRANSITION = 3, + + // subphases for air phase + SUBPHASE_VAPOR = 4, + SUBPHASE_BREATH_PREPARE = 5, + SUBPHASE_BREATH_MOVE = 6, }; -struct MANGOS_DLL_DECL boss_felmystAI : public ScriptedAI +/*###### +## boss_felmyst +######*/ + +struct boss_felmystAI : public ScriptedAI { boss_felmystAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_sunwell_plateau*)pCreature->GetInstanceData(); m_bHasTransformed = false; + m_uiMovementTimer = 2000; Reset(); } instance_sunwell_plateau* m_pInstance; bool m_bHasTransformed; + uint32 m_uiMovementTimer; uint8 m_uiPhase; uint32 m_uiBerserkTimer; @@ -87,13 +104,23 @@ struct MANGOS_DLL_DECL boss_felmystAI : public ScriptedAI uint32 m_uiEncapsulateTimer; uint32 m_uiGasNovaTimer; - void Reset() + // Air Phase timers + uint8 m_uiSubPhase; + bool m_bIsLeftSide; + + uint8 m_uiDemonicVaporCount; + uint8 m_uiCorruptionCount; + uint8 m_uiCorruptionIndex; + uint32 m_uiDemonicVaporTimer; + uint32 m_uiCorruptionTimer; + + void Reset() override { // Transform into Felmyst dragon DoCastSpellIfCan(m_creature, SPELL_FELBLAZE_VISUAL); m_uiPhase = PHASE_GROUND; - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; // Ground Phase m_uiCorrosionTimer = 30000; @@ -101,9 +128,17 @@ struct MANGOS_DLL_DECL boss_felmystAI : public ScriptedAI m_uiGasNovaTimer = 17000; m_uiEncapsulateTimer = urand(30000, 40000); m_uiFlyPhaseTimer = 60000; // flight phase after 1 min + + // Air phase + m_uiSubPhase = SUBPHASE_VAPOR; + m_uiDemonicVaporCount = 0; + m_uiDemonicVaporTimer = 1000; + m_uiCorruptionTimer = 0; + + SetCombatMovement(false); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bHasTransformed) { @@ -117,37 +152,50 @@ struct MANGOS_DLL_DECL boss_felmystAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void EnterEvadeMode() + void EnterEvadeMode() override { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); // Add the visual aura back when evading - workaround because there is no way to remove only the negative auras DoCastSpellIfCan(m_creature, SPELL_FELBLAZE_VISUAL, CAST_TRIGGERED); + // Also make sure that the charmed targets are killed + DoCastSpellIfCan(m_creature, SPELL_SOUL_SEVER, CAST_TRIGGERED); + + // Fly back to the home flight location if (m_creature->isAlive()) - m_creature->GetMotionMaster()->MoveTargetedHome(); + { + float fX, fY, fZ; + m_creature->SetLevitate(true); + m_creature->GetRespawnCoord(fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(PHASE_GROUND, fX, fY, 50.083f, false); + } m_creature->SetLootRecipient(NULL); Reset(); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoCastSpellIfCan(m_creature, SPELL_NOXIOUS_FUMES); if (m_pInstance) m_pInstance->SetData(TYPE_FELMYST, IN_PROGRESS); + + float fGroundZ = m_creature->GetMap()->GetHeight(m_creature->GetPhaseMask(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + m_creature->GetMotionMaster()->MovePoint(PHASE_TRANSITION, pWho->GetPositionX(), pWho->GetPositionY(), fGroundZ, false); + m_creature->HandleEmote(EMOTE_ONESHOT_LAND); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -155,20 +203,110 @@ struct MANGOS_DLL_DECL boss_felmystAI : public ScriptedAI m_pInstance->SetData(TYPE_FELMYST, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_FELMYST, FAIL); } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DEMONIC_VAPOR) + { + pSummoned->CastSpell(pSummoned, SPELL_VAPOR_SPAWN_TRIGGER, true); + pSummoned->CastSpell(pSummoned, SPELL_DEMONIC_VAPOR_PER, true); + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case PHASE_GROUND: + m_creature->SetWalk(false); + // ToDo: start WP movement here. Currently disabled because of some MMaps issues + // m_creature->GetMotionMaster()->MoveWaypoint(); + break; + case PHASE_AIR: + // switch from ground transition to flight phase + m_uiPhase = PHASE_AIR; + break; + case SUBPHASE_VAPOR: + // After the third breath land and resume phase 1 + if (m_uiCorruptionCount == 3) + { + m_uiPhase = PHASE_TRANSITION; + float fGroundZ = m_creature->GetMap()->GetHeight(m_creature->GetPhaseMask(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + m_creature->GetMotionMaster()->MovePoint(PHASE_TRANSITION, m_creature->getVictim()->GetPositionX(), m_creature->getVictim()->GetPositionY(), fGroundZ, false); + return; + } + + // prepare to move to flight trigger + ++m_uiCorruptionCount; + m_uiCorruptionTimer = 5000; + m_uiSubPhase = SUBPHASE_BREATH_PREPARE; + break; + case SUBPHASE_BREATH_PREPARE: + // move across the arena + if (!m_pInstance) + return; + + // Fly to the other side, casting the breath. Keep the same trigger index + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->SelectFelmystFlightTrigger(!m_bIsLeftSide, m_uiCorruptionIndex))) + { + DoScriptText(EMOTE_DEEP_BREATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SPEED_BURST, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FOG_CORRUPTION, CAST_TRIGGERED); + m_creature->GetMotionMaster()->MovePoint(SUBPHASE_BREATH_MOVE, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), false); + } + break; + case SUBPHASE_BREATH_MOVE: + if (!m_pInstance) + return; + + // remove speed aura + m_creature->RemoveAurasDueToSpell(SPELL_SPEED_BURST); + + // Get to the flight trigger on the same side of the arena + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(!m_bIsLeftSide ? NPC_FLIGHT_TRIGGER_LEFT : NPC_FLIGHT_TRIGGER_RIGHT)) + m_creature->GetMotionMaster()->MovePoint(SUBPHASE_VAPOR, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), false); + + // switch sides + m_bIsLeftSide = !m_bIsLeftSide; + break; + case PHASE_TRANSITION: + // switch back to ground combat from flight transition + m_uiPhase = PHASE_GROUND; + SetCombatMovement(true); + m_creature->SetLevitate(false); + DoStartMovement(m_creature->getVictim()); + break; + } + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_ENCAPSULATE_CHANNEL) pTarget->CastSpell(pTarget, SPELL_ENCAPSULATE, true, NULL, NULL, m_creature->GetObjectGuid()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (m_uiMovementTimer) + { + if (m_uiMovementTimer <= uiDiff) + { + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->MovePoint(PHASE_GROUND, m_creature->GetPositionX(), m_creature->GetPositionY(), 50.083f, false); + m_uiMovementTimer = 0; + } + else + m_uiMovementTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -186,46 +324,134 @@ struct MANGOS_DLL_DECL boss_felmystAI : public ScriptedAI m_uiBerserkTimer -= uiDiff; } - if (m_uiPhase == PHASE_GROUND) + switch (m_uiPhase) { - if (m_uiCleaveTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) - m_uiCleaveTimer = urand(2000, 5000); - } - else - m_uiCleaveTimer -= uiDiff; + case PHASE_GROUND: - if (m_uiCorrosionTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORROSION) == CAST_OK) - m_uiCorrosionTimer = 30000; - } - else - m_uiCorrosionTimer -= uiDiff; + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(2000, 5000); + } + else + m_uiCleaveTimer -= uiDiff; - if (m_uiGasNovaTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_GAS_NOVA) == CAST_OK) - m_uiGasNovaTimer = 23000; - } - else - m_uiGasNovaTimer -= uiDiff; + if (m_uiCorrosionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORROSION) == CAST_OK) + { + DoScriptText(SAY_BREATH, m_creature); + m_uiCorrosionTimer = 30000; + } + } + else + m_uiCorrosionTimer -= uiDiff; - if (m_uiEncapsulateTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (m_uiGasNovaTimer < uiDiff) { - if (DoCastSpellIfCan(pTarget, SPELL_ENCAPSULATE_CHANNEL) == CAST_OK) - m_uiEncapsulateTimer = urand(30000, 40000); + if (DoCastSpellIfCan(m_creature, SPELL_GAS_NOVA) == CAST_OK) + m_uiGasNovaTimer = 23000; } - } - else - m_uiEncapsulateTimer -= uiDiff; + else + m_uiGasNovaTimer -= uiDiff; + + if (m_uiEncapsulateTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ENCAPSULATE_CHANNEL) == CAST_OK) + m_uiEncapsulateTimer = urand(30000, 40000); + } + } + else + m_uiEncapsulateTimer -= uiDiff; - DoMeleeAttackIfReady(); + if (m_uiFlyPhaseTimer < uiDiff) + { + DoScriptText(SAY_TAKEOFF, m_creature); + + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->GetMotionMaster()->MovePoint(PHASE_AIR, m_creature->GetPositionX(), m_creature->GetPositionY(), 50.083f, false); + + m_uiPhase = PHASE_TRANSITION; + m_uiSubPhase = SUBPHASE_VAPOR; + m_uiDemonicVaporTimer = 1000; + m_uiDemonicVaporCount = 0; + m_uiFlyPhaseTimer = 60000; + } + else + m_uiFlyPhaseTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + case PHASE_AIR: + + switch (m_uiSubPhase) + { + case SUBPHASE_VAPOR: + + if (m_uiDemonicVaporTimer < uiDiff) + { + // After the second Demonic Vapor trial, start the breath phase + if (m_uiDemonicVaporCount == 2) + { + if (!m_pInstance) + return; + + // select the side on which we want to fly + m_bIsLeftSide = urand(0, 1) ? true : false; + m_uiCorruptionCount = 0; + m_uiSubPhase = SUBPHASE_BREATH_PREPARE; + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(m_bIsLeftSide ? NPC_FLIGHT_TRIGGER_LEFT : NPC_FLIGHT_TRIGGER_RIGHT)) + m_creature->GetMotionMaster()->MovePoint(SUBPHASE_VAPOR, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), false); + } + else + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_VAPOR) == CAST_OK) + { + ++m_uiDemonicVaporCount; + m_uiDemonicVaporTimer = 11000; + } + } + } + else + m_uiDemonicVaporTimer -= uiDiff; + + break; + case SUBPHASE_BREATH_PREPARE: + + if (m_uiCorruptionTimer) + { + if (m_uiCorruptionTimer <= uiDiff) + { + if (!m_pInstance) + return; + + // Fly to trigger on the same side - choose a random index for the trigger + m_uiCorruptionIndex = urand(0, 2); + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->SelectFelmystFlightTrigger(m_bIsLeftSide, m_uiCorruptionIndex))) + m_creature->GetMotionMaster()->MovePoint(SUBPHASE_BREATH_PREPARE, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), false); + + m_uiSubPhase = SUBPHASE_BREATH_MOVE; + m_uiCorruptionTimer = 0; + } + else + m_uiCorruptionTimer -= uiDiff; + } + + break; + case SUBPHASE_BREATH_MOVE: + // nothing here; this is handled in MovementInform + break; + } + break; + case PHASE_TRANSITION: + // nothing here; wait for transition to finish + break; } - // ToDo: add flight phase here } }; @@ -234,6 +460,42 @@ CreatureAI* GetAI_boss_felmyst(Creature* pCreature) return new boss_felmystAI(pCreature); } +/*###### +## npc_demonic_vapor +######*/ + +struct npc_demonic_vaporAI : public ScriptedAI +{ + npc_demonic_vaporAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override + { + // Start following the summoner (player) + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + m_creature->GetMotionMaster()->MoveFollow(pSummoner, 0, 0); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DEMONIC_VAPOR_TRAIL) + pSummoned->CastSpell(pSummoned, SPELL_DEMONIC_VAPOR, true); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_demonic_vapor(Creature* pCreature) +{ + return new npc_demonic_vaporAI(pCreature); +} + void AddSC_boss_felmyst() { Script* pNewScript; @@ -242,4 +504,9 @@ void AddSC_boss_felmyst() pNewScript->Name = "boss_felmyst"; pNewScript->GetAI = &GetAI_boss_felmyst; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_demonic_vapor"; + pNewScript->GetAI = &GetAI_npc_demonic_vapor; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp index 9eaa506b2..df3aa2818 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_kalecgos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,7 @@ EndScriptData */ enum { - //kalecgos dragon form + // kalecgos dragon form SAY_EVIL_AGGRO = -1580000, SAY_EVIL_SPELL_1 = -1580001, SAY_EVIL_SPELL_2 = -1580002, @@ -34,7 +34,7 @@ enum SAY_EVIL_SLAY_2 = -1580004, SAY_EVIL_ENRAGE = -1580005, - //kalecgos humanoid form + // kalecgos humanoid form SAY_GOOD_AGGRO = -1580006, SAY_GOOD_NEAR_DEATH_20 = -1580007, SAY_GOOD_NEAR_DEATH_10 = -1580008, @@ -48,9 +48,9 @@ enum SAY_SATH_SLAY_2 = -1580015, SAY_SATH_ENRAGE = -1580016, - //Kalecgos + // Kalecgos SPELL_SPECTRAL_BLAST = 44869, - SPELL_SPECTRAL_REALM_EJECT = 44845, // pull the players ouside the spectral realm in case of wipe + SPELL_SPECTRAL_REALM_NOTIFY = 44845, // cast by the players on teleport to notify boss SPELL_ARCANE_BUFFET = 45018, SPELL_FROST_BREATH = 44799, SPELL_TAIL_LASH = 45122, @@ -60,23 +60,24 @@ enum SPELL_HEROIC_STRIKE = 45026, SPELL_REVITALIZE = 45027, - //Sathrovarr + // Sathrovarr SPELL_SPECTRAL_INVISIBILITY = 44801, SPELL_CORRUPTING_STRIKE = 45029, SPELL_CURSE_OF_BOUNDLESS_AGONY = 45032, SPELL_SHADOW_BOLT_VOLLEY = 45031, - SPELL_TELEPORT_NORMAL_REALM = 46020, - SPELL_SPECTRAL_REALM_AURA = 46021, - SPELL_SPECTRAL_EXHAUSTION = 44867, - - //Misc + // Misc SPELL_BANISH = 44836 }; -static const uint32 aWildMagicSpells[6]= {44978, 45001, 45002, 45004, 45006, 45010}; +static const uint32 aWildMagicSpells[6] = {44978, 45001, 45002, 45004, 45006, 45010}; +static const float aKalecHumanLoc[4] = {1709.094f, 927.5035f, -74.28364f, 2.932153f}; + +/*###### +## boss_kalecgos +######*/ -struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI +struct boss_kalecgosAI : public ScriptedAI { boss_kalecgosAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -97,7 +98,7 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI bool m_bIsBanished; bool m_bIsEnraged; - void Reset() + void Reset() override { m_uiArcaneBuffetTimer = 8000; m_uiTailLashTimer = 5000; @@ -111,21 +112,21 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI m_bIsEnraged = false; } - void JustReachedHome() + void JustReachedHome() override { - // Eject all players and set event to fail - DoCastSpellIfCan(m_creature, SPELL_SPECTRAL_REALM_EJECT, CAST_TRIGGERED); - if (m_pInstance) + { + m_pInstance->DoEjectSpectralPlayers(); m_pInstance->SetData(TYPE_KALECGOS, FAIL); + } } - void EnterEvadeMode() + void EnterEvadeMode() override { // Check if the boss is uncorrupted when evading if (m_bIsUncorrupted) { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->LoadCreatureAddon(true); @@ -139,7 +140,7 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI ScriptedAI::EnterEvadeMode(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_EVIL_AGGRO, m_creature); @@ -147,7 +148,7 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI m_pInstance->SetData(TYPE_KALECGOS, IN_PROGRESS); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (uiDamage > m_creature->GetHealth()) { @@ -164,7 +165,7 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_EVIL_SLAY_1 : SAY_EVIL_SLAY_2, m_creature); } @@ -186,13 +187,13 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI pKalec->ForcedDespawn(); EnterEvadeMode(); - m_creature->setFaction(35); + m_creature->SetFactionTemporary(35, TEMPFACTION_RESTORE_RESPAWN); m_creature->GetMotionMaster()->MoveIdle(); DoScriptText(SAY_GOOD_PLRWIN, m_creature); m_uiExitTimer = 10000; } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE) return; @@ -206,7 +207,13 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A && m_pInstance) + m_pInstance->AddToSpectralRealm(pInvoker->GetObjectGuid()); + } + + void UpdateAI(const uint32 uiDiff) override { if (m_uiExitTimer) { @@ -216,7 +223,7 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 30.0f, fX, fY, fZ); fZ = 70.0f; - m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); m_creature->SetLevitate(true); m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); m_uiExitTimer = 0; @@ -308,7 +315,11 @@ struct MANGOS_DLL_DECL boss_kalecgosAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI +/*###### +## boss_sathrovarr +######*/ + +struct boss_sathrovarrAI : public ScriptedAI { boss_sathrovarrAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -324,7 +335,7 @@ struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI bool m_bIsBanished; bool m_bIsEnraged; - void Reset() + void Reset() override { // FIXME: Timers m_uiCorruptingStrikeTimer = 5000; @@ -337,24 +348,27 @@ struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_SPECTRAL_INVISIBILITY); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_SATH_AGGRO, m_creature); if (!m_pInstance) return; - // Human Kalec starts to attack too - if (Creature* pKalec = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS_HUMAN)) - pKalec->AI()->AttackStart(m_creature); + // spawn human Kalec; he starts to attack + m_creature->SummonCreature(NPC_KALECGOS_HUMAN, aKalecHumanLoc[0], aKalecHumanLoc[1], aKalecHumanLoc[2], aKalecHumanLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (uiDamage > m_creature->GetHealth()) { uiDamage = 0; + if (m_bIsBanished) + return; + + // banish Sathrovarr and eject the players if (DoCastSpellIfCan(m_creature, SPELL_BANISH, CAST_TRIGGERED) == CAST_OK) m_bIsBanished = true; @@ -363,16 +377,15 @@ struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI if (Creature* pKalecgos = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON)) { - // Eject all players and set Kalec to uncorrupted - pKalecgos->CastSpell(pKalecgos, SPELL_SPECTRAL_REALM_EJECT, true); - if (boss_kalecgosAI* pKalecgosAI = dynamic_cast(pKalecgos->AI())) pKalecgosAI->m_bIsUncorrupted = true; } + + m_pInstance->DoEjectSpectralPlayers(); } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { DoScriptText(urand(0, 1) ? SAY_SATH_SLAY_1 : SAY_SATH_SLAY_2, m_creature); @@ -384,7 +397,7 @@ struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // !!! Workaround which ejects the players from the spectral realm !!! if (pWho->GetTypeId() == TYPEID_PLAYER && pWho->IsWithinLOSInMap(m_creature) && pWho->IsWithinDistInMap(m_creature, 75.0f)) @@ -393,18 +406,33 @@ struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI { pWho->CastSpell(pWho, SPELL_TELEPORT_NORMAL_REALM, true); pWho->CastSpell(pWho, SPELL_SPECTRAL_EXHAUSTION, true); + + if (m_pInstance) + m_pInstance->RemoveFromSpectralRealm(pWho->GetObjectGuid()); } } ScriptedAI::MoveInLineOfSight(pWho); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_SATH_DEATH, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_KALECGOS_HUMAN) + pSummoned->AI()->AttackStart(m_creature); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A && m_pInstance) + m_pInstance->AddToSpectralRealm(pInvoker->GetObjectGuid()); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -466,7 +494,11 @@ struct MANGOS_DLL_DECL boss_sathrovarrAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_kalecgos_humanoidAI : public ScriptedAI +/*###### +## boss_kalecgos_humanoid +######*/ + +struct boss_kalecgos_humanoidAI : public ScriptedAI { boss_kalecgos_humanoidAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -482,9 +514,9 @@ struct MANGOS_DLL_DECL boss_kalecgos_humanoidAI : public ScriptedAI bool m_bHasYelled10Percent; bool m_bHasYelled20Percent; - void Reset() + void Reset() override { - //TODO: Times! + // TODO: Times! m_uiRevitalizeTimer = 30000; m_uiHeroicStrikeTimer = 8000; @@ -494,23 +526,21 @@ struct MANGOS_DLL_DECL boss_kalecgos_humanoidAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_SPECTRAL_INVISIBILITY); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_GOOD_AGGRO, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) { - if (Creature* pKalecgos = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS_DRAGON)) - pKalecgos->CastSpell(pKalecgos, SPELL_SPECTRAL_REALM_EJECT, true); - + m_pInstance->DoEjectSpectralPlayers(); m_pInstance->SetData(TYPE_KALECGOS, FAIL); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -563,6 +593,19 @@ CreatureAI* GetAI_boss_kalecgos_humanoid(Creature* pCreature) return new boss_kalecgos_humanoidAI(pCreature); } +bool EffectDummyCreature_spell_spectral_realm_notify(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_SPECTRAL_REALM_NOTIFY && uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() == TYPEID_PLAYER) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + + return true; + } + + return true; +} + void AddSC_boss_kalecgos() { Script* pNewScript; @@ -570,15 +613,18 @@ void AddSC_boss_kalecgos() pNewScript = new Script; pNewScript->Name = "boss_kalecgos"; pNewScript->GetAI = &GetAI_boss_kalecgos; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_spectral_realm_notify; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "boss_sathrovarr"; pNewScript->GetAI = &GetAI_boss_sathrovarr; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_spectral_realm_notify; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "boss_kalecgos_humanoid"; pNewScript->GetAI = &GetAI_boss_kalecgos_humanoid; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_spectral_realm_notify; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp index f8fd05dcb..c7d1241b4 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_kiljaeden.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,21 +16,17 @@ /* ScriptData SDName: boss_kiljaeden -SD%Complete: 50 -SDComment: Sinister Reflection need core and AI support; Orb of the Blue Fight activation NYI; Shield Orb summoning NYI; Armageddon NYI; Offcombat yells NYI; +SD%Complete: 90 +SDComment: Sinister Reflection needs AI support. SDCategory: Sunwell Plateau EndScriptData */ #include "precompiled.h" #include "sunwell_plateau.h" +#include "TemporarySummon.h" enum { - SAY_ORDER_1 = -1580064, - SAY_ORDER_2 = -1580065, - SAY_ORDER_3 = -1580066, - SAY_ORDER_4 = -1580067, - SAY_ORDER_5 = -1580068, SAY_EMERGE = -1580069, SAY_SLAY_1 = -1580070, SAY_SLAY_2 = -1580071, @@ -97,11 +93,16 @@ enum SPELL_RING_BLUE_FLAME = 45825, // cast by the orb targets when activated SPELL_ANVEENA_PRISON = 46367, SPELL_SACRIFICE_ANVEENA = 46474, + SPELL_ARCANE_BOLT = 45670, // used by Kalec + SPELL_SINISTER_REFL_CLASS = 45893, // increase the size of the clones + SPELL_SINISTER_REFL_CLONE = 45785, // clone the player + SPELL_VENGEANCE_BLUE_FLIGHT = 45839, // possess the dragon + SPELL_POSSESS_DRAKE_IMMUNE = 45838, // immunity while the player possesses the dragon // Npcs NPC_SHIELD_ORB = 25502, NPC_SINISTER_REFLECTION = 25708, - NPC_ARMAGEDDON = 25735, // uses spell 45914 followed by spell 45911, 45912, then by 45909 + NPC_ARMAGEDDON = 25735, // npc handled by eventAI NPC_BLUE_ORB_TARGET = 25640, // dummy npc near gameobjects 187869, 188114, 188115, 188116 // phases @@ -118,14 +119,15 @@ enum EVENT_DRAGON_ORB = 9, // outro - SPELL_TELEPORT_VISUAL = 41232, + SPELL_TELEPORT_VISUAL = 12980, SPELL_KALEC_TELEPORT = 46473, // teleports and transforms Kalec in human form + SPELL_ARCANE_PORTAL = 42047, SPELL_CALL_ENTROPIUS = 46818, SPELL_ENTROPIUS_BODY = 46819, SPELL_BLAZE_TO_LIGHT = 46821, SPELL_SUNWELL_IGNITION = 46822, - NPC_BOSS_PORTAL = 24925, + NPC_INERT_PORTAL = 26254, NPC_CORE_ENTROPIUS = 26262, NPC_SOLDIER = 26259, // summoned in 2 waves before Velen. Should move into 2 circle formations NPC_RIFTWALKER = 26289, @@ -143,13 +145,13 @@ static const DialogueEntry aPhaseDialogue[] = {SAY_KALECGOS_AWAKE_1, NPC_KALECGOS, 6000}, {SAY_ANVEENA_IMPRISONED, NPC_ANVEENA, 5000}, {SAY_PHASE_3, NPC_KILJAEDEN, 6000}, - {SAY_KALECGOS_ORB_1, NPC_KALECGOS, 0}, // phase 2 transition end + {SAY_KALECGOS_ORB_1, NPC_KALECGOS, 0}, // phase 2 transition end {PHASE_ARMAGEDDON, 0, 2000}, {EVENT_SWITCH_PHASE_3, 0, 14000}, {SAY_KALECGOS_AWAKE_2, NPC_KALECGOS, 7000}, {SAY_ANVEENA_LOST, NPC_ANVEENA, 7000}, {SAY_PHASE_4, NPC_KILJAEDEN, 6000}, - {EVENT_DRAGON_ORB, 0, 0}, // phase 3 transition end + {EVENT_DRAGON_ORB, 0, 0}, // phase 3 transition end {PHASE_SACRIFICE, 0, 2000}, {EVENT_SWITCH_PHASE_4, 0, 5000}, {SAY_KALECGOS_AWAKE_4, NPC_KALECGOS, 10000}, @@ -158,7 +160,7 @@ static const DialogueEntry aPhaseDialogue[] = {SAY_ANVEENA_SACRIFICE, NPC_ANVEENA, 5000}, {SAY_PHASE_5, NPC_KILJAEDEN, 13000}, {SAY_KALECGOS_ORB_4, NPC_KALECGOS, 5000}, - {SAY_KALECGOS_ENCOURAGE, NPC_KALECGOS, 0}, // phase 4 transition end + {SAY_KALECGOS_ENCOURAGE, NPC_KALECGOS, 0}, // phase 4 transition end {0, 0, 0}, }; @@ -167,7 +169,7 @@ static const DialogueEntry aOutroDialogue[] = { {NPC_KALECGOS, 0, 15000}, {SAY_KALECGOS_GOODBYE, NPC_KALECGOS, 40000}, - {NPC_BOSS_PORTAL, 0, 10000}, + {NPC_INERT_PORTAL, 0, 10000}, {POINT_SUMMON_SOLDIERS, 0, 18000}, {NPC_VELEN, 0, 1000}, {NPC_LIADRIN, 0, 4000}, @@ -190,21 +192,24 @@ static const DialogueEntry aOutroDialogue[] = {0, 0, 0}, }; -struct EventLocations -{ - float m_fX, m_fY, m_fZ, m_fO; -}; - static const EventLocations aOutroLocations[] = { - {1727.854f, 656.060f, 28.31f, 3.86f}, // portal summon loc - {1716.969f, 646.407f, 28.05f, 3.91f}, // velen summon loc - {1718.862f, 644.528f, 28.05f, 3.87f}, // liadrin summon loc + {1725.469f, 650.939f, 30.314f, 3.78f}, // portal summon loc + {1717.776f, 645.178f, 28.223f, 3.83f}, // velen summon loc + {1720.024f, 643.233f, 28.133f, 3.76f}, // liadrin summon loc {1712.110f, 641.044f, 27.80f}, // velen move forward - {1711.537f, 637.600f, 27.34f} // liadrin move forward + {1711.537f, 637.600f, 27.34f}, // liadrin move forward + {1698.946f, 628.206f, 83.003f, 0.76f}, // entropius core summon loc }; -struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI, private DialogueHelper +// Note: the Z loc should be 143.69 but currently we are not using it because it's too far away +static const float aKalegSpawnLoc[4] = {1734.431f, 593.1974f, 130.6977f, 4.55f}; + +/*###### +## npc_kiljaeden_controller +######*/ + +struct npc_kiljaeden_controllerAI : public Scripted_NoMovementAI, private DialogueHelper { npc_kiljaeden_controllerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature), DialogueHelper(aOutroDialogue) @@ -219,19 +224,13 @@ struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI ObjectGuid m_EntropiusGuid; ObjectGuid m_PortalGuid; - void Reset() + void Reset() override { // Visual spell before the encounter starts DoCastSpellIfCan(m_creature, SPELL_ANVEENA_DRAIN); } - // Wrapper to start the dialogue text from another AI - void DoStartOutroDialogue() - { - StartNextDialogueText(NPC_KALECGOS); - } - - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { if (!m_pInstance) return; @@ -241,14 +240,16 @@ struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI case NPC_KALECGOS: if (Creature* pKalec = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS)) { + pKalec->GetMotionMaster()->Clear(); + pKalec->GetMotionMaster()->MoveIdle(); pKalec->CastSpell(pKalec, SPELL_KALEC_TELEPORT, true); pKalec->SetLevitate(false); } - m_creature->SummonCreature(NPC_CORE_ENTROPIUS, m_creature->GetPositionX(), m_creature->GetPositionY(), 85.0f, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_CORE_ENTROPIUS, aOutroLocations[5].m_fX, aOutroLocations[5].m_fY, aOutroLocations[5].m_fZ, aOutroLocations[5].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0); break; - case NPC_BOSS_PORTAL: + case NPC_INERT_PORTAL: // ToDo: summon soldiers to the right - m_creature->SummonCreature(NPC_BOSS_PORTAL, aOutroLocations[0].m_fX, aOutroLocations[0].m_fY, aOutroLocations[0].m_fZ, aOutroLocations[0].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_INERT_PORTAL, aOutroLocations[0].m_fX, aOutroLocations[0].m_fY, aOutroLocations[0].m_fZ, aOutroLocations[0].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0); break; case POINT_SUMMON_SOLDIERS: // ToDo: summon soldiers to the left @@ -257,7 +258,7 @@ struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI m_creature->SummonCreature(NPC_VELEN, aOutroLocations[1].m_fX, aOutroLocations[1].m_fY, aOutroLocations[1].m_fZ, aOutroLocations[1].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0); break; case NPC_LIADRIN: - m_creature->SummonCreature(NPC_LIADRIN, aOutroLocations[2].m_fX, aOutroLocations[2].m_fY, aOutroLocations[2].m_fZ, aOutroLocations[2].m_fO, TEMPSUMMON_TIMED_DESPAWN, 4*MINUTE*IN_MILLISECONDS); + m_creature->SummonCreature(NPC_LIADRIN, aOutroLocations[2].m_fX, aOutroLocations[2].m_fY, aOutroLocations[2].m_fZ, aOutroLocations[2].m_fO, TEMPSUMMON_TIMED_DESPAWN, 4 * MINUTE * IN_MILLISECONDS); break; case SPELL_CALL_ENTROPIUS: if (Creature* pVelen = m_pInstance->GetSingleCreatureFromStorage(NPC_VELEN)) @@ -290,9 +291,9 @@ struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_VELEN: pSummoned->GetMotionMaster()->MovePoint(0, aOutroLocations[3].m_fX, aOutroLocations[3].m_fY, aOutroLocations[3].m_fZ); @@ -305,13 +306,21 @@ struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI pSummoned->SetLevitate(true); m_EntropiusGuid = pSummoned->GetObjectGuid(); break; - case NPC_BOSS_PORTAL: + case NPC_INERT_PORTAL: m_PortalGuid = pSummoned->GetObjectGuid(); + pSummoned->CastSpell(pSummoned, SPELL_ARCANE_PORTAL, true); break; } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // Start outro dialogue when Kil'jaeden is killed + if (pSummoned->GetEntry() == NPC_KILJAEDEN) + StartNextDialogueText(NPC_KALECGOS); + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; @@ -350,13 +359,17 @@ struct MANGOS_DLL_DECL npc_kiljaeden_controllerAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); } }; -struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private DialogueHelper +/*###### +## boss_kiljaeden +######*/ + +struct boss_kiljaedenAI : public Scripted_NoMovementAI, private DialogueHelper { boss_kiljaedenAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature), DialogueHelper(aPhaseDialogue) @@ -369,6 +382,8 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private instance_sunwell_plateau* m_pInstance; uint8 m_uiPhase; + uint8 m_uiMaxShieldOrbs; + uint8 m_uiShieldOrbCount; uint32 m_uiKalecSummonTimer; @@ -382,10 +397,12 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private uint32 m_uiArmageddonTimer; - void Reset() + void Reset() override { m_uiPhase = PHASE_INFERNO; m_uiKalecSummonTimer = 35000; + m_uiMaxShieldOrbs = 1; + m_uiShieldOrbCount = 0; m_uiSoulFlyTimer = 10000; m_uiLegionLightingTimer = urand(10000, 15000); @@ -398,7 +415,7 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private m_uiArmageddonTimer = 20000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_KILJAEDEN, IN_PROGRESS); @@ -407,7 +424,7 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private DoCastSpellIfCan(m_creature, SPELL_BIRTH); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -416,58 +433,79 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private // Reset the corrupt Sunwell aura if (Creature* pKiljaedenController = m_pInstance->GetSingleCreatureFromStorage(NPC_KILJAEDEN_CONTROLLER)) pKiljaedenController->CastSpell(pKiljaedenController, SPELL_ANVEENA_DRAIN, true); - - // Respawn Anveena if necessary - if (Creature* pAnveena = m_pInstance->GetSingleCreatureFromStorage(NPC_ANVEENA)) - { - if (!pAnveena->isAlive()) - pAnveena->Respawn(); - } - - // Despawn Kalec if already summoned - if (Creature* pKalec = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS, true)) - pKalec->ForcedDespawn(); } // Despawn on wipe m_creature->ForcedDespawn(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) - { m_pInstance->SetData(TYPE_KILJAEDEN, DONE); - - // Start the outro - if (Creature* pKiljaedenController = m_pInstance->GetSingleCreatureFromStorage(NPC_KILJAEDEN_CONTROLLER)) - { - if (npc_kiljaeden_controllerAI* pControllerAI = dynamic_cast(pKiljaedenController->AI())) - pControllerAI->DoStartOutroDialogue(); - } - } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_KALECGOS) { DoScriptText(SAY_KALECGOS_INTRO, pSummoned); - pSummoned->SetLevitate(true); + pSummoned->CastSpell(pSummoned, SPELL_ARCANE_BOLT, true); + pSummoned->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), pSummoned->GetPositionZ(), 30.0f); + } + else if (pSummoned->GetEntry() == NPC_SHIELD_ORB) + { + pSummoned->CastSpell(pSummoned, SPELL_SHADOW_BOLT_AURA, true); + + // Start the movement of the shadow orb - calculate new position based on the angle between the boss and orb + float fX, fY, fAng; + fAng = m_creature->GetAngle(pSummoned) + M_PI_F / 8; + // Normalize angle + if (fAng > 2 * M_PI_F) + fAng = fAng - 2 * M_PI_F; + + m_creature->GetNearPoint2D(fX, fY, 25.0f, fAng); + + // Move to new position + pSummoned->GetMotionMaster()->Clear(); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, pSummoned->GetPositionZ()); + } + else if (pSummoned->GetEntry() == NPC_SINISTER_REFLECTION) + { + if (pSummoned->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)pSummoned; + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + { + pPlayer->CastSpell(pSummoned, SPELL_SINISTER_REFL_CLONE, true); + pSummoned->CastSpell(pSummoned, SPELL_SINISTER_REFL_CLASS, true); + pSummoned->AI()->AttackStart(pPlayer); + } + } } } - void GetAIInformation(ChatHandler& reader) + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SHIELD_ORB) + --m_uiShieldOrbCount; + } + + void GetAIInformation(ChatHandler& reader) override { reader.PSendSysMessage("Kil'jaeden is currently in phase %u", m_uiPhase); } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { if (!m_pInstance) return; @@ -496,20 +534,30 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private DoCastSpellIfCan(m_creature, SPELL_SHADOW_SPIKE); break; case EVENT_DRAGON_ORB: + // Activate blue orbs if (Creature* pKalec = m_pInstance->GetSingleCreatureFromStorage(NPC_KALECGOS)) DoScriptText(irand(0, 1) ? SAY_KALECGOS_ORB_2 : SAY_KALECGOS_ORB_3, pKalec); - // no break + DoActivateDragonOrb(GO_ORB_BLUE_FLIGHT_2); + break; case SAY_KALECGOS_ORB_1: + DoActivateDragonOrb(GO_ORB_BLUE_FLIGHT_1); + break; case SAY_KALECGOS_ORB_4: - // ToDo: activate the blue dragon orbs + DoActivateDragonOrb(GO_ORB_BLUE_FLIGHT_3); + DoActivateDragonOrb(GO_ORB_BLUE_FLIGHT_4); break; case SAY_PHASE_3: + // Set next phase and increase the max shield orbs m_uiPhase = PHASE_DARKNESS; + ++m_uiMaxShieldOrbs; break; case SAY_PHASE_4: + // Set next phase and increase the max shield orbs m_uiPhase = PHASE_ARMAGEDDON; + ++m_uiMaxShieldOrbs; break; case SAY_PHASE_5: + // Set next phase and sacrifice Anveena if (Creature* pAnveena = m_pInstance->GetSingleCreatureFromStorage(NPC_ANVEENA)) { pAnveena->RemoveAurasDueToSpell(SPELL_ANVEENA_PRISON); @@ -521,7 +569,24 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private } } - void UpdateAI(const uint32 uiDiff) + // Wrapper to activate dragon orbs + void DoActivateDragonOrb(uint32 uiEntry) + { + if (!m_pInstance) + return; + + // Set the visual around the Orb + if (GameObject* pGo = m_pInstance->GetSingleGameObjectFromStorage(uiEntry)) + { + if (Creature* pTarget = GetClosestCreatureWithEntry(pGo, NPC_BLUE_ORB_TARGET, 5.0f)) + pTarget->CastSpell(pTarget, SPELL_RING_BLUE_FLAME, false); + } + + // Make the orb usable + m_pInstance->DoToggleGameObjectFlags(uiEntry, GO_FLAG_NO_INTERACT, false); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -555,7 +620,6 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private case PHASE_DARKNESS: // In the last phase he uses this spell more often - /* ToDo: Uncomment this spell when the Blue Dragonfight Orbs are implemented if (m_uiDarknessOfSoulsTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_DARKNESS_OF_SOULS) == CAST_OK) @@ -563,7 +627,6 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private } else m_uiDarknessOfSoulsTimer -= uiDiff; - */ if (m_uiFlameDartTimer < uiDiff) { @@ -584,7 +647,7 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private { if (m_uiKalecSummonTimer <= uiDiff) { - m_creature->SummonCreature(NPC_KALECGOS, m_creature->GetPositionX(), m_creature->GetPositionY(), 85.0f, 3.80f, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_KALECGOS, aKalegSpawnLoc[0], aKalegSpawnLoc[1], aKalegSpawnLoc[2], aKalegSpawnLoc[3], TEMPSUMMON_CORPSE_DESPAWN, 0); m_uiKalecSummonTimer = 0; } else @@ -618,6 +681,24 @@ struct MANGOS_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI, private else m_uiSoulFlyTimer -= uiDiff; + // Only spawn a Shadow orb when necessary + if (m_uiShieldOrbCount < m_uiMaxShieldOrbs) + { + if (m_uiShieldOrbTimer < uiDiff) + { + // Get some random coords for the Orb + float fX, fY, fZ; + m_creature->GetNearPoint2D(fX, fY, 25.0f, frand(0, 2 * M_PI_F)); + fZ = frand(35.0f, 45.0f); + + m_creature->SummonCreature(NPC_SHIELD_ORB, fX, fY, fZ, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + ++m_uiShieldOrbCount; + m_uiShieldOrbTimer = 30000; + } + else + m_uiShieldOrbTimer -= uiDiff; + } + // Go to next phase and start transition dialogue if (m_uiPhase == PHASE_INFERNO && m_creature->GetHealthPercent() < 85.0f) StartNextDialogueText(PHASE_DARKNESS); @@ -639,45 +720,163 @@ bool EffectAuraDummy_spell_aura_dummy_darkness_of_souls(const Aura* pAura, bool { pTarget->CastSpell(pTarget, pAura->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2), true); - switch (irand(0, 2)) + switch (urand(0, 2)) { - case 0: - DoScriptText(SAY_DARKNESS_1, pTarget); - break; - case 1: - DoScriptText(SAY_DARKNESS_2, pTarget); - break; - case 2: - DoScriptText(SAY_DARKNESS_3, pTarget); - break; + case 0: DoScriptText(SAY_DARKNESS_1, pTarget); break; + case 1: DoScriptText(SAY_DARKNESS_2, pTarget); break; + case 2: DoScriptText(SAY_DARKNESS_3, pTarget); break; } } } return true; } -CreatureAI* GetAI_boss_kiljaeden(Creature *pCreature) +/*###### +## npc_shield_orb +######*/ + +struct npc_shield_orbAI : public ScriptedAI +{ + npc_shield_orbAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); + Reset(); + } + + instance_sunwell_plateau* m_pInstance; + + void Reset() override { } + + // Handle circel movement around the boss + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId || !m_pInstance) + return; + + if (Creature* pSummoner = m_pInstance->GetSingleCreatureFromStorage(NPC_KILJAEDEN)) + { + // Calculate new position based on the angle between the boss and self + float fX, fY, fAng; + fAng = pSummoner->GetAngle(m_creature) + M_PI_F / 8; + // Normalize angle + if (fAng > 2 * M_PI_F) + fAng = fAng - 2 * M_PI_F; + + pSummoner->GetNearPoint2D(fX, fY, 25.0f, fAng); + + // Move to new position + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, m_creature->GetPositionZ()); + } + } + + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +/*###### +## npc_power_blue_flight +######*/ + +struct npc_power_blue_flightAI : public ScriptedAI +{ + npc_power_blue_flightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + m_bHasPossessed = false; + Reset(); + } + + bool m_bHasPossessed; + + void Reset() override { } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + pPlayer->RemoveAurasDueToSpell(SPELL_POSSESS_DRAKE_IMMUNE); + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_bHasPossessed) + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + { + pPlayer->CastSpell(m_creature, SPELL_VENGEANCE_BLUE_FLIGHT, true); + pPlayer->CastSpell(pPlayer, SPELL_POSSESS_DRAKE_IMMUNE, true); + } + } + + // Reset the No Interact flag of the closest orb + GameObject* pOrb = GetClosestGameObjectWithEntry(m_creature, GO_ORB_BLUE_FLIGHT_1, 10.0f); + if (!pOrb) + pOrb = GetClosestGameObjectWithEntry(m_creature, GO_ORB_BLUE_FLIGHT_2, 10.0f); + if (!pOrb) + pOrb = GetClosestGameObjectWithEntry(m_creature, GO_ORB_BLUE_FLIGHT_3, 10.0f); + if (!pOrb) + pOrb = GetClosestGameObjectWithEntry(m_creature, GO_ORB_BLUE_FLIGHT_4, 10.0f); + + if (pOrb) + pOrb->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + + m_bHasPossessed = true; + } + } +}; + +CreatureAI* GetAI_boss_kiljaeden(Creature* pCreature) { return new boss_kiljaedenAI(pCreature); } -CreatureAI* GetAI_npc_kiljaeden_controller(Creature *pCreature) +CreatureAI* GetAI_npc_kiljaeden_controller(Creature* pCreature) { return new npc_kiljaeden_controllerAI(pCreature); } +CreatureAI* GetAI_npc_shield_orb(Creature* pCreature) +{ + return new npc_shield_orbAI(pCreature); +} + +CreatureAI* GetAI_npc_power_blue_flight(Creature* pCreature) +{ + return new npc_power_blue_flightAI(pCreature); +} + void AddSC_boss_kiljaeden() { Script* pNewScript; pNewScript = new Script; - pNewScript->Name="boss_kiljaeden"; + pNewScript->Name = "boss_kiljaeden"; pNewScript->GetAI = &GetAI_boss_kiljaeden; pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_darkness_of_souls; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name="npc_kiljaeden_controller"; + pNewScript->Name = "npc_kiljaeden_controller"; pNewScript->GetAI = &GetAI_npc_kiljaeden_controller; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_shield_orb"; + pNewScript->GetAI = &GetAI_npc_shield_orb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_power_blue_flight"; + pNewScript->GetAI = &GetAI_npc_power_blue_flight; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp b/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp index fba08ea08..dd2739f79 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/boss_muru.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_muru -SD%Complete: 80 -SDComment: Spell Negative Energy for Entropius needs core support; Summon humanoids spells have some core issues; Dark Fiend, Singularity and Darkness NPCs need eventAI support +SD%Complete: 90 +SDComment: Small adjustments required SDCategory: Sunwell Plateau EndScriptData */ @@ -56,19 +56,32 @@ enum SPELL_SUMMON_DARKNESS = 46269, // summons 25879 by missile // portal spells - SPELL_SENTINEL_SUMMONER_VISUAL = 45989, // hits the summoner, so it will summon the sentinel + SPELL_SENTINEL_SUMMONER_VISUAL = 45989, // hits the summoner, so it will summon the sentinel; triggers 45988 SPELL_SUMMON_SENTINEL_SUMMONER = 45978, SPELL_TRANSFORM_VISUAL_1 = 46178, // Visual - has Muru as script target SPELL_TRANSFORM_VISUAL_2 = 46208, // Visual - has Muru as script target // Muru npcs NPC_VOID_SENTINEL_SUMMONER = 25782, - NPC_VOID_SENTINEL = 25772, // scripted in Acid + + // darkness spells + SPELL_VOID_ZONE_VISUAL = 46265, + SPELL_VOID_ZONE_PERIODIC = 46262, + SPELL_SUMMON_DARK_FIEND = 46263, + + // singularity spells + SPELL_BLACK_HOLE_VISUAL = 46242, + SPELL_BLACK_HOLE_VISUAL_2 = 46247, + SPELL_BLACK_HOLE_PASSIVE = 46228, MAX_TRANSFORM_CASTS = 10 }; -struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI +/*###### +## boss_muru +######*/ + +struct boss_muruAI : public Scripted_NoMovementAI { boss_muruAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -83,15 +96,15 @@ struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI uint32 m_uiDarkFiendsTimer; bool m_bIsTransition; - void Reset() + void Reset() override { - m_uiDarknessTimer = 45000; - m_uiSummonHumanoidsTimer = 15000; - m_uiDarkFiendsTimer = 0; - m_bIsTransition = false; + m_uiDarknessTimer = 45000; + m_uiSummonHumanoidsTimer = 15000; + m_uiDarkFiendsTimer = 0; + m_bIsTransition = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_MURU, IN_PROGRESS); @@ -100,13 +113,13 @@ struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI DoCastSpellIfCan(m_creature, SPELL_OPEN_PORTAL_PERIODIC, CAST_TRIGGERED); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_MURU, FAIL); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (uiDamage > m_creature->GetHealth()) { @@ -126,7 +139,7 @@ struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -168,7 +181,7 @@ struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND_8, CAST_TRIGGERED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -202,15 +215,18 @@ struct MANGOS_DLL_DECL boss_muruAI : public Scripted_NoMovementAI if (m_uiSummonHumanoidsTimer < uiDiff) { DoSummonHumanoids(); - m_uiSummonHumanoidsTimer = 1*MINUTE*IN_MILLISECONDS; + m_uiSummonHumanoidsTimer = 1 * MINUTE * IN_MILLISECONDS; } else m_uiSummonHumanoidsTimer -= uiDiff; } }; +/*###### +## boss_entropius +######*/ -struct MANGOS_DLL_DECL boss_entropiusAI : public ScriptedAI +struct boss_entropiusAI : public ScriptedAI { boss_entropiusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -223,61 +239,40 @@ struct MANGOS_DLL_DECL boss_entropiusAI : public ScriptedAI uint32 m_uiBlackHoleTimer; uint32 m_uiDarknessTimer; - GUIDList m_lSummonedCreaturesList; + GuidList m_lSummonedCreaturesList; - void Reset() + void Reset() override { m_uiBlackHoleTimer = 15000; m_uiDarknessTimer = 20000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, SPELL_NEGATIVE_ENERGY_ENT); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_MURU, DONE); - - // Despawn summoned creatures - DespawnSummonedCreatures(); - } - - void JustSummoned(Creature* pSummoned) - { - // Add the Darkness and Singularity into the list - m_lSummonedCreaturesList.push_back(pSummoned->GetObjectGuid()); - } - - // Wrapper to despawn the Singularities and Darkness on death or on evade - void DespawnSummonedCreatures() - { - for (GUIDList::const_iterator itr = m_lSummonedCreaturesList.begin(); itr != m_lSummonedCreaturesList.end(); ++itr) - { - if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) - pTemp->ForcedDespawn(); - } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { m_pInstance->SetData(TYPE_MURU, FAIL); // respawn muru - if (Creature* pMuru = m_pInstance->GetSingleCreatureFromStorage(NPC_MURU)) - pMuru->Respawn(); + m_creature->SummonCreature(NPC_MURU, afMuruSpawnLoc[0], afMuruSpawnLoc[1], afMuruSpawnLoc[2], afMuruSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); } // despawn boss and summons for reset - DespawnSummonedCreatures(); m_creature->ForcedDespawn(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -308,7 +303,11 @@ struct MANGOS_DLL_DECL boss_entropiusAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL npc_portal_targetAI : public Scripted_NoMovementAI +/*###### +## npc_portal_target +######*/ + +struct npc_portal_targetAI : public Scripted_NoMovementAI { npc_portal_targetAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -322,38 +321,38 @@ struct MANGOS_DLL_DECL npc_portal_targetAI : public Scripted_NoMovementAI uint32 m_uiTransformTimer; uint32 m_uiSentinelTimer; - void Reset() + void Reset() override { m_uiTransformCount = 0; m_uiTransformTimer = 0; m_uiSentinelTimer = 0; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Cast a visual ball on the summoner if (pSummoned->GetEntry() == NPC_VOID_SENTINEL_SUMMONER) DoCastSpellIfCan(pSummoned, SPELL_SENTINEL_SUMMONER_VISUAL, CAST_TRIGGERED); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { // These spells are dummies, but are used only to init the timers // They could use the EffectDummyCreature to handle this, but this makes code easier switch (pSpell->Id) { - // Init sentinel summon timer + // Init sentinel summon timer case SPELL_OPEN_PORTAL: m_uiSentinelTimer = 5000; break; - // Start transition effect + // Start transition effect case SPELL_OPEN_ALL_PORTALS: m_uiTransformTimer = 2000; break; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiSentinelTimer) { @@ -373,7 +372,7 @@ struct MANGOS_DLL_DECL npc_portal_targetAI : public Scripted_NoMovementAI { // Alternate the visuals ++m_uiTransformCount; - DoCastSpellIfCan(m_creature, m_uiTransformCount % 2 ? SPELL_TRANSFORM_VISUAL_1 : SPELL_TRANSFORM_VISUAL_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, (m_uiTransformCount % 2) ? SPELL_TRANSFORM_VISUAL_1 : SPELL_TRANSFORM_VISUAL_2, CAST_TRIGGERED); if (m_uiTransformCount < MAX_TRANSFORM_CASTS) m_uiTransformTimer = 1000; @@ -384,7 +383,7 @@ struct MANGOS_DLL_DECL npc_portal_targetAI : public Scripted_NoMovementAI } // Summon Entropius when reached half of the transition - if (m_uiTransformCount == MAX_TRANSFORM_CASTS/2) + if (m_uiTransformCount == MAX_TRANSFORM_CASTS / 2) { if (Creature* pMuru = m_pInstance->GetSingleCreatureFromStorage(NPC_MURU)) pMuru->CastSpell(pMuru, SPELL_SUMMON_ENTROPIUS, false); @@ -396,52 +395,116 @@ struct MANGOS_DLL_DECL npc_portal_targetAI : public Scripted_NoMovementAI } }; -struct MANGOS_DLL_DECL npc_void_sentinel_summonerAI : public Scripted_NoMovementAI +/*###### +## npc_darkness +######*/ + +struct npc_darknessAI : public Scripted_NoMovementAI { - npc_void_sentinel_summonerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + npc_darknessAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiActiveTimer; + + void Reset() override { - m_pInstance = ((instance_sunwell_plateau*)pCreature->GetInstanceData()); - Reset(); + DoCastSpellIfCan(m_creature, SPELL_VOID_ZONE_VISUAL, CAST_TRIGGERED); + m_uiActiveTimer = 5000; } - instance_sunwell_plateau* m_pInstance; + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() { } + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DARK_FIEND) + pSummoned->SetInCombatWithZone(); + } - void JustSummoned(Creature* pSummoned) + void UpdateAI(const uint32 uiDiff) override { - if (pSummoned->GetEntry() == NPC_VOID_SENTINEL) + if (m_uiActiveTimer) { - // Attack Muru's target - if (Creature* pMuru = m_pInstance->GetSingleCreatureFromStorage(NPC_MURU)) + if (m_uiActiveTimer <= uiDiff) { - if (Unit* pTarget = pMuru->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + DoCastSpellIfCan(m_creature, SPELL_VOID_ZONE_PERIODIC, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_FIEND, CAST_TRIGGERED); + m_uiActiveTimer = 0; } + else + m_uiActiveTimer -= uiDiff; } } +}; + +/*###### +## npc_singularity +######*/ + +struct npc_singularityAI : public Scripted_NoMovementAI +{ + npc_singularityAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiActiveTimer; + uint8 m_uiActivateStage; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_BLACK_HOLE_VISUAL, CAST_TRIGGERED); + m_uiActiveTimer = 1000; + m_uiActivateStage = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void UpdateAI(const uint32 uiDiff) { } + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiActiveTimer) + { + if (m_uiActiveTimer <= uiDiff) + { + switch (m_uiActivateStage) + { + case 0: + if (DoCastSpellIfCan(m_creature, SPELL_BLACK_HOLE_VISUAL_2) == CAST_OK) + m_uiActiveTimer = 4000; + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_BLACK_HOLE_PASSIVE) == CAST_OK) + m_uiActiveTimer = 0; + break; + } + ++m_uiActivateStage; + } + else + m_uiActiveTimer -= uiDiff; + } + } }; -CreatureAI* GetAI_boss_muru(Creature *pCreature) +CreatureAI* GetAI_boss_muru(Creature* pCreature) { return new boss_muruAI(pCreature); } -CreatureAI* GetAI_boss_entropius(Creature *pCreature) +CreatureAI* GetAI_boss_entropius(Creature* pCreature) { return new boss_entropiusAI(pCreature); } -CreatureAI* GetAI_npc_portal_target(Creature *pCreature) +CreatureAI* GetAI_npc_portal_target(Creature* pCreature) { return new npc_portal_targetAI(pCreature); } -CreatureAI* GetAI_npc_void_sentinel_summoner(Creature *pCreature) +CreatureAI* GetAI_npc_darkness(Creature* pCreature) { - return new npc_void_sentinel_summonerAI(pCreature); + return new npc_darknessAI(pCreature); +} + +CreatureAI* GetAI_npc_singularity(Creature* pCreature) +{ + return new npc_singularityAI(pCreature); } void AddSC_boss_muru() @@ -449,22 +512,27 @@ void AddSC_boss_muru() Script* pNewScript; pNewScript = new Script; - pNewScript->Name="boss_muru"; + pNewScript->Name = "boss_muru"; pNewScript->GetAI = &GetAI_boss_muru; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name="boss_entropius"; + pNewScript->Name = "boss_entropius"; pNewScript->GetAI = &GetAI_boss_entropius; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name="npc_portal_target"; + pNewScript->Name = "npc_portal_target"; pNewScript->GetAI = &GetAI_npc_portal_target; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name="npc_void_sentinel_summoner"; - pNewScript->GetAI = &GetAI_npc_void_sentinel_summoner; + pNewScript->Name = "npc_darkness"; + pNewScript->GetAI = &GetAI_npc_darkness; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_singularity"; + pNewScript->GetAI = &GetAI_npc_singularity; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp b/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp index bb117f042..a89f9961a 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp +++ b/scripts/eastern_kingdoms/sunwell_plateau/instance_sunwell_plateau.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,17 +35,20 @@ EndScriptData */ static const DialogueEntry aFelmystOutroDialogue[] = { - {NPC_KALECGOS, 0, 10000}, - {SAY_KALECGOS_OUTRO, NPC_KALECGOS, 10000}, - {SPELL_OPEN_BACK_DOOR, 0, 0}, + {NPC_KALECGOS_MADRIGOSA, 0, 10000}, + {SAY_KALECGOS_OUTRO, NPC_KALECGOS_MADRIGOSA, 5000}, + {NPC_FELMYST, 0, 5000}, + {SPELL_OPEN_BACK_DOOR, 0, 9000}, + {NPC_BRUTALLUS, 0, 0}, {0, 0, 0}, }; instance_sunwell_plateau::instance_sunwell_plateau(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aFelmystOutroDialogue), - m_uiMuruBerserkTimer(0), m_uiDeceiversKilled(0), + m_uiSpectralRealmTimer(5000), m_uiKalecRespawnTimer(0), - m_uiSpectralRealmTimer(5000) + m_uiMuruBerserkTimer(0), + m_uiKiljaedenYellTimer(90000) { Initialize(); } @@ -58,7 +61,7 @@ void instance_sunwell_plateau::Initialize() bool instance_sunwell_plateau::IsEncounterInProgress() const { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) return true; @@ -69,29 +72,35 @@ bool instance_sunwell_plateau::IsEncounterInProgress() const void instance_sunwell_plateau::OnPlayerEnter(Player* pPlayer) { - // Return if Felmyst already dead, or Brutallus alive - if (m_auiEncounter[TYPE_BRUTALLUS] != DONE || m_auiEncounter[TYPE_FELMYST] == DONE) - return; - - // Return if already summoned - if (GetSingleCreatureFromStorage(NPC_FELMYST, true)) - return; + // Spawn Felmyst if not already dead and Brutallus is complete + if (m_auiEncounter[TYPE_BRUTALLUS] == DONE && m_auiEncounter[TYPE_FELMYST] != DONE) + { + // Summon Felmyst in reload case if not already summoned + if (!GetSingleCreatureFromStorage(NPC_FELMYST, true)) + pPlayer->SummonCreature(NPC_FELMYST, aMadrigosaLoc[0].m_fX, aMadrigosaLoc[0].m_fY, aMadrigosaLoc[0].m_fZ, aMadrigosaLoc[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0, true); + } - // Summon Felmyst in reload case - pPlayer->SummonCreature(NPC_FELMYST, aMadrigosaGroundLoc[0], aMadrigosaGroundLoc[1], aMadrigosaGroundLoc[2], aMadrigosaGroundLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + // Spawn M'uru after the Eredar Twins + if (m_auiEncounter[TYPE_EREDAR_TWINS] == DONE && m_auiEncounter[TYPE_MURU] != DONE) + { + if (!GetSingleCreatureFromStorage(NPC_MURU, true)) + pPlayer->SummonCreature(NPC_MURU, afMuruSpawnLoc[0], afMuruSpawnLoc[1], afMuruSpawnLoc[2], afMuruSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + } } void instance_sunwell_plateau::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_KALECGOS_DRAGON: case NPC_KALECGOS_HUMAN: case NPC_SATHROVARR: case NPC_FLIGHT_TRIGGER_LEFT: + case NPC_FLIGHT_TRIGGER_RIGHT: case NPC_MADRIGOSA: case NPC_BRUTALLUS: case NPC_FELMYST: + case NPC_KALECGOS_MADRIGOSA: case NPC_ALYTHESS: case NPC_SACROLASH: case NPC_MURU: @@ -104,6 +113,24 @@ void instance_sunwell_plateau::OnCreatureCreate(Creature* pCreature) case NPC_LIADRIN: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_DECEIVER: + m_lDeceiversGuidList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_WORLD_TRIGGER: + // sort triggers for flightpath + if (pCreature->GetPositionZ() < 51.0f) + m_lAllFlightTriggersList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_WORLD_TRIGGER_LARGE: + if (pCreature->GetPositionY() < 523.0f) + m_lBackdoorTriggersList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_BERSERKER: + case NPC_FURY_MAGE: + case NPC_DARK_FIEND: + case NPC_VOID_SENTINEL: + m_lMuruTrashGuidList.push_back(pCreature->GetObjectGuid()); + return; } } @@ -126,9 +153,16 @@ void instance_sunwell_plateau::OnCreatureDeath(Creature* pCreature) } } +void instance_sunwell_plateau::OnCreatureEvade(Creature* pCreature) +{ + // Reset encounter if raid wipes at deceivers + if (pCreature->GetEntry() == NPC_DECEIVER) + SetData(TYPE_KILJAEDEN, FAIL); +} + void instance_sunwell_plateau::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_FORCEFIELD: case GO_BOSS_COLLISION_1: @@ -139,23 +173,16 @@ void instance_sunwell_plateau::OnObjectCreate(GameObject* pGo) if (m_auiEncounter[TYPE_KALECGOS] == DONE && m_auiEncounter[TYPE_BRUTALLUS] == DONE && m_auiEncounter[TYPE_FELMYST] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_FIRST_GATE: - break; - case GO_SECOND_GATE: - if (m_auiEncounter[TYPE_EREDAR_TWINS] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_MURU_ENTER_GATE: - if (m_auiEncounter[TYPE_EREDAR_TWINS] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_MURU_EXIT_GATE: if (m_auiEncounter[TYPE_MURU] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_THIRD_GATE: - if (m_auiEncounter[TYPE_MURU] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); + case GO_ORB_BLUE_FLIGHT_1: + case GO_ORB_BLUE_FLIGHT_2: + case GO_ORB_BLUE_FLIGHT_3: + case GO_ORB_BLUE_FLIGHT_4: break; default: @@ -166,7 +193,7 @@ void instance_sunwell_plateau::OnObjectCreate(GameObject* pGo) void instance_sunwell_plateau::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_KALECGOS: m_auiEncounter[uiType] = uiData; @@ -188,25 +215,20 @@ void instance_sunwell_plateau::SetData(uint32 uiType, uint32 uiData) break; case TYPE_BRUTALLUS: m_auiEncounter[uiType] = uiData; - // Temporary - until spells 46609 and 46637 are properly fixed - if (uiData == SPECIAL) - DoUseDoorOrButton(GO_ICE_BARRIER, MINUTE); break; case TYPE_FELMYST: m_auiEncounter[uiType] = uiData; if (uiData == DONE) - { - StartNextDialogueText(NPC_KALECGOS); - // Temporary - until spell 46650 is properly fixed - DoUseDoorOrButton(GO_FIRE_BARRIER); - } + StartNextDialogueText(NPC_KALECGOS_MADRIGOSA); + else if (uiData == IN_PROGRESS) + DoSortFlightTriggers(); break; case TYPE_EREDAR_TWINS: m_auiEncounter[uiType] = uiData; if (uiData == DONE) { - DoUseDoorOrButton(GO_SECOND_GATE); - DoUseDoorOrButton(GO_MURU_ENTER_GATE); + if (Player* pPlayer = GetPlayerInMap()) + pPlayer->SummonCreature(NPC_MURU, afMuruSpawnLoc[0], afMuruSpawnLoc[1], afMuruSpawnLoc[2], afMuruSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); } break; case TYPE_MURU: @@ -214,18 +236,43 @@ void instance_sunwell_plateau::SetData(uint32 uiType, uint32 uiData) // combat door DoUseDoorOrButton(GO_MURU_ENTER_GATE); if (uiData == DONE) - { DoUseDoorOrButton(GO_MURU_EXIT_GATE); - DoUseDoorOrButton(GO_THIRD_GATE); - } else if (uiData == IN_PROGRESS) - m_uiMuruBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiMuruBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + if (uiData == FAIL || uiData == DONE) + { + // clear all the trash mobs + for (GuidList::const_iterator itr = m_lMuruTrashGuidList.begin(); itr != m_lMuruTrashGuidList.end(); ++itr) + { + if (Creature* pTrash = instance->GetCreature(*itr)) + pTrash->ForcedDespawn(); + } + + m_lMuruTrashGuidList.clear(); + } break; case TYPE_KILJAEDEN: m_auiEncounter[uiType] = uiData; - // When event fails the deceivers are respawned so restart the counter if (uiData == FAIL) + { m_uiDeceiversKilled = 0; + + // Reset Orbs + DoToggleGameObjectFlags(GO_ORB_BLUE_FLIGHT_1, GO_FLAG_NO_INTERACT, true); + DoToggleGameObjectFlags(GO_ORB_BLUE_FLIGHT_2, GO_FLAG_NO_INTERACT, true); + DoToggleGameObjectFlags(GO_ORB_BLUE_FLIGHT_3, GO_FLAG_NO_INTERACT, true); + DoToggleGameObjectFlags(GO_ORB_BLUE_FLIGHT_4, GO_FLAG_NO_INTERACT, true); + + // Respawn deceivers + for (GuidList::const_iterator itr = m_lDeceiversGuidList.begin(); itr != m_lDeceiversGuidList.end(); ++itr) + { + if (Creature* pDeceiver = instance->GetCreature(*itr)) + { + if (!pDeceiver->isAlive()) + pDeceiver->Respawn(); + } + } + } break; } @@ -235,7 +282,7 @@ void instance_sunwell_plateau::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; m_strInstData = saveStream.str(); @@ -244,7 +291,7 @@ void instance_sunwell_plateau::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_sunwell_plateau::GetData(uint32 uiType) +uint32 instance_sunwell_plateau::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -273,18 +320,36 @@ void instance_sunwell_plateau::Update(uint32 uiDiff) // Muru berserk timer; needs to be done here because it involves two distinct creatures if (m_auiEncounter[TYPE_MURU] == IN_PROGRESS) { - if (m_uiMuruBerserkTimer <= uiDiff) + if (m_uiMuruBerserkTimer < uiDiff) { if (Creature* pEntrpius = GetSingleCreatureFromStorage(NPC_ENTROPIUS, true)) pEntrpius->CastSpell(pEntrpius, SPELL_MURU_BERSERK, true); else if (Creature* pMuru = GetSingleCreatureFromStorage(NPC_MURU)) pMuru->CastSpell(pMuru, SPELL_MURU_BERSERK, true); - m_uiMuruBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiMuruBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; } else m_uiMuruBerserkTimer -= uiDiff; } + + if (m_auiEncounter[TYPE_KILJAEDEN] == NOT_STARTED || m_auiEncounter[TYPE_KILJAEDEN] == FAIL) + { + if (m_uiKiljaedenYellTimer < uiDiff) + { + switch (urand(0, 4)) + { + case 0: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_1, NPC_KILJAEDEN_CONTROLLER); break; + case 1: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_2, NPC_KILJAEDEN_CONTROLLER); break; + case 2: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_3, NPC_KILJAEDEN_CONTROLLER); break; + case 3: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_4, NPC_KILJAEDEN_CONTROLLER); break; + case 4: DoOrSimulateScriptTextForThisInstance(SAY_ORDER_5, NPC_KILJAEDEN_CONTROLLER); break; + } + m_uiKiljaedenYellTimer = 90000; + } + else + m_uiKiljaedenYellTimer -= uiDiff; + } } void instance_sunwell_plateau::Load(const char* in) @@ -299,9 +364,9 @@ void instance_sunwell_plateau::Load(const char* in) std::istringstream loadStream(in); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> - m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; + m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -310,24 +375,100 @@ void instance_sunwell_plateau::Load(const char* in) OUT_LOAD_INST_DATA_COMPLETE; } +static bool sortByPositionX(Creature* pFirst, Creature* pSecond) +{ + return pFirst && pSecond && pFirst->GetPositionX() > pSecond->GetPositionX(); +} + +void instance_sunwell_plateau::DoSortFlightTriggers() +{ + if (m_lAllFlightTriggersList.empty()) + { + script_error_log("Instance Sunwell Plateau: ERROR Failed to load flight triggers for creature id %u.", NPC_FELMYST); + return; + } + + std::list lTriggers; // Valid pointers, only used locally + for (GuidList::const_iterator itr = m_lAllFlightTriggersList.begin(); itr != m_lAllFlightTriggersList.end(); ++itr) + { + if (Creature* pTrigger = instance->GetCreature(*itr)) + lTriggers.push_back(pTrigger); + } + + if (lTriggers.empty()) + return; + + // sort the flight triggers; first by position X, then group them by Y (left and right) + lTriggers.sort(sortByPositionX); + for (std::list::iterator itr = lTriggers.begin(); itr != lTriggers.end(); ++itr) + { + if ((*itr)->GetPositionY() < 600.0f) + m_vRightFlightTriggersVect.push_back((*itr)->GetObjectGuid()); + else + m_vLeftFlightTriggersVect.push_back((*itr)->GetObjectGuid()); + } +} + +ObjectGuid instance_sunwell_plateau::SelectFelmystFlightTrigger(bool bLeftSide, uint8 uiIndex) +{ + // Return the flight trigger from the selected index + GuidVector& vTemp = bLeftSide ? m_vLeftFlightTriggersVect : m_vRightFlightTriggersVect; + + if (uiIndex >= vTemp.size()) + return ObjectGuid(); + + return vTemp[uiIndex]; +} + +void instance_sunwell_plateau::DoEjectSpectralPlayers() +{ + for (GuidSet::const_iterator itr = m_spectralRealmPlayers.begin(); itr != m_spectralRealmPlayers.end(); ++itr) + { + if (Player* pPlayer = instance->GetPlayer(*itr)) + { + if (!pPlayer->HasAura(SPELL_SPECTRAL_REALM_AURA)) + continue; + + pPlayer->CastSpell(pPlayer, SPELL_TELEPORT_NORMAL_REALM, true); + pPlayer->CastSpell(pPlayer, SPELL_SPECTRAL_EXHAUSTION, true); + pPlayer->RemoveAurasDueToSpell(SPELL_SPECTRAL_REALM_AURA); + } + } +} + void instance_sunwell_plateau::JustDidDialogueStep(int32 iEntry) { switch (iEntry) { - case NPC_KALECGOS: + case NPC_KALECGOS_MADRIGOSA: if (Creature* pTrigger = GetSingleCreatureFromStorage(NPC_FLIGHT_TRIGGER_LEFT)) { - if (Creature* pKalec = pTrigger->SummonCreature(NPC_KALECGOS, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 1*MINUTE*IN_MILLISECONDS)) + if (Creature* pKalec = pTrigger->SummonCreature(NPC_KALECGOS_MADRIGOSA, aKalecLoc[0].m_fX, aKalecLoc[0].m_fY, aKalecLoc[0].m_fZ, aKalecLoc[0].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 0)) { pKalec->SetWalk(false); pKalec->SetLevitate(true); - pKalec->GetMotionMaster()->MovePoint(0, aMadrigosaFlyLoc[0], aMadrigosaFlyLoc[1], aMadrigosaFlyLoc[2]); + pKalec->GetMotionMaster()->MovePoint(0, aKalecLoc[1].m_fX, aKalecLoc[1].m_fY, aKalecLoc[1].m_fZ, false); } } break; + case NPC_FELMYST: + if (Creature* pKalec = GetSingleCreatureFromStorage(NPC_KALECGOS_MADRIGOSA)) + pKalec->GetMotionMaster()->MovePoint(0, aKalecLoc[2].m_fX, aKalecLoc[2].m_fY, aKalecLoc[2].m_fZ, false); + break; case SPELL_OPEN_BACK_DOOR: - if (Creature* pKalec = GetSingleCreatureFromStorage(NPC_KALECGOS)) - pKalec->CastSpell(pKalec, SPELL_OPEN_BACK_DOOR, true); + if (Creature* pKalec = GetSingleCreatureFromStorage(NPC_KALECGOS_MADRIGOSA)) + { + // ToDo: update this when the AoE spell targeting will support many explicit target. Kalec should target all creatures from the list + if (Creature* pTrigger = instance->GetCreature(m_lBackdoorTriggersList.front())) + pKalec->CastSpell(pTrigger, SPELL_OPEN_BACK_DOOR, true); + } + break; + case NPC_BRUTALLUS: + if (Creature* pKalec = GetSingleCreatureFromStorage(NPC_KALECGOS_MADRIGOSA)) + { + pKalec->ForcedDespawn(10000); + pKalec->GetMotionMaster()->MovePoint(0, aKalecLoc[3].m_fX, aKalecLoc[3].m_fY, aKalecLoc[3].m_fZ, false); + } break; } } diff --git a/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h b/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h index 3ba53dc15..ba514b3cc 100644 --- a/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h +++ b/scripts/eastern_kingdoms/sunwell_plateau/sunwell_plateau.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -19,15 +19,22 @@ enum NPC_KALECGOS_DRAGON = 24850, // kalecgos blue dragon hostile NPC_KALECGOS_HUMAN = 24891, // kalecgos human form in spectral realm NPC_SATHROVARR = 24892, - NPC_MADRIGOSA = 25160, + NPC_MADRIGOSA = 24895, NPC_FLIGHT_TRIGGER_LEFT = 25357, // Related to Felmyst flight path. Also the anchor to summon Madrigosa - // NPC_FLIGHT_TRIGGER_RIGHT = 25358, // related to Felmyst flight path + NPC_FLIGHT_TRIGGER_RIGHT = 25358, // related to Felmyst flight path + NPC_WORLD_TRIGGER = 22515, + NPC_WORLD_TRIGGER_LARGE = 23472, // ground triggers spawned in Brutallus / Felmyst arena NPC_BRUTALLUS = 24882, NPC_FELMYST = 25038, + NPC_KALECGOS_MADRIGOSA = 24844, // kalecgos blue dragon; spawns after Felmyst NPC_ALYTHESS = 25166, NPC_SACROLASH = 25165, NPC_MURU = 25741, NPC_ENTROPIUS = 25840, + NPC_BERSERKER = 25798, // muru trash mobs - scripted in Acid + NPC_FURY_MAGE = 25799, + NPC_DARK_FIEND = 25744, + NPC_VOID_SENTINEL = 25772, NPC_DECEIVER = 25588, NPC_KILJAEDEN = 25315, NPC_KILJAEDEN_CONTROLLER = 25608, // kiljaeden event controller @@ -41,17 +48,33 @@ enum GO_BOSS_COLLISION_2 = 188524, GO_ICE_BARRIER = 188119, // used to block the players path during the Brutallus intro event GO_FIRE_BARRIER = 188075, // door after felmyst - GO_FIRST_GATE = 187766, // door between felmyst and eredar twins - GO_SECOND_GATE = 187764, // door after eredar twins + // GO_FIRST_GATE = 187766, // door between felmyst and eredar twins + // GO_SECOND_GATE = 187764, // door after eredar twins GO_MURU_ENTER_GATE = 187990, // muru gates GO_MURU_EXIT_GATE = 188118, - GO_THIRD_GATE = 187765, // door after muru; why another? + // GO_THIRD_GATE = 187765, // door after muru; why another? + + GO_ORB_BLUE_FLIGHT_1 = 188115, // orbs used in the Kil'jaeden fight + GO_ORB_BLUE_FLIGHT_2 = 188116, + GO_ORB_BLUE_FLIGHT_3 = 187869, + GO_ORB_BLUE_FLIGHT_4 = 188114, SAY_KALECGOS_OUTRO = -1580043, SAY_TWINS_INTRO = -1580044, + // Kil'jaeden yells + SAY_ORDER_1 = -1580064, + SAY_ORDER_2 = -1580065, + SAY_ORDER_3 = -1580066, + SAY_ORDER_4 = -1580067, + SAY_ORDER_5 = -1580068, + AREATRIGGER_TWINS = 4937, + // Kalec spectral realm spells + SPELL_TELEPORT_NORMAL_REALM = 46020, + SPELL_SPECTRAL_REALM_AURA = 46021, + SPELL_SPECTRAL_EXHAUSTION = 44867, // Felmyst ouro spell SPELL_OPEN_BACK_DOOR = 46650, // Opens the fire barrier - script effect for 46652 // used by both muru and entropius @@ -62,35 +85,59 @@ enum MAX_DECEIVERS = 3 }; -// Used to summon Felmyst in reload case. This is the place where Madrigosa is killed in the intro event -static const float aMadrigosaGroundLoc[4] = {1459.35f, 636.81f, 19.94f, 4.88f}; -// Used as an anchor to move Madrigosa and Kalec during the cinematic -static const float aMadrigosaFlyLoc[3] = {1459.35f, 636.81f, 59.234f}; +struct EventLocations +{ + float m_fX, m_fY, m_fZ, m_fO; +}; + +static const EventLocations aMadrigosaLoc[] = +{ + {1463.82f, 661.212f, 19.79f, 4.88f}, // reload spawn loc - the place where to spawn Felmyst + {1463.82f, 661.212f, 39.234f}, // fly loc during the cinematig +}; -class MANGOS_DLL_DECL instance_sunwell_plateau : public ScriptedInstance, private DialogueHelper +static const EventLocations aKalecLoc[] = +{ + {1573.146f, 755.2025f, 99.524f, 3.59f}, // spawn loc + {1474.235f, 624.0703f, 29.325f}, // first move + {1511.655f, 550.7028f, 25.510f}, // open door + {1648.255f, 519.377f, 165.848f}, // fly away +}; + +static const float afMuruSpawnLoc[4] = { 1816.25f, 625.484f, 69.603f, 5.624f }; + +class instance_sunwell_plateau : public ScriptedInstance, private DialogueHelper { public: instance_sunwell_plateau(Map* pMap); ~instance_sunwell_plateau() {} - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature); + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnPlayerEnter(Player* pPlayer); - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void Update(uint32 uiDiff) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + ObjectGuid SelectFelmystFlightTrigger(bool bLeftSide, uint8 uiIndex); - void Update(uint32 uiDiff); + void AddToSpectralRealm(ObjectGuid playerGuid) { m_spectralRealmPlayers.insert(playerGuid); } + void RemoveFromSpectralRealm(ObjectGuid playerGuid) { m_spectralRealmPlayers.erase(playerGuid); } + void DoEjectSpectralPlayers(); - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: - void JustDidDialogueStep(int32 iEntry); + void JustDidDialogueStep(int32 iEntry) override; + void DoSortFlightTriggers(); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; @@ -100,5 +147,14 @@ class MANGOS_DLL_DECL instance_sunwell_plateau : public ScriptedInstance, privat uint32 m_uiSpectralRealmTimer; uint32 m_uiKalecRespawnTimer; uint32 m_uiMuruBerserkTimer; + uint32 m_uiKiljaedenYellTimer; + + GuidSet m_spectralRealmPlayers; + GuidVector m_vRightFlightTriggersVect; + GuidVector m_vLeftFlightTriggersVect; + GuidList m_lAllFlightTriggersList; + GuidList m_lBackdoorTriggersList; + GuidList m_lDeceiversGuidList; + GuidList m_lMuruTrashGuidList; }; #endif diff --git a/scripts/eastern_kingdoms/swamp_of_sorrows.cpp b/scripts/eastern_kingdoms/swamp_of_sorrows.cpp index 6c01a1e9a..95217731f 100644 --- a/scripts/eastern_kingdoms/swamp_of_sorrows.cpp +++ b/scripts/eastern_kingdoms/swamp_of_sorrows.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -47,50 +47,50 @@ enum Galen EMOTE_DISAPPEAR = -1000588 }; -struct MANGOS_DLL_DECL npc_galen_goodwardAI : public npc_escortAI +struct npc_galen_goodwardAI : public npc_escortAI { npc_galen_goodwardAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } ObjectGuid m_galensCageGuid; uint32 m_uiPeriodicSay; - void Reset() + void Reset() override { m_uiPeriodicSay = 6000; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) DoScriptText(urand(0, 1) ? SAY_ATTACKED_1 : SAY_ATTACKED_2, m_creature, pWho); } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { switch (uiPointId) { case 0: + { + GameObject* pCage = NULL; + if (m_galensCageGuid) + pCage = m_creature->GetMap()->GetGameObject(m_galensCageGuid); + else + pCage = GetClosestGameObjectWithEntry(m_creature, GO_GALENS_CAGE, INTERACTION_DISTANCE); + + if (pCage) { - GameObject* pCage = NULL; - if (m_galensCageGuid) - pCage = m_creature->GetMap()->GetGameObject(m_galensCageGuid); - else - pCage = GetClosestGameObjectWithEntry(m_creature, GO_GALENS_CAGE, INTERACTION_DISTANCE); - - if (pCage) - { - pCage->UseDoorOrButton(); - m_galensCageGuid = pCage->GetObjectGuid(); - } - break; + pCage->UseDoorOrButton(); + m_galensCageGuid = pCage->GetObjectGuid(); } + break; + } case 21: DoScriptText(EMOTE_DISAPPEAR, m_creature); break; } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { @@ -111,7 +111,7 @@ struct MANGOS_DLL_DECL npc_galen_goodwardAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_uiPeriodicSay < uiDiff) @@ -138,7 +138,7 @@ bool QuestAccept_npc_galen_goodward(Player* pPlayer, Creature* pCreature, const if (npc_galen_goodwardAI* pEscortAI = dynamic_cast(pCreature->AI())) { pEscortAI->Start(false, pPlayer, pQuest); - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_QUEST_ACCEPTED, pCreature); } } diff --git a/scripts/eastern_kingdoms/tirisfal_glades.cpp b/scripts/eastern_kingdoms/tirisfal_glades.cpp index cff10fbd4..50c0c9e8d 100644 --- a/scripts/eastern_kingdoms/tirisfal_glades.cpp +++ b/scripts/eastern_kingdoms/tirisfal_glades.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -42,7 +42,7 @@ enum GO_DOOR = 176594 }; -bool GOUse_go_mausoleum_door(Player* pPlayer, GameObject* pGo) +bool GOUse_go_mausoleum_door(Player* pPlayer, GameObject* /*pGo*/) { if (pPlayer->GetQuestStatus(QUEST_ULAG) != QUEST_STATUS_INCOMPLETE) return false; @@ -50,7 +50,7 @@ bool GOUse_go_mausoleum_door(Player* pPlayer, GameObject* pGo) if (GameObject* pTrigger = GetClosestGameObjectWithEntry(pPlayer, GO_TRIGGER, 30.0f)) { pTrigger->SetGoState(GO_STATE_READY); - pPlayer->SummonCreature(NPC_ULAG, 2390.26f, 336.47f, 40.01f, 2.26f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); + pPlayer->SummonCreature(NPC_ULAG, 2390.26f, 336.47f, 40.01f, 2.26f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000); return false; } @@ -65,7 +65,7 @@ bool GOUse_go_mausoleum_trigger(Player* pPlayer, GameObject* pGo) if (GameObject* pDoor = GetClosestGameObjectWithEntry(pPlayer, GO_DOOR, 30.0f)) { pGo->SetGoState(GO_STATE_ACTIVE); - pDoor->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_INTERACT_COND); + pDoor->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); return true; } @@ -84,30 +84,25 @@ enum FACTION_HOSTILE = 168 }; -struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI +struct npc_calvin_montagueAI : public ScriptedAI { npc_calvin_montagueAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiNormFaction = pCreature->getFaction(); Reset(); } - uint32 m_uiNormFaction; uint32 m_uiPhase; uint32 m_uiPhaseTimer; ObjectGuid m_playerGuid; - void Reset() + void Reset() override { m_uiPhase = 0; m_uiPhaseTimer = 5000; m_playerGuid.Clear(); - - if (m_creature->getFaction() != m_uiNormFaction) - m_creature->setFaction(m_uiNormFaction); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim() || m_creature->IsFriendlyTo(pAttacker)) return; @@ -115,13 +110,12 @@ struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { - if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() < 15)) + if (uiDamage > m_creature->GetHealth() || ((m_creature->GetHealth() - uiDamage) * 100 / m_creature->GetMaxHealth() < 15)) { uiDamage = 0; - m_creature->setFaction(m_uiNormFaction); m_creature->CombatStop(true); m_uiPhase = 1; @@ -131,7 +125,7 @@ struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiPhase) { @@ -143,7 +137,7 @@ struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI return; } - switch(m_uiPhase) + switch (m_uiPhase) { case 1: DoScriptText(SAY_COMPLETE, m_creature); @@ -153,7 +147,7 @@ struct MANGOS_DLL_DECL npc_calvin_montagueAI : public ScriptedAI if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) pPlayer->AreaExploredOrEventHappens(QUEST_590); - m_creature->CastSpell(m_creature,SPELL_DRINK,true); + m_creature->CastSpell(m_creature, SPELL_DRINK, true); ++m_uiPhase; break; case 3: @@ -180,7 +174,7 @@ bool QuestAccept_npc_calvin_montague(Player* pPlayer, Creature* pCreature, const { if (pQuest->GetQuestId() == QUEST_590) { - pCreature->setFaction(FACTION_HOSTILE); + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN); pCreature->AI()->AttackStart(pPlayer); } return true; diff --git a/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp b/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp index e80356294..873995736 100644 --- a/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp +++ b/scripts/eastern_kingdoms/uldaman/boss_archaedas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Archaedas -SD%Complete: 60 -SDComment: Need correct way to deal with awaken vault and guardian spells, waiting for additions in mangos for them (target combination 22/7) +SD%Complete: 100 +SDComment: SDCategory: Uldaman EndScriptData */ @@ -26,21 +26,21 @@ EndScriptData */ enum { + SPELL_ARCHAEDAS_AWAKEN_VISUAL = 10347, SPELL_GROUND_TREMOR = 6524, - SPELL_AWAKEN_EARTHEN_GUARDIAN = 10252, - SPELL_AWAKEN_VAULT_WARDER = 10258, - SPELL_AWAKEN_EARTHEN_DWARF = 10259, - - SPELL_ARCHAEDAS_AWAKEN_VISUAL = 10347, + SPELL_AWAKEN_EARTHEN_GUARDIAN = 10252, // awaken all 7076 npcs + SPELL_AWAKEN_VAULT_WARDER = 10258, // awaken 2 npcs 10120 + SPELL_AWAKEN_EARTHEN_DWARF = 10259, // awaken random npc 7309 or 7077 SAY_AGGRO = -1070001, SAY_AWAKE_GUARDIANS = -1070002, SAY_AWAKE_WARDERS = -1070003, - SAY_UNIT_SLAIN = -1070004 + SAY_UNIT_SLAIN = -1070004, + EMOTE_BREAKS_FREE = -1070005, }; -struct MANGOS_DLL_DECL boss_archaedasAI : public ScriptedAI +struct boss_archaedasAI : public ScriptedAI { boss_archaedasAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -52,65 +52,50 @@ struct MANGOS_DLL_DECL boss_archaedasAI : public ScriptedAI uint32 m_uiAwakeningTimer; uint32 m_uiAwakeDwarfTimer; + uint32 m_uiTremorTimer; uint8 m_uiSubevent; bool m_bDwarvesAwaken; - bool m_bGuardiansAwaken; - bool m_bWardersAwaken; - void Reset() + uint8 m_uiHpPhaseCheck; + + void Reset() override { m_uiAwakeningTimer = 1000; m_uiSubevent = 0; m_uiAwakeDwarfTimer = 10000; - m_bGuardiansAwaken = false; - m_bWardersAwaken = false; + m_uiTremorTimer = urand(7000, 14000); m_bDwarvesAwaken = false; + m_uiHpPhaseCheck = 1; + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ARCHAEDAS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_UNIT_SLAIN, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { // open door to vault (handled by instance script) if (m_pInstance) m_pInstance->SetData(TYPE_ARCHAEDAS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ARCHAEDAS, FAIL); } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) - { - if (pTarget->GetTypeId() != TYPEID_PLAYER) - { - if (pTarget->HasAura(SPELL_STONED, EFFECT_INDEX_0)) - { - pTarget->RemoveAurasDueToSpell(SPELL_STONED); - - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - pTarget->SetInCombatWith(pUnit); - pTarget->AddThreat(pUnit); - } - } - } - } - - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // so many things are based in this script on instance data // so if we don't have access to it better do nothing @@ -122,16 +107,22 @@ struct MANGOS_DLL_DECL boss_archaedasAI : public ScriptedAI { if (m_uiAwakeningTimer <= uiDiff) { - switch(m_uiSubevent) + switch (m_uiSubevent) { case 0: DoCastSpellIfCan(m_creature, SPELL_ARCHAEDAS_AWAKEN_VISUAL); + m_uiAwakeningTimer = 2000; break; case 1: - DoScriptText(SAY_AGGRO,m_creature,NULL); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoScriptText(EMOTE_BREAKS_FREE, m_creature); + m_uiAwakeningTimer = 3000; break; case 2: + DoScriptText(SAY_AGGRO, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // Attack player if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_pInstance->GetGuid(DATA_EVENT_STARTER))) AttackStart(pPlayer); else @@ -142,7 +133,6 @@ struct MANGOS_DLL_DECL boss_archaedasAI : public ScriptedAI } ++m_uiSubevent; - m_uiAwakeningTimer = 5000; } else m_uiAwakeningTimer -= uiDiff; @@ -151,12 +141,22 @@ struct MANGOS_DLL_DECL boss_archaedasAI : public ScriptedAI if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Phase switch + if (m_creature->GetHealthPercent() < 100.0f - 33.4f * (float)m_uiHpPhaseCheck) + { + if (DoCastSpellIfCan(m_creature, m_uiHpPhaseCheck == 1 ? SPELL_AWAKEN_EARTHEN_GUARDIAN : SPELL_AWAKEN_VAULT_WARDER) == CAST_OK) + { + DoScriptText(m_uiHpPhaseCheck == 1 ? SAY_AWAKE_GUARDIANS : SAY_AWAKE_WARDERS, m_creature); + ++m_uiHpPhaseCheck; + } + } + // Awake random Dwarf if (!m_bDwarvesAwaken && m_creature->GetHealthPercent() >= 33.0f) { - if (m_uiAwakeDwarfTimer <= uiDiff) + if (m_uiAwakeDwarfTimer < uiDiff) { - if (Creature* pEarthen = m_pInstance->GetClosestDwarfNotInCombat(m_creature, PHASE_ARCHA_1)) + if (Creature* pEarthen = m_pInstance->GetClosestDwarfNotInCombat(m_creature)) { if (DoCastSpellIfCan(pEarthen, SPELL_AWAKEN_EARTHEN_DWARF) == CAST_OK) m_uiAwakeDwarfTimer = urand(9000, 12000); @@ -168,64 +168,67 @@ struct MANGOS_DLL_DECL boss_archaedasAI : public ScriptedAI m_uiAwakeDwarfTimer -= uiDiff; } - //Awake Earthen Guardians - if (!m_bGuardiansAwaken && m_creature->GetHealthPercent() <= 66.0f) + if (m_uiTremorTimer < uiDiff) { - if (Creature* pGuard = m_pInstance->GetClosestDwarfNotInCombat(m_creature, PHASE_ARCHA_2)) - { - if (DoCastSpellIfCan(pGuard, SPELL_AWAKEN_EARTHEN_GUARDIAN) == CAST_OK) - { - DoScriptText(SAY_AWAKE_GUARDIANS, m_creature); - m_bGuardiansAwaken = true; - } - } - } - - // Awake Warders - if (!m_bWardersAwaken && m_creature->GetHealthPercent() <= 33.0f) - { - if (Creature* pWarder = m_pInstance->GetClosestDwarfNotInCombat(m_creature, PHASE_ARCHA_3)) - { - if (DoCastSpellIfCan(pWarder, SPELL_AWAKEN_VAULT_WARDER) == CAST_OK) - { - DoScriptText(SAY_AWAKE_WARDERS, m_creature); - m_bWardersAwaken = true; - } - } + if (DoCastSpellIfCan(m_creature, SPELL_GROUND_TREMOR) == CAST_OK) + m_uiTremorTimer = urand(8000, 17000); } + else + m_uiTremorTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL npc_archaeras_addAI : public ScriptedAI +CreatureAI* GetAI_boss_archaedas(Creature* pCreature) { - npc_archaeras_addAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } + return new boss_archaedasAI(pCreature); +} - void Reset() +bool EffectDummyCreature_npc_vault_warder(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_AWAKEN_VAULT_WARDER && uiEffIndex == EFFECT_INDEX_0) { - } + if (pCreatureTarget->GetEntry() == NPC_VAULT_WARDER) + { + pCreatureTarget->RemoveAurasDueToSpell(SPELL_STONED); - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + ScriptedInstance* pInstance = (ScriptedInstance*)pCreatureTarget->GetInstanceData(); + if (!pInstance) + return true; - DoMeleeAttackIfReady(); + if (Creature* pArchaedas = pInstance->GetSingleCreatureFromStorage(NPC_ARCHAEDAS)) + pCreatureTarget->AI()->AttackStart(pArchaedas->getVictim()); + + return true; + } } -}; -CreatureAI* GetAI_boss_archaedas(Creature* pCreature) -{ - return new boss_archaedasAI(pCreature); + return false; } -CreatureAI* GetAI_npc_archaeras_add(Creature* pCreature) +bool EffectAuraDummy_spell_aura_dummy_awaken_dwarf(const Aura* pAura, bool bApply) { - return new npc_archaeras_addAI(pCreature); + if (bApply) + return true; + + if ((pAura->GetId() == SPELL_AWAKEN_EARTHEN_DWARF || pAura->GetId() == SPELL_AWAKEN_EARTHEN_GUARDIAN) && pAura->GetEffIndex() == EFFECT_INDEX_0) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + pTarget->RemoveAurasDueToSpell(SPELL_STONED); + + ScriptedInstance* pInstance = (ScriptedInstance*)pTarget->GetInstanceData(); + if (!pInstance) + return true; + + if (Creature* pArchaedas = pInstance->GetSingleCreatureFromStorage(NPC_ARCHAEDAS)) + pTarget->AI()->AttackStart(pArchaedas->getVictim()); + } + } + + return true; } void AddSC_boss_archaedas() @@ -239,6 +242,7 @@ void AddSC_boss_archaedas() pNewScript = new Script; pNewScript->Name = "mob_archaeras_add"; - pNewScript->GetAI = &GetAI_npc_archaeras_add; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_vault_warder; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_awaken_dwarf; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp b/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp index a7a39fc9a..987828c60 100644 --- a/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp +++ b/scripts/eastern_kingdoms/uldaman/instance_uldaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,8 +26,8 @@ EndScriptData #include "uldaman.h" instance_uldaman::instance_uldaman(Map* pMap) : ScriptedInstance(pMap), - m_uiStoneKeepersFallen(0), - m_uiKeeperCooldown(5000) + m_uiKeeperCooldown(0), + m_uiStoneKeepersFallen(0) { Initialize(); } @@ -39,20 +39,19 @@ void instance_uldaman::Initialize() void instance_uldaman::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_TEMPLE_DOOR_UPPER: - if (m_auiEncounter[0] == DONE) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_TEMPLE_DOOR_LOWER: - if (m_auiEncounter[0] == DONE) + if (GetData(TYPE_ALTAR_EVENT) == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ANCIENT_VAULT: - if (m_auiEncounter[1] == DONE) + if (GetData(TYPE_ARCHAEDAS) == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + case GO_ANCIENT_TREASURE: + break; default: return; } @@ -61,19 +60,17 @@ void instance_uldaman::OnObjectCreate(GameObject* pGo) void instance_uldaman::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_HALLSHAPER: case NPC_CUSTODIAN: - case NPC_GUARDIAN: - case NPC_VAULT_WARDER: m_lWardens.push_back(pCreature->GetObjectGuid()); - pCreature->SetNoCallAssistance(true); // no assistance break; case NPC_STONE_KEEPER: - // FIXME - This isAlive check is currently useless - m_mKeeperMap[pCreature->GetObjectGuid()] = pCreature->isAlive(); - pCreature->SetNoCallAssistance(true); // no assistance + m_lKeepers.push_back(pCreature->GetObjectGuid()); + break; + case NPC_ARCHAEDAS: + m_mNpcEntryGuidStore[NPC_ARCHAEDAS] = pCreature->GetObjectGuid(); break; default: break; @@ -82,40 +79,33 @@ void instance_uldaman::OnCreatureCreate(Creature* pCreature) void instance_uldaman::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ALTAR_EVENT: if (uiData == DONE) { DoUseDoorOrButton(GO_TEMPLE_DOOR_UPPER); DoUseDoorOrButton(GO_TEMPLE_DOOR_LOWER); - - m_auiEncounter[0] = uiData; } + else if (uiData == IN_PROGRESS) + { + // Also do a reset before starting the event - this will respawn dead Keepers + DoResetKeeperEvent(); + m_uiKeeperCooldown = 5000; + } + else if (uiData == NOT_STARTED) + { + DoResetKeeperEvent(); + m_uiStoneKeepersFallen = 0; + } + m_auiEncounter[0] = uiData; break; case TYPE_ARCHAEDAS: - if (uiData == FAIL) - { - for (GUIDList::const_iterator itr = m_lWardens.begin(); itr != m_lWardens.end(); ++itr) - { - if (Creature* pWarden = instance->GetCreature(*itr)) - { - pWarden->SetDeathState(JUST_DIED); - pWarden->Respawn(); - pWarden->SetNoCallAssistance(true); - } - } - } - else if (uiData == DONE) + if (uiData == DONE) { - for (GUIDList::const_iterator itr = m_lWardens.begin(); itr != m_lWardens.end(); ++itr) - { - Creature* pWarden = instance->GetCreature(*itr); - if (pWarden && pWarden->isAlive()) - pWarden->ForcedDespawn(); - } DoUseDoorOrButton(GO_ANCIENT_VAULT); + DoRespawnGameObject(GO_ANCIENT_TREASURE, HOUR); } m_auiEncounter[1] = uiData; break; @@ -148,7 +138,7 @@ void instance_uldaman::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -159,27 +149,30 @@ void instance_uldaman::Load(const char* chrIn) void instance_uldaman::SetData64(uint32 uiData, uint64 uiGuid) { - switch(uiData) + switch (uiData) { + // ToDo: check if this one is used in ACID. Otherwise it can be dropped case DATA_EVENT_STARTER: m_playerGuid = ObjectGuid(uiGuid); - break; + break; } } -uint32 instance_uldaman::GetData(uint32 uiType) +uint32 instance_uldaman::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { + case TYPE_ALTAR_EVENT: + return m_auiEncounter[0]; case TYPE_ARCHAEDAS: return m_auiEncounter[1]; } return 0; } -uint64 instance_uldaman::GetData64(uint32 uiData) +uint64 instance_uldaman::GetData64(uint32 uiData) const { - switch(uiData) + switch (uiData) { case DATA_EVENT_STARTER: return m_playerGuid.GetRawValue(); @@ -193,58 +186,45 @@ void instance_uldaman::StartEvent(uint32 uiEventId, Player* pPlayer) if (uiEventId == EVENT_ID_ALTAR_KEEPER) { - if (m_auiEncounter[0] == NOT_STARTED) - m_auiEncounter[0] = IN_PROGRESS; + if (GetData(TYPE_ALTAR_EVENT) == NOT_STARTED) + SetData(TYPE_ALTAR_EVENT, IN_PROGRESS); + } + else if (uiEventId == EVENT_ID_ALTAR_ARCHAEDAS) + { + if (GetData(TYPE_ARCHAEDAS) == NOT_STARTED || GetData(TYPE_ARCHAEDAS) == FAIL) + SetData(TYPE_ARCHAEDAS, SPECIAL); } - else if (m_auiEncounter[1] == NOT_STARTED || m_auiEncounter[1] == FAIL) - m_auiEncounter[1] = SPECIAL; } void instance_uldaman::DoResetKeeperEvent() { - m_auiEncounter[0] = NOT_STARTED; - m_uiStoneKeepersFallen = 0; + if (m_lKeepers.empty()) + { + script_error_log("Instance Uldaman: ERROR creature %u couldn't be found or something really bad happened.", NPC_STONE_KEEPER); + return; + } - for (std::map::iterator itr = m_mKeeperMap.begin(); itr != m_mKeeperMap.end(); ++itr) + // Force reset all keepers to the original state + for (GuidList::const_iterator itr = m_lKeepers.begin(); itr != m_lKeepers.end(); ++itr) { - if (Creature* pKeeper = instance->GetCreature(itr->first)) + if (Creature* pKeeper = instance->GetCreature(*itr)) { - pKeeper->SetDeathState(JUST_DIED); - pKeeper->Respawn(); - pKeeper->SetNoCallAssistance(true); - itr->second = true; + if (!pKeeper->isAlive()) + pKeeper->Respawn(); } } } -Creature* instance_uldaman::GetClosestDwarfNotInCombat(Creature* pSearcher, uint32 uiPhase) +Creature* instance_uldaman::GetClosestDwarfNotInCombat(Creature* pSearcher) { std::list lTemp; - for (GUIDList::const_iterator itr = m_lWardens.begin(); itr != m_lWardens.end(); ++itr) + for (GuidList::const_iterator itr = m_lWardens.begin(); itr != m_lWardens.end(); ++itr) { Creature* pTemp = instance->GetCreature(*itr); if (pTemp && pTemp->isAlive() && !pTemp->getVictim()) - { - switch(uiPhase) - { - case PHASE_ARCHA_1: - if (pTemp->GetEntry() != NPC_CUSTODIAN && pTemp->GetEntry() != NPC_HALLSHAPER) - continue; - break; - case PHASE_ARCHA_2: - if (pTemp->GetEntry() != NPC_GUARDIAN) - continue; - break; - case PHASE_ARCHA_3: - if (pTemp->GetEntry() != NPC_VAULT_WARDER) - continue; - break; - } - lTemp.push_back(pTemp); - } } if (lTemp.empty()) @@ -254,59 +234,66 @@ Creature* instance_uldaman::GetClosestDwarfNotInCombat(Creature* pSearcher, uint return lTemp.front(); } -void instance_uldaman::Update(uint32 uiDiff) +void instance_uldaman::OnCreatureEvade(Creature* pCreature) +{ + // Reset Altar event + if (pCreature->GetEntry() == NPC_STONE_KEEPER) + SetData(TYPE_ALTAR_EVENT, NOT_STARTED); +} + +void instance_uldaman::OnCreatureDeath(Creature* pCreature) { - if (m_auiEncounter[0] == IN_PROGRESS) + if (pCreature->GetEntry() == NPC_STONE_KEEPER) { - if (m_uiKeeperCooldown >= uiDiff) - m_uiKeeperCooldown -= uiDiff; + ++m_uiStoneKeepersFallen; + + if (m_lKeepers.size() == m_uiStoneKeepersFallen) + SetData(TYPE_ALTAR_EVENT, DONE); else - { m_uiKeeperCooldown = 5000; + } +} - if (!m_mKeeperMap.empty()) +void instance_uldaman::Update(uint32 uiDiff) +{ + if (GetData(TYPE_ALTAR_EVENT) != IN_PROGRESS) + return; + + if (!m_uiKeeperCooldown) + return; + + if (m_uiKeeperCooldown <= uiDiff) + { + for (GuidList::const_iterator itr = m_lKeepers.begin(); itr != m_lKeepers.end(); ++itr) + { + // Get Keeper which is alive and out of combat + Creature* pKeeper = instance->GetCreature(*itr); + if (!pKeeper || !pKeeper->isAlive() || pKeeper->getVictim()) + continue; + + // Get starter player for attack + Player* pPlayer = pKeeper->GetMap()->GetPlayer(m_playerGuid); + if (!pPlayer || !pPlayer->isAlive()) { - for(std::map::iterator itr = m_mKeeperMap.begin(); itr != m_mKeeperMap.end(); ++itr) + // If he's not available, then get a random player, within a reasonamble distance in map + pPlayer = GetPlayerInMap(true, false); + if (!pPlayer || !pPlayer->IsWithinDistInMap(pKeeper, 50.0f)) { - // died earlier - if (!itr->second) - continue; - - if (Creature* pKeeper = instance->GetCreature(itr->first)) - { - if (pKeeper->isAlive() && !pKeeper->getVictim()) - { - if (Player* pPlayer = pKeeper->GetMap()->GetPlayer(m_playerGuid)) - { - // we should use group instead, event starter can be dead while group is still fighting - if (pPlayer->isAlive() && !pPlayer->isInCombat()) - { - pKeeper->RemoveAurasDueToSpell(SPELL_STONED); - pKeeper->SetInCombatWith(pPlayer); - pKeeper->AddThreat(pPlayer); - } - else - { - if (!pPlayer->isAlive()) - DoResetKeeperEvent(); - } - } - - break; - } - else if (!pKeeper->isAlive()) - { - itr->second = pKeeper->isAlive(); - ++m_uiStoneKeepersFallen; - } - } + SetData(TYPE_ALTAR_EVENT, NOT_STARTED); + return; } - - if (m_uiStoneKeepersFallen == m_mKeeperMap.size()) - SetData(TYPE_ALTAR_EVENT, DONE); } + + // Attack the player + pKeeper->RemoveAurasDueToSpell(SPELL_STONED); + pKeeper->AI()->AttackStart(pPlayer); + break; } + + m_uiKeeperCooldown = 0; } + else + m_uiKeeperCooldown -= uiDiff; } InstanceData* GetInstanceData_instance_uldaman(Map* pMap) @@ -314,7 +301,7 @@ InstanceData* GetInstanceData_instance_uldaman(Map* pMap) return new instance_uldaman(pMap); } -bool ProcessEventId_event_spell_altar_boss_aggro(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_spell_altar_boss_aggro(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool bIsStart) { if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { diff --git a/scripts/eastern_kingdoms/uldaman/uldaman.cpp b/scripts/eastern_kingdoms/uldaman/uldaman.cpp index 851f0eb60..f08432020 100644 --- a/scripts/eastern_kingdoms/uldaman/uldaman.cpp +++ b/scripts/eastern_kingdoms/uldaman/uldaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/eastern_kingdoms/uldaman/uldaman.h b/scripts/eastern_kingdoms/uldaman/uldaman.h index c7977851b..425bcc2f2 100644 --- a/scripts/eastern_kingdoms/uldaman/uldaman.h +++ b/scripts/eastern_kingdoms/uldaman/uldaman.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -16,51 +16,53 @@ enum GO_TEMPLE_DOOR_UPPER = 124367, GO_TEMPLE_DOOR_LOWER = 141869, GO_ANCIENT_VAULT = 124369, + GO_ANCIENT_TREASURE = 141979, + NPC_ARCHAEDAS = 2748, NPC_CUSTODIAN = 7309, NPC_HALLSHAPER = 7077, NPC_GUARDIAN = 7076, NPC_VAULT_WARDER = 10120, NPC_STONE_KEEPER = 4857, - PHASE_ARCHA_1 = 1, - PHASE_ARCHA_2 = 2, - PHASE_ARCHA_3 = 3, - SPELL_STONED = 10255, + SPELL_FREEZE_ANIM = 16245, EVENT_ID_ALTAR_KEEPER = 2228, // spell 11568 EVENT_ID_ALTAR_ARCHAEDAS = 2268 // spell 10340 }; -class MANGOS_DLL_DECL instance_uldaman : public ScriptedInstance +class instance_uldaman : public ScriptedInstance { public: instance_uldaman(Map* pMap); ~instance_uldaman() {} - void Initialize(); + void Initialize() override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; - void Update(uint32 uiDiff); + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - void SetData64(uint32 uiData, uint64 uiGuid); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiData); + void Update(uint32 uiDiff) override; - void StartEvent(uint32 uiEventId, Player* pPlayer); + void SetData(uint32 uiType, uint32 uiData) override; + void SetData64(uint32 uiData, uint64 uiGuid) override; + uint32 GetData(uint32 uiType) const override; + uint64 GetData64(uint32 uiData) const override; - void DoResetKeeperEvent(); + void StartEvent(uint32 uiEventId, Player* pPlayer); - Creature* GetClosestDwarfNotInCombat(Creature* pSearcher, uint32 uiPhase); + Creature* GetClosestDwarfNotInCombat(Creature* pSearcher); - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: + void DoResetKeeperEvent(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; @@ -69,8 +71,8 @@ class MANGOS_DLL_DECL instance_uldaman : public ScriptedInstance uint32 m_uiKeeperCooldown; uint32 m_uiStoneKeepersFallen; - GUIDList m_lWardens; - std::map m_mKeeperMap; + GuidList m_lWardens; + GuidList m_lKeepers; }; #endif diff --git a/scripts/eastern_kingdoms/undercity.cpp b/scripts/eastern_kingdoms/undercity.cpp index e34f1051d..729fe1cbb 100644 --- a/scripts/eastern_kingdoms/undercity.cpp +++ b/scripts/eastern_kingdoms/undercity.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -23,7 +23,6 @@ EndScriptData */ /* ContentData npc_lady_sylvanas_windrunner -npc_highborne_lamenter EndContentData */ #include "precompiled.h" @@ -32,85 +31,100 @@ EndContentData */ ## npc_lady_sylvanas_windrunner ######*/ -#define SAY_LAMENT_END -1000196 -#define EMOTE_LAMENT_END -1000197 +enum +{ + EMOTE_LAMENT_START = -1000193, + SAY_LAMENT_END = -1000196, + EMOTE_LAMENT_END = -1000197, + + SPELL_HIGHBORNE_AURA = 37090, + SPELL_SYLVANAS_CAST = 36568, + SPELL_RIBBON_OF_SOULS = 37099, + + NPC_HIGHBORNE_LAMENTER = 21628, + NPC_HIGHBORNE_BUNNY = 21641, -#define SOUND_CREDIT 10896 -#define ENTRY_HIGHBORNE_LAMENTER 21628 -#define ENTRY_HIGHBORNE_BUNNY 21641 + QUEST_ID_JOURNEY_UNDERCITY = 9180, -#define SPELL_HIGHBORNE_AURA 37090 -#define SPELL_SYLVANAS_CAST 36568 -#define SPELL_RIBBON_OF_SOULS 34432 //the real one to use might be 37099 + MAX_LAMENTERS = 4, +}; -float HighborneLoc[4][3]= +static const float aHighborneLoc[MAX_LAMENTERS][4] = { - {1285.41f, 312.47f, 0.51f}, - {1286.96f, 310.40f, 1.00f}, - {1289.66f, 309.66f, 1.52f}, - {1292.51f, 310.50f, 1.99f}, + {1285.41f, 312.47f, -61.0f, 0.51f}, + {1286.96f, 310.40f, -61.0f, 1.00f}, + {1289.66f, 309.66f, -61.0f, 1.52f}, + {1292.51f, 310.50f, -61.0f, 1.99f}, }; -#define HIGHBORNE_LOC_Y -61.00f -#define HIGHBORNE_LOC_Y_NEW -55.50f -struct MANGOS_DLL_DECL npc_lady_sylvanas_windrunnerAI : public ScriptedAI +struct npc_lady_sylvanas_windrunnerAI : public ScriptedAI { npc_lady_sylvanas_windrunnerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 LamentEvent_Timer; - bool LamentEvent; - ObjectGuid m_targetGuid; - - float myX; - float myY; - float myZ; + uint32 m_uiLamentEventTimer; + uint32 m_uiSummonTimer; - void Reset() + void Reset() override { - myX = m_creature->GetPositionX(); - myY = m_creature->GetPositionY(); - myZ = m_creature->GetPositionZ(); - - LamentEvent_Timer = 5000; - LamentEvent = false; - m_targetGuid.Clear(); + m_uiLamentEventTimer = 0; + m_uiSummonTimer = 0; } - void JustSummoned(Creature *summoned) + void JustSummoned(Creature* pSummoned) override { - if (summoned->GetEntry() == ENTRY_HIGHBORNE_BUNNY) + if (pSummoned->GetEntry() == NPC_HIGHBORNE_BUNNY) + pSummoned->CastSpell(pSummoned, SPELL_RIBBON_OF_SOULS, false); + else if (pSummoned->GetEntry() == NPC_HIGHBORNE_LAMENTER) { - if (Creature* pBunny = m_creature->GetMap()->GetCreature(m_targetGuid)) - { - pBunny->NearTeleportTo(pBunny->GetPositionX(), pBunny->GetPositionY(), myZ+15.0f, 0.0f); - summoned->CastSpell(pBunny,SPELL_RIBBON_OF_SOULS,false); - } + pSummoned->CastSpell(pSummoned, SPELL_HIGHBORNE_AURA, false); - m_targetGuid = summoned->GetObjectGuid(); + pSummoned->SetLevitate(true); + pSummoned->GetMotionMaster()->MovePoint(0, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ() + 5.0f); } } - void UpdateAI(const uint32 diff) + void DoStartLamentEvent() + { + DoScriptText(EMOTE_LAMENT_START, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SYLVANAS_CAST); + m_uiSummonTimer = 13000; + } + + void UpdateAI(const uint32 uiDiff) override { - if (LamentEvent) + if (m_uiLamentEventTimer) { - if (LamentEvent_Timer < diff) + if (m_uiLamentEventTimer <= uiDiff) { - float raX = myX; - float raY = myY; - float raZ = myZ; + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_HIGHBORNE_BUNNY, fX, fY, fZ + 15.0f, 0, TEMPSUMMON_TIMED_DESPAWN, 3000); - m_creature->GetRandomPoint(myX,myY,myZ,20.0,raX,raY,raZ); - m_creature->SummonCreature(ENTRY_HIGHBORNE_BUNNY,raX,raY,myZ,0,TEMPSUMMON_TIMED_DESPAWN,3000); + m_uiLamentEventTimer = 2000; - LamentEvent_Timer = 2000; - if (!m_creature->HasAura(SPELL_SYLVANAS_CAST, EFFECT_INDEX_0)) + if (!m_creature->HasAura(SPELL_SYLVANAS_CAST)) { DoScriptText(SAY_LAMENT_END, m_creature); DoScriptText(EMOTE_LAMENT_END, m_creature); - LamentEvent = false; + m_uiLamentEventTimer = 0; } - }else LamentEvent_Timer -= diff; + } + else + m_uiLamentEventTimer -= uiDiff; + } + + if (m_uiSummonTimer) + { + if (m_uiSummonTimer <= uiDiff) + { + for (uint8 i = 0; i < MAX_LAMENTERS; ++i) + m_creature->SummonCreature(NPC_HIGHBORNE_LAMENTER, aHighborneLoc[i][0], aHighborneLoc[i][1], aHighborneLoc[i][2], aHighborneLoc[i][3], TEMPSUMMON_TIMED_DESPAWN, 160000); + + m_uiLamentEventTimer = 2000; + m_uiSummonTimer = 0; + } + else + m_uiSummonTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -125,73 +139,17 @@ CreatureAI* GetAI_npc_lady_sylvanas_windrunner(Creature* pCreature) return new npc_lady_sylvanas_windrunnerAI(pCreature); } -bool QuestRewarded_npc_lady_sylvanas_windrunner(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool QuestRewarded_npc_lady_sylvanas_windrunner(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) { - if (pQuest->GetQuestId() == 9180) + if (pQuest->GetQuestId() == QUEST_ID_JOURNEY_UNDERCITY) { if (npc_lady_sylvanas_windrunnerAI* pSylvanAI = dynamic_cast(pCreature->AI())) - { - pSylvanAI->LamentEvent = true; - pSylvanAI->DoPlaySoundToSet(pCreature, SOUND_CREDIT); - } - - pCreature->CastSpell(pCreature,SPELL_SYLVANAS_CAST,false); - - for(uint8 i = 0; i < 4; ++i) - pCreature->SummonCreature(ENTRY_HIGHBORNE_LAMENTER, HighborneLoc[i][0], HighborneLoc[i][1], HIGHBORNE_LOC_Y, HighborneLoc[i][2], TEMPSUMMON_TIMED_DESPAWN, 160000); + pSylvanAI->DoStartLamentEvent(); } return true; } -/*###### -## npc_highborne_lamenter -######*/ - -struct MANGOS_DLL_DECL npc_highborne_lamenterAI : public ScriptedAI -{ - npc_highborne_lamenterAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 EventMove_Timer; - uint32 EventCast_Timer; - bool EventMove; - bool EventCast; - - void Reset() - { - EventMove_Timer = 10000; - EventCast_Timer = 17500; - EventMove = true; - EventCast = true; - } - - void UpdateAI(const uint32 diff) - { - if (EventMove) - { - if (EventMove_Timer < diff) - { - m_creature->SetLevitate(true); - m_creature->MonsterMoveWithSpeed(m_creature->GetPositionX(),m_creature->GetPositionY(),HIGHBORNE_LOC_Y_NEW,3.f); - EventMove = false; - }else EventMove_Timer -= diff; - } - if (EventCast) - { - if (EventCast_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_HIGHBORNE_AURA); - EventCast = false; - }else EventCast_Timer -= diff; - } - } -}; - -CreatureAI* GetAI_npc_highborne_lamenter(Creature* pCreature) -{ - return new npc_highborne_lamenterAI(pCreature); -} - void AddSC_undercity() { Script* pNewScript; @@ -201,9 +159,4 @@ void AddSC_undercity() pNewScript->GetAI = &GetAI_npc_lady_sylvanas_windrunner; pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_lady_sylvanas_windrunner; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_highborne_lamenter"; - pNewScript->GetAI = &GetAI_npc_highborne_lamenter; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/western_plaguelands.cpp b/scripts/eastern_kingdoms/western_plaguelands.cpp index 7a70b3b26..fa6181a32 100644 --- a/scripts/eastern_kingdoms/western_plaguelands.cpp +++ b/scripts/eastern_kingdoms/western_plaguelands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,116 +17,79 @@ /* ScriptData SDName: Western_Plaguelands SD%Complete: 90 -SDComment: Quest support: 5216,5219,5222,5225,5229,5231,5233,5235. +SDComment: Quest support: 5216, 5219, 5222, 5225, 5229, 5231, 5233, 5235, 5862, 5944, 9446. SDCategory: Western Plaguelands EndScriptData */ /* ContentData -npc_myranda_hag npc_the_scourge_cauldron +npc_anchorite_truuen +npc_taelan_fordring +npc_isillien +npc_tirion_fordring EndContentData */ #include "precompiled.h" - -/*###### -## npc_myranda_the_hag -######*/ - -enum -{ - QUEST_SUBTERFUGE = 5862, - QUEST_IN_DREAMS = 5944, - SPELL_SCARLET_ILLUSION = 17961 -}; - -#define GOSSIP_ITEM_ILLUSION "I am ready for the illusion, Myranda." - -bool GossipHello_npc_myranda_the_hag(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(QUEST_SUBTERFUGE) == QUEST_STATUS_COMPLETE && - !pPlayer->GetQuestRewardStatus(QUEST_IN_DREAMS) && !pPlayer->HasAura(SPELL_SCARLET_ILLUSION)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ILLUSION, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(4773, pCreature->GetObjectGuid()); - return true; - } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_myranda_the_hag(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, SPELL_SCARLET_ILLUSION, false); - } - return true; -} +#include "escort_ai.h" /*###### ## npc_the_scourge_cauldron ######*/ -struct MANGOS_DLL_DECL npc_the_scourge_cauldronAI : public ScriptedAI +struct npc_the_scourge_cauldronAI : public ScriptedAI { npc_the_scourge_cauldronAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() {} + void Reset() override {} void DoDie() { - //summoner dies here + // summoner dies here m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - //override any database `spawntimesecs` to prevent duplicated summons + // override any database `spawntimesecs` to prevent duplicated summons uint32 rTime = m_creature->GetRespawnDelay(); - if (rTime<600) + if (rTime < 600) m_creature->SetRespawnDelay(600); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* who) override { if (!who || who->GetTypeId() != TYPEID_PLAYER) return; if (who->GetTypeId() == TYPEID_PLAYER) { - switch(m_creature->GetAreaId()) + switch (m_creature->GetAreaId()) { - case 199: //felstone + case 199: // felstone if (((Player*)who)->GetQuestStatus(5216) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5229) == QUEST_STATUS_INCOMPLETE) + ((Player*)who)->GetQuestStatus(5229) == QUEST_STATUS_INCOMPLETE) { - m_creature->SummonCreature(11075, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); + m_creature->SummonCreature(11075, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); DoDie(); } break; - case 200: //dalson + case 200: // dalson if (((Player*)who)->GetQuestStatus(5219) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5231) == QUEST_STATUS_INCOMPLETE) + ((Player*)who)->GetQuestStatus(5231) == QUEST_STATUS_INCOMPLETE) { - m_creature->SummonCreature(11077, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); + m_creature->SummonCreature(11077, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); DoDie(); } break; - case 201: //gahrron + case 201: // gahrron if (((Player*)who)->GetQuestStatus(5225) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE) + ((Player*)who)->GetQuestStatus(5235) == QUEST_STATUS_INCOMPLETE) { - m_creature->SummonCreature(11078, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + m_creature->SummonCreature(11078, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); DoDie(); } break; - case 202: //writhing + case 202: // writhing if (((Player*)who)->GetQuestStatus(5222) == QUEST_STATUS_INCOMPLETE || - ((Player*)who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE) + ((Player*)who)->GetQuestStatus(5233) == QUEST_STATUS_INCOMPLETE) { - m_creature->SummonCreature(11076, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,600000); + m_creature->SummonCreature(11076, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); DoDie(); } break; @@ -141,21 +104,995 @@ CreatureAI* GetAI_npc_the_scourge_cauldron(Creature* pCreature) } /*###### -## +## npc_anchorite_truuen +######*/ + +enum +{ + SAY_BEGIN = -1000910, + SAY_FIRST_STOP = -1000911, + SAY_CONTINUE = -1000912, + SAY_FIRST_ATTACK = -1000913, + SAY_PURITY = -1000914, + SAY_SECOND_ATTACK = -1000915, + SAY_CLEANSE = -1000916, + SAY_WELCOME = -1000917, + SAY_EPILOGUE_1 = -1000918, + SAY_EPILOGUE_2 = -1000919, + + NPC_PRIEST_THELDANIS = 1854, + NPC_HUNGERING_WRAITH = 1802, + NPC_HAUNDING_VISION = 4472, + NPC_BLIGHTED_ZOMBIE = 4475, + NPC_GHOST_OF_UTHER = 17233, + + QUEST_ID_TOMB_LIGHTBRINGER = 9446, +}; + +struct npc_anchorite_truuenAI: public npc_escortAI +{ + npc_anchorite_truuenAI(Creature* pCreature): npc_escortAI(pCreature) { Reset(); } + + ObjectGuid m_utherGhostGuid; + + void Reset() override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_BEGIN, m_creature); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 4: + DoScriptText(SAY_FIRST_STOP, m_creature); + break; + case 5: + DoScriptText(SAY_CONTINUE, m_creature); + break; + case 10: + DoScriptText(SAY_FIRST_ATTACK, m_creature); + // spawn first attacker wave + m_creature->SummonCreature(NPC_HAUNDING_VISION, 1045.26f, -1576.50f, 62.42f, 2.82f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_HUNGERING_WRAITH, 1021.74f, -1547.49f, 63.44f, 5.24f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + break; + case 11: + DoScriptText(SAY_PURITY, m_creature); + break; + case 21: + DoScriptText(SAY_SECOND_ATTACK, m_creature); + // spawn second attacker wave + m_creature->SummonCreature(NPC_BLIGHTED_ZOMBIE, 1123.08f, -1738.70f, 61.65f, 3.63f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_BLIGHTED_ZOMBIE, 1117.07f, -1763.47f, 62.72f, 1.83f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_BLIGHTED_ZOMBIE, 1096.79f, -1719.14f, 62.69f, 4.88f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_BLIGHTED_ZOMBIE, 1068.92f, -1739.68f, 62.23f, 6.21f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + break; + case 22: + DoScriptText(SAY_CLEANSE, m_creature); + break; + case 35: + if (Creature* pPriest = GetClosestCreatureWithEntry(m_creature, NPC_PRIEST_THELDANIS, 60.0f)) + DoScriptText(SAY_WELCOME, pPriest); + break; + case 38: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_creature->SummonCreature(NPC_GHOST_OF_UTHER, 972.96f, -1824.82f, 82.54f, 0.27f, TEMPSUMMON_TIMED_DESPAWN, 45000); + // complete the quest - the event continues with the dialogue + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_TOMB_LIGHTBRINGER, m_creature); + break; + case 39: + if (Creature* pUther = m_creature->GetMap()->GetCreature(m_utherGhostGuid)) + { + pUther->SetFacingToObject(m_creature); + DoScriptText(SAY_EPILOGUE_1, pUther); + } + break; + case 40: + if (Creature* pUther = m_creature->GetMap()->GetCreature(m_utherGhostGuid)) + DoScriptText(SAY_EPILOGUE_2, pUther); + break; + case 41: + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() != NPC_GHOST_OF_UTHER) + pSummoned->AI()->AttackStart(m_creature); + else + m_utherGhostGuid = pSummoned->GetObjectGuid(); + } +}; + +CreatureAI* GetAI_npc_anchorite_truuen(Creature* pCreature) +{ + return new npc_anchorite_truuenAI(pCreature); +} + +bool QuestAccept_npc_anchorite_truuen(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_TOMB_LIGHTBRINGER) + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + +/*###### +## npc_taelan_fordring ######*/ +enum +{ + // scarlet end quest texts + SAY_SCARLET_COMPLETE_1 = -1001076, + SAY_SCARLET_COMPLETE_2 = -1001077, + + // escort text + SAY_ESCORT_START = -1001078, + SAY_EXIT_KEEP = -1001079, + EMOTE_MOUNT = -1001080, + SAY_REACH_TOWER = -1001081, + SAY_ISILLIEN_1 = -1001082, + SAY_ISILLIEN_2 = -1001083, + SAY_ISILLIEN_3 = -1001084, + SAY_ISILLIEN_4 = -1001085, + SAY_ISILLIEN_5 = -1001086, + SAY_ISILLIEN_6 = -1001087, + EMOTE_ISILLIEN_ATTACK = -1001088, + SAY_ISILLIEN_ATTACK = -1001089, + SAY_KILL_TAELAN_1 = -1001090, + EMOTE_ISILLIEN_LAUGH = -1001091, + SAY_KILL_TAELAN_2 = -1001092, + EMOTE_ATTACK_PLAYER = -1001093, + SAY_TIRION_1 = -1001094, + SAY_TIRION_2 = -1001095, + SAY_TIRION_3 = -1001096, + SAY_TIRION_4 = -1001097, + SAY_TIRION_5 = -1001098, + SAY_EPILOG_1 = -1001099, + EMOTE_KNEEL = -1001100, + SAY_EPILOG_2 = -1001101, + EMOTE_HOLD_TAELAN = -1001102, + SAY_EPILOG_3 = -1001103, + SAY_EPILOG_4 = -1001104, + SAY_EPILOG_5 = -1001105, + + // spells + SPELL_DEVOTION_AURA = 17232, + SPELL_CRUSADER_STRIKE = 14518, + SPELL_HOLY_STRIKE = 17143, + SPELL_HOLY_CLEAVE = 18819, + SPELL_HOLY_LIGHT = 15493, + SPELL_LAY_ON_HANDS = 17233, + SPELL_TAELAN_SUFFERING = 18810, + + // isillen spells + SPELL_DOMINATE_MIND = 14515, + SPELL_FLASH_HEAL = 10917, + SPELL_GREATER_HEAL = 10965, + SPELL_MANA_BURN = 15800, + SPELL_MIND_BLAST = 17194, + SPELL_MIND_FLAY = 17165, + SPELL_TAELAN_DEATH = 18969, + + // npcs + NPC_TAELAN_FORDRING = 1842, + NPC_SCARLET_CAVALIER = 1836, + NPC_ISILLIEN = 1840, + NPC_TIRION_FORDRING = 12126, // Todo: add mount + NPC_CRIMSON_ELITE = 12128, + + MODEL_TAELAN_MOUNT = 2410, // ToDo: fix id! + + // quests + QUEST_ID_SCARLET_SUBTERFUGE = 5862, + QUEST_ID_IN_DREAMS = 5944, +}; + +static const int32 aCavalierYells[] = { -1001072, -1001073, -1001074, -1001075 }; + +static const DialogueEntry aScarletDialogue[] = +{ + // Scarlet Subterfuge ending dialogue + {NPC_SCARLET_CAVALIER, 0, 3000}, + {QUEST_ID_SCARLET_SUBTERFUGE, 0, 7000}, + {SAY_SCARLET_COMPLETE_1, NPC_TAELAN_FORDRING, 2000}, + {QUEST_ID_IN_DREAMS, 0, 0}, + {SPELL_DEVOTION_AURA, 0, 3000}, + {SAY_SCARLET_COMPLETE_2, NPC_TAELAN_FORDRING, 0}, + // In Dreams event dialogue + {SAY_EXIT_KEEP, NPC_TAELAN_FORDRING, 6000}, + {EMOTE_MOUNT, NPC_TAELAN_FORDRING, 4000}, + {MODEL_TAELAN_MOUNT, 0, 0}, + {SAY_REACH_TOWER, NPC_TAELAN_FORDRING, 4000}, + {SAY_ISILLIEN_1, NPC_ISILLIEN, 2000}, + {SAY_ISILLIEN_2, NPC_TAELAN_FORDRING, 3000}, + {SAY_ISILLIEN_3, NPC_TAELAN_FORDRING, 10000}, + {SAY_ISILLIEN_4, NPC_ISILLIEN, 7000}, + {SAY_ISILLIEN_5, NPC_ISILLIEN, 5000}, + {SAY_ISILLIEN_6, NPC_ISILLIEN, 6000}, + {EMOTE_ISILLIEN_ATTACK, NPC_ISILLIEN, 3000}, + {SAY_ISILLIEN_ATTACK, NPC_ISILLIEN, 3000}, + {SPELL_CRUSADER_STRIKE, 0, 0}, + {SAY_KILL_TAELAN_1, NPC_ISILLIEN, 1000}, + {EMOTE_ISILLIEN_LAUGH, NPC_ISILLIEN, 4000}, + {SAY_KILL_TAELAN_2, NPC_ISILLIEN, 10000}, + {EMOTE_ATTACK_PLAYER, NPC_ISILLIEN, 0}, + {NPC_TIRION_FORDRING, 0, 5000}, + {NPC_ISILLIEN, 0, 10000}, + {SAY_TIRION_1, NPC_TIRION_FORDRING, 4000}, + {SAY_TIRION_2, NPC_ISILLIEN, 6000}, + {SAY_TIRION_3, NPC_TIRION_FORDRING, 4000}, + {SAY_TIRION_4, NPC_TIRION_FORDRING, 3000}, + {SAY_TIRION_5, NPC_ISILLIEN, 0}, + {EMOTE_KNEEL, NPC_TIRION_FORDRING, 4000}, + {SAY_EPILOG_2, NPC_TIRION_FORDRING, 5000}, + {EMOTE_HOLD_TAELAN, NPC_TIRION_FORDRING, 5000}, + {SAY_EPILOG_3, NPC_TIRION_FORDRING, 6000}, + {SAY_EPILOG_4, NPC_TIRION_FORDRING, 7000}, + {SAY_EPILOG_5, NPC_TIRION_FORDRING, 0}, + {0, 0, 0}, +}; + +struct npc_taelan_fordringAI: public npc_escortAI, private DialogueHelper +{ + npc_taelan_fordringAI(Creature* pCreature): npc_escortAI(pCreature), + DialogueHelper(aScarletDialogue) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_bScarletComplete = false; + m_bFightStarted = false; + m_bTaelanDead = false; + m_bHasMount = false; + Reset(); + } + + bool m_bScarletComplete; + bool m_bFightStarted; + bool m_bHasMount; + bool m_bTaelanDead; + + ObjectGuid m_isillenGuid; + ObjectGuid m_tirionGuid; + GuidList m_lCavalierGuids; + + uint32 m_uiHolyCleaveTimer; + uint32 m_uiHolyStrikeTimer; + uint32 m_uiCrusaderStrike; + uint32 m_uiHolyLightTimer; + + void Reset() override + { + m_uiHolyCleaveTimer = urand(11000, 15000); + m_uiHolyStrikeTimer = urand(6000, 8000); + m_uiCrusaderStrike = urand(1000, 5000); + m_uiHolyLightTimer = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_bHasMount) + m_creature->Unmount(); + + DoCastSpellIfCan(m_creature, SPELL_DEVOTION_AURA); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bTaelanDead) + return; + + npc_escortAI::MoveInLineOfSight(pWho); + } + + void EnterEvadeMode() override + { + if (m_bTaelanDead) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(0); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + Reset(); + } + else + { + if (m_bHasMount) + m_creature->Mount(MODEL_TAELAN_MOUNT); + + npc_escortAI::EnterEvadeMode(); + } + } + + void JustReachedHome() override + { + if (m_bScarletComplete) + { + StartNextDialogueText(SPELL_DEVOTION_AURA); + m_bScarletComplete = false; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + DoScriptText(SAY_ESCORT_START, m_creature); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_FRIEND_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + } + else if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetTypeId() == TYPEID_PLAYER && uiMiscValue == QUEST_ID_SCARLET_SUBTERFUGE) + StartNextDialogueText(NPC_SCARLET_CAVALIER); + else if (eventType == AI_EVENT_CUSTOM_B && pInvoker->GetEntry() == NPC_ISILLIEN) + { + StartNextDialogueText(NPC_TIRION_FORDRING); + m_creature->SummonCreature(NPC_TIRION_FORDRING, 2620.273f, -1920.917f, 74.25f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 25: + SetEscortPaused(true); + StartNextDialogueText(SAY_EXIT_KEEP); + break; + case 55: + SetEscortPaused(true); + StartNextDialogueText(SAY_REACH_TOWER); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_ISILLIEN: + SendAIEvent(AI_EVENT_START_ESCORT, m_creature, pSummoned); + m_isillenGuid = pSummoned->GetObjectGuid(); + + // summon additional crimson elites + float fX, fY, fZ; + pSummoned->GetNearPoint(pSummoned, fX, fY, fZ, 0, 5.0f, M_PI_F * 1.25f); + pSummoned->SummonCreature(NPC_CRIMSON_ELITE, fX, fY, fZ, pSummoned->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + pSummoned->GetNearPoint(pSummoned, fX, fY, fZ, 0, 5.0f, 0); + pSummoned->SummonCreature(NPC_CRIMSON_ELITE, fX, fY, fZ, pSummoned->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + break; + case NPC_TIRION_FORDRING: + m_tirionGuid = pSummoned->GetObjectGuid(); + SendAIEvent(AI_EVENT_START_ESCORT, m_creature, pSummoned); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ISILLIEN) + { + if (Creature* pTirion = m_creature->GetMap()->GetCreature(m_tirionGuid)) + DoScriptText(SAY_EPILOG_1, pTirion); + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 /*uiMotionType*/, uint32 uiPointId) override + { + if (pSummoned->GetEntry() != NPC_TIRION_FORDRING) + return; + + if (uiPointId == 100) + { + StartNextDialogueText(SAY_TIRION_1); + if (Creature* pIsillien = m_creature->GetMap()->GetCreature(m_isillenGuid)) + pSummoned->SetFacingToObject(pIsillien); + } + else if (uiPointId == 200) + StartNextDialogueText(EMOTE_KNEEL); + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case NPC_SCARLET_CAVALIER: + { + // kneel and make everyone worried + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + std::list lCavaliersInRange; + GetCreatureListWithEntryInGrid(lCavaliersInRange, m_creature, NPC_SCARLET_CAVALIER, 10.0f); + + uint8 uiIndex = 0; + for (std::list::const_iterator itr = lCavaliersInRange.begin(); itr != lCavaliersInRange.end(); ++itr) + { + m_lCavalierGuids.push_back((*itr)->GetObjectGuid()); + (*itr)->SetFacingToObject(m_creature); + DoScriptText(aCavalierYells[uiIndex], (*itr)); + ++uiIndex; + } + break; + } + case QUEST_ID_SCARLET_SUBTERFUGE: + { + float fX, fY, fZ; + for (GuidList::const_iterator itr = m_lCavalierGuids.begin(); itr != m_lCavalierGuids.end(); ++itr) + { + if (Creature* pCavalier = m_creature->GetMap()->GetCreature(*itr)) + { + m_creature->GetContactPoint(pCavalier, fX, fY, fZ); + pCavalier->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + break; + } + case SAY_SCARLET_COMPLETE_1: + // stand up and knock down effect + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCastSpellIfCan(m_creature, SPELL_TAELAN_SUFFERING); + break; + case QUEST_ID_IN_DREAMS: + // force attack + for (GuidList::const_iterator itr = m_lCavalierGuids.begin(); itr != m_lCavalierGuids.end(); ++itr) + { + if (Creature* pCavalier = m_creature->GetMap()->GetCreature(*itr)) + pCavalier->AI()->AttackStart(m_creature); + } + m_bScarletComplete = true; + break; + case SAY_SCARLET_COMPLETE_2: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + break; + case MODEL_TAELAN_MOUNT: + // mount when outside + m_bHasMount = true; + SetEscortPaused(false); + m_creature->Mount(MODEL_TAELAN_MOUNT); + break; + case SAY_REACH_TOWER: + // start fight event + m_creature->SummonCreature(NPC_ISILLIEN, 2693.12f, -1943.04f, 72.04f, 2.11f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + break; + case SAY_ISILLIEN_2: + if (Creature* pIsillien = m_creature->GetMap()->GetCreature(m_isillenGuid)) + m_creature->SetFacingToObject(pIsillien); + break; + case SPELL_CRUSADER_STRIKE: + { + // spawn additioinal elites + m_creature->SummonCreature(NPC_CRIMSON_ELITE, 2711.32f, -1882.67f, 67.89f, 3.2f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + m_creature->SummonCreature(NPC_CRIMSON_ELITE, 2710.93f, -1878.90f, 67.97f, 3.2f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + m_creature->SummonCreature(NPC_CRIMSON_ELITE, 2710.53f, -1875.28f, 67.90f, 3.2f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15 * MINUTE * IN_MILLISECONDS); + + std::list lElitesInRange; + Player* pPlayer = GetPlayerForEscort(); + if (!pPlayer) + return; + + GetCreatureListWithEntryInGrid(lElitesInRange, m_creature, NPC_CRIMSON_ELITE, 70.0f); + + for (std::list::const_iterator itr = lElitesInRange.begin(); itr != lElitesInRange.end(); ++itr) + (*itr)->AI()->AttackStart(pPlayer); + + // Isillien only attacks Taelan + if (Creature* pIsillien = m_creature->GetMap()->GetCreature(m_isillenGuid)) + { + pIsillien->AI()->AttackStart(m_creature); + AttackStart(pIsillien); + } + + m_bFightStarted = true; + break; + } + case SAY_KILL_TAELAN_1: + // kill taelan and attack players + if (Creature* pIsillien = m_creature->GetMap()->GetCreature(m_isillenGuid)) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pIsillien); + break; + case EMOTE_ATTACK_PLAYER: + // attack players + if (Creature* pIsillien = m_creature->GetMap()->GetCreature(m_isillenGuid)) + { + if (Player* pPlayer = GetPlayerForEscort()) + pIsillien->AI()->AttackStart(pPlayer); + } + break; + // tirion event + case SAY_TIRION_5: + if (Creature* pIsillien = m_creature->GetMap()->GetCreature(m_isillenGuid)) + { + if (Creature* pTirion = m_creature->GetMap()->GetCreature(m_tirionGuid)) + { + pTirion->AI()->AttackStart(pIsillien); + pIsillien->AI()->AttackStart(pTirion); + } + } + break; + // epilog dialogue + case EMOTE_HOLD_TAELAN: + if (Creature* pTirion = m_creature->GetMap()->GetCreature(m_tirionGuid)) + pTirion->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case SAY_EPILOG_4: + if (Creature* pTirion = m_creature->GetMap()->GetCreature(m_tirionGuid)) + pTirion->SetStandState(UNIT_STAND_STATE_STAND); + break; + case SAY_EPILOG_5: + if (Creature* pTirion = m_creature->GetMap()->GetCreature(m_tirionGuid)) + { + if (Player* pPlayer = GetPlayerForEscort()) + { + pPlayer->GroupEventHappens(QUEST_ID_IN_DREAMS, m_creature); + pTirion->SetFacingToObject(pPlayer); + } + + pTirion->ForcedDespawn(3 * MINUTE * IN_MILLISECONDS); + pTirion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } + m_creature->ForcedDespawn(3 * MINUTE * IN_MILLISECONDS); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_TAELAN_FORDRING: return m_creature; + case NPC_ISILLIEN: return m_creature->GetMap()->GetCreature(m_isillenGuid); + case NPC_TIRION_FORDRING: return m_creature->GetMap()->GetCreature(m_tirionGuid); + + default: + return NULL; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bTaelanDead) + return; + + if (!m_bTaelanDead && m_creature->GetHealthPercent() < 50.0f) + { + StartNextDialogueText(SAY_KILL_TAELAN_1); + m_bTaelanDead = true; + } + + if (m_uiHolyCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_CLEAVE) == CAST_OK) + m_uiHolyCleaveTimer = urand(11000, 13000); + } + else + m_uiHolyCleaveTimer -= uiDiff; + + if (m_uiHolyStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_STRIKE) == CAST_OK) + m_uiHolyStrikeTimer = urand(9000, 14000); + } + else + m_uiHolyStrikeTimer -= uiDiff; + + if (m_uiCrusaderStrike < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSADER_STRIKE) == CAST_OK) + m_uiCrusaderStrike = urand(7000, 12000); + } + else + m_uiCrusaderStrike -= uiDiff; + + if (m_creature->GetHealthPercent() < 75.0f) + { + if (m_uiHolyLightTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HOLY_LIGHT) == CAST_OK) + m_uiHolyLightTimer = urand(10000, 15000); + } + } + else + m_uiHolyLightTimer -= uiDiff; + } + + if (!m_bFightStarted && m_creature->GetHealthPercent() < 15.0f) + DoCastSpellIfCan(m_creature, SPELL_LAY_ON_HANDS); + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_taelan_fordring(Creature* pCreature) +{ + return new npc_taelan_fordringAI(pCreature); +} + +bool QuestAccept_npc_taelan_fordring(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_IN_DREAMS) + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + +bool QuestRewarded_npc_taelan_fordring(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_SCARLET_SUBTERFUGE) + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + +bool EffectDummyCreature_npc_taelan_fordring(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_TAELAN_DEATH && uiEffIndex == EFFECT_INDEX_0 && pCaster->GetEntry() == NPC_ISILLIEN) + { + pCreatureTarget->AI()->EnterEvadeMode(); + pCaster->SetFacingToObject(pCreatureTarget); + ((Creature*)pCaster)->AI()->EnterEvadeMode(); + + return true; + } + + return false; +} + +/*###### +## npc_isillien +######*/ + +struct npc_isillienAI: public npc_escortAI +{ + npc_isillienAI(Creature* pCreature): npc_escortAI(pCreature) + { + m_bTirionSpawned = false; + m_bTaelanDead = false; + Reset(); + } + + bool m_bTirionSpawned; + bool m_bTaelanDead; + + ObjectGuid m_taelanGuid; + + uint32 m_uiManaBurnTimer; + uint32 m_uFlashHealTimer; + uint32 m_uiGreaterHealTimer; + uint32 m_uiHolyLightTimer; + uint32 m_uiDominateTimer; + uint32 m_uiMindBlastTimer; + uint32 m_uiMindFlayTimer; + + void Reset() override + { + m_uiManaBurnTimer = urand(7000, 12000); + m_uFlashHealTimer = urand(10000, 15000); + m_uiDominateTimer = urand(10000, 14000); + m_uiMindBlastTimer = urand(0, 1000); + m_uiMindFlayTimer = urand(3000, 7000); + m_uiGreaterHealTimer = 0; + } + + void MoveInLineOfSight(Unit* /*pWho*/) override + { + // attack only on request + } + + void EnterEvadeMode() override + { + // evade and keep the same posiiton + if (m_bTaelanDead) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + + m_creature->GetMotionMaster()->MoveIdle(); + + Reset(); + } + else + npc_escortAI::EnterEvadeMode(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (pSender->GetEntry() != NPC_TAELAN_FORDRING) + return; + + // move outside the tower + if (eventType == AI_EVENT_START_ESCORT) + Start(false); + else if (eventType == AI_EVENT_CUSTOM_A) + { + // kill Taelan + DoCastSpellIfCan(pInvoker, SPELL_TAELAN_DEATH, CAST_INTERRUPT_PREVIOUS); + m_bTaelanDead = true; + m_taelanGuid = pInvoker->GetObjectGuid(); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + SetEscortPaused(true); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // start event epilog + if (!m_bTirionSpawned && m_creature->GetHealthPercent() < 20.0f) + { + if (Creature* pTaelan = m_creature->GetMap()->GetCreature(m_taelanGuid)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pTaelan); + m_bTirionSpawned = true; + } + + // combat spells + if (m_uiMindBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIND_BLAST) == CAST_OK) + m_uiMindBlastTimer = urand(3000, 5000); + } + else + m_uiMindBlastTimer -= uiDiff; + + if (m_uiMindFlayTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIND_FLAY) == CAST_OK) + m_uiMindFlayTimer = urand(9000, 15000); + } + else + m_uiMindFlayTimer -= uiDiff; + + if (m_uiManaBurnTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MANA_BURN) == CAST_OK) + m_uiManaBurnTimer = urand(8000, 12000); + } + else + m_uiManaBurnTimer -= uiDiff; + + if (m_uiDominateTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_DOMINATE_MIND, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DOMINATE_MIND) == CAST_OK) + m_uiDominateTimer = urand(25000, 30000); + } + } + else + m_uiDominateTimer -= uiDiff; + + if (m_uFlashHealTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FLASH_HEAL) == CAST_OK) + m_uFlashHealTimer = urand(10000, 15000); + } + } + else + m_uFlashHealTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 50.0f) + { + if (m_uiGreaterHealTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GREATER_HEAL) == CAST_OK) + m_uiGreaterHealTimer = urand(15000, 20000); + } + else + m_uiGreaterHealTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_isillien(Creature* pCreature) +{ + return new npc_isillienAI(pCreature); +} + +/*###### +## npc_tirion_fordring +######*/ + +struct npc_tirion_fordringAI: public npc_escortAI +{ + npc_tirion_fordringAI(Creature* pCreature): npc_escortAI(pCreature) { Reset(); } + + ObjectGuid m_taelanGuid; + + uint32 m_uiHolyCleaveTimer; + uint32 m_uiHolyStrikeTimer; + uint32 m_uiCrusaderStrike; + + void Reset() override + { + m_uiHolyCleaveTimer = urand(11000, 15000); + m_uiHolyStrikeTimer = urand(6000, 8000); + m_uiCrusaderStrike = urand(1000, 5000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_DEVOTION_AURA); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // attack only on request + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + + // on evade go to Taelan + if (Creature* pTaelan = m_creature->GetMap()->GetCreature(m_taelanGuid)) + { + float fX, fY, fZ; + pTaelan->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(200, fX, fY, fZ); + } + + Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (pSender->GetEntry() != NPC_TAELAN_FORDRING) + return; + + if (eventType == AI_EVENT_START_ESCORT) + { + Start(true); + m_taelanGuid = pInvoker->GetObjectGuid(); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + SetEscortPaused(true); + + // unmount and go to Taelan + m_creature->Unmount(); + if (Creature* pTaelan = m_creature->GetMap()->GetCreature(m_taelanGuid)) + { + float fX, fY, fZ; + pTaelan->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(100, fX, fY, fZ); + } + break; + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + // custom points; ignore in escort AI + if (uiPointId == 100 || uiPointId == 200) + return; + + npc_escortAI::MovementInform(uiMoveType, uiPointId); + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // combat spells + if (m_uiHolyCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_CLEAVE) == CAST_OK) + m_uiHolyCleaveTimer = urand(12000, 15000); + } + else + m_uiHolyCleaveTimer -= uiDiff; + + if (m_uiHolyStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_STRIKE) == CAST_OK) + m_uiHolyStrikeTimer = urand(8000, 11000); + } + else + m_uiHolyStrikeTimer -= uiDiff; + + if (m_uiCrusaderStrike < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRUSADER_STRIKE) == CAST_OK) + m_uiCrusaderStrike = urand(7000, 9000); + } + else + m_uiCrusaderStrike -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_tirion_fordring(Creature* pCreature) +{ + return new npc_tirion_fordringAI(pCreature); +} + void AddSC_western_plaguelands() { Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "npc_myranda_the_hag"; - pNewScript->pGossipHello = &GossipHello_npc_myranda_the_hag; - pNewScript->pGossipSelect = &GossipSelect_npc_myranda_the_hag; + pNewScript->Name = "npc_the_scourge_cauldron"; + pNewScript->GetAI = &GetAI_npc_the_scourge_cauldron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_anchorite_truuen"; + pNewScript->GetAI = &GetAI_npc_anchorite_truuen; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_anchorite_truuen; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_the_scourge_cauldron"; - pNewScript->GetAI = &GetAI_npc_the_scourge_cauldron; + pNewScript->Name = "npc_taelan_fordring"; + pNewScript->GetAI = &GetAI_npc_taelan_fordring; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_taelan_fordring; + pNewScript->pQuestRewardedNPC = &QuestRewarded_npc_taelan_fordring; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_taelan_fordring; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_isillien"; + pNewScript->GetAI = &GetAI_npc_isillien; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tirion_fordring"; + pNewScript->GetAI = &GetAI_npc_tirion_fordring; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/westfall.cpp b/scripts/eastern_kingdoms/westfall.cpp index fe0d3cb9c..bb5bf2caf 100644 --- a/scripts/eastern_kingdoms/westfall.cpp +++ b/scripts/eastern_kingdoms/westfall.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -47,7 +47,7 @@ enum EQUIP_ID_RIFLE = 2511 }; -struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI +struct npc_daphne_stilwellAI : public npc_escortAI { npc_daphne_stilwellAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -58,11 +58,11 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI uint32 m_uiWPHolder; uint32 m_uiShootTimer; - void Reset() + void Reset() override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { - switch(m_uiWPHolder) + switch (m_uiWPHolder) { case 7: DoScriptText(SAY_DS_DOWN_1, m_creature); break; case 8: DoScriptText(SAY_DS_DOWN_2, m_creature); break; @@ -75,11 +75,11 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI m_uiShootTimer = 0; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { m_uiWPHolder = uiPointId; - switch(uiPointId) + switch (uiPointId) { case 4: SetEquipmentSlots(false, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE, EQUIP_ID_RIFLE); @@ -87,24 +87,24 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI m_creature->HandleEmote(EMOTE_STATE_USESTANDING_NOSHEATHE); break; case 7: - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836f, 1569.755f, 54.267f, 4.230f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697f, 1569.124f, 54.421f, 4.206f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237f, 1568.307f, 54.620f, 4.206f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836f, 1569.755f, 54.267f, 4.230f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697f, 1569.124f, 54.421f, 4.206f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237f, 1568.307f, 54.620f, 4.206f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 8: m_creature->SetSheath(SHEATH_STATE_RANGED); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836f, 1569.755f, 54.267f, 4.230f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697f, 1569.124f, 54.421f, 4.206f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237f, 1568.307f, 54.620f, 4.206f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.037f, 1570.213f, 54.961f, 4.283f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836f, 1569.755f, 54.267f, 4.230f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697f, 1569.124f, 54.421f, 4.206f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237f, 1568.307f, 54.620f, 4.206f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.037f, 1570.213f, 54.961f, 4.283f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 9: m_creature->SetSheath(SHEATH_STATE_RANGED); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836f, 1569.755f, 54.267f, 4.230f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697f, 1569.124f, 54.421f, 4.206f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237f, 1568.307f, 54.620f, 4.206f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.037f, 1570.213f, 54.961f, 4.283f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.018f, 1570.738f, 54.828f, 4.220f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11450.836f, 1569.755f, 54.267f, 4.230f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.697f, 1569.124f, 54.421f, 4.206f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.237f, 1568.307f, 54.620f, 4.206f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11448.037f, 1570.213f, 54.961f, 4.283f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + m_creature->SummonCreature(NPC_DEFIAS_RAIDER, -11449.018f, 1570.738f, 54.828f, 4.220f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 10: SetRun(false); @@ -124,7 +124,7 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI } } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!pWho) return; @@ -139,12 +139,12 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -155,7 +155,6 @@ struct MANGOS_DLL_DECL npc_daphne_stilwellAI : public npc_escortAI if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOOT); - } else m_uiShootTimer -= uiDiff; @@ -197,11 +196,11 @@ enum QUEST_DEFIAS_BROTHERHOOD = 155 }; -struct MANGOS_DLL_DECL npc_defias_traitorAI : public npc_escortAI +struct npc_defias_traitorAI : public npc_escortAI { npc_defias_traitorAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { @@ -222,12 +221,12 @@ struct MANGOS_DLL_DECL npc_defias_traitorAI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature, pWho); } - void Reset() { } + void Reset() override { } }; bool QuestAccept_npc_defias_traitor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) diff --git a/scripts/eastern_kingdoms/wetlands.cpp b/scripts/eastern_kingdoms/wetlands.cpp index 3a51a7d05..6967bbefa 100644 --- a/scripts/eastern_kingdoms/wetlands.cpp +++ b/scripts/eastern_kingdoms/wetlands.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Wetlands -SD%Complete: 80 +SD%Complete: 100 SDComment: Quest support: 1249 SDCategory: Wetlands EndScriptData */ @@ -35,88 +35,157 @@ EndContentData */ enum { - QUEST_MISSING_DIPLO_PT11 = 1249, - FACTION_ENEMY = 168, + SAY_SLIM_AGGRO = -1000977, + SAY_SLIM_DEFEAT = -1000978, + SAY_FRIEND_DEFEAT = -1000979, + SAY_SLIM_NOTES = -1000980, + + QUEST_MISSING_DIPLOMAT11 = 1249, + FACTION_ENEMY = 168, // ToDo: faction needs to be confirmed! + SPELL_STEALTH = 1785, - SPELL_CALL_FRIENDS = 16457, //summons 1x friend + SPELL_CALL_FRIENDS = 16457, // summon npc 4971 + NPC_SLIMS_FRIEND = 4971, NPC_TAPOKE_SLIM_JAHN = 4962 }; -struct MANGOS_DLL_DECL npc_tapoke_slim_jahnAI : public npc_escortAI +static const DialogueEntry aDiplomatDialogue[] = +{ + {SAY_SLIM_DEFEAT, NPC_TAPOKE_SLIM_JAHN, 4000}, + {SAY_SLIM_NOTES, NPC_TAPOKE_SLIM_JAHN, 7000}, + {QUEST_MISSING_DIPLOMAT11, 0, 0}, + {0, 0, 0}, +}; + +struct npc_tapoke_slim_jahnAI : public npc_escortAI, private DialogueHelper { - npc_tapoke_slim_jahnAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + npc_tapoke_slim_jahnAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aDiplomatDialogue) + { + Reset(); + } bool m_bFriendSummoned; + bool m_bEventComplete; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { m_bFriendSummoned = false; + m_bEventComplete = false; + } } - void WaypointReached(uint32 uiPointId) + void JustReachedHome() override { - switch(uiPointId) + // after the npc is defeated, start the dialog right after it reaches the evade point + if (m_bEventComplete) { - case 2: - if (m_creature->HasStealthAura()) - m_creature->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + StartNextDialogueText(SAY_SLIM_DEFEAT); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: SetRun(); - m_creature->setFaction(FACTION_ENEMY); + m_creature->RemoveAurasDueToSpell(SPELL_STEALTH); + m_creature->SetFactionTemporary(FACTION_ENEMY, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_COMBAT_STOP); + break; + case 6: + // fail the quest if he escapes + if (Player* pPlayer = GetPlayerForEscort()) + JustDied(pPlayer); break; } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - Player* pPlayer = GetPlayerForEscort(); - - if (HasEscortState(STATE_ESCORT_ESCORTING) && !m_bFriendSummoned && pPlayer) + if (HasEscortState(STATE_ESCORT_ESCORTING) && !m_bFriendSummoned) { - for(uint8 i = 0; i < 3; ++i) - m_creature->CastSpell(m_creature, SPELL_CALL_FRIENDS, true); - - m_bFriendSummoned = true; + if (DoCastSpellIfCan(m_creature, SPELL_CALL_FRIENDS) == CAST_OK) + { + DoScriptText(SAY_SLIM_AGGRO, m_creature); + m_bFriendSummoned = true; + } } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { + // Note: may not work on guardian pets if (Player* pPlayer = GetPlayerForEscort()) pSummoned->AI()->AttackStart(pPlayer); } - void AttackedBy(Unit* pAttacker) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (m_creature->getVictim()) + if (!HasEscortState(STATE_ESCORT_ESCORTING)) return; - if (m_creature->IsFriendlyTo(pAttacker)) - return; + if (m_creature->GetHealthPercent() < 20.0f || uiDamage > m_creature->GetHealth()) + { + // despawn friend - Note: may not work on guardian pets + if (Creature* pFriend = GetClosestCreatureWithEntry(m_creature, NPC_SLIMS_FRIEND, 10.0f)) + { + DoScriptText(SAY_FRIEND_DEFEAT, pFriend); + pFriend->ForcedDespawn(1000); + } + + // set escort on pause and evade + uiDamage = 0; + m_bEventComplete = true; + + SetEscortPaused(true); + EnterEvadeMode(); + } + } - AttackStart(pAttacker); + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + // start escort + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue), true); } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void JustDidDialogueStep(int32 iEntry) override { - if (m_creature->GetHealthPercent() < 20.0f) + if (iEntry == QUEST_MISSING_DIPLOMAT11) { + // complete quest if (Player* pPlayer = GetPlayerForEscort()) - { - pPlayer->GroupEventHappens(QUEST_MISSING_DIPLO_PT11, m_creature); + pPlayer->GroupEventHappens(QUEST_MISSING_DIPLOMAT11, m_creature); - uiDamage = 0; + // despawn and respawn at inn + m_creature->ForcedDespawn(1000); + m_creature->SetRespawnDelay(2); + } + } - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_TAPOKE_SLIM_JAHN) + return m_creature; - SetRun(false); - } - } + return NULL; + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); } }; @@ -131,19 +200,19 @@ CreatureAI* GetAI_npc_tapoke_slim_jahn(Creature* pCreature) bool QuestAccept_npc_mikhail(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - if (pQuest->GetQuestId() == QUEST_MISSING_DIPLO_PT11) + if (pQuest->GetQuestId() == QUEST_MISSING_DIPLOMAT11) { Creature* pSlim = GetClosestCreatureWithEntry(pCreature, NPC_TAPOKE_SLIM_JAHN, 25.0f); - if (!pSlim) return false; - if (!pSlim->HasStealthAura()) + if (!pSlim->HasAura(SPELL_STEALTH)) pSlim->CastSpell(pSlim, SPELL_STEALTH, true); - if (npc_tapoke_slim_jahnAI* pEscortAI = dynamic_cast(pSlim->AI())) - pEscortAI->Start(false, pPlayer, pQuest); + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pSlim, pQuest->GetQuestId()); + return true; } + return false; } diff --git a/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp b/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp index e1e84c9f9..1ca1a83e2 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_akilzon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Akilzon -SD%Complete: 50 -SDComment: TODO: Correct timers, correct details, remove hack for eagles +SD%Complete: 80 +SDComment: Timers; Some details may need adjustments. SDCategory: Zul'Aman EndScriptData */ @@ -38,26 +38,20 @@ enum EMOTE_STORM = -1568033, SPELL_STATIC_DISRUPTION = 43622, - SPELL_STATIC_VISUAL = 45265, - SPELL_CALL_LIGHTNING = 43661, SPELL_GUST_OF_WIND = 43621, - SPELL_ELECTRICAL_STORM = 43648, SPELL_STORMCLOUD_VISUAL = 45213, - SPELL_BERSERK = 45078, + // spell used by eagles + SPELL_EAGLE_SWOOP = 44732, + NPC_SOARING_EAGLE = 24858, MAX_EAGLE_COUNT = 6, - - //SE_LOC_X_MAX = 400, - //SE_LOC_X_MIN = 335, - //SE_LOC_Y_MAX = 1435, - //SE_LOC_Y_MIN = 1370 }; -struct MANGOS_DLL_DECL boss_akilzonAI : public ScriptedAI +struct boss_akilzonAI : public ScriptedAI { boss_akilzonAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -73,20 +67,18 @@ struct MANGOS_DLL_DECL boss_akilzonAI : public ScriptedAI uint32 m_uiStormTimer; uint32 m_uiSummonEagleTimer; uint32 m_uiBerserkTimer; - bool m_bIsBerserk; - void Reset() + void Reset() override { - m_uiStaticDisruptTimer = urand(7000, 14000); - m_uiCallLightTimer = urand(15000, 25000); - m_uiGustOfWindTimer = urand(20000, 30000); - m_uiStormTimer = 50000; - m_uiSummonEagleTimer = 65000; - m_uiBerserkTimer = MINUTE*8*IN_MILLISECONDS; - m_bIsBerserk = false; + m_uiStaticDisruptTimer = urand(7000, 14000); + m_uiCallLightTimer = urand(15000, 25000); + m_uiGustOfWindTimer = urand(20000, 30000); + m_uiStormTimer = 50000; + m_uiSummonEagleTimer = 65000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -94,12 +86,12 @@ struct MANGOS_DLL_DECL boss_akilzonAI : public ScriptedAI m_pInstance->SetData(TYPE_AKILZON, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -109,83 +101,102 @@ struct MANGOS_DLL_DECL boss_akilzonAI : public ScriptedAI m_pInstance->SetData(TYPE_AKILZON, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_AKILZON, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SOARING_EAGLE) + { + pSummoned->SetLevitate(true); pSummoned->SetInCombatWithZone(); + } } void DoSummonEagles() { - for(uint32 i = 0; i < MAX_EAGLE_COUNT; ++i) + for (uint32 i = 0; i < MAX_EAGLE_COUNT; ++i) { float fX, fY, fZ; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+15.0f, 30.0f, fX, fY, fZ); - - m_creature->SummonCreature(NPC_SOARING_EAGLE, fX, fY, fZ, m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 15.0f, 30.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_SOARING_EAGLE, fX, fY, fZ, m_creature->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiCallLightTimer < uiDiff) { - m_creature->CastSpell(m_creature->getVictim(), SPELL_CALL_LIGHTNING, false); - m_uiCallLightTimer = urand(15000, 25000); - }else m_uiCallLightTimer -= uiDiff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CALL_LIGHTNING) == CAST_OK) + m_uiCallLightTimer = urand(15000, 25000); + } + else + m_uiCallLightTimer -= uiDiff; if (m_uiStaticDisruptTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - m_creature->CastSpell(pTarget, SPELL_STATIC_DISRUPTION, false); - - m_uiStaticDisruptTimer = urand(7000, 14000); - }else m_uiStaticDisruptTimer -= uiDiff; + { + if (DoCastSpellIfCan(pTarget, SPELL_STATIC_DISRUPTION) == CAST_OK) + m_uiStaticDisruptTimer = urand(7000, 14000); + } + } + else + m_uiStaticDisruptTimer -= uiDiff; if (m_uiStormTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(EMOTE_STORM, m_creature); - m_creature->CastSpell(pTarget, SPELL_ELECTRICAL_STORM, false); + if (DoCastSpellIfCan(pTarget, SPELL_ELECTRICAL_STORM) == CAST_OK) + { + DoScriptText(EMOTE_STORM, m_creature); + m_uiStormTimer = 55000; + } } - - m_uiStormTimer = 60000; - }else m_uiStormTimer -= uiDiff; + } + else + m_uiStormTimer -= uiDiff; if (m_uiGustOfWindTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - m_creature->CastSpell(pTarget, SPELL_GUST_OF_WIND, false); - - m_uiGustOfWindTimer = urand(20000, 30000); - }else m_uiGustOfWindTimer -= uiDiff; + { + if (DoCastSpellIfCan(pTarget, SPELL_GUST_OF_WIND) == CAST_OK) + m_uiGustOfWindTimer = urand(20000, 30000); + } + } + else + m_uiGustOfWindTimer -= uiDiff; if (m_uiSummonEagleTimer < uiDiff) { - DoScriptText(urand(0,1) ? SAY_SUMMON : SAY_SUMMON_ALT, m_creature); + DoScriptText(urand(0, 1) ? SAY_SUMMON : SAY_SUMMON_ALT, m_creature); DoSummonEagles(); m_uiSummonEagleTimer = 60000; - }else m_uiSummonEagleTimer -= uiDiff; + } + else + m_uiSummonEagleTimer -= uiDiff; - if (!m_bIsBerserk && m_uiBerserkTimer < uiDiff) + if (m_uiBerserkTimer) { - DoScriptText(SAY_ENRAGE, m_creature); - m_creature->CastSpell(m_creature, SPELL_BERSERK, true); - m_bIsBerserk = true; - }else m_uiBerserkTimer -= uiDiff; + if (m_uiBerserkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } DoMeleeAttackIfReady(); } @@ -196,13 +207,7 @@ CreatureAI* GetAI_boss_akilzon(Creature* pCreature) return new boss_akilzonAI(pCreature); } -enum -{ - SPELL_EAGLE_SWOOP = 44732, - POINT_ID_RANDOM = 1 -}; - -struct MANGOS_DLL_DECL mob_soaring_eagleAI : public ScriptedAI +struct mob_soaring_eagleAI : public ScriptedAI { mob_soaring_eagleAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -215,18 +220,15 @@ struct MANGOS_DLL_DECL mob_soaring_eagleAI : public ScriptedAI uint32 m_uiEagleSwoopTimer; uint32 m_uiReturnTimer; bool m_bCanMoveToRandom; - bool m_bCanCast; - void Reset() + void Reset() override { - m_uiEagleSwoopTimer = urand(2000, 6000); - m_uiReturnTimer = 800; - m_bCanMoveToRandom = false; - m_bCanCast = true; - + m_uiEagleSwoopTimer = 0; + m_uiReturnTimer = 800; + m_bCanMoveToRandom = false; } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!pWho) return; @@ -239,12 +241,12 @@ struct MANGOS_DLL_DECL mob_soaring_eagleAI : public ScriptedAI } } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { - if (uiType != POINT_MOTION_TYPE) + if (uiType != POINT_MOTION_TYPE || !uiPointId) return; - m_bCanCast = true; + m_uiEagleSwoopTimer = urand(2000, 6000); } void DoMoveToRandom() @@ -255,44 +257,45 @@ struct MANGOS_DLL_DECL mob_soaring_eagleAI : public ScriptedAI if (Creature* pAzkil = m_pInstance->GetSingleCreatureFromStorage(NPC_AKILZON)) { float fX, fY, fZ; - pAzkil->GetRandomPoint(pAzkil->GetPositionX(), pAzkil->GetPositionY(), pAzkil->GetPositionZ()+15.0f, 30.0f, fX, fY, fZ); + pAzkil->GetRandomPoint(pAzkil->GetPositionX(), pAzkil->GetPositionY(), pAzkil->GetPositionZ() + 15.0f, 30.0f, fX, fY, fZ); m_creature->SetWalk(false); - m_creature->GetMotionMaster()->MovePoint(POINT_ID_RANDOM, fX, fY, fZ); - - m_bCanMoveToRandom = false; + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_bCanMoveToRandom) + if (m_uiReturnTimer) { - if (m_uiReturnTimer < uiDiff) + if (m_uiReturnTimer <= uiDiff) { DoMoveToRandom(); - m_uiReturnTimer = 800; - }else m_uiReturnTimer -= uiDiff; + m_uiReturnTimer = 0; + } + else + m_uiReturnTimer -= uiDiff; } - if (!m_bCanCast) - return; - - if (m_uiEagleSwoopTimer < uiDiff) + if (m_uiEagleSwoopTimer) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (m_uiEagleSwoopTimer <= uiDiff) { - DoCastSpellIfCan(pTarget,SPELL_EAGLE_SWOOP); - - m_bCanMoveToRandom = true; - m_bCanCast = false; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_EAGLE_SWOOP) == CAST_OK) + { + m_uiEagleSwoopTimer = 0; + m_uiReturnTimer = 1000; + } + } } - - m_uiEagleSwoopTimer = urand(4000, 6000); - }else m_uiEagleSwoopTimer -= uiDiff; + else + m_uiEagleSwoopTimer -= uiDiff; + } } }; diff --git a/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp b/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp index 7922a35c8..2e0d1b3a0 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_halazzi.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,14 +16,13 @@ /* ScriptData SDName: Boss_Halazzi -SD%Complete: 70 -SDComment: Details and timers need check. +SD%Complete: 90 +SDComment: A few details and timers need check. SDCategory: Zul'Aman EndScriptData */ #include "precompiled.h" #include "zulaman.h" -#include "ObjectMgr.h" enum { @@ -39,28 +38,34 @@ enum SAY_EVENT1 = -1568043, SAY_EVENT2 = -1568044, - SPELL_DUAL_WIELD = 42459, - SPELL_SABER_LASH = 43267, - SPELL_FRENZY = 43139, - SPELL_FLAMESHOCK = 43303, - SPELL_EARTHSHOCK = 43305, + // generic spells SPELL_BERSERK = 45078, + SPELL_TRANSFORM_TO_ORIGINAL = 43311, + // SPELL_DUAL_WIELD = 42459, // spell not confirmed + // SPELL_TRANSFIGURE = 44054, // purpose unk - //SPELL_TRANSFORM_TO_ORIGINAL = 43311, - - //SPELL_TRANSFIGURE = 44054, + // Phase single spells + SPELL_SABER_LASH = 43267, + SPELL_FRENZY = 43139, - SPELL_TRANSFIGURE_TO_TROLL = 43142, - //SPELL_TRANSFIGURE_TO_TROLL_TRIGGERED = 43573, + // Phase switch spells + SPELL_HALAZZI_TRANSFORM_SUMMON = 43143, // summons 24143 + SPELL_TRANSFIGURE_TO_TROLL = 43142, // triggers 43573 + SPELL_TRANSFIGURE_TRANSFORM = 43573, SPELL_TRANSFORM_TO_LYNX_75 = 43145, SPELL_TRANSFORM_TO_LYNX_50 = 43271, SPELL_TRANSFORM_TO_LYNX_25 = 43272, + SPELL_HALAZZI_TRANSFORM_DUMMY = 43615, + // SPELL_HALAZZI_TRANSFORM_VISUAL= 43293, - SPELL_SUMMON_LYNX = 43143, - SPELL_SUMMON_TOTEM = 43302, + // Phase spirits spells + SPELL_FLAMESHOCK = 43303, + SPELL_EARTHSHOCK = 43305, + SPELL_LIGHTNING_TOTEM = 43302, // summons 24224 - NPC_TOTEM = 24224 + NPC_HALAZZI_TROLL = 24144, // dummy creature - used to update stats + NPC_SPIRIT_LYNX = 24143, }; enum HalazziPhase @@ -70,7 +75,7 @@ enum HalazziPhase PHASE_FINAL = 2 }; -struct MANGOS_DLL_DECL boss_halazziAI : public ScriptedAI +struct boss_halazziAI : public ScriptedAI { boss_halazziAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -80,44 +85,49 @@ struct MANGOS_DLL_DECL boss_halazziAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiPhase; + HalazziPhase m_uiPhase; + uint32 m_uiPhaseCounter; uint32 m_uiFrenzyTimer; uint32 m_uiSaberLashTimer; uint32 m_uiShockTimer; uint32 m_uiTotemTimer; - uint32 m_uiCheckTimer; uint32 m_uiBerserkTimer; - bool m_bIsBerserk; - void Reset() + bool m_bHasTransformed; + + ObjectGuid m_spiritLynxGuid; + + void Reset() override { - m_uiPhase = PHASE_SINGLE; // reset phase - m_uiPhaseCounter = 3; + m_uiPhase = PHASE_SINGLE; + m_uiPhaseCounter = 3; - m_uiCheckTimer = IN_MILLISECONDS; - m_uiFrenzyTimer = 16*IN_MILLISECONDS; - m_uiSaberLashTimer = 20*IN_MILLISECONDS; - m_uiShockTimer = 10*IN_MILLISECONDS; - m_uiTotemTimer = 12*IN_MILLISECONDS; - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; - m_bIsBerserk = false; + m_uiFrenzyTimer = 16000; + m_uiSaberLashTimer = 20000; + m_uiShockTimer = 10000; + m_uiTotemTimer = 12000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; - m_creature->SetMaxHealth(m_creature->GetCreatureInfo()->maxhealth); + m_bHasTransformed = false; + } - if (m_pInstance) - { - if (Creature* pSpiritLynx = m_pInstance->GetSingleCreatureFromStorage(NPC_SPIRIT_LYNX)) - pSpiritLynx->ForcedDespawn(); - } + void EnterEvadeMode() override + { + // Transform back on evade + if (DoCastSpellIfCan(m_creature, SPELL_TRANSFORM_TO_ORIGINAL) == CAST_OK) + m_creature->UpdateEntry(NPC_HALAZZI); + + ScriptedAI::EnterEvadeMode(); } - void JustReachedHome() + void JustReachedHome() override { - m_pInstance->SetData(TYPE_HALAZZI, FAIL); + if (m_pInstance) + m_pInstance->SetData(TYPE_HALAZZI, FAIL); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -125,7 +135,7 @@ struct MANGOS_DLL_DECL boss_halazziAI : public ScriptedAI m_pInstance->SetData(TYPE_HALAZZI, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -133,7 +143,7 @@ struct MANGOS_DLL_DECL boss_halazziAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -141,170 +151,142 @@ struct MANGOS_DLL_DECL boss_halazziAI : public ScriptedAI m_pInstance->SetData(TYPE_HALAZZI, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SPIRIT_LYNX) + { + m_spiritLynxGuid = pSummoned->GetObjectGuid(); pSummoned->SetInCombatWithZone(); + pSummoned->CastSpell(m_creature, SPELL_HALAZZI_TRANSFORM_DUMMY, true); + } } - void DoUpdateStats(const CreatureInfo* pInfo) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - m_creature->SetMaxHealth(pInfo->maxhealth); - - if (m_uiPhase == PHASE_SINGLE) + if (pSpell->Id == SPELL_TRANSFIGURE_TRANSFORM) { - m_creature->SetHealth(m_creature->GetMaxHealth()/4*m_uiPhaseCounter); - --m_uiPhaseCounter; + DoCastSpellIfCan(m_creature, SPELL_HALAZZI_TRANSFORM_SUMMON, CAST_TRIGGERED); + m_creature->UpdateEntry(NPC_HALAZZI_TROLL); + + m_uiPhase = PHASE_TOTEM; + m_uiShockTimer = 10000; + m_uiTotemTimer = 12000; } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + // Wrapper to handle the phase transform + void DoReuniteSpirits() { - if (pSpell->EffectApplyAuraName[0] != SPELL_AURA_TRANSFORM) - return; + uint32 uiSpellId = 0; - // possibly hack and health should be set by Aura::HandleAuraTransform() - if (const CreatureInfo* pInfo = GetCreatureTemplateStore(pSpell->EffectMiscValue[0])) - DoUpdateStats(pInfo); - - if (m_uiPhase == PHASE_TOTEM) - DoCastSpellIfCan(m_creature, SPELL_SUMMON_LYNX); - } - - void PhaseChange() - { - if (m_uiPhase == PHASE_SINGLE) + // Each health level has it's own spell - but they all do the same thing + switch (m_uiPhaseCounter) { - if (m_creature->GetHealthPercent() <= float(25*m_uiPhaseCounter)) - { - if (!m_uiPhaseCounter) - { - // final phase - m_uiPhase = PHASE_FINAL; - m_uiFrenzyTimer = 16*IN_MILLISECONDS; - m_uiSaberLashTimer = 20*IN_MILLISECONDS; - } - else - { - m_uiPhase = PHASE_TOTEM; - m_uiShockTimer = 10*IN_MILLISECONDS; - m_uiTotemTimer = 12*IN_MILLISECONDS; - - DoScriptText(SAY_SPLIT, m_creature); - m_creature->CastSpell(m_creature, SPELL_TRANSFIGURE_TO_TROLL, false); - } - } + case 3: uiSpellId = SPELL_TRANSFORM_TO_LYNX_75; break; + case 2: uiSpellId = SPELL_TRANSFORM_TO_LYNX_50; break; + case 1: uiSpellId = SPELL_TRANSFORM_TO_LYNX_25; break; } - else - { - Creature* pSpiritLynx = m_pInstance->GetSingleCreatureFromStorage(NPC_SPIRIT_LYNX); - if (m_creature->GetHealthPercent() < 10.0f || - (pSpiritLynx && pSpiritLynx->GetHealthPercent() < 10.0f)) - { - m_uiPhase = PHASE_SINGLE; - - DoScriptText(SAY_MERGE, m_creature); - - uint32 uiSpellId = 0; - - switch(m_uiPhaseCounter) - { - case 3: uiSpellId = SPELL_TRANSFORM_TO_LYNX_75; break; - case 2: uiSpellId = SPELL_TRANSFORM_TO_LYNX_50; break; - case 1: uiSpellId = SPELL_TRANSFORM_TO_LYNX_25; break; - } + if (DoCastSpellIfCan(m_creature, uiSpellId) == CAST_OK) + { + DoScriptText(SAY_MERGE, m_creature); + // Update stats back to the original Halazzi + m_creature->UpdateEntry(NPC_HALAZZI); - m_creature->CastSpell(m_creature, uiSpellId, false); + // Despawn the Lynx + if (Creature* pLynx = m_creature->GetMap()->GetCreature(m_spiritLynxGuid)) + pLynx->ForcedDespawn(); - if (pSpiritLynx) - pSpiritLynx->ForcedDespawn(); + // Set the proper health level - workaround for missing server side spell 43538 + m_creature->SetHealth(m_creature->GetMaxHealth() / 4 * m_uiPhaseCounter); + --m_uiPhaseCounter; - m_uiFrenzyTimer = 16*IN_MILLISECONDS; - m_uiSaberLashTimer = 20*IN_MILLISECONDS; - } + m_uiPhase = m_uiPhaseCounter > 0 ? PHASE_SINGLE : PHASE_FINAL; + m_uiFrenzyTimer = 16000; + m_uiSaberLashTimer = 20000; + m_bHasTransformed = false; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!m_bIsBerserk) + if (m_uiBerserkTimer) { - if (m_uiBerserkTimer < uiDiff) + if (m_uiBerserkTimer <= uiDiff) { - DoScriptText(SAY_BERSERK, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); - m_bIsBerserk = true; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } } else m_uiBerserkTimer -= uiDiff; } - if (m_uiPhase != PHASE_FINAL) + // Abilities used only in the single or final phase + if (m_uiPhase == PHASE_SINGLE || m_uiPhase == PHASE_FINAL) { - if (m_uiCheckTimer < uiDiff) + // Split boss at 75%, 50% and 25% + if (!m_bHasTransformed && m_creature->GetHealthPercent() <= float(25 * m_uiPhaseCounter)) { - if (m_pInstance) - PhaseChange(); - else - m_uiPhase = PHASE_FINAL; - - m_uiCheckTimer = IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature, SPELL_TRANSFIGURE_TO_TROLL) == CAST_OK) + { + DoScriptText(SAY_SPLIT, m_creature); + m_bHasTransformed = true; + } } - else - m_uiCheckTimer -= uiDiff; - } - if (m_uiPhase == PHASE_FINAL || m_uiPhase == PHASE_SINGLE) - { if (m_uiFrenzyTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_FRENZY); - m_uiFrenzyTimer = 16*IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + m_uiFrenzyTimer = 16000; } else m_uiFrenzyTimer -= uiDiff; if (m_uiSaberLashTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_SABERLASH1 : SAY_SABERLASH2, m_creature); - - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SABER_LASH); - m_uiSaberLashTimer = 20*IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SABER_LASH) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SABERLASH1 : SAY_SABERLASH2, m_creature); + m_uiSaberLashTimer = 20000; + } } else m_uiSaberLashTimer -= uiDiff; } - if (m_uiPhase == PHASE_FINAL || m_uiPhase == PHASE_TOTEM) + // Abilities used during the split phase or when the boss is below 25% health + if (m_uiPhase == PHASE_TOTEM || m_uiPhase == PHASE_FINAL) { if (m_uiTotemTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_TOTEM); - m_uiTotemTimer = 20*IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_TOTEM) == CAST_OK) + m_uiTotemTimer = 20000; } else m_uiTotemTimer -= uiDiff; if (m_uiShockTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (pTarget->IsNonMeleeSpellCasted(false)) - DoCastSpellIfCan(pTarget, SPELL_EARTHSHOCK); - else - DoCastSpellIfCan(pTarget, SPELL_FLAMESHOCK); - - m_uiShockTimer = urand(10000, 14000); + if (DoCastSpellIfCan(pTarget, urand(0, 1) ? SPELL_EARTHSHOCK : SPELL_FLAMESHOCK) == CAST_OK) + m_uiShockTimer = urand(10000, 14000); } } else m_uiShockTimer -= uiDiff; } + // Transform back from Totem phase + if (m_uiPhase == PHASE_TOTEM && m_creature->GetHealthPercent() < 20.0f) + DoReuniteSpirits(); + DoMeleeAttackIfReady(); } }; @@ -320,7 +302,7 @@ enum SPELL_SHRED_ARMOR = 43243 }; -struct MANGOS_DLL_DECL boss_spirit_lynxAI : public ScriptedAI +struct boss_spirit_lynxAI : public ScriptedAI { boss_spirit_lynxAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -332,19 +314,16 @@ struct MANGOS_DLL_DECL boss_spirit_lynxAI : public ScriptedAI uint32 m_uiFrenzyTimer; uint32 m_uiShredArmorTimer; + bool m_bHasUnited; - void Reset() + void Reset() override { - m_uiFrenzyTimer = urand(10000, 20000); //first frenzy after 10-20 seconds + m_uiFrenzyTimer = urand(10000, 20000); // first frenzy after 10-20 seconds m_uiShredArmorTimer = 4000; + m_bHasUnited = false; } - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (!m_pInstance) return; @@ -353,7 +332,7 @@ struct MANGOS_DLL_DECL boss_spirit_lynxAI : public ScriptedAI pHalazzi->AI()->KilledUnit(pVictim); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -361,7 +340,7 @@ struct MANGOS_DLL_DECL boss_spirit_lynxAI : public ScriptedAI if (m_uiFrenzyTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_LYNX_FRENZY); - m_uiFrenzyTimer = urand(20000, 30000); //subsequent frenzys casted every 20-30 seconds + m_uiFrenzyTimer = urand(20000, 30000); // subsequent frenzys casted every 20-30 seconds } else m_uiFrenzyTimer -= uiDiff; @@ -374,6 +353,18 @@ struct MANGOS_DLL_DECL boss_spirit_lynxAI : public ScriptedAI else m_uiShredArmorTimer -= uiDiff; + // Unite spirits at 10% health + // Note: maybe there is some spell related to this - needs research + if (!m_bHasUnited && m_creature->GetHealthPercent() < 10.0f && m_pInstance) + { + if (Creature* pHalazzi = m_pInstance->GetSingleCreatureFromStorage(NPC_HALAZZI)) + { + if (boss_halazziAI* pBossAI = dynamic_cast(pHalazzi->AI())) + pBossAI->DoReuniteSpirits(); + } + m_bHasUnited = true; + } + DoMeleeAttackIfReady(); } }; diff --git a/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp b/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp index 7d85c1650..de3c79a6f 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_janalai.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Janalai -SD%Complete: 75 -SDComment: +SD%Complete: 90 +SDComment: The hatchers may need some additional behavior adjustments. SDCategory: Zul'Aman EndScriptData */ @@ -37,59 +37,47 @@ enum SAY_EVENT_STRANGERS = -1568008, SAY_EVENT_FRIENDS = -1568009, - //Jan'alai + // Jan'alai SPELL_FLAME_BREATH = 43140, - SPELL_FIRE_WALL = 43113, + SPELL_HATCH_ALL_EGGS = 43144, // triggers 42493 + SPELL_TELEPORT_TO_CENTER = 43098, + SPELL_SUMMON_ALL_PLAYERS = 43096, // triggers 43097 SPELL_ENRAGE = 44779, - SPELL_TELETOCENTER = 43098, - SPELL_SUMMONALL = 43097, SPELL_BERSERK = 47008, SPELL_SUMMON_HATCHER_1 = 43962, SPELL_SUMMON_HATCHER_2 = 45340, - //Fire Bob Spells + // Fire Bob Spells SPELL_FIRE_BOMB_CHANNEL = 42621, - SPELL_FIRE_BOMB_THROW = 42628, - SPELL_FIRE_BOMB_DUMMY = 42629, - SPELL_FIRE_BOMB_DAMAGE = 42630, + SPELL_FIRE_BOMB_THROW = 42628, // triggers 42629 + SPELL_FIRE_BOMB_EXPLODE = 42631, // triggers 42630 - //NPC's + // NPCs NPC_FIRE_BOMB = 23920, NPC_AMANI_HATCHER_1 = 23818, NPC_AMANI_HATCHER_2 = 24504, NPC_HATCHLING = 23598, + NPC_DRAGONHAWK_EGG = 23817, - //Hatcher Spells - SPELL_HATCH_EGG = 43734, //spell 42471 also exist - SPELL_HATCH_ALL_EGGS = 43144, - - //Eggs spells - SPELL_SUMMON_DRAGONHAWK = 42493, + // Hatcher Spells + SPELL_HATCH_EGG_1 = 43734, + SPELL_HATCH_EGG_2 = 42471, - //Hatchling Spells - SPELL_FLAMEBUFFED = 43299 -}; - -//spells should summon Fire Bomb, used in Throw5Bombs() -static uint32 m_auiSpellFireBombSummon[]= -{ - 42622, 42623, 42624, 42625, 42626 -}; + // Fire Wall + SPELL_FIRE_WALL = 43113, -const int area_dx = 44; -const int area_dy = 51; + // Eggs spells + SPELL_SUMMON_DRAGONHAWK = 42493, -float JanalainPos[1][3] = -{ - {-33.93f, 1149.27f, 19.0f} + MAX_EGGS_ON_SIDE = 20, // there are 20 eggs spawned on each side }; -float FireWallCoords[4][4] = +static const float afFireWallCoords[4][4] = { - {-10.13f, 1149.27f, 19.0f, M_PI_F}, - {-33.93f, 1123.90f, 19.0f, 0.5f*M_PI_F}, - {-54.80f, 1150.08f, 19.0f, 0.0f}, - {-33.93f, 1175.68f, 19.0f, 1.5f*M_PI_F} + { -10.13f, 1149.27f, 19.0f, M_PI_F}, + { -33.93f, 1123.90f, 19.0f, 0.5f * M_PI_F}, + { -54.80f, 1150.08f, 19.0f, 0.0f}, + { -33.93f, 1175.68f, 19.0f, 1.5f * M_PI_F} }; struct WaypointDef @@ -97,45 +85,27 @@ struct WaypointDef float m_fX, m_fY, m_fZ; }; -WaypointDef m_aHatcherRight[]= +static const WaypointDef m_aHatcherRight[] = { - {-86.203f, 1136.834f, 5.594f}, //this is summon point, not regular waypoint - {-74.783f, 1145.827f, 5.420f}, - {-56.957f, 1146.713f, 18.725f}, - {-45.428f, 1141.697f, 18.709f}, - {-34.002f, 1124.427f, 18.711f}, - {-34.085f, 1106.158f, 18.711f} + { -74.783f, 1145.827f, 5.420f}, + { -54.476f, 1146.934f, 18.705f}, + { -56.957f, 1146.713f, 18.725f}, + { -45.428f, 1141.697f, 18.709f}, + { -34.002f, 1124.427f, 18.711f}, + { -34.085f, 1106.158f, 18.711f} }; -WaypointDef m_aHatcherLeft[]= +static const WaypointDef m_aHatcherLeft[] = { - {-85.420f, 1167.321f, 5.594f}, //this is summon point, not regular waypoint - {-73.569f, 1154.960f, 5.510f}, - {-56.985f, 1153.373f, 18.608f}, - {-45.515f, 1158.356f, 18.709f}, - {-33.314f, 1174.816f, 18.709f}, - {-33.097f, 1195.359f, 18.709f} + { -73.569f, 1154.960f, 5.510f}, + { -54.264f, 1153.968f, 18.705f}, + { -56.985f, 1153.373f, 18.608f}, + { -45.515f, 1158.356f, 18.709f}, + { -33.314f, 1174.816f, 18.709f}, + { -33.097f, 1195.359f, 18.709f} }; -float hatcherway_l[5][3] = -{ - {-87.46f, 1170.09f, 6.0f}, - {-74.41f, 1154.75f, 6.0f}, - {-52.74f, 1153.32f, 19.0f}, - {-33.37f, 1172.46f, 19.0f}, - {-33.09f, 1203.87f, 19.0f} -}; - -float hatcherway_r[5][3] = -{ - {-86.57f, 1132.85f, 6.0f}, - {-73.94f, 1146.00f, 6.0f}, - {-52.29f, 1146.51f, 19.0f}, - {-33.57f, 1125.72f, 19.0f}, - {-34.29f, 1095.22f, 19.0f} -}; - -struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI +struct boss_janalaiAI : public ScriptedAI { boss_janalaiAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -146,77 +116,48 @@ struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI ScriptedInstance* m_pInstance; uint32 m_uiFireBreathTimer; - - GUIDList m_lBombsGUIDList; - std::list m_lEggsRemainingList; - - uint32 m_uiBombTimer; - uint32 m_uiBombSequenzeTimer; - uint32 m_uiBombPhase; - uint32 m_uiBombCounter; - uint32 m_uiEnrageTimer; uint32 m_uiHatcherTimer; - uint32 m_uiWipeTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiBombTimer; + uint32 m_uiBombAuraTimer; + uint32 m_uiExplodeTimer; - bool m_bIsBombing; - bool m_bCanBlowUpBombs; - bool m_bIsEggRemaining; + uint8 m_uiEggsHatchedLeft; + uint8 m_uiEggsHatchedRight; + + bool m_bIsFlameWall; + bool m_bHasHatchedEggs; bool m_bIsEnraged; - bool m_bCanEnrage; ObjectGuid m_hatcherOneGuid; ObjectGuid m_hatcherTwoGuid; - void Reset() + void Reset() override { - m_lEggsRemainingList.clear(); - - if (Creature* pHatcher = m_creature->GetMap()->GetCreature(m_hatcherOneGuid)) - { - pHatcher->AI()->EnterEvadeMode(); - pHatcher->SetDeathState(JUST_DIED); - m_hatcherOneGuid.Clear(); - } - - if (Creature* pHatcher = m_creature->GetMap()->GetCreature(m_hatcherTwoGuid)) - { - pHatcher->AI()->EnterEvadeMode(); - pHatcher->SetDeathState(JUST_DIED); - m_hatcherTwoGuid.Clear(); - } - m_uiFireBreathTimer = 8000; - - m_uiBombTimer = 30000; - m_bIsBombing = false; - m_uiBombSequenzeTimer = 1500; - m_uiBombPhase = 0; - m_uiBombCounter = 0; - m_bCanBlowUpBombs = false; - m_bIsEggRemaining = true; - - m_uiEnrageTimer = MINUTE*5*IN_MILLISECONDS; - m_uiHatcherTimer = 10000; - m_uiWipeTimer = MINUTE*10*IN_MILLISECONDS; - m_bIsEnraged = false; - m_bCanEnrage = false; + m_uiEnrageTimer = 5 * MINUTE * IN_MILLISECONDS; + m_uiHatcherTimer = 10000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiBombTimer = 30000; + m_uiBombAuraTimer = 0; + m_uiExplodeTimer = 0; + + m_uiEggsHatchedLeft = 0; + m_uiEggsHatchedRight = 0; + + m_bHasHatchedEggs = false; + m_bIsEnraged = false; + m_bIsFlameWall = false; } - void JustReachedHome() + void JustReachedHome() override { - for (GUIDList::const_iterator itr = m_lBombsGUIDList.begin(); itr != m_lBombsGUIDList.end(); ++itr) - { - if (Creature* pBomb = m_creature->GetMap()->GetCreature(*itr)) - pBomb->ForcedDespawn(); - } - m_lBombsGUIDList.clear(); - if (m_pInstance) m_pInstance->SetData(TYPE_JANALAI, FAIL); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -224,12 +165,12 @@ struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI m_pInstance->SetData(TYPE_JANALAI, DONE); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -237,325 +178,193 @@ struct MANGOS_DLL_DECL boss_janalaiAI : public ScriptedAI m_pInstance->SetData(TYPE_JANALAI, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_AMANI_HATCHER_1: m_hatcherOneGuid = pSummoned->GetObjectGuid(); + // If all the eggs from one side are hatched, move to the other side + if (m_uiEggsHatchedRight == MAX_EGGS_ON_SIDE) + pSummoned->GetMotionMaster()->MovePoint(1, m_aHatcherLeft[0].m_fX, m_aHatcherLeft[0].m_fY, m_aHatcherLeft[0].m_fZ); + else + pSummoned->GetMotionMaster()->MovePoint(1, m_aHatcherRight[0].m_fX, m_aHatcherRight[0].m_fY, m_aHatcherRight[0].m_fZ); break; case NPC_AMANI_HATCHER_2: m_hatcherTwoGuid = pSummoned->GetObjectGuid(); + // If all the eggs from one side are hatched, move to the other side + if (m_uiEggsHatchedLeft == MAX_EGGS_ON_SIDE) + pSummoned->GetMotionMaster()->MovePoint(1, m_aHatcherRight[0].m_fX, m_aHatcherRight[0].m_fY, m_aHatcherRight[0].m_fZ); + else + pSummoned->GetMotionMaster()->MovePoint(1, m_aHatcherLeft[0].m_fX, m_aHatcherLeft[0].m_fY, m_aHatcherLeft[0].m_fZ); break; case NPC_FIRE_BOMB: - if (m_bIsBombing) + if (!m_bIsFlameWall) + DoCastSpellIfCan(pSummoned, SPELL_FIRE_BOMB_THROW, CAST_TRIGGERED); + else + pSummoned->CastSpell(pSummoned, SPELL_FIRE_WALL, true); + break; + case NPC_HATCHLING: + pSummoned->SetInCombatWithZone(); + // Count the Hatched eggs + pSummoned->GetPositionY() > 1100.0f ? ++m_uiEggsHatchedLeft : ++m_uiEggsHatchedRight; + // Notify the script when all the eggs were hatched + if (m_uiEggsHatchedRight == MAX_EGGS_ON_SIDE && m_uiEggsHatchedLeft == MAX_EGGS_ON_SIDE) + m_bHasHatchedEggs = true; + // Change the side of the hatcher if necessary + if (m_uiEggsHatchedRight == MAX_EGGS_ON_SIDE && m_uiEggsHatchedLeft < MAX_EGGS_ON_SIDE) { - //store bombs in list to be used in BlowUpBombs() - m_lBombsGUIDList.push_back(pSummoned->GetObjectGuid()); - - if (pSummoned->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) - pSummoned->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - //visual spell, spell hit pSummoned after a short time - m_creature->CastSpell(pSummoned,SPELL_FIRE_BOMB_THROW,true); + if (Creature* pHatcer = m_creature->GetMap()->GetCreature(m_hatcherOneGuid)) + pHatcer->GetMotionMaster()->MovePoint(1, m_aHatcherLeft[5].m_fX, m_aHatcherLeft[5].m_fY, m_aHatcherLeft[5].m_fZ); } - else + if (m_uiEggsHatchedLeft == MAX_EGGS_ON_SIDE && m_uiEggsHatchedRight < MAX_EGGS_ON_SIDE) { - pSummoned->CastSpell(pSummoned, SPELL_FIRE_WALL, true); + if (Creature* pHatcer = m_creature->GetMap()->GetCreature(m_hatcherTwoGuid)) + pHatcer->GetMotionMaster()->MovePoint(1, m_aHatcherRight[5].m_fX, m_aHatcherRight[5].m_fY, m_aHatcherRight[5].m_fZ); } break; } } - void SpellHitTarget(Unit* pUnit, const SpellEntry* pSpell) - { - //when spell actually hit the fire bombs, make then cast spell(making them "visible") - if (pUnit->GetEntry() == NPC_FIRE_BOMB && pSpell->Id == SPELL_FIRE_BOMB_THROW) - pUnit->CastSpell(pUnit,SPELL_FIRE_BOMB_DUMMY,false); - } - - void CreateFireWall() // Create Firewall + // Wrapper to create the firewalls during Bomb phase + void DoCreateFireWall() { - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1],FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1]+5,FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[0][0],FireWallCoords[0][1]-5,FireWallCoords[0][2],FireWallCoords[0][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[1][0]-2,FireWallCoords[1][1]-2,FireWallCoords[1][2],FireWallCoords[1][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[1][0]+2,FireWallCoords[1][1]+2,FireWallCoords[1][2],FireWallCoords[1][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1],FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1]-5,FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[2][0],FireWallCoords[2][1]+5,FireWallCoords[2][2],FireWallCoords[2][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[3][0]-2,FireWallCoords[3][1],FireWallCoords[3][2],FireWallCoords[3][3],TEMPSUMMON_TIMED_DESPAWN,11500); - - m_creature->SummonCreature(NPC_FIRE_BOMB,FireWallCoords[3][0]+2,FireWallCoords[3][1],FireWallCoords[3][2],FireWallCoords[3][3],TEMPSUMMON_TIMED_DESPAWN,11500); + // This function involves a lot of guesswork!!! + // The npc entry isn't sure and the locations are guessed + m_bIsFlameWall = true; + m_creature->SummonCreature(NPC_FIRE_BOMB, afFireWallCoords[0][0], afFireWallCoords[0][1], afFireWallCoords[0][2], afFireWallCoords[0][3], TEMPSUMMON_TIMED_DESPAWN, 12000); + m_creature->SummonCreature(NPC_FIRE_BOMB, afFireWallCoords[1][0], afFireWallCoords[1][1], afFireWallCoords[1][2], afFireWallCoords[1][3], TEMPSUMMON_TIMED_DESPAWN, 12000); + m_creature->SummonCreature(NPC_FIRE_BOMB, afFireWallCoords[2][0], afFireWallCoords[2][1], afFireWallCoords[2][2], afFireWallCoords[2][3], TEMPSUMMON_TIMED_DESPAWN, 12000); + m_creature->SummonCreature(NPC_FIRE_BOMB, afFireWallCoords[3][0], afFireWallCoords[3][1], afFireWallCoords[3][2], afFireWallCoords[3][3], TEMPSUMMON_TIMED_DESPAWN, 12000); + m_bIsFlameWall = false; } - void Throw5Bombs() + void UpdateAI(const uint32 uiDiff) override { - //all available spells (each spell has different radius for summon location) - uint8 uiMaxBombs = sizeof(m_auiSpellFireBombSummon)/sizeof(uint32); - - //float fX, fY, fZ; - //float fRadius = 5.0f; - - for(uint8 i = 0; i < uiMaxBombs; ++i) - { - m_creature->CastSpell(m_creature, m_auiSpellFireBombSummon[i], true); - - //workaround part - //m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), fRadius+(fRadius*i), fX, fY, fZ); - //m_creature->SummonCreature(NPC_FIRE_BOMB, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN, MINUTE*IN_MILLISECONDS); - } - - ++m_uiBombCounter; - } - - //Teleport every player into the middle if more than 20 yards away (possibly what spell 43096 should do) - void TeleportPlayersOutOfRange() - { - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) - { - Unit* pTemp = m_creature->GetMap()->GetUnit(*i); - - if (pTemp && pTemp->GetTypeId() == TYPEID_PLAYER && !m_creature->IsWithinDist(pTemp, 20.0f)) - m_creature->CastSpell(pTemp, SPELL_SUMMONALL, true); - } - } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - void BlowUpBombs() - { - for (GUIDList::const_iterator itr = m_lBombsGUIDList.begin(); itr != m_lBombsGUIDList.end(); ++itr) + // Start bombing + if (m_uiBombTimer < uiDiff) { - if (Creature* pBomb = m_creature->GetMap()->GetCreature(*itr)) + if (DoCastSpellIfCan(m_creature, SPELL_FIRE_BOMB_CHANNEL) == CAST_OK) { - //do damage and then remove aura (making them "disappear") - pBomb->CastSpell(pBomb, SPELL_FIRE_BOMB_DAMAGE, false, NULL, NULL, m_creature->GetObjectGuid()); - pBomb->RemoveAurasDueToSpell(SPELL_FIRE_BOMB_DUMMY); + DoCastSpellIfCan(m_creature, SPELL_TELEPORT_TO_CENTER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_ALL_PLAYERS, CAST_TRIGGERED); + DoScriptText(SAY_FIRE_BOMBS, m_creature); + DoCreateFireWall(); + + m_uiBombAuraTimer = 5000; + m_uiBombTimer = urand(20000, 40000); } } + else + m_uiBombTimer -= uiDiff; - m_lBombsGUIDList.clear(); - } - - void DoHatchRemainingEggs() - { - GetCreatureListWithEntryInGrid(m_lEggsRemainingList, m_creature, NPC_EGG, 125.0f); - - if (!m_lEggsRemainingList.empty()) + if (m_uiFireBreathTimer < uiDiff) { - for(std::list::iterator itr = m_lEggsRemainingList.begin(); itr != m_lEggsRemainingList.end(); ++itr) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if ((*itr)->isAlive()) - (*itr)->CastSpell((*itr), SPELL_SUMMON_DRAGONHAWK, true); - } - - m_bIsEggRemaining = false; - - if (!m_pInstance) - return; - - if (uint32 uiEggsRemaining_Right = m_pInstance->GetData(TYPE_J_EGGS_RIGHT)) - { - for(uint32 i = 0; i < uiEggsRemaining_Right; ++i) - m_pInstance->SetData(TYPE_J_EGGS_RIGHT, SPECIAL); - } - - if (uint32 uiEggsRemaining_Left = m_pInstance->GetData(TYPE_J_EGGS_LEFT)) - { - for(uint32 i = 0; i < uiEggsRemaining_Left; ++i) - m_pInstance->SetData(TYPE_J_EGGS_LEFT, SPECIAL); + if (DoCastSpellIfCan(pTarget, SPELL_FLAME_BREATH) == CAST_OK) + m_uiFireBreathTimer = 8000; } } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + else + m_uiFireBreathTimer -= uiDiff; - //blow up bombs happen after bombing is over, so handle this here - if (m_bCanBlowUpBombs) + // Remove bomb aura after five seconds + if (m_uiBombAuraTimer) { - if (m_uiBombSequenzeTimer < uiDiff) + if (m_uiBombAuraTimer <= uiDiff) { - BlowUpBombs(); - m_bCanBlowUpBombs = false; + m_creature->RemoveAurasDueToSpell(SPELL_FIRE_BOMB_CHANNEL); + m_uiBombAuraTimer = 0; + m_uiExplodeTimer = 5000; } else - m_uiBombSequenzeTimer -= uiDiff; + m_uiBombAuraTimer -= uiDiff; } - if (!m_bIsBombing) // every Spell if NOT Bombing + // Explode the summoned bombs on timer + if (m_uiExplodeTimer) { - if (m_uiBombTimer < uiDiff) + if (m_uiExplodeTimer <= uiDiff) { - DoScriptText(SAY_FIRE_BOMBS, m_creature); - - //first clear movement - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MovementExpired(); - - //then teleport self - DoCastSpellIfCan(m_creature, SPELL_TELETOCENTER, CAST_INTERRUPT_PREVIOUS | CAST_TRIGGERED); - - //then players and create the firewall - TeleportPlayersOutOfRange(); - CreateFireWall(); - - //prepare variables for bombing sequenze - m_lBombsGUIDList.clear(); - - m_uiBombPhase = 0; - m_uiBombSequenzeTimer = 500; - m_uiBombCounter = 0; - - m_uiBombTimer = urand(20000, 40000); - m_bIsBombing = true; - - //we don't want anything else to happen this Update() - return; + if (DoCastSpellIfCan(m_creature, SPELL_FIRE_BOMB_EXPLODE) == CAST_OK) + m_uiExplodeTimer = 0; } else - m_uiBombTimer -= uiDiff; - - //FIRE BREATH several videos says every 8Secounds - if (m_uiFireBreathTimer < uiDiff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_FLAME_BREATH); - m_uiFireBreathTimer = 8000; - }else m_uiFireBreathTimer -= uiDiff; - - //enrage if under 25% hp before 5 min. - if (m_creature->GetHealthPercent() < 25.0f && !m_bIsEnraged) - { - m_bCanEnrage = true; - m_uiEnrageTimer = 600000; - } - - //Enrage but only if not bombing - if (m_bCanEnrage && !m_bIsEnraged) - { - DoScriptText(SAY_BERSERK, m_creature); - - DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_INTERRUPT_PREVIOUS); - m_bIsEnraged = true; - } + m_uiExplodeTimer -= uiDiff; + } - //Hatch All - if (m_bIsEggRemaining && m_creature->GetHealthPercent() < 35.0f) + // Hatch all eggs at 35% health + if (!m_bHasHatchedEggs && m_creature->GetHealthPercent() < 35.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_HATCH_ALL_EGGS) == CAST_OK) { DoScriptText(SAY_ALL_EGGS, m_creature); - - DoCastSpellIfCan(m_creature, SPELL_HATCH_ALL_EGGS, CAST_INTERRUPT_PREVIOUS); - - DoHatchRemainingEggs(); + m_bHasHatchedEggs = true; } - - DoMeleeAttackIfReady(); } - else // every Spell if Bombing + + // Soft Enrage - after 5 min, or at 20% health + if (!m_bIsEnraged) { - if (m_uiBombSequenzeTimer < uiDiff) + if (m_uiEnrageTimer < uiDiff) { - switch(m_uiBombPhase) - { - case 0: - DoCastSpellIfCan(m_creature, SPELL_FIRE_BOMB_CHANNEL, CAST_TRIGGERED); - m_uiBombSequenzeTimer = 500; - ++m_uiBombPhase; - break; - case 1: - if (m_uiBombCounter < 8) - { - Throw5Bombs(); - m_uiBombSequenzeTimer = 500; - } - else - { - m_uiBombSequenzeTimer = 1000; - ++m_uiBombPhase; - } - break; - case 2: - m_bCanBlowUpBombs = true; - m_uiBombSequenzeTimer = 2000; - m_creature->RemoveAurasDueToSpell(SPELL_FIRE_BOMB_CHANNEL); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_bIsBombing = false; - break; - } - + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bIsEnraged = true; } else - m_uiBombSequenzeTimer -= uiDiff; - } + m_uiEnrageTimer -= uiDiff; - //Enrage after 5 minutes - if (m_uiEnrageTimer < uiDiff) - { - m_bCanEnrage = true; - m_uiEnrageTimer = 600000; + if (m_creature->GetHealthPercent() < 20.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_bIsEnraged = true; + } } - else - m_uiEnrageTimer -= uiDiff; - //Call Hatcher - if (m_bIsEggRemaining) + // Spawn Hatchers - if necessary + if (!m_bHasHatchedEggs) { if (m_uiHatcherTimer < uiDiff) { - if (!m_pInstance || (m_pInstance->GetData(TYPE_J_EGGS_LEFT) == 0 && m_pInstance->GetData(TYPE_J_EGGS_RIGHT) == 0)) - m_bIsEggRemaining = false; - else - { - DoScriptText(SAY_SUMMON_HATCHER, m_creature); + DoScriptText(SAY_SUMMON_HATCHER, m_creature); - Creature* pHatcer1 = m_creature->GetMap()->GetCreature(m_hatcherOneGuid); - Creature* pHatcer2 = m_creature->GetMap()->GetCreature(m_hatcherTwoGuid); + Creature* pHatcer1 = m_creature->GetMap()->GetCreature(m_hatcherOneGuid); + Creature* pHatcer2 = m_creature->GetMap()->GetCreature(m_hatcherTwoGuid); - if (!pHatcer1 || (pHatcer1 && !pHatcer1->isAlive())) - { - if (Creature* pHatcher = m_creature->SummonCreature(NPC_AMANI_HATCHER_1, m_aHatcherRight[0].m_fX, m_aHatcherRight[0].m_fY, m_aHatcherRight[0].m_fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - pHatcher->GetMotionMaster()->MovePoint(1, m_aHatcherRight[1].m_fX, m_aHatcherRight[1].m_fY, m_aHatcherRight[1].m_fZ); - } + if (!pHatcer1 || !pHatcer1->isAlive()) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_HATCHER_1, CAST_TRIGGERED); - if (!pHatcer2 || (pHatcer2 && !pHatcer2->isAlive())) - { - if (Creature* pHatcher = m_creature->SummonCreature(NPC_AMANI_HATCHER_2, m_aHatcherLeft[0].m_fX, m_aHatcherLeft[0].m_fY, m_aHatcherLeft[0].m_fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - pHatcher->GetMotionMaster()->MovePoint(1, m_aHatcherLeft[1].m_fX, m_aHatcherLeft[1].m_fY, m_aHatcherLeft[1].m_fZ); - } - - m_uiHatcherTimer = 90000; - } + if (!pHatcer2 || !pHatcer2->isAlive()) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_HATCHER_2, CAST_TRIGGERED); + m_uiHatcherTimer = 90000; } else m_uiHatcherTimer -= uiDiff; } - //WIPE after 10 minutes - if (m_uiWipeTimer < uiDiff) + // Hard enrage + if (m_uiBerserkTimer) { - if (DoCastSpellIfCan(m_creature,SPELL_ENRAGE) == CAST_OK) + if (m_uiBerserkTimer <= uiDiff) { - DoScriptText(SAY_BERSERK, m_creature); - m_uiWipeTimer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } } + else + m_uiBerserkTimer -= uiDiff; } - else - m_uiWipeTimer -= uiDiff; - //check for reset ... exploit preventing ... pulled from his podest + DoMeleeAttackIfReady(); + + // check for reset ... exploit preventing ... pulled from his podest EnterEvadeIfOutOfCombatArea(uiDiff); } }; @@ -565,25 +374,7 @@ CreatureAI* GetAI_boss_janalaiAI(Creature* pCreature) return new boss_janalaiAI(pCreature); } -struct MANGOS_DLL_DECL npc_janalai_firebombAI : public ScriptedAI -{ - npc_janalai_firebombAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() {} - - void AttackStart(Unit* pWho) {} - - void MoveInLineOfSight(Unit* pWho) {} - - void UpdateAI(const uint32 uiDiff) {} -}; - -CreatureAI* GetAI_npc_janalai_firebombAI(Creature* pCreature) -{ - return new npc_janalai_firebombAI(pCreature); -} - -struct MANGOS_DLL_DECL npc_amanishi_hatcherAI : public ScriptedAI +struct npc_amanishi_hatcherAI : public ScriptedAI { npc_amanishi_hatcherAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -595,107 +386,91 @@ struct MANGOS_DLL_DECL npc_amanishi_hatcherAI : public ScriptedAI uint32 m_uiWaypoint; uint32 m_uiHatchlingTimer; - uint32 m_uiHatchlingCount; - bool m_bCanMoveNext; + uint8 m_uiHatchlingCount; + uint8 m_uiEggsHatched; bool m_bWaypointEnd; - void Reset() + void Reset() override { - m_uiWaypoint = 0; - m_uiHatchlingTimer = 1000; - m_uiHatchlingCount = 1; - m_bCanMoveNext = false; - m_bWaypointEnd = false; + m_uiWaypoint = 0; + m_uiHatchlingTimer = 0; + m_uiHatchlingCount = 0; + m_uiEggsHatched = 0; + m_bWaypointEnd = false; + m_creature->SetWalk(false); } - void MoveInLineOfSight(Unit* pWho) {} + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } - void AttackStart(Unit* pWho) + void MovementInform(uint32 uiType, uint32 uiPointId) override { - if (!pWho) + if (uiType != POINT_MOTION_TYPE) return; - if (m_creature->Attack(pWho, false)) + // Used when a hatcher is forced to switch sides + if (m_bWaypointEnd && uiPointId) { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); - } - } - - void MovementInform(uint32 uiType, uint32 uiPointId) - { - if (uiType != POINT_MOTION_TYPE || m_bWaypointEnd) + m_creature->GetMotionMaster()->Clear(); + m_uiHatchlingTimer = 1000; return; + } - uint32 uiCount = (m_creature->GetEntry() == NPC_AMANI_HATCHER_1) ? - (sizeof(m_aHatcherRight)/sizeof(WaypointDef)) : (sizeof(m_aHatcherLeft)/sizeof(WaypointDef)); + uint32 uiCount = m_creature->GetEntry() == NPC_AMANI_HATCHER_1 ? countof(m_aHatcherRight) : countof(m_aHatcherLeft); - m_uiWaypoint = uiPointId+1; + m_uiWaypoint = uiPointId + 1; if (uiCount == m_uiWaypoint) + { + m_creature->GetMotionMaster()->Clear(); + m_uiHatchlingTimer = 1000; m_bWaypointEnd = true; - - m_bCanMoveNext = true; + } + else + { + if (m_creature->GetEntry() == NPC_AMANI_HATCHER_1) + m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, m_aHatcherRight[m_uiWaypoint].m_fX, m_aHatcherRight[m_uiWaypoint].m_fY, m_aHatcherRight[m_uiWaypoint].m_fZ); + else + m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, m_aHatcherLeft[m_uiWaypoint].m_fX, m_aHatcherLeft[m_uiWaypoint].m_fY, m_aHatcherLeft[m_uiWaypoint].m_fZ); + } } - void DoHatchEggs(uint32 uiCount) + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpell) override { - uint32 uiSaveRightOrLeft = m_creature->GetEntry() == NPC_AMANI_HATCHER_1 ? TYPE_J_EGGS_RIGHT : TYPE_J_EGGS_LEFT; + if ((pSpell->Id != SPELL_HATCH_EGG_1 && pSpell->Id != SPELL_HATCH_EGG_2) || pTarget->GetEntry() != NPC_DRAGONHAWK_EGG) + return; - for(uint32 i = 0; i < uiCount; ++i) - { - if (Creature* pEgg = GetClosestCreatureWithEntry(m_creature, NPC_EGG, 40.0f)) - pEgg->CastSpell(pEgg, SPELL_SUMMON_DRAGONHAWK, true); + // If we already hatched the number of eggs allowed per hatch phase, stop the hatching + if (m_uiEggsHatched >= m_uiHatchlingCount) + return; - m_pInstance->SetData(uiSaveRightOrLeft, SPECIAL); + if (!m_pInstance) + return; + + if (Creature* pJanalai = m_pInstance->GetSingleCreatureFromStorage(NPC_JANALAI)) + { + pTarget->CastSpell(pTarget, SPELL_SUMMON_DRAGONHAWK, true, NULL, NULL, pJanalai->GetObjectGuid()); + ++m_uiEggsHatched; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_bCanMoveNext) - { - m_bCanMoveNext = false; - - if (m_bWaypointEnd) - m_creature->GetMotionMaster()->Clear(); - else - { - if (m_creature->GetEntry() == NPC_AMANI_HATCHER_1) - m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, m_aHatcherRight[m_uiWaypoint].m_fX, m_aHatcherRight[m_uiWaypoint].m_fY, m_aHatcherRight[m_uiWaypoint].m_fZ); - else - m_creature->GetMotionMaster()->MovePoint(m_uiWaypoint, m_aHatcherLeft[m_uiWaypoint].m_fX, m_aHatcherLeft[m_uiWaypoint].m_fY, m_aHatcherLeft[m_uiWaypoint].m_fZ); - } - } + if (!m_bWaypointEnd) + return; - if (m_bWaypointEnd) + if (m_uiHatchlingTimer) { - if (m_uiHatchlingTimer < uiDiff) + if (m_uiHatchlingTimer <= uiDiff) { - m_uiHatchlingTimer = 10000; - - if (!m_pInstance) - return; - - uint32 uiEggsRemaining = m_creature->GetEntry() == NPC_AMANI_HATCHER_1 ? m_pInstance->GetData(TYPE_J_EGGS_RIGHT) : m_pInstance->GetData(TYPE_J_EGGS_LEFT); - - if (!uiEggsRemaining) + // Note: there are 2 Hatch Eggs spells. Not sure which one to use + if (DoCastSpellIfCan(m_creature, SPELL_HATCH_EGG_2) == CAST_OK) { - //instead, should run to other side and start hatch if eggs remain - m_creature->ForcedDespawn(); - return; + m_uiHatchlingTimer = m_uiHatchlingCount < 5 ? 10000 : 0; + m_uiEggsHatched = 0; + ++m_uiHatchlingCount; } - else if (m_uiHatchlingCount >= uiEggsRemaining/2) - m_uiHatchlingCount = uiEggsRemaining; - - DoCastSpellIfCan(m_creature,SPELL_HATCH_EGG); - - DoHatchEggs(m_uiHatchlingCount); - - ++m_uiHatchlingCount; - } else m_uiHatchlingTimer -= uiDiff; @@ -708,62 +483,38 @@ CreatureAI* GetAI_npc_amanishi_hatcherAI(Creature* pCreature) return new npc_amanishi_hatcherAI(pCreature); } -struct MANGOS_DLL_DECL npc_hatchlingAI : public ScriptedAI +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_dragonhawk_eggAI : public Scripted_NoMovementAI { - npc_hatchlingAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + npc_dragonhawk_eggAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} - ScriptedInstance* m_pInstance; - - uint32 m_uiBufferTimer; - bool m_bIsStarted; - - void Reset() - { - m_uiBufferTimer = 7000; - m_bIsStarted = false; - } + void Reset() override {} - void UpdateAI(const uint32 uiDiff) - { - if (!m_bIsStarted) - { - if (m_creature->GetPositionY() > 1150) - m_creature->GetMotionMaster()->MovePoint(0, hatcherway_l[3][0] + rand()%4-2, hatcherway_l[3][1] + rand()%4-2, hatcherway_l[3][2]); - else - m_creature->GetMotionMaster()->MovePoint(0, hatcherway_r[3][0] + rand()%4-2, hatcherway_r[3][1] + rand()%4-2, hatcherway_r[3][2]); - m_bIsStarted = true; - } - - if (m_pInstance && m_pInstance->GetData(TYPE_JANALAI) == FAIL) - { - m_creature->ForcedDespawn(); - return; - } + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} +}; - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; +CreatureAI* GetAI_npc_dragonhawk_eggAI(Creature* pCreature) +{ + return new npc_dragonhawk_eggAI(pCreature); +} - if (m_uiBufferTimer < uiDiff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, SPELL_FLAMEBUFFED); +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_janalai_firebombAI : public Scripted_NoMovementAI +{ + npc_janalai_firebombAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} - m_uiBufferTimer = 7000; - } - else - m_uiBufferTimer -= uiDiff; + void Reset() override {} - DoMeleeAttackIfReady(); - } + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} }; -CreatureAI* GetAI_npc_hatchlingAI(Creature* pCreature) +CreatureAI* GetAI_npc_janalai_firebombAI(Creature* pCreature) { - return new npc_hatchlingAI(pCreature); + return new npc_janalai_firebombAI(pCreature); } void AddSC_boss_janalai() @@ -775,6 +526,11 @@ void AddSC_boss_janalai() pNewScript->GetAI = &GetAI_boss_janalaiAI; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_dragonhawk_egg"; + pNewScript->GetAI = &GetAI_npc_dragonhawk_eggAI; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "npc_janalai_firebomb"; pNewScript->GetAI = &GetAI_npc_janalai_firebombAI; @@ -784,9 +540,4 @@ void AddSC_boss_janalai() pNewScript->Name = "npc_amanishi_hatcher"; pNewScript->GetAI = &GetAI_npc_amanishi_hatcherAI; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_hatchling"; - pNewScript->GetAI = &GetAI_npc_hatchlingAI; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp b/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp index 5bcd66a79..418e57892 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_malacrass.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Boss_Malacrass -SD%Complete: 70 +SD%Complete: 80 SDComment: Contain adds and adds selection; Stolen abilities timers need improvement SDCategory: Zul'Aman EndScriptData */ @@ -49,34 +49,34 @@ enum SPELL_SIPHON_SOUL = 43501, SPELL_DRAIN_POWER = 44131, - //for various powers he uses after using soul drain - //Death Knight + // for various powers he uses after using soul drain + // Death Knight SPELL_DK_DEATH_AND_DECAY = 61603, SPELL_DK_PLAGUE_STRIKE = 61600, SPELL_DK_MARK_OF_BLOOD = 61606, - //Druid + // Druid SPELL_DR_THORNS = 43420, SPELL_DR_LIFEBLOOM = 43421, SPELL_DR_MOONFIRE = 43545, - //Hunter + // Hunter SPELL_HU_EXPLOSIVE_TRAP = 43444, SPELL_HU_FREEZING_TRAP = 43447, SPELL_HU_SNAKE_TRAP = 43449, - //Mage + // Mage SPELL_MG_FIREBALL = 41383, SPELL_MG_FROST_NOVA = 43426, SPELL_MG_ICE_LANCE = 43427, SPELL_MG_FROSTBOLT = 43428, - //Paladin + // Paladin SPELL_PA_CONSECRATION = 43429, SPELL_PA_AVENGING_WRATH = 43430, SPELL_PA_HOLY_LIGHT = 43451, - //Priest + // Priest SPELL_PR_HEAL = 41372, SPELL_PR_MIND_BLAST = 41374, SPELL_PR_SW_DEATH = 41375, @@ -84,27 +84,27 @@ enum SPELL_PR_MIND_CONTROL = 43550, SPELL_PR_PAIN_SUPP = 44416, - //Rogue + // Rogue SPELL_RO_WOUND_POISON = 39665, SPELL_RO_BLIND = 43433, SPELL_RO_SLICE_DICE = 43547, - //Shaman + // Shaman SPELL_SH_CHAIN_LIGHT = 43435, SPELL_SH_FIRE_NOVA = 43436, SPELL_SH_HEALING_WAVE = 43548, - //Warlock + // Warlock SPELL_WL_CURSE_OF_DOOM = 43439, SPELL_WL_RAIN_OF_FIRE = 43440, SPELL_WL_UNSTABLE_AFFL = 35183, - //Warrior + // Warrior SPELL_WR_MORTAL_STRIKE = 43441, SPELL_WR_WHIRLWIND = 43442, SPELL_WR_SPELL_REFLECT = 43443, - //misc + // misc TARGET_TYPE_RANDOM = 0, TARGET_TYPE_VICTIM = 1, TARGET_TYPE_SELF = 2, @@ -113,25 +113,22 @@ enum MAX_ACTIVE_ADDS = 4 }; -//Adds X positions -static float m_afAddPosX[4] = {128.279f, 123.261f, 112.084f, 106.473f}; - -const float ADD_POS_Y = 921.279f; -const float ADD_POS_Z = 33.889f; -const float ADD_ORIENT = 1.527f; - -struct SpawnGroup +// Adds positions +static const float m_aAddPositions[MAX_ACTIVE_ADDS][4] = { - uint32 m_uiCreatureEntry; - uint32 m_uiCreatureEntryAlt; + {128.279f, 921.279f, 33.889f, 1.527f}, + {123.261f, 921.279f, 33.889f, 1.527f}, + {112.084f, 921.279f, 33.889f, 1.527f}, + {106.473f, 921.279f, 33.889f, 1.527f}, }; -SpawnGroup m_auiSpawnEntry[] = +// Each position is a random of two spawns +static const uint32 aSpawnEntries[MAX_ACTIVE_ADDS][2] = { - {24240, 24241}, //Alyson Antille / Thurg - {24242, 24243}, //Slither / Lord Raadan - {24244, 24245}, //Gazakroth / Fenstalker - {24246, 24247}, //Darkheart / Koragg + {NPC_ALYSON, NPC_THURG}, + {NPC_SLITHER, NPC_RADAAN}, + {NPC_GAZAKROTH, NPC_FENSTALKER}, + {NPC_DARKHEART, NPC_KORAGG}, }; struct PlayerAbilityStruct @@ -144,72 +141,83 @@ struct PlayerAbilityStruct // Classes are in the same order as they are in DBC static PlayerAbilityStruct m_aMalacrassStolenAbility[][4] = { - { // 0* shadow priest - exception: it seems that the priest has two specs. We use this slot for the shadow priest + { + // 0* shadow priest - exception: it seems that the priest has two specs. We use this slot for the shadow priest {SPELL_PR_MIND_CONTROL, TARGET_TYPE_RANDOM, 15000, 30000}, {SPELL_PR_MIND_BLAST, TARGET_TYPE_RANDOM, 23000, 30000}, {SPELL_PR_SW_DEATH, TARGET_TYPE_RANDOM, 5000, 16000} }, - { // 1 warrior + { + // 1 warrior {SPELL_WR_SPELL_REFLECT, TARGET_TYPE_SELF, 2000, 30000}, {SPELL_WR_WHIRLWIND, TARGET_TYPE_SELF, 10000, 30000}, {SPELL_WR_MORTAL_STRIKE, TARGET_TYPE_VICTIM, 6000, 15000} }, - { // 2 paladin + { + // 2 paladin {SPELL_PA_CONSECRATION, TARGET_TYPE_SELF, 10000, 30000}, {SPELL_PA_HOLY_LIGHT, TARGET_TYPE_FRIENDLY, 17000, 30000}, {SPELL_PA_AVENGING_WRATH, TARGET_TYPE_SELF, 0, 30000} }, - { // 3 hunter + { + // 3 hunter {SPELL_HU_EXPLOSIVE_TRAP, TARGET_TYPE_SELF, 12000, 30000}, {SPELL_HU_FREEZING_TRAP, TARGET_TYPE_SELF, 3000, 30000}, {SPELL_HU_SNAKE_TRAP, TARGET_TYPE_SELF, 21000, 30000} }, - { // 4 rogue + { + // 4 rogue {SPELL_RO_WOUND_POISON, TARGET_TYPE_VICTIM, 3000, 17000}, {SPELL_RO_SLICE_DICE, TARGET_TYPE_SELF, 17000, 30000}, {SPELL_RO_BLIND, TARGET_TYPE_RANDOM, 12000, 30000} }, - { // 5 priest + { + // 5 priest {SPELL_PR_PAIN_SUPP, TARGET_TYPE_FRIENDLY, 24000, 30000}, {SPELL_PR_HEAL, TARGET_TYPE_FRIENDLY, 16000, 30000}, {SPELL_PR_PSYCHIC_SCREAM, TARGET_TYPE_RANDOM, 8000, 30000} }, - { // 6 death knight + { + // 6 death knight {SPELL_DK_DEATH_AND_DECAY, TARGET_TYPE_RANDOM, 25000, 30000}, {SPELL_DK_PLAGUE_STRIKE, TARGET_TYPE_VICTIM, 5000, 17000}, {SPELL_DK_MARK_OF_BLOOD, TARGET_TYPE_RANDOM, 14000, 30000} }, - { // 7 shaman + { + // 7 shaman {SPELL_SH_FIRE_NOVA, TARGET_TYPE_SELF, 25000, 30000}, {SPELL_SH_HEALING_WAVE, TARGET_TYPE_FRIENDLY, 15000, 30000}, {SPELL_SH_CHAIN_LIGHT, TARGET_TYPE_RANDOM, 4000, 16000} }, - { // 8 mage + { + // 8 mage {SPELL_MG_FIREBALL, TARGET_TYPE_RANDOM, 8000, 30000}, {SPELL_MG_FROSTBOLT, TARGET_TYPE_RANDOM, 25000, 30000}, {SPELL_MG_ICE_LANCE, TARGET_TYPE_RANDOM, 2000, 18000}, {SPELL_MG_FROST_NOVA, TARGET_TYPE_SELF, 17000, 30000} }, - { // 9 warlock + { + // 9 warlock {SPELL_WL_CURSE_OF_DOOM, TARGET_TYPE_RANDOM, 0, 30000}, {SPELL_WL_RAIN_OF_FIRE, TARGET_TYPE_RANDOM, 16000, 30000}, {SPELL_WL_UNSTABLE_AFFL, TARGET_TYPE_RANDOM, 8000, 13000} }, - { // 10 unused - no class in DBC here + { + // 10 unused - no class in DBC here }, - { // 11 druid + { + // 11 druid {SPELL_DR_LIFEBLOOM, TARGET_TYPE_FRIENDLY, 15000, 30000}, {SPELL_DR_THORNS, TARGET_TYPE_SELF, 0, 30000}, {SPELL_DR_MOONFIRE, TARGET_TYPE_RANDOM, 8000, 13000} } }; -struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI +struct boss_malacrassAI : public ScriptedAI { boss_malacrassAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_lAddsEntryList.clear(); Reset(); } @@ -223,11 +231,10 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI bool m_bCanUsePlayerSpell; + std::vector m_vAddsEntryList; std::vector m_vPlayerSpellTimer; - std::list m_lAddsEntryList; - ObjectGuid m_aAddGuid[MAX_ACTIVE_ADDS]; - void Reset() + void Reset() override { m_uiSpiritBoltsTimer = 30000; m_uiDrainPowerTimer = 0; @@ -237,86 +244,59 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI m_bCanUsePlayerSpell = false; - InitializeAdds(); + DoInitializeAdds(); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_MALACRASS, FAIL); - - for(uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) - { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aAddGuid[i])) - pAdd->AI()->EnterEvadeMode(); - } } - void InitializeAdds() + void DoInitializeAdds() { - //not if m_creature are dead, so avoid + // not if m_creature are dead, so avoid if (!m_creature->isAlive()) return; - uint8 j = 0; - - //it's empty, so first time - if (m_lAddsEntryList.empty()) + // it's empty, so first time + if (m_vAddsEntryList.empty()) { - //fill list with entries from creature array - for(uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) - m_lAddsEntryList.push_back(rand()%2 ? m_auiSpawnEntry[i].m_uiCreatureEntry : m_auiSpawnEntry[i].m_uiCreatureEntryAlt); + m_vAddsEntryList.resize(MAX_ACTIVE_ADDS); - //summon mobs from the list - for(std::list::iterator itr = m_lAddsEntryList.begin(); itr != m_lAddsEntryList.end(); ++itr) + for (uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) { - if (Creature* pAdd = m_creature->SummonCreature((*itr), m_afAddPosX[j], ADD_POS_Y, ADD_POS_Z, ADD_ORIENT, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_aAddGuid[j] = pAdd->GetObjectGuid(); - - ++j; + uint8 uiAddVersion = urand(0, 1); + m_vAddsEntryList[i] = aSpawnEntries[i][uiAddVersion]; + m_creature->SummonCreature(aSpawnEntries[i][uiAddVersion], m_aAddPositions[i][0], m_aAddPositions[i][1], m_aAddPositions[i][2], m_aAddPositions[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); } } + // Resummon the killed adds else { - for(std::list::iterator itr = m_lAddsEntryList.begin(); itr != m_lAddsEntryList.end(); ++itr) + if (!m_pInstance) + return; + + for (uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) { - Creature* pAdd = m_creature->GetMap()->GetCreature(m_aAddGuid[j]); + // If we already have the creature on the map, then don't summon it + if (m_pInstance->GetSingleCreatureFromStorage(m_vAddsEntryList[i], true)) + continue; - //object already removed, not exist - if (!pAdd) - { - if (pAdd = m_creature->SummonCreature((*itr), m_afAddPosX[j], ADD_POS_Y, ADD_POS_Z, ADD_ORIENT, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_aAddGuid[j] = pAdd->GetObjectGuid(); - } - ++j; + m_creature->SummonCreature(m_vAddsEntryList[i], m_aAddPositions[i][0], m_aAddPositions[i][1], m_aAddPositions[i][2], m_aAddPositions[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); } } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - AddsAttack(pWho); - - if (!m_pInstance) - return; - m_pInstance->SetData(TYPE_MALACRASS, IN_PROGRESS); - } - - void AddsAttack(Unit* pWho) - { - for(uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) - { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aAddGuid[i])) - { - if (!pAdd->getVictim()) - pAdd->AI()->AttackStart(pWho); - } - } + if (m_pInstance) + m_pInstance->SetData(TYPE_MALACRASS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -324,18 +304,25 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - CleanAdds(); - if (!m_pInstance) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_MALACRASS, DONE); + } - m_pInstance->SetData(TYPE_MALACRASS, DONE); + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_ADD_DIED1, m_creature); break; + case 1: DoScriptText(SAY_ADD_DIED2, m_creature); break; + case 2: DoScriptText(SAY_ADD_DIED3, m_creature); break; + } } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { // Set the player's class when hit with soul siphon if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_SIPHON_SOUL) @@ -357,28 +344,11 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI } } - void CleanAdds() - { - for(uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) - { - if (Creature* pAdd = m_creature->GetMap()->GetCreature(m_aAddGuid[i])) - { - pAdd->AI()->EnterEvadeMode(); - pAdd->SetDeathState(JUST_DIED); - } - } - - for (uint8 i = 0; i < MAX_ACTIVE_ADDS; ++i) - m_aAddGuid[i].Clear(); - - m_lAddsEntryList.clear(); - } - bool CanUseSpecialAbility(uint32 uiSpellIndex) { Unit* pTarget = NULL; - switch(m_aMalacrassStolenAbility[m_uiPlayerClass][uiSpellIndex].m_uiTargetType) + switch (m_aMalacrassStolenAbility[m_uiPlayerClass][uiSpellIndex].m_uiTargetType) { case TARGET_TYPE_SELF: pTarget = m_creature; @@ -403,7 +373,7 @@ struct MANGOS_DLL_DECL boss_malacrassAI : public ScriptedAI return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -471,517 +441,6 @@ CreatureAI* GetAI_boss_malacrass(Creature* pCreature) return new boss_malacrassAI(pCreature); } -//common AI for adds -struct MANGOS_DLL_DECL boss_malacrass_addAI : public ScriptedAI -{ - boss_malacrass_addAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - void Reset() { } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void MoveInLineOfSight(Unit* pWho) - { - } - - void KilledUnit(Unit* pVictim) - { - if (!m_pInstance) - return; - - if (Creature* pMalacrass = m_pInstance->GetSingleCreatureFromStorage(NPC_MALACRASS)) - pMalacrass->AI()->KilledUnit(pVictim); - } - - void JustDied(Unit* pKiller) - { - if (!m_pInstance) - return; - - if (Creature* pMalacrass = m_pInstance->GetSingleCreatureFromStorage(NPC_MALACRASS)) - { - switch(urand(0, 2)) - { - case 0: DoScriptText(SAY_ADD_DIED1, pMalacrass); break; - case 1: DoScriptText(SAY_ADD_DIED2, pMalacrass); break; - case 2: DoScriptText(SAY_ADD_DIED3, pMalacrass); break; - } - } - } -}; - -enum -{ - SPELL_BLOODLUST = 43578, - SPELL_CLEAVE = 15496 -}; - -struct MANGOS_DLL_DECL mob_thurgAI : public boss_malacrass_addAI -{ - mob_thurgAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiBloodlustTimer; - uint32 m_uiCleaveTimer; - - void Reset() - { - m_uiBloodlustTimer = 15000; - m_uiCleaveTimer = 10000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiBloodlustTimer < uiDiff) - { - std::list lTempList = DoFindFriendlyMissingBuff(50.0f, SPELL_BLOODLUST); - - if (!lTempList.empty()) - { - Unit* pTarget = *(lTempList.begin()); - DoCastSpellIfCan(pTarget, SPELL_BLOODLUST); - } - - m_uiBloodlustTimer = 12000; - } - else - m_uiBloodlustTimer -= uiDiff; - - if (m_uiCleaveTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = 12000; - } - else - m_uiCleaveTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_thurg(Creature* pCreature) -{ - return new mob_thurgAI(pCreature); -} - -enum -{ - SPELL_ARCANE_TORRENT = 33390, - SPELL_FLASH_HEAL = 43575, - SPELL_DISPEL_MAGIC = 43577 -}; - -const float RANGE_FRIENDLY_TARGET = 40.0; - -struct MANGOS_DLL_DECL mob_alyson_antilleAI : public boss_malacrass_addAI -{ - mob_alyson_antilleAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiArcaneTorrentTimer; - uint32 m_uiFlashHealTimer; - uint32 m_uiDispelMagicTimer; - - void Reset() - { - m_uiArcaneTorrentTimer = 0; - m_uiFlashHealTimer = 2500; - m_uiDispelMagicTimer = 10000; - } - - void AttackStart(Unit* pWho) - { - if (!pWho) - return; - - if (m_creature->Attack(pWho, false)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); - - m_creature->GetMotionMaster()->MoveChase(pWho, 20.0f); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiArcaneTorrentTimer < uiDiff) - { - if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER | SELECT_FLAG_IN_MELEE_RANGE)) - { - DoCastSpellIfCan(m_creature, SPELL_ARCANE_TORRENT); - m_uiArcaneTorrentTimer = 60000; - } - else - m_uiArcaneTorrentTimer = 1000; - } - else - m_uiArcaneTorrentTimer -= uiDiff; - - if (m_uiFlashHealTimer < uiDiff) - { - //this will fail if we previously was following target and pTarget is now different than before - if (Unit* pTarget = DoSelectLowestHpFriendly(RANGE_FRIENDLY_TARGET*2, 30000)) - { - if (pTarget->IsWithinDistInMap(m_creature, RANGE_FRIENDLY_TARGET)) - { - DoCastSpellIfCan(pTarget, SPELL_FLASH_HEAL); - - //if not already chasing, start chase - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), 20.0f); - } - else - { - //if chasing, start follow target instead - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - { - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MoveFollow(pTarget, 20.0f, 0.0f); - } - } - } - - m_uiFlashHealTimer = 2500; - } - else - m_uiFlashHealTimer -= uiDiff; - - if (m_uiDispelMagicTimer < uiDiff) - { - Unit* pTarget = NULL; - std::list lTempList = DoFindFriendlyCC(RANGE_FRIENDLY_TARGET); - - if (!lTempList.empty()) - pTarget = *(lTempList.begin()); - else - pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (pTarget) - DoCastSpellIfCan(pTarget, SPELL_DISPEL_MAGIC); - - m_uiDispelMagicTimer = 12000; - } - else - m_uiDispelMagicTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_alyson_antille(Creature* pCreature) -{ - return new mob_alyson_antilleAI(pCreature); -} - -enum -{ - SPELL_FIREBOLT = 43584 -}; - -struct MANGOS_DLL_DECL mob_gazakrothAI : public boss_malacrass_addAI -{ - mob_gazakrothAI(Creature* pCreature) : boss_malacrass_addAI(pCreature){ Reset(); } - - uint32 m_uiFireboltTimer; - - void Reset() - { - m_uiFireboltTimer = 1000; - } - - void AttackStart(Unit* pWho) - { - if (!pWho) - return; - - if (m_creature->Attack(pWho, false)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); - - m_creature->GetMotionMaster()->MoveChase(pWho, 20.0f); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiFireboltTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBOLT); - m_uiFireboltTimer = 1000; - } - else - m_uiFireboltTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_gazakroth(Creature* pCreature) -{ - return new mob_gazakrothAI(pCreature); -} - -enum -{ - SPELL_FLAME_BREATH = 43582, - SPELL_THUNDERCLAP = 43583 -}; - -struct MANGOS_DLL_DECL mob_lord_raadanAI : public boss_malacrass_addAI -{ - mob_lord_raadanAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiFlameBreathTimer; - uint32 m_uiThunderclapTimer; - - void Reset() - { - m_uiFlameBreathTimer = 8000; - m_uiThunderclapTimer = 13000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiThunderclapTimer < uiDiff) - { - if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, SPELL_THUNDERCLAP, SELECT_FLAG_PLAYER)) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_THUNDERCLAP); - m_uiThunderclapTimer = 12000; - } - else - m_uiThunderclapTimer = 1000; - } - else - m_uiThunderclapTimer -= uiDiff; - - if (m_uiFlameBreathTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BREATH); - m_uiFlameBreathTimer = 12000; - } - else - m_uiFlameBreathTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_lord_raadan(Creature* pCreature) -{ - return new mob_lord_raadanAI(pCreature); -} - -enum -{ - SPELL_PSYCHIC_WAIL = 43590 -}; - -struct MANGOS_DLL_DECL mob_darkheartAI : public boss_malacrass_addAI -{ - mob_darkheartAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiPsychicWailTimer; - - void Reset() - { - m_uiPsychicWailTimer = 8000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiPsychicWailTimer < uiDiff) - { - if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, uint32(0), SELECT_FLAG_PLAYER | SELECT_FLAG_IN_MELEE_RANGE)) - { - DoCastSpellIfCan(m_creature, SPELL_PSYCHIC_WAIL); - m_uiPsychicWailTimer = 12000; - } - else - m_uiPsychicWailTimer = 1000; - } - else - m_uiPsychicWailTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_darkheart(Creature* pCreature) -{ - return new mob_darkheartAI(pCreature); -} - -enum -{ - SPELL_VENOM_SPIT = 43579 -}; - -struct MANGOS_DLL_DECL mob_slitherAI : public boss_malacrass_addAI -{ - mob_slitherAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiVenomSpitTimer; - - void Reset() - { - m_uiVenomSpitTimer = 4000; - } - - void AttackStart(Unit* pWho) - { - if (!pWho) - return; - - if (m_creature->Attack(pWho, false)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); - - m_creature->GetMotionMaster()->MoveChase(pWho, 20.0f); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiVenomSpitTimer < uiDiff) - { - if (Unit* pVictim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pVictim, SPELL_VENOM_SPIT); - - m_uiVenomSpitTimer = 2500; - } - else - m_uiVenomSpitTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_slither(Creature* pCreature) -{ - return new mob_slitherAI(pCreature); -} - -enum -{ - SPELL_VOLATILE_INFECTION = 43586 -}; - -struct MANGOS_DLL_DECL mob_fenstalkerAI : public boss_malacrass_addAI -{ - mob_fenstalkerAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiVolatileInfectionTimer; - - void Reset() - { - m_uiVolatileInfectionTimer = 15000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiVolatileInfectionTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_VOLATILE_INFECTION); - m_uiVolatileInfectionTimer = 12000; - } - else - m_uiVolatileInfectionTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_fenstalker(Creature* pCreature) -{ - return new mob_fenstalkerAI(pCreature); -} - -enum -{ - SPELL_COLD_STARE = 43593, - SPELL_MIGHTY_BLOW = 43592, -}; - -struct MANGOS_DLL_DECL mob_koraggAI : public boss_malacrass_addAI -{ - mob_koraggAI(Creature* pCreature) : boss_malacrass_addAI(pCreature) { Reset(); } - - uint32 m_uiColdStareTimer; - uint32 m_uiMightyBlowTimer; - - void Reset() - { - m_uiColdStareTimer = 15000; - m_uiMightyBlowTimer = 10000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiMightyBlowTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTY_BLOW); - m_uiMightyBlowTimer = 12000; - } - else - m_uiMightyBlowTimer -= uiDiff; - - if (m_uiColdStareTimer < uiDiff) - { - if (Unit* pVictim = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pVictim, SPELL_COLD_STARE); - - m_uiColdStareTimer = 12000; - } - else - m_uiColdStareTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_koragg(Creature* pCreature) -{ - return new mob_koraggAI(pCreature); -} - void AddSC_boss_malacrass() { Script* pNewScript; @@ -990,44 +449,4 @@ void AddSC_boss_malacrass() pNewScript->Name = "boss_malacrass"; pNewScript->GetAI = &GetAI_boss_malacrass; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_thurg"; - pNewScript->GetAI = &GetAI_mob_thurg; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_gazakroth"; - pNewScript->GetAI = &GetAI_mob_gazakroth; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_lord_raadan"; - pNewScript->GetAI = &GetAI_mob_lord_raadan; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_darkheart"; - pNewScript->GetAI = &GetAI_mob_darkheart; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_slither"; - pNewScript->GetAI = &GetAI_mob_slither; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_fenstalker"; - pNewScript->GetAI = &GetAI_mob_fenstalker; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_koragg"; - pNewScript->GetAI = &GetAI_mob_koragg; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_alyson_antille"; - pNewScript->GetAI = &GetAI_mob_alyson_antille; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp b/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp index 07925ef87..8074cb4e6 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_nalorakk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Nalorakk -SD%Complete: 80 -SDComment: Todo: Trash Waves +SD%Complete: 95 +SDComment: Small adjustments may be required SDCategory: Zul'Aman EndScriptData */ @@ -26,11 +26,6 @@ EndScriptData */ enum { - SAY_WAVE1_AGGRO = -1568010, - SAY_WAVE2_STAIR1 = -1568011, - SAY_WAVE3_STAIR2 = -1568012, - SAY_WAVE4_PLATFORM = -1568013, - SAY_EVENT1_SACRIFICE = -1568014, SAY_EVENT2_SACRIFICE = -1568015, @@ -43,7 +38,7 @@ enum SAY_SLAY2 = -1568022, SAY_DEATH = -1568023, - SPELL_BERSERK = 45078, //unsure, this increases damage, size and speed + SPELL_BERSERK = 45078, // unsure, this increases damage, size and speed // Defines for Troll form SPELL_BRUTAL_SWIPE = 42384, @@ -57,15 +52,16 @@ enum SPELL_DEAFENING_ROAR = 42398 }; -struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI +struct boss_nalorakkAI : public ScriptedAI { boss_nalorakkAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_zulaman*)pCreature->GetInstanceData(); + m_uiCurrentWave = 0; Reset(); } - ScriptedInstance* m_pInstance; + instance_zulaman* m_pInstance; uint32 m_uiChangeFormTimer; uint32 m_uiBrutalSwipeTimer; @@ -75,9 +71,10 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI uint32 m_uiRendFleshTimer; uint32 m_uiDeafeningRoarTimer; uint32 m_uiBerserkTimer; + uint8 m_uiCurrentWave; bool m_bIsInBearForm; - void Reset() + void Reset() override { m_uiChangeFormTimer = 45000; m_uiBrutalSwipeTimer = 12000; @@ -86,11 +83,67 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI m_uiLaceratingSlashTimer = 6000; m_uiRendFleshTimer = 6000; m_uiDeafeningRoarTimer = 20000; - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; m_bIsInBearForm = false; } - void Aggro(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override + { + ScriptedAI::MoveInLineOfSight(pWho); + + if (m_pInstance && m_pInstance->IsBearPhaseInProgress()) + return; + + if (pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, aBearEventInfo[m_uiCurrentWave].fAggroDist)) + { + DoScriptText(aBearEventInfo[m_uiCurrentWave].iYellId, m_creature); + if (m_pInstance) + m_pInstance->SendNextBearWave(pWho); + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE) + return; + + if (uiPointId) + { + m_creature->SetFacingTo(aBearEventInfo[m_uiCurrentWave].fO); + + if (m_uiCurrentWave < MAX_BEAR_WAVES - 1) + { + if (m_pInstance) + m_pInstance->SetBearEventProgress(false); + ++m_uiCurrentWave; + } + else + { + // Set the instance data to fail on movement inform because we are not moving the boss to home position + if (m_pInstance) + m_pInstance->SetData(TYPE_NALORAKK, FAIL); + } + } + } + + // Nalorakk evades only after the trash waves are finished + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + // Boss should evade on the top of the platform + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(1, aBearEventInfo[m_uiCurrentWave].fX, aBearEventInfo[m_uiCurrentWave].fY, aBearEventInfo[m_uiCurrentWave].fZ); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -98,12 +151,12 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI m_pInstance->SetData(TYPE_NALORAKK, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -113,13 +166,7 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI m_pInstance->SetData(TYPE_NALORAKK, DONE); } - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_NALORAKK, FAIL); - } - - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -140,7 +187,7 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI m_uiBerserkTimer -= uiDiff; } - //Spells for Troll Form (only to be casted if we NOT have bear phase aura) + // Spells for Troll Form (only to be casted if we NOT have bear phase aura) if (!m_bIsInBearForm) { // Brutal Swipe (some sources may say otherwise, but I've never seen this in Bear form) @@ -164,10 +211,10 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI // Surge if (m_uiSurgeTimer < uiDiff) { - //select a random unit other than the main tank + // select a random unit other than the main tank Unit* pTtarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - //if there aren't other units, cast on the tank + // if there aren't other units, cast on the tank if (!pTtarget) pTtarget = m_creature->getVictim(); @@ -197,7 +244,7 @@ struct MANGOS_DLL_DECL boss_nalorakkAI : public ScriptedAI else m_uiChangeFormTimer -= uiDiff; } - //Spells for Bear Form (only to be casted if we have bear phase aura) + // Spells for Bear Form (only to be casted if we have bear phase aura) else { // Timer to yell and reset spell timers when bear aura expires diff --git a/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp b/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp index bd71104d4..be3bc396f 100644 --- a/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp +++ b/scripts/eastern_kingdoms/zulaman/boss_zuljin.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Zuljin -SD%Complete: 70 -SDComment: Timers. Lynx phase abilities NYI +SD%Complete: 90 +SDComment: Timers should be improved. SDCategory: Zul'Aman EndScriptData */ @@ -45,30 +45,32 @@ enum // Troll Form SPELL_WHIRLWIND = 17207, - SPELL_GRIEVOUS_THROW = 43093, //removes debuff after full healed + SPELL_GRIEVOUS_THROW = 43093, // removes debuff after full healed // Bear Form - SPELL_CREEPING_PARALYSIS = 43095, //should cast on the whole raid - SPELL_OVERPOWER = 43456, //use after melee attack dodged + SPELL_CREEPING_PARALYSIS = 43095, // should cast on the whole raid + SPELL_OVERPOWER = 43456, // use after melee attack dodged // Eagle Form - SPELL_ENERGY_STORM = 43983, //enemy area aura, trigger 42577 on vortexes which cast 43137 on targets - SPELL_SUMMON_CYCLONE = 43112, //summon four feather vortex - NPC_FEATHER_VORTEX = 24136, //ToDo: script via ACID - SPELL_CYCLONE_VISUAL = 43119, //trigger 43147 visual - SPELL_CYCLONE_PASSIVE = 43120, //trigger 43121 (4y aoe) every second + SPELL_ENERGY_STORM = 43983, // enemy area aura, trigger 42577 on vortexes which cast 43137 on targets + SPELL_SUMMON_CYCLONE = 43112, // summon four feather vortex + NPC_FEATHER_VORTEX = 24136, // ToDo: script via ACID + SPELL_CYCLONE_VISUAL = 43119, // trigger 43147 visual + SPELL_CYCLONE_PASSIVE = 43120, // trigger 43121 (4y aoe) every second + SPELL_CYCLONE = 43121, // Lynx Form - SPELL_CLAW_RAGE_HASTE = 42583, // Charges a random target and applies dummy effect 43149 on it + SPELL_CLAW_RAGE = 42583, // Charges a random target and applies dummy effect 43149 on it SPELL_CLAW_RAGE_TRIGGER = 43149, - SPELL_LYNX_RUSH_HASTE = 43152, // Charges 9 targets in a row - Dummy effect should apply 43153 + SPELL_LYNX_RUSH = 43152, // Charges 9 targets in a row - Dummy effect should apply 43153 + SPELL_LYNX_RUSH_CHARGE = 43153, // Dragonhawk Form - SPELL_FLAME_WHIRL = 43213, //trigger two spells + SPELL_FLAME_WHIRL = 43213, // trigger two spells SPELL_FLAME_BREATH = 43215, - SPELL_SUMMON_PILLAR = 43216, //summon 24187 + SPELL_SUMMON_PILLAR = 43216, // summon 24187 NPC_COLUMN_OF_FIRE = 24187, - SPELL_PILLAR_TRIGGER = 43218, //trigger 43217 + SPELL_PILLAR_TRIGGER = 43218, // trigger 43217 // Cosmetic SPELL_SPIRIT_DRAINED = 42520, @@ -83,6 +85,7 @@ enum SPELL_BERSERK = 45078, // Berserk timer or existance is unk MAX_VORTEXES = 4, + MAX_LYNX_RUSH = 10, POINT_ID_CENTER = 0, PHASE_BEAR = 0, @@ -108,10 +111,14 @@ static const BossPhase aZuljinPhases[] = {SPELL_SHAPE_OF_THE_DRAGONHAWK, SAY_DRAGONHAWK_TRANSFORM, EMOTE_DRAGONHAWK_SPIRIT, NPC_DRAGONHAWK_SPIRIT, PHASE_DRAGONHAWK} }; -//coords for going for changing form +// coords for going for changing form static const float fZuljinMoveLoc[3] = {120.148811f, 703.713684f, 45.111477f}; -struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI +/*###### +## boss_zuljin +######*/ + +struct boss_zuljinAI : public ScriptedAI { boss_zuljinAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -133,6 +140,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI uint32 m_uiClawRageTimer; uint32 m_uiLynxRushTimer; + uint8 m_uiLynxRushCount; uint32 m_uiFlameWhirlTimer; uint32 m_uiFlameBreathTimer; @@ -142,9 +150,9 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI bool m_bIsInTransition; uint32 m_uiTransformTimer; - GUIDList m_lSummonsList; + GuidList m_lSummonsList; - void Reset() + void Reset() override { m_uiHealthCheck = 80; m_uiPhase = PHASE_TROLL; @@ -156,7 +164,8 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI m_uiOverpowerTimer = 5000; m_uiClawRageTimer = 5000; - m_uiLynxRushTimer = 14000; + m_uiLynxRushTimer = 15000; + m_uiLynxRushCount = 0; m_uiFlameWhirlTimer = 7000; m_uiFlameBreathTimer = 15000; @@ -167,7 +176,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI SetCombatMovement(true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -175,7 +184,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI m_pInstance->SetData(TYPE_ZULJIN, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ZULJIN, FAIL); @@ -194,12 +203,12 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -209,9 +218,9 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI m_pInstance->SetData(TYPE_ZULJIN, DONE); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 60.0f)) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 60.0f)) { DoScriptText(SAY_INTRO, m_creature); m_bHasTaunted = true; @@ -220,25 +229,28 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } + // Function to handle the Feather Vortexes despawn on phase change void DoDespawnVortexes() { - for (GUIDList::const_iterator itr = m_lSummonsList.begin(); itr != m_lSummonsList.end(); ++itr) + for (GuidList::const_iterator itr = m_lSummonsList.begin(); itr != m_lSummonsList.end(); ++itr) { if (Creature* pVortex = m_creature->GetMap()->GetCreature(*itr)) pVortex->ForcedDespawn(); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_FEATHER_VORTEX: pSummoned->CastSpell(pSummoned, SPELL_CYCLONE_VISUAL, true); pSummoned->CastSpell(pSummoned, SPELL_CYCLONE_PASSIVE, true); m_lSummonsList.push_back(pSummoned->GetObjectGuid()); - if (m_creature->getVictim()) - pSummoned->AI()->AttackStart(m_creature->getVictim()); + + // Attack random target + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0, 0); break; case NPC_COLUMN_OF_FIRE: pSummoned->CastSpell(pSummoned, SPELL_PILLAR_TRIGGER, true); @@ -246,7 +258,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI } } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_ID_CENTER) return; @@ -262,11 +274,11 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI pSpirit->CastSpell(m_creature, SPELL_SPIRIT_DRAIN, false); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_SPIRIT_DRAIN) { - DoCastSpellIfCan(m_creature, aZuljinPhases[m_uiPhase].uiSpiritSpellId); + DoCastSpellIfCan(m_creature, aZuljinPhases[m_uiPhase].uiSpiritSpellId, CAST_INTERRUPT_PREVIOUS); DoScriptText(aZuljinPhases[m_uiPhase].iYellId, m_creature); DoScriptText(aZuljinPhases[m_uiPhase].iEmoteId, m_creature); @@ -286,15 +298,23 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_ENERGY_STORM, CAST_TRIGGERED); // summon 4 vortexes - for (uint8 i = 0; i < MAX_VORTEXES; ++i) - DoCastSpellIfCan(m_creature, SPELL_SUMMON_CYCLONE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_CYCLONE, CAST_TRIGGERED); } m_bIsInTransition = false; } } - void UpdateAI(const uint32 uiDiff) + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pSpellEntry->Id == SPELL_CLAW_RAGE && pTarget->GetTypeId() == TYPEID_PLAYER) + { + DoCastSpellIfCan(m_creature, SPELL_CLAW_RAGE_TRIGGER, CAST_TRIGGERED); + m_uiLynxRushTimer += 8000; + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || m_bIsInTransition) return; @@ -337,7 +357,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI { case PHASE_TROLL: - if(m_uiWhirlwindTimer < uiDiff) + if (m_uiWhirlwindTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) m_uiWhirlwindTimer = urand(15000, 20000); @@ -345,9 +365,9 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI else m_uiWhirlwindTimer -= uiDiff; - if(m_uiGrievousThrowTimer < uiDiff) + if (m_uiGrievousThrowTimer < uiDiff) { - if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if (DoCastSpellIfCan(pTarget, SPELL_GRIEVOUS_THROW) == CAST_OK) m_uiGrievousThrowTimer = 10000; @@ -359,7 +379,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI break; case PHASE_BEAR: - if(m_uiParalysisTimer < uiDiff) + if (m_uiParalysisTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_CREEPING_PARALYSIS) == CAST_OK) m_uiParalysisTimer = 27000; @@ -367,7 +387,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI else m_uiParalysisTimer -= uiDiff; - if(m_uiOverpowerTimer < uiDiff) + if (m_uiOverpowerTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_OVERPOWER) == CAST_OK) m_uiOverpowerTimer = urand(12000, 16000); @@ -380,13 +400,49 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI // Nothing here; Spells casted just once at the beginning of the phase; break; case PHASE_LYNX: - // ToDo: Note for further development of this phase! - // In this phase the boss used two melee spells: SPELL_CLAW_RAGE_HASTE and SPELL_LYNX_RUSH_HASTE - // However the way these spells are used and what are their mechanics and timers is highly unknown + + // Don't apply Claw Rage during Lynx Rush + if (!m_uiLynxRushCount) + { + if (m_uiClawRageTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_CLAW_RAGE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CLAW_RAGE) == CAST_OK) + m_uiClawRageTimer = urand(15000, 20000); + } + } + else + m_uiClawRageTimer -= uiDiff; + } + + if (m_uiLynxRushTimer < uiDiff) + { + if (!m_uiLynxRushCount) + DoCastSpellIfCan(m_creature, SPELL_LYNX_RUSH); + else + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_LYNX_RUSH_CHARGE); + } + + ++m_uiLynxRushCount; + + if (m_uiLynxRushCount == MAX_LYNX_RUSH) + { + m_uiLynxRushTimer = urand(20000, 25000); + m_uiLynxRushCount = 0; + } + else + m_uiLynxRushTimer = 400; + } + else + m_uiLynxRushTimer -= uiDiff; + break; case PHASE_DRAGONHAWK: - if(m_uiFlameWhirlTimer < uiDiff) + if (m_uiFlameWhirlTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_FLAME_WHIRL) == CAST_OK) m_uiFlameWhirlTimer = 15000; @@ -394,7 +450,7 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI else m_uiFlameWhirlTimer -= uiDiff; - if(m_uiPillarOfFireTimer < uiDiff) + if (m_uiPillarOfFireTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_PILLAR) == CAST_OK) m_uiPillarOfFireTimer = urand(17000, 22000); @@ -402,13 +458,10 @@ struct MANGOS_DLL_DECL boss_zuljinAI : public ScriptedAI else m_uiPillarOfFireTimer -= uiDiff; - if(m_uiFlameBreathTimer < uiDiff) + if (m_uiFlameBreathTimer < uiDiff) { - if(Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BREATH) == CAST_OK) - m_uiFlameBreathTimer = 15000; - } + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BREATH) == CAST_OK) + m_uiFlameBreathTimer = 15000; } else m_uiFlameBreathTimer -= uiDiff; @@ -425,6 +478,45 @@ CreatureAI* GetAI_boss_zuljin(Creature* pCreature) return new boss_zuljinAI(pCreature); } +/*###### +## npc_feather_vortex +######*/ + +struct npc_feather_vortexAI : public ScriptedAI +{ + npc_feather_vortexAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() override { } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pSpellEntry->Id == SPELL_CYCLONE && pTarget->GetTypeId() == TYPEID_PLAYER && m_pInstance) + { + if (Creature* pZuljin = m_pInstance->GetSingleCreatureFromStorage(NPC_ZULJIN)) + { + // Change target on player hit + if (Unit* pTarget = pZuljin->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->GetMotionMaster()->MoveFollow(pTarget, 0, 0); + } + } + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_feather_vortex(Creature* pCreature) +{ + return new npc_feather_vortexAI(pCreature); +} + void AddSC_boss_zuljin() { Script* pNewScript; @@ -433,4 +525,9 @@ void AddSC_boss_zuljin() pNewScript->Name = "boss_zuljin"; pNewScript->GetAI = &GetAI_boss_zuljin; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_feather_vortex"; + pNewScript->GetAI = &GetAI_npc_feather_vortex; + pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp b/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp index 06c5203fc..dcabcbfa0 100644 --- a/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp +++ b/scripts/eastern_kingdoms/zulaman/instance_zulaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,11 +25,10 @@ EndScriptData */ #include "zulaman.h" instance_zulaman::instance_zulaman(Map* pMap) : ScriptedInstance(pMap), - m_uiEventTimer(MINUTE*IN_MILLISECONDS), + m_uiEventTimer(MINUTE* IN_MILLISECONDS), m_uiGongCount(0), - - m_uiEggsRemainingCount_Left(20), - m_uiEggsRemainingCount_Right(20) + m_uiBearEventPhase(0), + m_bIsBearPhaseInProgress(false) { Initialize(); } @@ -52,19 +51,39 @@ bool instance_zulaman::IsEncounterInProgress() const return false; } +void instance_zulaman::OnPlayerEnter(Player* /*pPlayer*/) +{ + if (GetData(TYPE_EVENT_RUN) == IN_PROGRESS) + { + DoUpdateWorldState(WORLD_STATE_ID, 1); + DoUpdateWorldState(WORLD_STATE_COUNTER, GetData(TYPE_RUN_EVENT_TIME)); + } +} + void instance_zulaman::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_AKILZON: case NPC_HALAZZI: + case NPC_NALORAKK: + case NPC_JANALAI: case NPC_MALACRASS: + case NPC_ZULJIN: case NPC_HARRISON: - case NPC_SPIRIT_LYNX: case NPC_BEAR_SPIRIT: case NPC_EAGLE_SPIRIT: case NPC_LYNX_SPIRIT: case NPC_DRAGONHAWK_SPIRIT: + // Insert Malacrass companions here for better handling + case NPC_ALYSON: + case NPC_THURG: + case NPC_SLITHER: + case NPC_RADAAN: + case NPC_GAZAKROTH: + case NPC_FENSTALKER: + case NPC_DARKHEART: + case NPC_KORAGG: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; @@ -73,21 +92,81 @@ void instance_zulaman::OnCreatureCreate(Creature* pCreature) case NPC_ASHLI: m_aEventNpcInfo[INDEX_HALAZZI].npGuid = pCreature->GetObjectGuid(); break; case NPC_HARKOR: m_aEventNpcInfo[INDEX_AKILZON].npGuid = pCreature->GetObjectGuid(); break; - case NPC_EGG: - if (m_auiEncounter[TYPE_JANALAI] != DONE) - m_lEggsGUIDList.push_back(pCreature->GetObjectGuid()); + case NPC_MEDICINE_MAN: + case NPC_TRIBES_MAN: + case NPC_WARBRINGER: + case NPC_AXETHROWER: + if (pCreature->GetPositionZ() > 10.0f && pCreature->GetPositionZ() < 15.0f) + m_aNalorakkEvent[0].sBearTrashGuidSet.insert(pCreature->GetObjectGuid()); + else if (pCreature->GetPositionZ() > 25.0f && pCreature->GetPositionZ() < 30.0f) + m_aNalorakkEvent[1].sBearTrashGuidSet.insert(pCreature->GetObjectGuid()); + else if (pCreature->GetPositionZ() > 40.0f && pCreature->GetPositionZ() < 41.0f) + m_aNalorakkEvent[2].sBearTrashGuidSet.insert(pCreature->GetObjectGuid()); + else if (pCreature->GetPositionZ() > 41.0f) + m_aNalorakkEvent[3].sBearTrashGuidSet.insert(pCreature->GetObjectGuid()); + break; + } +} + +void instance_zulaman::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_MEDICINE_MAN: + case NPC_TRIBES_MAN: + case NPC_WARBRINGER: + case NPC_AXETHROWER: + if (m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.find(pCreature->GetObjectGuid()) != m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.end()) + { + ++m_aNalorakkEvent[m_uiBearEventPhase].uiTrashKilled; + if (m_aNalorakkEvent[m_uiBearEventPhase].uiTrashKilled == m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.size()) + { + if (Creature* pNalorakk = GetSingleCreatureFromStorage(NPC_NALORAKK)) + { + ++m_uiBearEventPhase; + if (m_uiBearEventPhase == MAX_BEAR_WAVES) + pNalorakk->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + else + { + pNalorakk->SetWalk(false); + pNalorakk->GetMotionMaster()->MovePoint(1, aBearEventInfo[m_uiBearEventPhase].fX, aBearEventInfo[m_uiBearEventPhase].fY, aBearEventInfo[m_uiBearEventPhase].fZ); + } + } + } + } + break; + } +} + +void instance_zulaman::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_MEDICINE_MAN: + case NPC_TRIBES_MAN: + case NPC_WARBRINGER: + case NPC_AXETHROWER: + for (GuidSet::const_iterator itr = m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.begin(); itr != m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.end(); ++itr) + { + Creature* pTemp = instance->GetCreature(*itr); + if (pTemp && !pTemp->isAlive()) + pTemp->Respawn(); + } + m_aNalorakkEvent[m_uiBearEventPhase].uiTrashKilled = 0; + m_bIsBearPhaseInProgress = false; break; } } void instance_zulaman::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_STRANGE_GONG: break; case GO_MASSIVE_GATE: - if (m_auiEncounter[TYPE_EVENT_RUN] == DONE || m_auiEncounter[TYPE_EVENT_RUN] == FAIL) + // The gate needs to be opened even if the event is still in progress + if (m_auiEncounter[TYPE_EVENT_RUN] == DONE || m_auiEncounter[TYPE_EVENT_RUN] == FAIL || m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_WIND_DOOR: @@ -117,7 +196,7 @@ void instance_zulaman::OnObjectCreate(GameObject* pGo) void instance_zulaman::SetData(uint32 uiType, uint32 uiData) { - debug_log("SD2: Instance Zulaman: SetData received for type %u with data %u",uiType,uiData); + debug_log("SD2: Instance Zulaman: SetData received for type %u with data %u", uiType, uiData); switch (uiType) { @@ -187,24 +266,8 @@ void instance_zulaman::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; case TYPE_JANALAI: - if (uiData == FAIL) - { - m_uiEggsRemainingCount_Left = 20; - m_uiEggsRemainingCount_Right = 20; - - for(GUIDList::const_iterator itr = m_lEggsGUIDList.begin(); itr != m_lEggsGUIDList.end(); ++itr) - { - if (Creature* pEgg = instance->GetCreature(*itr)) - { - if (!pEgg->isAlive()) - pEgg->Respawn(); - } - } - } if (uiData == DONE) { - m_lEggsGUIDList.clear(); - if (m_auiEncounter[TYPE_EVENT_RUN] == IN_PROGRESS) DoChestEvent(INDEX_JANALAI); } @@ -235,12 +298,6 @@ void instance_zulaman::SetData(uint32 uiType, uint32 uiData) DoUpdateWorldState(WORLD_STATE_COUNTER, m_auiEncounter[uiType]); break; - case TYPE_J_EGGS_RIGHT: - --m_uiEggsRemainingCount_Right; - break; - case TYPE_J_EGGS_LEFT: - --m_uiEggsRemainingCount_Left; - break; case TYPE_RAND_VENDOR_1: m_auiRandVendor[0] = uiData; break; @@ -249,7 +306,7 @@ void instance_zulaman::SetData(uint32 uiType, uint32 uiData) break; default: - error_log("SD2: Instance Zulaman: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Zulaman: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); return; } @@ -266,8 +323,8 @@ void instance_zulaman::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7]; m_strInstData = saveStream.str(); @@ -288,7 +345,7 @@ void instance_zulaman::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; // Skip m_auiEncounter[7], to start the time event properly if needed for (uint8 i = 0; i < MAX_ENCOUNTER - 1; ++i) @@ -304,7 +361,7 @@ void instance_zulaman::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_zulaman::GetData(uint32 uiType) +uint32 instance_zulaman::GetData(uint32 uiType) const { switch (uiType) { @@ -319,13 +376,79 @@ uint32 instance_zulaman::GetData(uint32 uiType) return m_auiEncounter[uiType]; case TYPE_RAND_VENDOR_1: return m_auiRandVendor[0]; case TYPE_RAND_VENDOR_2: return m_auiRandVendor[1]; - case TYPE_J_EGGS_LEFT: return m_uiEggsRemainingCount_Left; - case TYPE_J_EGGS_RIGHT: return m_uiEggsRemainingCount_Right; default: return 0; } } +void instance_zulaman::SendNextBearWave(Unit* pTarget) +{ + for (GuidSet::const_iterator itr = m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.begin(); itr != m_aNalorakkEvent[m_uiBearEventPhase].sBearTrashGuidSet.end(); ++itr) + { + Creature* pTemp = instance->GetCreature(*itr); + if (pTemp && pTemp->isAlive()) + { + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->AI()->AttackStart(pTarget); + + // For the first wave we need to make them jump to the ground before attacking + if (!m_uiBearEventPhase) + { + float fX, fY, fZ; + pTemp->GetRandomPoint(35.31f, 1412.24f, 2.04f, 3.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MoveJump(fX, fY, fZ, pTemp->GetSpeed(MOVE_RUN) * 2, 5.0f); + } + } + } + + m_bIsBearPhaseInProgress = true; +} + +bool instance_zulaman::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const +{ + switch (uiInstanceConditionId) + { + case INSTANCE_CONDITION_ID_NORMAL_MODE: // Not rescued + case INSTANCE_CONDITION_ID_HARD_MODE: // Rescued as first + case INSTANCE_CONDITION_ID_HARD_MODE_2: // Rescued as first + case INSTANCE_CONDITION_ID_HARD_MODE_3: // Rescued as second + case INSTANCE_CONDITION_ID_HARD_MODE_4: // Rescued as third + { + if (!pConditionSource) + break; + + int32 index = -1; + switch (pConditionSource->GetEntry()) + { + case NPC_TANZAR: + case GO_TANZARS_TRUNK: + index = INDEX_NALORAKK; + break; + case NPC_KRAZ: + case GO_KRAZS_PACKAGE: + index = INDEX_JANALAI; + break; + case NPC_ASHLI: + case GO_ASHLIS_BAG: + index = INDEX_HALAZZI; + break; + case NPC_HARKOR: + case GO_HARKORS_SATCHEL: + index = INDEX_AKILZON; + break; + } + if (index < 0) + break; + + return m_aEventNpcInfo[index].uiSavePosition == uiInstanceConditionId; + } + } + + script_error_log("instance_zulaman::CheckConditionCriteriaMeet called with unsupported Id %u. Called with param plr %s, src %s, condition source type %u", + uiInstanceConditionId, pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", pConditionSource ? pConditionSource->GetGuidStr().c_str() : "NULL", conditionSourceType); + return false; +} + uint8 instance_zulaman::GetKilledPreBosses() { return (m_auiEncounter[TYPE_AKILZON] == DONE ? 1 : 0) + (m_auiEncounter[TYPE_NALORAKK] == DONE ? 1 : 0) + (m_auiEncounter[TYPE_JANALAI] == DONE ? 1 : 0) + (m_auiEncounter[TYPE_HALAZZI] == DONE ? 1 : 0); @@ -391,7 +514,7 @@ void instance_zulaman::Update(uint32 uiDiff) SetData(TYPE_RUN_EVENT_TIME, m_auiEncounter[TYPE_RUN_EVENT_TIME]); debug_log("SD2: Instance Zulaman: minute decrease to %u.", m_auiEncounter[TYPE_RUN_EVENT_TIME]); - m_uiEventTimer = MINUTE*IN_MILLISECONDS; + m_uiEventTimer = MINUTE * IN_MILLISECONDS; } else m_uiEventTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/zulaman/zulaman.cpp b/scripts/eastern_kingdoms/zulaman/zulaman.cpp index d8305a5ea..7efe5cc1b 100644 --- a/scripts/eastern_kingdoms/zulaman/zulaman.cpp +++ b/scripts/eastern_kingdoms/zulaman/zulaman.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -40,7 +40,7 @@ enum NPC_FOREST_FROG = 24396 }; -struct MANGOS_DLL_DECL npc_forest_frogAI : public ScriptedAI +struct npc_forest_frogAI : public ScriptedAI { npc_forest_frogAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -50,52 +50,52 @@ struct MANGOS_DLL_DECL npc_forest_frogAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() { } + void Reset() override { } void DoSpawnRandom() { if (m_pInstance) { uint32 cEntry = 0; - switch(urand(0, 10)) + switch (urand(0, 10)) { - case 0: cEntry = 24024; break; //Kraz // wrong here? - case 1: cEntry = 24397; break; //Mannuth - case 2: cEntry = 24403; break; //Deez - case 3: cEntry = 24404; break; //Galathryn - case 4: cEntry = 24405; break; //Adarrah - case 5: cEntry = 24406; break; //Fudgerick - case 6: cEntry = 24407; break; //Darwen - case 7: cEntry = 24445; break; //Mitzi - case 8: cEntry = 24448; break; //Christian - case 9: cEntry = 24453; break; //Brennan - case 10: cEntry = 24455; break; //Hollee + case 0: cEntry = 24024; break; // Kraz // wrong here? + case 1: cEntry = 24397; break; // Mannuth + case 2: cEntry = 24403; break; // Deez + case 3: cEntry = 24404; break; // Galathryn + case 4: cEntry = 24405; break; // Adarrah + case 5: cEntry = 24406; break; // Fudgerick + case 6: cEntry = 24407; break; // Darwen + case 7: cEntry = 24445; break; // Mitzi + case 8: cEntry = 24448; break; // Christian + case 9: cEntry = 24453; break; // Brennan + case 10: cEntry = 24455; break; // Hollee } if (!m_pInstance->GetData(TYPE_RAND_VENDOR_1)) if (!urand(0, 9)) - cEntry = 24408; //Gunter + cEntry = 24408; // Gunter if (!m_pInstance->GetData(TYPE_RAND_VENDOR_2)) if (!urand(0, 9)) - cEntry = 24409; //Kyren + cEntry = 24409; // Kyren if (cEntry) m_creature->UpdateEntry(cEntry); if (cEntry == 24408) - m_pInstance->SetData(TYPE_RAND_VENDOR_1,DONE); + m_pInstance->SetData(TYPE_RAND_VENDOR_1, DONE); if (cEntry == 24409) - m_pInstance->SetData(TYPE_RAND_VENDOR_2,DONE); + m_pInstance->SetData(TYPE_RAND_VENDOR_2, DONE); } } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* caster, const SpellEntry* spell) override { if (spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->GetTypeId() == TYPEID_PLAYER && m_creature->GetEntry() == NPC_FOREST_FROG) { - //increase or decrease chance of mojo? + // increase or decrease chance of mojo? if (!urand(0, 49)) DoCastSpellIfCan(caster, SPELL_PUSH_MOJO, CAST_TRIGGERED); else @@ -118,12 +118,12 @@ enum SAY_AT_GONG = -1568080, SAY_OPEN_ENTRANCE = -1568081, + GOSSIP_ITEM_ID_BEGIN = -3568000, + SPELL_BANGING_THE_GONG = 45225 }; -#define GOSSIP_ITEM_BEGIN "Thanks for the concern, but we intend to explore Zul'Aman." - -struct MANGOS_DLL_DECL npc_harrison_jones_zaAI : public npc_escortAI +struct npc_harrison_jones_zaAI : public npc_escortAI { npc_harrison_jones_zaAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -133,20 +133,20 @@ struct MANGOS_DLL_DECL npc_harrison_jones_zaAI : public npc_escortAI ScriptedInstance* m_pInstance; - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { if (!m_pInstance) return; - switch(uiPointId) + switch (uiPointId) { case 1: DoScriptText(SAY_AT_GONG, m_creature); m_pInstance->DoToggleGameObjectFlags(GO_STRANGE_GONG, GO_FLAG_NO_INTERACT, false); - //Start bang gong for 2min - m_creature->CastSpell(m_creature, SPELL_BANGING_THE_GONG, false); + // Start bang gong for 2min + DoCastSpellIfCan(m_creature, SPELL_BANGING_THE_GONG); SetEscortPaused(true); break; case 3: @@ -154,12 +154,12 @@ struct MANGOS_DLL_DECL npc_harrison_jones_zaAI : public npc_escortAI break; case 4: m_pInstance->SetData(TYPE_EVENT_RUN, IN_PROGRESS); - //TODO: Spawn group of Amani'shi Savage and make them run to entrance + // TODO: Spawn group of Amani'shi Savage and make them run to entrance break; } } - void Reset() { } + void Reset() override { } void StartEvent() { @@ -171,7 +171,7 @@ struct MANGOS_DLL_DECL npc_harrison_jones_zaAI : public npc_escortAI { SetEscortPaused(bOnHold); - //Stop banging gong if still + // Stop banging gong if still if (m_pInstance && m_pInstance->GetData(TYPE_EVENT_RUN) == SPECIAL && m_creature->HasAura(SPELL_BANGING_THE_GONG)) m_creature->RemoveAurasDueToSpell(SPELL_BANGING_THE_GONG); } @@ -185,15 +185,15 @@ bool GossipHello_npc_harrison_jones_za(Player* pPlayer, Creature* pCreature) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pInstance && pInstance->GetData(TYPE_EVENT_RUN) == NOT_STARTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ID_BEGIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_harrison_jones_za(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_harrison_jones_za(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { if (npc_harrison_jones_zaAI* pHarrisonAI = dynamic_cast(pCreature->AI())) pHarrisonAI->StartEvent(); @@ -212,8 +212,8 @@ CreatureAI* GetAI_npc_harrison_jones_za(Creature* pCreature) ## go_strange_gong ######*/ -//Unsure how this Gong must work. Here we always return false to allow Mangos always process further. -bool GOUse_go_strange_gong(Player* pPlayer, GameObject* pGo) +// Unsure how this Gong must work. Here we always return false to allow Mangos always process further. +bool GOUse_go_strange_gong(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); @@ -228,7 +228,7 @@ bool GOUse_go_strange_gong(Player* pPlayer, GameObject* pGo) pHarrisonAI->SetHoldState(false); } else - error_log("SD2: Instance Zulaman: go_strange_gong failed"); + script_error_log("Instance Zulaman: go_strange_gong failed"); pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); return false; diff --git a/scripts/eastern_kingdoms/zulaman/zulaman.h b/scripts/eastern_kingdoms/zulaman/zulaman.h index 4a5fd0d21..512d919d2 100644 --- a/scripts/eastern_kingdoms/zulaman/zulaman.h +++ b/scripts/eastern_kingdoms/zulaman/zulaman.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -10,6 +10,7 @@ enum InstanceZA MAX_ENCOUNTER = 8, MAX_VENDOR = 2, MAX_CHESTS = 4, + MAX_BEAR_WAVES = 4, SAY_INST_RELEASE = -1568067, // TODO Event NYI SAY_INST_BEGIN = -1568068, @@ -24,6 +25,12 @@ enum InstanceZA SAY_INST_SACRIF2 = -1568077, SAY_INST_COMPLETE = -1568078, + // Bear event yells + SAY_WAVE1_AGGRO = -1568010, + SAY_WAVE2_STAIR1 = -1568011, + SAY_WAVE3_STAIR2 = -1568012, + SAY_WAVE4_PLATFORM = -1568013, + WORLD_STATE_ID = 3104, WORLD_STATE_COUNTER = 3106, @@ -39,18 +46,28 @@ enum InstanceZA TYPE_RAND_VENDOR_1 = 8, TYPE_RAND_VENDOR_2 = 9, - TYPE_J_EGGS_RIGHT = 10, - TYPE_J_EGGS_LEFT = 11, - NPC_AKILZON = 23574, - // NPC_NALORAKK = 23576, - // NPC_JANALAI = 23578, + NPC_NALORAKK = 23576, + NPC_JANALAI = 23578, NPC_HALAZZI = 23577, NPC_MALACRASS = 24239, - // NPC_ZULJIN = 23863, - - NPC_EGG = 23817, - NPC_SPIRIT_LYNX = 24143, + NPC_ZULJIN = 23863, + + // Narolakk event npcs + NPC_MEDICINE_MAN = 23581, + NPC_TRIBES_MAN = 23582, + NPC_AXETHROWER = 23542, + NPC_WARBRINGER = 23580, + + // Malacrass companions + NPC_ALYSON = 24240, + NPC_THURG = 24241, + NPC_SLITHER = 24242, + NPC_RADAAN = 24243, + NPC_GAZAKROTH = 24244, + NPC_FENSTALKER = 24245, + NPC_DARKHEART = 24246, + NPC_KORAGG = 24247, NPC_HARRISON = 24358, // Time Run Event NPCs @@ -64,6 +81,7 @@ enum InstanceZA NPC_ASHIL_CORPSE = 24441, NPC_HARKOR_CORPSE = 24443, + // Zul'jin event spirits NPC_BEAR_SPIRIT = 23878, // They should all have aura 42466 NPC_EAGLE_SPIRIT = 23880, NPC_LYNX_SPIRIT = 23877, @@ -78,7 +96,6 @@ enum InstanceZA GO_WOODEN_DOOR = 186306, GO_FIRE_DOOR = 186859, - // unused, expected to be possible to handle within Database! GO_TANZARS_TRUNK = 186648, GO_KRAZS_PACKAGE = 186667, GO_ASHLIS_BAG = 186672, @@ -110,24 +127,53 @@ struct TimeEventNpcInfo ObjectGuid npGuid; }; -class MANGOS_DLL_DECL instance_zulaman : public ScriptedInstance +struct NalorakkBearEventInfo +{ + int iYellId; + float fX, fY, fZ, fO, fAggroDist; +}; + +static const NalorakkBearEventInfo aBearEventInfo[MAX_BEAR_WAVES] = +{ + {SAY_WAVE1_AGGRO, 0, 0, 0, 0, 45.0f}, + {SAY_WAVE2_STAIR1, -54.948f, 1419.772f, 27.303f, 0.03f, 37.0f}, + {SAY_WAVE3_STAIR2, -80.303f, 1372.622f, 40.764f, 1.67f, 35.0f}, + {SAY_WAVE4_PLATFORM, -77.495f, 1294.760f, 48.487f, 1.66f, 60.0f} +}; + +struct NalorakkTrashInfo +{ + GuidSet sBearTrashGuidSet; + uint8 uiTrashKilled; +}; + +class instance_zulaman : public ScriptedInstance { public: instance_zulaman(Map* pMap); - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature); + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + bool IsBearPhaseInProgress() { return m_bIsBearPhaseInProgress; } + void SetBearEventProgress(bool bIsInProgress) { m_bIsBearPhaseInProgress = bIsInProgress; } + void SendNextBearWave(Unit* pTarget); - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; private: uint8 GetKilledPreBosses(); @@ -142,9 +188,9 @@ class MANGOS_DLL_DECL instance_zulaman : public ScriptedInstance uint32 m_uiEventTimer; uint32 m_uiGongCount; - GUIDList m_lEggsGUIDList; - uint32 m_uiEggsRemainingCount_Left; - uint32 m_uiEggsRemainingCount_Right; + NalorakkTrashInfo m_aNalorakkEvent[MAX_BEAR_WAVES]; + uint8 m_uiBearEventPhase; + bool m_bIsBearPhaseInProgress; }; #endif diff --git a/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp b/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp index 70341fba9..d4873531e 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_arlokk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,7 +41,7 @@ enum NPC_ZULIAN_PROWLER = 15101 }; -struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI +struct boss_arlokkAI : public ScriptedAI { boss_arlokkAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -64,7 +64,7 @@ struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI bool m_bIsPhaseTwo; - void Reset() + void Reset() override { m_uiShadowWordPainTimer = 8000; m_uiGougeTimer = 14000; @@ -84,21 +84,21 @@ struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI m_creature->SetVisibility(VISIBILITY_ON); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ARLOKK, FAIL); - //we should be summoned, so despawn + // we should be summoned, so despawn m_creature->ForcedDespawn(); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); // Restore visibility in case of killed by dots @@ -109,14 +109,14 @@ struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI m_pInstance->SetData(TYPE_ARLOKK, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Just attack a random target. The Marked player will attract them automatically if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -127,9 +127,9 @@ struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI if (m_pInstance) { if (Creature* pTrigger = m_pInstance->SelectRandomPantherTrigger(true)) - m_creature->SummonCreature(NPC_ZULIAN_PROWLER, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_ZULIAN_PROWLER, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); if (Creature* pTrigger = m_pInstance->SelectRandomPantherTrigger(false)) - m_creature->SummonCreature(NPC_ZULIAN_PROWLER, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_ZULIAN_PROWLER, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); } m_uiSummonTimer = 5000; @@ -189,7 +189,7 @@ struct MANGOS_DLL_DECL boss_arlokkAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, SPELL_GOUGE) == CAST_OK) { if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-80); + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -80); m_uiGougeTimer = urand(17000, 27000); } @@ -268,7 +268,7 @@ CreatureAI* GetAI_boss_arlokk(Creature* pCreature) return new boss_arlokkAI(pCreature); } -bool GOUse_go_gong_of_bethekk(Player* pPlayer, GameObject* pGo) +bool GOUse_go_gong_of_bethekk(Player* /*pPlayer*/, GameObject* pGo) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) { diff --git a/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp b/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp deleted file mode 100644 index 1fe1fc7f5..000000000 --- a/scripts/eastern_kingdoms/zulgurub/boss_gahzranka.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Gahz'ranka -SD%Complete: 85 -SDComment: Massive Geyser with knockback not working. Spell buggy. -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_FROSTBREATH 16099 -#define SPELL_MASSIVEGEYSER 22421 //Not working. Cause its a summon... -#define SPELL_SLAM 24326 - -struct MANGOS_DLL_DECL boss_gahzrankaAI : public ScriptedAI -{ - boss_gahzrankaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 Frostbreath_Timer; - uint32 MassiveGeyser_Timer; - uint32 Slam_Timer; - - void Reset() - { - Frostbreath_Timer = 8000; - MassiveGeyser_Timer = 25000; - Slam_Timer = 17000; - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Frostbreath_Timer - if (Frostbreath_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBREATH); - Frostbreath_Timer = urand(7000, 11000); - }else Frostbreath_Timer -= diff; - - //MassiveGeyser_Timer - if (MassiveGeyser_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MASSIVEGEYSER); - DoResetThreat(); - - MassiveGeyser_Timer = urand(22000, 32000); - }else MassiveGeyser_Timer -= diff; - - //Slam_Timer - if (Slam_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SLAM); - Slam_Timer = urand(12000, 20000); - }else Slam_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gahzranka(Creature* pCreature) -{ - return new boss_gahzrankaAI(pCreature); -} - -void AddSC_boss_gahzranka() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_gahzranka"; - pNewScript->GetAI = &GetAI_boss_gahzranka; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp b/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp deleted file mode 100644 index d861b60d5..000000000 --- a/scripts/eastern_kingdoms/zulgurub/boss_grilek.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Grilek -SD%Complete: 100 -SDComment: -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "zulgurub.h" - -#define SPELL_AVARTAR 24646 //The Enrage Spell -#define SPELL_GROUNDTREMOR 6524 - -struct MANGOS_DLL_DECL boss_grilekAI : public ScriptedAI -{ - boss_grilekAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Avartar_Timer; - uint32 GroundTremor_Timer; - - void Reset() - { - Avartar_Timer = urand(15000, 25000); - GroundTremor_Timer = urand(8000, 16000); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Avartar_Timer - if (Avartar_Timer < diff) - { - - DoCastSpellIfCan(m_creature, SPELL_AVARTAR); - Unit* target = NULL; - - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); - - if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); - if (target) - AttackStart(target); - - Avartar_Timer = urand(25000, 35000); - }else Avartar_Timer -= diff; - - //GroundTremor_Timer - if (GroundTremor_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GROUNDTREMOR); - GroundTremor_Timer = urand(12000, 16000); - }else GroundTremor_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_grilek(Creature* pCreature) -{ - return new boss_grilekAI(pCreature); -} - -void AddSC_boss_grilek() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_grilek"; - pNewScript->GetAI = &GetAI_boss_grilek; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp b/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp index 28637c8d9..530399cdf 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_hakkar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Hakkar -SD%Complete: 95 -SDComment: Blood siphon spell buggy cause of Core Issue. +SD%Complete: 100 +SDComment: SDCategory: Zul'Gurub EndScriptData */ @@ -29,7 +29,7 @@ enum SAY_AGGRO = -1309020, SAY_FLEEING = -1309021, - SPELL_BLOOD_SIPHON = 24324, // Related Spells 24322, 24323, 24324, likely starting spell is 24324 (disabled until proper fixed) + SPELL_BLOOD_SIPHON = 24324, // triggers 24322 or 24323 on caster SPELL_CORRUPTED_BLOOD = 24328, SPELL_CAUSE_INSANITY = 24327, SPELL_WILL_OF_HAKKAR = 24178, @@ -43,7 +43,7 @@ enum SPELL_ASPECT_OF_ARLOKK = 24690 }; -struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI +struct boss_hakkarAI : public ScriptedAI { boss_hakkarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -65,13 +65,13 @@ struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI uint32 m_uiAspectOfThekalTimer; uint32 m_uiAspectOfArlokkTimer; - void Reset() + void Reset() override { m_uiBloodSiphonTimer = 90000; m_uiCorruptedBloodTimer = 25000; m_uiCauseInsanityTimer = 17000; m_uiWillOfHakkarTimer = 17000; - m_uiEnrageTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; m_uiAspectOfJeklikTimer = 4000; m_uiAspectOfVenoxisTimer = 7000; @@ -80,7 +80,7 @@ struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI m_uiAspectOfArlokkTimer = 18000; } - void Aggro(Unit *who) + void Aggro(Unit* /*who*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -100,20 +100,18 @@ struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - /* Disabled as needs core fix// Blood Siphon Timer - * This also will requre spells 24320 24321 to be implemented (and used by the "Son of Hakkar" npcs) if (m_uiBloodSiphonTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_SIPHON) == CAST_OK) m_uiBloodSiphonTimer = 90000; } else - m_uiBloodSiphonTimer -= uiDiff; */ + m_uiBloodSiphonTimer -= uiDiff; // Corrupted Blood Timer if (m_uiCorruptedBloodTimer < uiDiff) @@ -158,7 +156,7 @@ struct MANGOS_DLL_DECL boss_hakkarAI : public ScriptedAI if (m_uiEnrageTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) - m_uiEnrageTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; } else m_uiEnrageTimer -= uiDiff; diff --git a/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp b/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp index b3f72e2c4..f103b11a0 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_hazzarah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -33,7 +33,7 @@ enum SPELL_SUMMON_ILLUSION_3 = 24729, }; -struct MANGOS_DLL_DECL boss_hazzarahAI : public ScriptedAI +struct boss_hazzarahAI : public ScriptedAI { boss_hazzarahAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -42,7 +42,7 @@ struct MANGOS_DLL_DECL boss_hazzarahAI : public ScriptedAI uint32 m_uiEarthShockTimer; uint32 m_uiIllusionsTimer; - void Reset() + void Reset() override { m_uiManaBurnTimer = urand(4000, 10000); m_uiSleepTimer = urand(10000, 18000); @@ -50,13 +50,13 @@ struct MANGOS_DLL_DECL boss_hazzarahAI : public ScriptedAI m_uiIllusionsTimer = urand(10000, 18000); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp b/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp index 4f3e10946..3d90380d7 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_jeklik.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Jeklik SD%Complete: 85 -SDComment: Problem in finding the right flying batriders for spawning and making them fly. +SDComment: Some minor improvements are required; Bat rider movement not implemented SDCategory: Zul'Gurub EndScriptData */ @@ -28,25 +28,41 @@ enum { SAY_AGGRO = -1309002, SAY_RAIN_FIRE = -1309003, + SAY_SHRIEK = -1309026, + SAY_HEAL = -1309027, SAY_DEATH = -1309004, + // Bat spells SPELL_CHARGE = 22911, - SPELL_SONICBURST = 23918, - SPELL_SCREECH = 6605, + SPELL_SONIC_BURST = 23918, + // SPELL_PSYHIC_SCREAM = 22884, // spell not confirmed - needs research + SPELL_SWOOP = 23919, + SPELL_SUMMON_FRENZIED_BATS = 23974, + + // Troll form spells SPELL_SHADOW_WORD_PAIN = 23952, SPELL_MIND_FLAY = 23953, - SPELL_CHAIN_MIND_FLAY = 26044, // Right ID unknown. So disabled + SPELL_BLOOD_LEECH = 22644, SPELL_GREATERHEAL = 23954, + + // Common spells + SPELL_GREEN_CHANNELING = 13540, // visual for idle mode SPELL_BAT_FORM = 23966, // Batriders Spell - SPELL_BOMB = 40332, // Wrong ID but Magmadars bomb is not working... - - NPC_BLOODSEEKER_BAT = 11368, + SPELL_LIQUID_FIRE = 23968, // script effect - triggers 23971, + SPELL_UNSTABLE_CONCOCTION = 24024, + SPELL_TRASH = 8876, + SPELL_DEMORALIZING_SHOUT = 23511, + SPELL_BATTLE_COMMAND = 5115, + SPELL_INFECTED_BITE = 16128, + + // npcs NPC_FRENZIED_BAT = 14965, + NPC_BAT_RIDER = 14750, }; -struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI +struct boss_jeklikAI : public ScriptedAI { boss_jeklikAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -57,63 +73,129 @@ struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI ScriptedInstance* m_pInstance; uint32 m_uiChargeTimer; + uint32 m_uiSwoopTimer; uint32 m_uiSonicBurstTimer; - uint32 m_uiScreechTimer; uint32 m_uiSpawnBatsTimer; uint32 m_uiShadowWordPainTimer; uint32 m_uiMindFlayTimer; uint32 m_uiChainMindFlayTimer; uint32 m_uiGreaterHealTimer; - uint32 m_uiSpawnFlyingBatsTimer; + uint32 m_uiFlyingBatsTimer; bool m_bIsPhaseOne; - void Reset() + GuidList m_lBombRiderGuidsList; + + void Reset() override { - m_uiChargeTimer = 20000; - m_uiSonicBurstTimer = 8000; - m_uiScreechTimer = 13000; - m_uiSpawnBatsTimer = 60000; + m_uiChargeTimer = 20000; + m_uiSwoopTimer = 5000; + m_uiSonicBurstTimer = 8000; + m_uiSpawnBatsTimer = 50000; m_uiShadowWordPainTimer = 6000; - m_uiMindFlayTimer = 11000; - m_uiChainMindFlayTimer = 26000; - m_uiGreaterHealTimer = 50000; - m_uiSpawnFlyingBatsTimer = 10000; + m_uiMindFlayTimer = 11000; + m_uiChainMindFlayTimer = 26000; + m_uiGreaterHealTimer = 20000; + m_uiFlyingBatsTimer = 30000; + + m_bIsPhaseOne = true; - m_bIsPhaseOne = true; + DoCastSpellIfCan(m_creature, SPELL_GREEN_CHANNELING); + SetCombatMovement(false); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BAT_FORM); + + // Note: on aggro the bats from the cave behind the boss should fly outside! + if (DoCastSpellIfCan(m_creature, SPELL_BAT_FORM) == CAST_OK) + { + m_creature->SetLevitate(true); + // override MMaps, by allowing the boss to fly up from the ledge + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, -12281.58f, -1392.84f, 146.1f); + } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + DoDespawnBombRiders(); if (m_pInstance) m_pInstance->SetData(TYPE_JEKLIK, DONE); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override + { + DoDespawnBombRiders(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_JEKLIK, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FRENZIED_BAT) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + else if (pSummoned->GetEntry() == NPC_BAT_RIDER) + { + pSummoned->CastSpell(pSummoned, SPELL_LIQUID_FIRE, true); + m_lBombRiderGuidsList.push_back(pSummoned->GetObjectGuid()); + } + + pSummoned->SetLevitate(true); + } + + void EnterEvadeMode() override + { + // Override MMaps, and teleport to original position + float fX, fY, fZ, fO; + m_creature->GetRespawnCoord(fX, fY, fZ, &fO); + m_creature->NearTeleportTo(fX, fY, fZ, fO); + + ScriptedAI::EnterEvadeMode(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + } + + // Wrapper to despawn the bomb riders on evade / death + void DoDespawnBombRiders() { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + if (m_lBombRiderGuidsList.empty()) + return; + + for (GuidList::const_iterator itr = m_lBombRiderGuidsList.begin(); itr != m_lBombRiderGuidsList.end(); ++itr) + { + if (Creature* pRider = m_creature->GetMap()->GetCreature(*itr)) + pRider->ForcedDespawn(); + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Bat phase if (m_bIsPhaseOne) { // Phase Switch at 50% if (m_creature->GetHealthPercent() < 50.0f) { m_creature->RemoveAurasDueToSpell(SPELL_BAT_FORM); + m_creature->SetLevitate(false); DoResetThreat(); m_bIsPhaseOne = false; return; @@ -122,46 +204,43 @@ struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI if (m_uiChargeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) m_uiChargeTimer = urand(15000, 30000); + } } else m_uiChargeTimer -= uiDiff; - if (m_uiSonicBurstTimer < uiDiff) + if (m_uiSwoopTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_SONICBURST) == CAST_OK) - m_uiSonicBurstTimer = urand(8000, 13000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SWOOP) == CAST_OK) + m_uiSwoopTimer = urand(4000, 9000); } else - m_uiSonicBurstTimer -= uiDiff; + m_uiSwoopTimer -= uiDiff; - if (m_uiScreechTimer < uiDiff) + if (m_uiSonicBurstTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_SCREECH) == CAST_OK) - m_uiScreechTimer = urand(18000, 26000); + if (DoCastSpellIfCan(m_creature, SPELL_SONIC_BURST) == CAST_OK) + m_uiSonicBurstTimer = urand(8000, 13000); } else - m_uiScreechTimer -= uiDiff; + m_uiSonicBurstTimer -= uiDiff; if (m_uiSpawnBatsTimer < uiDiff) { - // TODO There are some bats in the cave behind the boss, perhaps they should be called - float fX, fY, fZ, fO, fNewX, fNewY, fNewZ; - m_creature->GetRespawnCoord(fX, fY, fZ, &fO); - for (uint8 i = 0; i < 6; ++i) + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FRENZIED_BATS) == CAST_OK) { - // Get a point a little bit behind Jeklik respawn pos - m_creature->GetRandomPoint(fX - 5.0f, fY + 5.0f, fZ, 5.0f, fNewX, fNewY, fNewZ); - m_creature->SummonCreature(NPC_BLOODSEEKER_BAT, fNewX, fNewY, fNewZ, fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + DoScriptText(SAY_SHRIEK, m_creature); + m_uiSpawnBatsTimer = 60000; } - - m_uiSpawnBatsTimer = 60000; } else m_uiSpawnBatsTimer -= uiDiff; } - else // Phase Two + // Troll phase + else { if (m_uiShadowWordPainTimer < uiDiff) { @@ -184,7 +263,7 @@ struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI if (m_uiChainMindFlayTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_MIND_FLAY) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_LEECH) == CAST_OK) m_uiChainMindFlayTimer = urand(15000, 30000); } else @@ -193,81 +272,116 @@ struct MANGOS_DLL_DECL boss_jeklikAI : public ScriptedAI if (m_uiGreaterHealTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_GREATERHEAL, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_HEAL, m_creature); m_uiGreaterHealTimer = urand(25000, 35000); + } } else m_uiGreaterHealTimer -= uiDiff; - if (m_uiSpawnFlyingBatsTimer < uiDiff) + if (m_uiFlyingBatsTimer) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - m_creature->SummonCreature(NPC_FRENZIED_BAT, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ() + 15.0f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - - m_uiSpawnFlyingBatsTimer = urand(10000, 15000); + if (m_uiFlyingBatsTimer <= uiDiff) + { + // Note: the bat riders summoning and movement may need additional research + for (uint8 i = 0; i < 3; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->SummonCreature(NPC_BAT_RIDER, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ() + 15.0f, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + DoScriptText(SAY_RAIN_FIRE, m_creature); + + m_uiFlyingBatsTimer = 0; + } + else + m_uiFlyingBatsTimer -= uiDiff; } - else - m_uiSpawnFlyingBatsTimer -= uiDiff; } DoMeleeAttackIfReady(); } }; -// Flying Bat -struct MANGOS_DLL_DECL mob_batriderAI : public ScriptedAI +struct npc_gurubashi_bat_riderAI : public ScriptedAI { - mob_batriderAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_gurubashi_bat_riderAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsSummon = m_creature->IsTemporarySummon(); Reset(); } - ScriptedInstance* m_pInstance; + bool m_bIsSummon; + bool m_bHasDoneConcoction; + + uint32 m_uiInfectedBiteTimer; + uint32 m_uiBattleCommandTimer; + + void Reset() override + { + m_uiInfectedBiteTimer = 6500; + m_uiBattleCommandTimer = 8000; + + m_bHasDoneConcoction = false; + + DoCastSpellIfCan(m_creature, SPELL_TRASH); + } - uint32 m_uiBombTimer; - uint32 m_uiCheckTimer; + void Aggro(Unit* /*pWho*/) override + { + // Don't attack if is summoned by Jeklik - the npc gets aggro because of the Liquid Fire + if (m_bIsSummon) + return; + + DoCastSpellIfCan(m_creature, SPELL_DEMORALIZING_SHOUT); + // For normal mobs flag needs to be removed + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void AttackStart(Unit* pWho) override + { + // Don't attack if is summoned by Jeklik + if (m_bIsSummon) + return; - void Reset() + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override { - m_uiBombTimer = 2000; - m_uiCheckTimer = 1000; + // Don't attack if is summoned by Jeklik + if (m_bIsSummon) + return; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + ScriptedAI::MoveInLineOfSight(pWho); } - void UpdateAI (const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // Bomb Timer - if (m_uiBombTimer < uiDiff) + if (!m_bHasDoneConcoction && m_creature->GetHealthPercent() < 50.0f) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - DoCastSpellIfCan(pTarget, SPELL_BOMB); - m_uiBombTimer = 5000; - } + if (DoCastSpellIfCan(m_creature, SPELL_UNSTABLE_CONCOCTION) == CAST_OK) + m_bHasDoneConcoction = true; + } + + if (m_uiInfectedBiteTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INFECTED_BITE) == CAST_OK) + m_uiInfectedBiteTimer = 6500; } else - m_uiBombTimer -= uiDiff; + m_uiInfectedBiteTimer -= uiDiff; - // Check Timer - if (m_uiCheckTimer < uiDiff) + if (m_uiBattleCommandTimer < uiDiff) { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_JEKLIK) == DONE) - { - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - return; - } - } - m_uiCheckTimer = 1000; + if (DoCastSpellIfCan(m_creature, SPELL_BATTLE_COMMAND) == CAST_OK) + m_uiBattleCommandTimer = 25000; } else - m_uiCheckTimer -= uiDiff; + m_uiBattleCommandTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -278,9 +392,9 @@ CreatureAI* GetAI_boss_jeklik(Creature* pCreature) return new boss_jeklikAI(pCreature); } -CreatureAI* GetAI_mob_batrider(Creature* pCreature) +CreatureAI* GetAI_npc_gurubashi_bat_rider(Creature* pCreature) { - return new mob_batriderAI(pCreature); + return new npc_gurubashi_bat_riderAI(pCreature); } void AddSC_boss_jeklik() @@ -293,7 +407,7 @@ void AddSC_boss_jeklik() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_batrider"; - pNewScript->GetAI = &GetAI_mob_batrider; + pNewScript->Name = "npc_gurubashi_bat_rider"; + pNewScript->GetAI = &GetAI_npc_gurubashi_bat_rider; pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp b/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp index 8110af909..d779e27d4 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_jindo.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,10 +35,7 @@ enum SPELL_SHADE_OF_JINDO = 24308, // Spell was removed from DBC around TBC; will summon npcs manually! SPELL_HEALING_WARD_HEAL = 24311, - - // Shade of Jindo Spell - SPELL_SHADOWSHOCK = 19460, - SPELL_SHADE_OF_JINDO_PASSIVE = 24307, // shade invisibility, needs core support to prevent removing when attacking + SPELL_SHADE_OF_JINDO_PASSIVE = 24307, // npcs NPC_SHADE_OF_JINDO = 14986, @@ -53,7 +50,7 @@ static const float aPitTeleportLocs[4] = -11583.7783f, -1249.4278f, 77.5471f, 4.745f }; -struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI +struct boss_jindoAI : public ScriptedAI { boss_jindoAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -69,7 +66,7 @@ struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI uint32 m_uiDelusionsTimer; uint32 m_uiTeleportTimer; - void Reset() + void Reset() override { m_uiBrainWashTotemTimer = 20000; m_uiHealingWardTimer = 16000; @@ -78,18 +75,18 @@ struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI m_uiTeleportTimer = 5000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_POWERFULL_HEALING_WARD) m_uiHealingWardTimer = 15000; // how long delay? } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -136,8 +133,8 @@ struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI { float fX, fY, fZ; m_creature->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 5.0f, fX, fY, fZ); - if (Creature* pSummoned = m_creature->SummonCreature(NPC_SHADE_OF_JINDO, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - pSummoned->AI()->AttackStart(pTarget); + if (Creature* pSummoned = m_creature->SummonCreature(NPC_SHADE_OF_JINDO, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 15000)) + pSummoned->CastSpell(pSummoned, SPELL_SHADE_OF_JINDO_PASSIVE, true); m_uiDelusionsTimer = urand(4000, 12000); } @@ -157,7 +154,7 @@ struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI for (uint8 i = 0; i < MAX_SKELETONS; ++i) { m_creature->GetRandomPoint(aPitTeleportLocs[0], aPitTeleportLocs[1], aPitTeleportLocs[2], 4.0f, fX, fY, fZ); - if (Creature* pSummoned = m_creature->SummonCreature(NPC_SACRIFICED_TROLL, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + if (Creature* pSummoned = m_creature->SummonCreature(NPC_SACRIFICED_TROLL, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 15000)) pSummoned->AI()->AttackStart(pTarget); } @@ -172,21 +169,21 @@ struct MANGOS_DLL_DECL boss_jindoAI : public ScriptedAI }; // HACK script! Should not need to have totems in sd2 -struct MANGOS_DLL_DECL mob_healing_wardAI : public ScriptedAI +struct mob_healing_wardAI : public ScriptedAI { mob_healing_wardAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiHealTimer; - void Reset() + void Reset() override { m_uiHealTimer = 3000; // Timer unknown, sources go over 1s, per tick to 3s, keep 3s as in original script } - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} - void UpdateAI (const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Heal Timer if (m_uiHealTimer < uiDiff) @@ -199,43 +196,6 @@ struct MANGOS_DLL_DECL mob_healing_wardAI : public ScriptedAI } }; -// TODO Move to Acid -struct MANGOS_DLL_DECL mob_shade_of_jindoAI : public ScriptedAI -{ - mob_shade_of_jindoAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiShadowShockTimer; - - void Reset() - { - m_uiShadowShockTimer = 1000; - DoCastSpellIfCan(m_creature, SPELL_SHADE_OF_JINDO_PASSIVE); - } - - void UpdateAI (const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // ShadowShock Timer - if (m_uiShadowShockTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOWSHOCK) == CAST_OK) - m_uiShadowShockTimer = 2000; - } - else - m_uiShadowShockTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - CreatureAI* GetAI_boss_jindo(Creature* pCreature) { return new boss_jindoAI(pCreature); @@ -246,11 +206,6 @@ CreatureAI* GetAI_mob_healing_ward(Creature* pCreature) return new mob_healing_wardAI(pCreature); } -CreatureAI* GetAI_mob_shade_of_jindo(Creature* pCreature) -{ - return new mob_shade_of_jindoAI(pCreature); -} - void AddSC_boss_jindo() { Script* pNewScript; @@ -264,9 +219,4 @@ void AddSC_boss_jindo() pNewScript->Name = "mob_healing_ward"; pNewScript->GetAI = &GetAI_mob_healing_ward; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_shade_of_jindo"; - pNewScript->GetAI = &GetAI_mob_shade_of_jindo; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp b/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp index 7fbc43235..a5a4e736f 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_mandokir.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -27,7 +27,7 @@ EndScriptData */ enum { NPC_OHGAN = 14988, - NPC_CHAINED_SPIRIT = 15117, //resing spirits + NPC_CHAINED_SPIRIT = 15117, // resing spirits SAY_AGGRO = -1309015, SAY_DING_KILL = -1309016, @@ -47,10 +47,10 @@ enum SPELL_SUMMON_PLAYER = 25104, SPELL_LEVEL_UP = 24312, - //Ohgans Spells + // Ohgans Spells SPELL_SUNDERARMOR = 24317, - //Chained Spirit Spells + // Chained Spirit Spells SPELL_REVIVE = 24341, POINT_DOWNSTAIRS = 1 @@ -61,32 +61,30 @@ struct SpawnLocations float fX, fY, fZ, fAng; }; -static SpawnLocations aSpirits[]= +static SpawnLocations aSpirits[] = { - {-12150.9f, -1956.24f, 133.407f, 2.57835f}, - {-12157.1f, -1972.78f, 133.947f, 2.64903f}, - {-12172.3f, -1982.63f, 134.061f, 1.48664f}, - {-12194.0f, -1979.54f, 132.194f, 1.45916f}, - {-12211.3f, -1978.49f, 133.580f, 1.35705f}, - {-12228.4f, -1977.10f, 132.728f, 1.25495f}, - {-12250.0f, -1964.78f, 135.066f, 0.92901f}, - {-12264.0f, -1953.08f, 134.072f, 0.62663f}, - {-12289.0f, -1924.00f, 132.620f, 5.37829f}, - {-12267.3f, -1902.26f, 131.328f, 5.32724f}, - {-12255.3f, -1893.53f, 134.026f, 5.06413f}, - {-12229.9f, -1891.39f, 134.704f, 4.40047f}, - {-12215.9f, -1889.09f, 137.273f, 4.70285f}, - {-12200.5f, -1890.69f, 135.777f, 4.84422f}, - {-12186.0f, -1890.12f, 134.261f, 4.36513f}, - {-12246.3f, -1890.09f, 135.475f, 4.73427f}, - {-12170.7f, -1894.85f, 133.852f, 3.51690f}, - {-12279.0f, -1931.92f, 136.130f, 0.04151f}, - {-12266.1f, -1940.72f, 132.606f, 0.70910f} + { -12150.9f, -1956.24f, 133.407f, 2.57835f}, + { -12157.1f, -1972.78f, 133.947f, 2.64903f}, + { -12172.3f, -1982.63f, 134.061f, 1.48664f}, + { -12194.0f, -1979.54f, 132.194f, 1.45916f}, + { -12211.3f, -1978.49f, 133.580f, 1.35705f}, + { -12228.4f, -1977.10f, 132.728f, 1.25495f}, + { -12250.0f, -1964.78f, 135.066f, 0.92901f}, + { -12264.0f, -1953.08f, 134.072f, 0.62663f}, + { -12289.0f, -1924.00f, 132.620f, 5.37829f}, + { -12267.3f, -1902.26f, 131.328f, 5.32724f}, + { -12255.3f, -1893.53f, 134.026f, 5.06413f}, + { -12229.9f, -1891.39f, 134.704f, 4.40047f}, + { -12215.9f, -1889.09f, 137.273f, 4.70285f}, + { -12200.5f, -1890.69f, 135.777f, 4.84422f}, + { -12186.0f, -1890.12f, 134.261f, 4.36513f}, + { -12246.3f, -1890.09f, 135.475f, 4.73427f}, + { -12170.7f, -1894.85f, 133.852f, 3.51690f}, + { -12279.0f, -1931.92f, 136.130f, 0.04151f}, + { -12266.1f, -1940.72f, 132.606f, 0.70910f} }; -static SpawnLocations aMandokirDownstairsPos = {-12196.30f, -1948.37f, 130.31f, 3.77f}; - -struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI +struct boss_mandokirAI : public ScriptedAI { boss_mandokirAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -96,65 +94,78 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiWatch_Timer; - uint32 m_uiCleave_Timer; - uint32 m_uiWhirlwind_Timer; - uint32 m_uiFear_Timer; - uint32 m_uiMortalStrike_Timer; - uint32 m_uiCheck_Timer; + uint32 m_uiWatchTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiFearTimer; + uint32 m_uiMortalStrikeTimer; + uint32 m_uiCheckTimer; uint8 m_uiKillCount; - bool m_bRaptorDead; - bool m_bMandokirDownstairs; - float m_fTargetThreat; ObjectGuid m_watchTargetGuid; - ObjectGuid m_ohganGuid; - void Reset() + void Reset() override { - m_uiWatch_Timer = 33000; - m_uiCleave_Timer = 7000; - m_uiWhirlwind_Timer = 20000; - m_uiFear_Timer = 1000; - m_uiMortalStrike_Timer = 1000; - m_uiCheck_Timer = 1000; + m_uiWatchTimer = 33000; + m_uiCleaveTimer = 7000; + m_uiWhirlwindTimer = 20000; + m_uiFearTimer = 1000; + m_uiMortalStrikeTimer = 1000; + m_uiCheckTimer = 1000; - m_uiKillCount = 0; + m_uiKillCount = 0; + + m_fTargetThreat = 0.0f; + } - m_bRaptorDead = false; - m_bMandokirDownstairs = false; + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); - m_fTargetThreat = 0.0f; - m_watchTargetGuid.Clear(); + for (uint8 i = 0; i < countof(aSpirits); ++i) + m_creature->SummonCreature(NPC_CHAINED_SPIRIT, aSpirits[i].fX, aSpirits[i].fY, aSpirits[i].fZ, aSpirits[i].fAng, TEMPSUMMON_CORPSE_DESPAWN, 0); - if (Creature* pOhgan = m_creature->GetMap()->GetCreature(m_ohganGuid)) - pOhgan->ForcedDespawn(); + // At combat start Mandokir is mounted so we must unmount it first + m_creature->Unmount(); + + // And summon his raptor + m_creature->SummonCreature(NPC_OHGAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 35000); + + if (m_pInstance) + m_pInstance->SetData(TYPE_OHGAN, IN_PROGRESS); } - // should evade to bottom of the stairs when raid fail - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_OHGAN, FAIL); + } - std::list lSpirits; //despawn spirits - GetCreatureListWithEntryInGrid(lSpirits, m_creature, NPC_CHAINED_SPIRIT, DEFAULT_VISIBILITY_INSTANCE); + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_OHGAN, DONE); + } - if (!lSpirits.empty()) - { - for(std::list::iterator iter = lSpirits.begin(); iter != lSpirits.end(); ++iter) - { - if ((*iter) && (*iter)->isAlive()) - (*iter)->ForcedDespawn(); - } - } + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + // should evade to bottom of the stairs when raid fail + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(0, aMandokirDownstairsPos[0], aMandokirDownstairsPos[1], aMandokirDownstairsPos[2]); - m_bMandokirDownstairs = false; + m_creature->SetLootRecipient(NULL); + + Reset(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) { @@ -174,52 +185,36 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI } DoCastSpellIfCan(m_creature, SPELL_LEVEL_UP, CAST_TRIGGERED); - m_creature->SetLevel(m_creature->getLevel() + 1); m_uiKillCount = 0; } if (m_creature->isInCombat()) { - if (Creature *pSpirit = GetClosestCreatureWithEntry(pVictim, NPC_CHAINED_SPIRIT, 50.0f)) + if (Creature* pSpirit = GetClosestCreatureWithEntry(pVictim, NPC_CHAINED_SPIRIT, 50.0f)) pSpirit->CastSpell(pVictim, SPELL_REVIVE, false); } } } - void Aggro(Unit* pWho) - { - DoScriptText(SAY_AGGRO, m_creature); - - uint32 uiCount = sizeof(aSpirits)/sizeof(SpawnLocations); - - for(uint8 i = 0; i < uiCount; ++i) - m_creature->SummonCreature(NPC_CHAINED_SPIRIT, aSpirits[i].fX, aSpirits[i].fY, aSpirits[i].fZ, aSpirits[i].fAng, TEMPSUMMON_CORPSE_DESPAWN, 0); - - //At combat start Mandokir is mounted so we must unmount it first - m_creature->Unmount(); - - //And summon his raptor - m_creature->SummonCreature(NPC_OHGAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); - } - - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_OHGAN) { - m_ohganGuid = pSummoned->GetObjectGuid(); - if (m_creature->getVictim()) pSummoned->AI()->AttackStart(m_creature->getVictim()); } } - void SummonedCreatureDespawn(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_OHGAN) - m_ohganGuid.Clear(); + { + DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_TRIGGERED); + DoScriptText(EMOTE_RAGE, m_creature); + } } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_WATCH) { @@ -228,49 +223,39 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI m_watchTargetGuid = pTarget->GetObjectGuid(); m_fTargetThreat = m_creature->getThreatManager().getThreat(pTarget); - m_uiWatch_Timer = 6000; + m_uiWatchTimer = 6000; - //Could use this instead of hard coded timer for the above (but no script access), - //but would still a hack since we should better use the dummy, at aura removal - //SpellDurationEntry* const pDuration = sSpellDurationStore.LookupEntry(pSpell->DurationIndex); + // Could use this instead of hard coded timer for the above (but no script access), + // but would still a hack since we should better use the dummy, at aura removal + // SpellDurationEntry* const pDuration = sSpellDurationStore.LookupEntry(pSpell->DurationIndex); } } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) return; if (uiPointId == POINT_DOWNSTAIRS) { - // evaded at least once, and then attackable - if (m_pInstance->GetData(TYPE_OHGAN) == FAIL) - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - else - m_creature->SetInCombatWithZone(); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->SetInCombatWithZone(); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_bMandokirDownstairs && m_pInstance && (m_pInstance->GetData(TYPE_OHGAN) == SPECIAL || m_pInstance->GetData(TYPE_OHGAN) == FAIL)) - { - m_bMandokirDownstairs = true; - m_creature->SetWalk(false); - m_creature->GetMotionMaster()->MovePoint(POINT_DOWNSTAIRS, aMandokirDownstairsPos.fX, aMandokirDownstairsPos.fY, aMandokirDownstairsPos.fZ); - } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiWatch_Timer < uiDiff) + if (m_uiWatchTimer < uiDiff) { - //If someone is watched + // If someone is watched if (m_watchTargetGuid) { Player* pWatchTarget = m_creature->GetMap()->GetPlayer(m_watchTargetGuid); - //If threat is higher that previously saved, mandokir will act + // If threat is higher that previously saved, mandokir will act if (pWatchTarget && pWatchTarget->isAlive() && m_creature->getThreatManager().getThreat(pWatchTarget) > m_fTargetThreat) { if (!m_creature->IsWithinLOSInMap(pWatchTarget)) @@ -290,38 +275,38 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI } } - m_uiWatch_Timer = 20000; + m_uiWatchTimer = 20000; } else - m_uiWatch_Timer -= uiDiff; + m_uiWatchTimer -= uiDiff; if (!m_watchTargetGuid) { - //Cleave - if (m_uiCleave_Timer < uiDiff) + // Cleave + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleave_Timer = 7000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 7000; } else - m_uiCleave_Timer -= uiDiff; + m_uiCleaveTimer -= uiDiff; - //Whirlwind - if (m_uiWhirlwind_Timer < uiDiff) + // Whirlwind + if (m_uiWhirlwindTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlwind_Timer = 18000; + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = 18000; } else - m_uiWhirlwind_Timer -= uiDiff; + m_uiWhirlwindTimer -= uiDiff; - //If more then 3 targets in melee range mandokir will cast fear - if (m_uiFear_Timer < uiDiff) + // If more then 3 targets in melee range mandokir will cast fear + if (m_uiFearTimer < uiDiff) { uint8 uiTargetInRangeCount = 0; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + for (ThreatList::const_iterator i = tList.begin(); i != tList.end(); ++i) { Unit* pTarget = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); @@ -330,63 +315,43 @@ struct MANGOS_DLL_DECL boss_mandokirAI : public ScriptedAI } if (uiTargetInRangeCount > 3) - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEAR); + DoCastSpellIfCan(m_creature, SPELL_FEAR); - m_uiFear_Timer = 4000; + m_uiFearTimer = 4000; } else - m_uiFear_Timer -= uiDiff; + m_uiFearTimer -= uiDiff; - //Mortal Strike if target below 50% hp + // Mortal Strike if target below 50% hp if (m_creature->getVictim()->GetHealthPercent() < 50.0f) { - if (m_uiMortalStrike_Timer < uiDiff) + if (m_uiMortalStrikeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - m_uiMortalStrike_Timer = 15000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiMortalStrikeTimer = 15000; } else - m_uiMortalStrike_Timer -= uiDiff; + m_uiMortalStrikeTimer -= uiDiff; } } - //Checking if Ohgan is dead. If yes Mandokir will enrage. - if (!m_bRaptorDead && m_pInstance && m_pInstance->GetData(TYPE_OHGAN) == DONE) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - DoScriptText(EMOTE_RAGE, m_creature); - m_bRaptorDead = true; - } - DoMeleeAttackIfReady(); } }; -//Ohgan -struct MANGOS_DLL_DECL mob_ohganAI : public ScriptedAI +// Ohgan +struct mob_ohganAI : public ScriptedAI { - mob_ohganAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + mob_ohganAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - ScriptedInstance* m_pInstance; - - uint32 m_uiSunderArmor_Timer; + uint32 m_uiSunderArmorTimer; - void Reset() + void Reset() override { - m_uiSunderArmor_Timer = 5000; - } - - void JustDied(Unit* pKiller) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_OHGAN, DONE); + m_uiSunderArmorTimer = 5000; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) { @@ -398,19 +363,19 @@ struct MANGOS_DLL_DECL mob_ohganAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // SunderArmor - if (m_uiSunderArmor_Timer < uiDiff) + if (m_uiSunderArmorTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDERARMOR); - m_uiSunderArmor_Timer = urand(10000, 15000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SUNDERARMOR) == CAST_OK) + m_uiSunderArmorTimer = urand(10000, 15000); } else - m_uiSunderArmor_Timer -= uiDiff; + m_uiSunderArmorTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp b/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp index aaae7219e..32e59d9fc 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_marli.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Marli -SD%Complete: 100 -SDComment: Vilebranch Speaker respawned when wipe? +SD%Complete: 90 +SDComment: Enlarge for small spiders NYI SDCategory: Zul'Gurub EndScriptData */ @@ -26,316 +26,210 @@ EndScriptData */ enum { - GO_EGG = 179985, - - // the spider - NPC_SPAWN_OF_MARLI = 15041, - SAY_AGGRO = -1309005, SAY_TRANSFORM = -1309006, - SAY_TRANSFORMBACK = -1309024, + SAY_TRANSFORM_BACK = -1309025, SAY_SPIDER_SPAWN = -1309007, SAY_DEATH = -1309008, + // Spider form spells + SPELL_CORROSIVE_POISON = 24111, SPELL_CHARGE = 22911, - SPELL_ENVELOPINGWEBS = 24110, - SPELL_POISONVOLLEY = 24099, - SPELL_SPIDER_FORM = 24084, + SPELL_ENVELOPING_WEBS = 24110, + SPELL_POISON_SHOCK = 24112, // purpose of this spell is unk + + // Troll form spells + SPELL_POISON_VOLLEY = 24099, SPELL_DRAIN_LIFE = 24300, - SPELL_CORROSIVE_POISON = 24111, + SPELL_ENLARGE = 24109, // purpose of this spell is unk + SPELL_SPIDER_EGG = 24082, // removed from DBC - should trigger 24081 which summons 15041 + + // common spells + SPELL_SPIDER_FORM = 24084, SPELL_TRANSFORM_BACK = 24085, SPELL_TRASH = 3391, - SPELL_HATCH = 24083, //visual - - //The Spider Spells - SPELL_LEVELUP = 24312 //visual + SPELL_HATCH_EGGS = 24083, // note this should only target 4 eggs! }; -struct MANGOS_DLL_DECL boss_marliAI : public ScriptedAI +struct boss_marliAI : public ScriptedAI { boss_marliAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_uiDefaultModel = m_creature->GetDisplayId(); Reset(); } ScriptedInstance* m_pInstance; - uint32 m_uiPoisonVolley_Timer; - uint32 m_uiSpawnSpider_Timer; - uint32 m_uiCharge_Timer; - uint32 m_uiAspect_Timer; - uint32 m_uiTransform_Timer; - uint32 m_uiTransformBack_Timer; - uint32 m_uiDrainLife_Timer; - uint32 m_uiCorrosivePoison_Timer; - uint32 m_uiWebs_Timer; - uint32 m_uiTrash_Timer; + uint32 m_uiPoisonVolleyTimer; + uint32 m_uiSpawnSpiderTimer; + uint32 m_uiChargeTimer; + uint32 m_uiTransformTimer; + uint32 m_uiDrainLifeTimer; + uint32 m_uiCorrosivePoisonTimer; + uint32 m_uiWebsTimer; + uint32 m_uiTrashTimer; - bool m_bFirstSpidersAreSpawned; bool m_bIsInPhaseTwo; - bool m_bHasWebbed; - uint32 m_uiDefaultModel; - - void Reset() + void Reset() override { - m_uiPoisonVolley_Timer = 15000; - m_uiSpawnSpider_Timer = 20000; - m_uiAspect_Timer = 12000; - m_uiTransform_Timer = 60000; - m_uiTransformBack_Timer = 60000; - m_uiDrainLife_Timer = 30000; - m_uiCorrosivePoison_Timer = 1000; - m_uiWebs_Timer = 5000; - m_uiTrash_Timer = 5000; - - m_bFirstSpidersAreSpawned = false; - m_bIsInPhaseTwo = false; - m_bHasWebbed = false; - - std::list lSpiderEggs; - GetGameObjectListWithEntryInGrid(lSpiderEggs, m_creature, GO_EGG, DEFAULT_VISIBILITY_INSTANCE); - if (lSpiderEggs.empty()) - debug_log("SD2: boss_marli, no Eggs with the entry %u were found", GO_EGG); - else - { - for(std::list::iterator iter = lSpiderEggs.begin(); iter != lSpiderEggs.end(); ++iter) - { - if ((*iter)->GetGoState() == GO_STATE_ACTIVE) - (*iter)->SetGoState(GO_STATE_READY); - } - } + m_uiPoisonVolleyTimer = 15000; + m_uiSpawnSpiderTimer = 55000; + m_uiTransformTimer = 60000; + m_uiDrainLifeTimer = 30000; + m_uiCorrosivePoisonTimer = 1000; + m_uiWebsTimer = 5000; + m_uiTrashTimer = 5000; + + m_bIsInPhaseTwo = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - if (!m_bFirstSpidersAreSpawned) - { - DoScriptText(SAY_SPIDER_SPAWN, m_creature); - DoCastSpellIfCan(m_creature, SPELL_HATCH); - - for(uint8 i = 0; i < 4 ; ++i) - { - if (GameObject *pEgg = SelectNextEgg()) - { - pEgg->SetGoState(GO_STATE_ACTIVE); - m_creature->SummonCreature(NPC_SPAWN_OF_MARLI, pEgg->GetPositionX(), pEgg->GetPositionY(), pEgg->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - } - } - - m_bFirstSpidersAreSpawned = true; - } + DoCastSpellIfCan(m_creature, SPELL_HATCH_EGGS); } - GameObject* SelectNextEgg() + void JustDied(Unit* /*pKiller*/) override { - std::list lEggs; - GetGameObjectListWithEntryInGrid(lEggs, m_creature, GO_EGG, DEFAULT_VISIBILITY_INSTANCE); - if (lEggs.empty()) - debug_log("SD2: boss_marli, no Eggs with the entry %i were found", GO_EGG); - else - { - lEggs.sort(ObjectDistanceOrder(m_creature)); - for(std::list::iterator iter = lEggs.begin(); iter != lEggs.end(); ++iter) - { - if ((*iter)->GetGoState() == (GO_STATE_READY)) - return (*iter); - } - } - return NULL; - } + DoScriptText(SAY_DEATH, m_creature); - void JustSummoned(Creature* pSummoned) - { - if (pSummoned->GetEntry() == NPC_SPAWN_OF_MARLI) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - pSummoned->AI()->AttackStart(pTarget); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_MARLI, DONE); } - void JustDied(Unit* pKiller) + void JustReachedHome() override { - DoScriptText(SAY_DEATH, m_creature); - if (m_pInstance) - m_pInstance->SetData(TYPE_MARLI, DONE); + m_pInstance->SetData(TYPE_MARLI, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Troll phase if (!m_bIsInPhaseTwo) { - if (m_uiPoisonVolley_Timer < uiDiff) + if (m_uiPoisonVolleyTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_POISONVOLLEY); - m_uiPoisonVolley_Timer = urand(10000, 20000); + if (DoCastSpellIfCan(m_creature, SPELL_POISON_VOLLEY) == CAST_OK) + m_uiPoisonVolleyTimer = urand(10000, 20000); } else - m_uiPoisonVolley_Timer -= uiDiff; + m_uiPoisonVolleyTimer -= uiDiff; - if (m_uiDrainLife_Timer < uiDiff) + if (m_uiDrainLifeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DRAIN_LIFE); - m_uiDrainLife_Timer = urand(20000, 50000); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DRAIN_LIFE) == CAST_OK) + m_uiDrainLifeTimer = urand(20000, 50000); + } } else - m_uiDrainLife_Timer -= uiDiff; + m_uiDrainLifeTimer -= uiDiff; - if (m_uiSpawnSpider_Timer < uiDiff) + if (m_uiSpawnSpiderTimer < uiDiff) { - if (GameObject *pEgg = SelectNextEgg()) + // Workaround for missing spell 24082 - creature always selects the closest egg for hatch + if (m_pInstance) { - pEgg->SetGoState(GO_STATE_ACTIVE); - m_creature->SummonCreature(NPC_SPAWN_OF_MARLI, pEgg->GetPositionX(), pEgg->GetPositionY(), pEgg->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (GameObject* pEgg = GetClosestGameObjectWithEntry(m_creature, GO_SPIDER_EGG, 30.0f)) + { + if (urand(0, 1)) + DoScriptText(SAY_SPIDER_SPAWN, m_creature); + + pEgg->Use(m_creature); + m_uiSpawnSpiderTimer = 60000; + } } - m_uiSpawnSpider_Timer = urand(20000, 30000); } else - m_uiSpawnSpider_Timer -= uiDiff; + m_uiSpawnSpiderTimer -= uiDiff; } + // Spider phase else { - if (!m_bHasWebbed && m_uiWebs_Timer < uiDiff) + if (m_uiWebsTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ENVELOPINGWEBS); - m_uiWebs_Timer = urand(10000, 15000); - m_uiCharge_Timer = 1000; - m_bHasWebbed = true; + if (DoCastSpellIfCan(m_creature, SPELL_ENVELOPING_WEBS) == CAST_OK) + { + m_uiWebsTimer = urand(15000, 20000); + m_uiChargeTimer = 1000; + } } else - m_uiWebs_Timer -= uiDiff; + m_uiWebsTimer -= uiDiff; - if (m_bHasWebbed && m_uiCharge_Timer < uiDiff) + if (m_uiChargeTimer) { - //Shouldn't be random target but highestaggro not Webbed player - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (m_uiChargeTimer < uiDiff) { - DoCastSpellIfCan(pTarget, SPELL_CHARGE); - DoResetThreat(); - AttackStart(pTarget); - m_bHasWebbed = false; - /* - DoResetThreat(); - Unit* pTarget = NULL; - uint8 i = 0 ; - while (i < 5) // max 3 tries to get a random target with power_mana + // ToDo: research if the selected target shouldn't have the enveloping webs aura + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_CHARGE, SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) { - ++i; //not aggro leader - pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (pTarget && pTarget->getPowerType() == POWER_MANA) - i=5; + DoResetThreat(); + m_uiChargeTimer = 0; } - */ + } } - m_uiWebs_Timer = urand(10000, 20000); + else + m_uiChargeTimer -= uiDiff; } - else - m_uiCharge_Timer -= uiDiff; - if (m_uiCorrosivePoison_Timer < uiDiff) + if (m_uiCorrosivePoisonTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CORROSIVE_POISON); - m_uiCorrosivePoison_Timer = urand(25000, 35000); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CORROSIVE_POISON) == CAST_OK) + m_uiCorrosivePoisonTimer = urand(25000, 35000); + } } else - m_uiCorrosivePoison_Timer -= uiDiff; + m_uiCorrosivePoisonTimer -= uiDiff; } - if (m_uiTransformBack_Timer < uiDiff) + // Transform from Troll to Spider and back + if (m_uiTransformTimer < uiDiff) { if (!m_bIsInPhaseTwo) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(SAY_TRANSFORM, m_creature); - DoCastSpellIfCan(m_creature,SPELL_SPIDER_FORM); - - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35))); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35))); - m_creature->UpdateDamagePhysical(BASE_ATTACK); - - DoResetThreat(); - - m_bIsInPhaseTwo = true; + if (DoCastSpellIfCan(m_creature, SPELL_SPIDER_FORM) == CAST_OK) + { + DoScriptText(SAY_TRANSFORM, m_creature); + DoResetThreat(); + m_uiTransformTimer = 60000; + m_uiWebsTimer = 5000; + m_bIsInPhaseTwo = true; + } } else { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoScriptText(SAY_TRANSFORMBACK, m_creature); - DoCastSpellIfCan(m_creature,SPELL_TRANSFORM_BACK); - - m_creature->SetDisplayId(m_uiDefaultModel); - - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 1))); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 1))); - m_creature->UpdateDamagePhysical(BASE_ATTACK); - - m_bIsInPhaseTwo = false; + if (DoCastSpellIfCan(m_creature, SPELL_TRANSFORM_BACK) == CAST_OK) + { + DoScriptText(SAY_TRANSFORM_BACK, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_SPIDER_FORM); + m_bIsInPhaseTwo = false; + m_uiTransformTimer = 60000; + } } - - m_uiTransformBack_Timer = urand(55000, 70000); } else - m_uiTransformBack_Timer -= uiDiff; - - if (m_uiTrash_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH); - m_uiTrash_Timer = urand(10000, 20000); - } - else - m_uiTrash_Timer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -//Spawn of Marli -struct MANGOS_DLL_DECL mob_spawn_of_marliAI : public ScriptedAI -{ - mob_spawn_of_marliAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - m_pInstance = (ScriptedInstance*)m_creature->GetInstanceData(); - } + m_uiTransformTimer -= uiDiff; - ScriptedInstance* m_pInstance; - uint32 m_uiLevelUp_Timer; - - void Reset() - { - m_uiLevelUp_Timer = 3000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiLevelUp_Timer < uiDiff) + if (m_uiTrashTimer < uiDiff) { - if (m_pInstance && m_pInstance->GetData(TYPE_MARLI) != DONE) - { - DoCastSpellIfCan(m_creature,SPELL_LEVELUP); - m_creature->SetLevel(m_creature->getLevel() + 1); - } - m_uiLevelUp_Timer = 3000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiTrashTimer = urand(10000, 20000); } else - m_uiLevelUp_Timer -= uiDiff; + m_uiTrashTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -346,11 +240,6 @@ CreatureAI* GetAI_boss_marli(Creature* pCreature) return new boss_marliAI(pCreature); } -CreatureAI* GetAI_mob_spawn_of_marli(Creature* pCreature) -{ - return new mob_spawn_of_marliAI(pCreature); -} - void AddSC_boss_marli() { Script* pNewScript; @@ -359,9 +248,4 @@ void AddSC_boss_marli() pNewScript->Name = "boss_marli"; pNewScript->GetAI = &GetAI_boss_marli; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_spawn_of_marli"; - pNewScript->GetAI = &GetAI_mob_spawn_of_marli; - pNewScript->RegisterSelf(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp b/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp index 1bd4063c8..fcc418da8 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_renataki.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_TRASH = 3391 }; -struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI +struct boss_renatakiAI : public ScriptedAI { boss_renatakiAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -40,7 +40,7 @@ struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI uint32 m_uiGougeTimer; uint32 m_uiThousandBladesTimer; - void Reset() + void Reset() override { m_uiVanishTimer = urand(25000, 30000); m_uiAmbushTimer = 0; @@ -48,7 +48,7 @@ struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI m_uiThousandBladesTimer = urand(4000, 8000); } - void EnterEvadeMode() + void EnterEvadeMode() override { // If is vanished, don't evade if (m_uiAmbushTimer) @@ -57,7 +57,7 @@ struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI ScriptedAI::EnterEvadeMode(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -95,7 +95,7 @@ struct MANGOS_DLL_DECL boss_renatakiAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, SPELL_GOUGE) == CAST_OK) { if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-50); + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -50); m_uiGougeTimer = urand(7000, 20000); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp b/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp index 0a673a966..5efaf1d81 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_thekal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_MORTAL_CLEAVE = 22859, SPELL_SILENCE = 23207, - SPELL_FRENZY = 23342, + SPELL_FRENZY = 23128, SPELL_FORCE_PUNCH = 24189, SPELL_CHARGE = 24408, SPELL_ENRAGE = 23537, @@ -45,7 +45,7 @@ enum SPELL_GREATER_HEAL = 24208, SPELL_DISARM = 22691, - //Zealot Lor'Khan Spells + // Zealot Lor'Khan Spells SPELL_SWEEPING_STRIKES = 18765, SPELL_SINISTER_STRIKE = 15667, SPELL_GOUGE = 24698, @@ -59,7 +59,7 @@ enum }; // abstract base class for faking death -struct MANGOS_DLL_DECL boss_thekalBaseAI : public ScriptedAI +struct boss_thekalBaseAI : public ScriptedAI { boss_thekalBaseAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -71,7 +71,7 @@ struct MANGOS_DLL_DECL boss_thekalBaseAI : public ScriptedAI virtual void OnFakeingDeath() {} virtual void OnRevive() {} - void DamageTaken(Unit* pKiller, uint32& uiDamage) + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; @@ -137,7 +137,7 @@ struct MANGOS_DLL_DECL boss_thekalBaseAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI +struct boss_thekalAI : public boss_thekalBaseAI { boss_thekalAI(Creature* pCreature) : boss_thekalBaseAI(pCreature) { @@ -158,7 +158,7 @@ struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI bool m_bEnraged; - void Reset() + void Reset() override { m_uiMortalCleaveTimer = 4000; m_uiSilenceTimer = 9000; @@ -176,12 +176,12 @@ struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI Revive(true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -197,7 +197,7 @@ struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI pLorkhan->ForcedDespawn(); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_THEKAL, FAIL); @@ -252,7 +252,7 @@ struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -335,7 +335,7 @@ struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI if (m_uiSummonTigersTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_TIGERS) == CAST_OK) - m_uiSummonTigersTimer = urand(10000, 14000); + m_uiSummonTigersTimer = 50000; } else m_uiSummonTigersTimer -= uiDiff; @@ -357,7 +357,7 @@ struct MANGOS_DLL_DECL boss_thekalAI : public boss_thekalBaseAI ## mob_zealot_lorkhan ######*/ -struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI +struct mob_zealot_lorkhanAI : public boss_thekalBaseAI { mob_zealot_lorkhanAI(Creature* pCreature) : boss_thekalBaseAI(pCreature) { @@ -373,7 +373,7 @@ struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI uint32 m_uiDisarmTimer; uint32 m_uiResurrectTimer; - void Reset() + void Reset() override { m_uiShieldTimer = 1000; m_uiBloodLustTimer = 16000; @@ -387,7 +387,7 @@ struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI Revive(true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LORKHAN, IN_PROGRESS); @@ -401,7 +401,7 @@ struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI m_pInstance->SetData(TYPE_LORKHAN, SPECIAL); } - void UpdateAI (const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -458,14 +458,14 @@ struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI Creature* pThekal = m_pInstance->GetSingleCreatureFromStorage(NPC_THEKAL); Creature* pZath = m_pInstance->GetSingleCreatureFromStorage(NPC_ZATH); - switch(urand(0, 1)) + switch (urand(0, 1)) { case 0: - if (pThekal && m_creature->IsWithinDistInMap(pThekal, 3*ATTACK_DISTANCE)) + if (pThekal && m_creature->IsWithinDistInMap(pThekal, 3 * ATTACK_DISTANCE)) DoCastSpellIfCan(pThekal, SPELL_GREATER_HEAL); break; case 1: - if (pZath && m_creature->IsWithinDistInMap(pZath, 3*ATTACK_DISTANCE)) + if (pZath && m_creature->IsWithinDistInMap(pZath, 3 * ATTACK_DISTANCE)) DoCastSpellIfCan(pZath, SPELL_GREATER_HEAL); break; } @@ -496,7 +496,7 @@ struct MANGOS_DLL_DECL mob_zealot_lorkhanAI : public boss_thekalBaseAI ## npc_zealot_zath ######*/ -struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI +struct mob_zealot_zathAI : public boss_thekalBaseAI { mob_zealot_zathAI(Creature* pCreature) : boss_thekalBaseAI(pCreature) { @@ -513,7 +513,7 @@ struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI uint32 m_uiBlindTimer; uint32 m_uiResurrectTimer; - void Reset() + void Reset() override { m_uiSweepingStrikesTimer = 13000; m_uiSinisterStrikeTimer = 8000; @@ -528,7 +528,7 @@ struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI Revive(true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ZATH, IN_PROGRESS); @@ -542,7 +542,7 @@ struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI m_pInstance->SetData(TYPE_ZATH, SPECIAL); } - void UpdateAI (const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -595,7 +595,7 @@ struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GOUGE) == CAST_OK) { if (m_creature->getThreatManager().getThreat(m_creature->getVictim())) - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(),-100); + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -100); m_uiGougeTimer = urand(17000, 27000); } @@ -628,15 +628,15 @@ struct MANGOS_DLL_DECL mob_zealot_zathAI : public boss_thekalBaseAI } }; -bool EffectDummyCreature_thekal_resurrection(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_thekal_resurrection(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_RESURRECT && uiEffIndex == EFFECT_INDEX_0) { if (boss_thekalBaseAI* pFakerAI = dynamic_cast(pCreatureTarget->AI())) pFakerAI->Revive(); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp b/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp index 0305e5386..b8407e46b 100644 --- a/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp +++ b/scripts/eastern_kingdoms/zulgurub/boss_venoxis.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,90 +26,69 @@ EndScriptData */ enum { - NPC_RAZZASHI_COBRA = 11373, - - SAY_TRANSFORM = -1309000, - SAY_DEATH = -1309001, - - SPELL_HOLY_FIRE = 23860, - SPELL_HOLY_WRATH = 23979, - SPELL_VENOMSPIT = 23862, - SPELL_HOLY_NOVA = 23858, - SPELL_POISON_CLOUD = 23861, - SPELL_SNAKE_FORM = 23849, - SPELL_RENEW = 23895, - SPELL_BERSERK = 23537, - SPELL_DISPELL = 23859, - SPELL_PARASITIC = 23865, - SPELL_TRASH = 3391 + SAY_TRANSFORM = -1309000, + SAY_DEATH = -1309001, + + // troll spells + SPELL_HOLY_FIRE = 23860, + SPELL_HOLY_WRATH = 23979, + SPELL_HOLY_NOVA = 23858, + SPELL_DISPELL = 23859, + SPELL_RENEW = 23895, + + // serpent spells + SPELL_VENOMSPIT = 23862, + SPELL_POISON_CLOUD = 23861, + SPELL_PARASITIC_SERPENT = 23867, + + // common spells + SPELL_SNAKE_FORM = 23849, + SPELL_FRENZY = 23537, + SPELL_TRASH = 3391 }; -struct MANGOS_DLL_DECL boss_venoxisAI : public ScriptedAI +struct boss_venoxisAI : public ScriptedAI { boss_venoxisAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_fDefaultSize = m_creature->GetFloatValue(OBJECT_FIELD_SCALE_X); Reset(); } ScriptedInstance* m_pInstance; - uint32 m_uiHolyFire_Timer; - uint32 m_uiHolyWrath_Timer; - uint32 m_uiVenomSpit_Timer; - uint32 m_uiRenew_Timer; - uint32 m_uiPoisonCloud_Timer; - uint32 m_uiHolyNova_Timer; - uint32 m_uiDispell_Timer; - uint32 m_uiParasitic_Timer; - uint32 m_uiTrash_Timer; - - uint8 m_uiTargetsInRangeCount; + uint32 m_uiHolyWrathTimer; + uint32 m_uiVenomSpitTimer; + uint32 m_uiRenewTimer; + uint32 m_uiPoisonCloudTimer; + uint32 m_uiHolySpellTimer; + uint32 m_uiDispellTimer; + uint32 m_uiTrashTimer; bool m_bPhaseTwo; bool m_bInBerserk; - float m_fDefaultSize; - - void Reset() + void Reset() override { - m_uiHolyFire_Timer = 10000; - m_uiHolyWrath_Timer = 60500; - m_uiVenomSpit_Timer = 5500; - m_uiRenew_Timer = 30500; - m_uiPoisonCloud_Timer = 2000; - m_uiHolyNova_Timer = 5000; - m_uiDispell_Timer = 35000; - m_uiParasitic_Timer = 10000; - m_uiTrash_Timer = 5000; - - m_uiTargetsInRangeCount = 0; - - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, m_fDefaultSize); - - m_bPhaseTwo = false; - m_bInBerserk = false; + m_uiHolyWrathTimer = 40000; + m_uiVenomSpitTimer = 5500; + m_uiRenewTimer = 30000; + m_uiPoisonCloudTimer = 2000; + m_uiHolySpellTimer = 10000; + m_uiDispellTimer = 35000; + m_uiTrashTimer = 5000; + + m_bPhaseTwo = false; + m_bInBerserk = false; } - void JustReachedHome() + void JustReachedHome() override { - std::list m_lCobras; - GetCreatureListWithEntryInGrid(m_lCobras, m_creature, NPC_RAZZASHI_COBRA, DEFAULT_VISIBILITY_INSTANCE); - - if (m_lCobras.empty()) - debug_log("SD2: boss_venoxis, no Cobras with the entry %u were found", NPC_RAZZASHI_COBRA); - else - { - for(std::list::iterator iter = m_lCobras.begin(); iter != m_lCobras.end(); ++iter) - { - if ((*iter) && !(*iter)->isAlive()) - (*iter)->Respawn(); - } - } + if (m_pInstance) + m_pInstance->SetData(TYPE_VENOXIS, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -117,134 +96,116 @@ struct MANGOS_DLL_DECL boss_venoxisAI : public ScriptedAI m_pInstance->SetData(TYPE_VENOXIS, DONE); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) - { - if (!m_bPhaseTwo && (m_creature->GetHealth()+uiDamage)*100 / m_creature->GetMaxHealth() < 50) - { - DoScriptText(SAY_TRANSFORM, m_creature); - - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature,SPELL_SNAKE_FORM); - - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, m_fDefaultSize*2); - const CreatureInfo *cinfo = m_creature->GetCreatureInfo(); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 25))); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 25))); - m_creature->UpdateDamagePhysical(BASE_ATTACK); - DoResetThreat(); - m_bPhaseTwo = true; - } - - if (m_bPhaseTwo && !m_bInBerserk && (m_creature->GetHealth()+uiDamage)*100 / m_creature->GetMaxHealth() < 11) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - m_bInBerserk = true; - } - } - - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Troll phase if (!m_bPhaseTwo) { - if (m_uiDispell_Timer < uiDiff) + if (m_uiDispellTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_DISPELL); - m_uiDispell_Timer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_DISPELL) == CAST_OK) + m_uiDispellTimer = urand(15000, 30000); } else - m_uiDispell_Timer -= uiDiff; + m_uiDispellTimer -= uiDiff; - if (m_uiRenew_Timer < uiDiff) + if (m_uiRenewTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_RENEW); - m_uiRenew_Timer = urand(20000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_RENEW) == CAST_OK) + m_uiRenewTimer = urand(20000, 30000); } else - m_uiRenew_Timer -= uiDiff; + m_uiRenewTimer -= uiDiff; - if (m_uiHolyWrath_Timer < uiDiff) + if (m_uiHolyWrathTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_WRATH); - m_uiHolyWrath_Timer = urand(15000, 25000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_WRATH) == CAST_OK) + m_uiHolyWrathTimer = urand(15000, 25000); } else - m_uiHolyWrath_Timer -= uiDiff; + m_uiHolyWrathTimer -= uiDiff; - if (m_uiHolyNova_Timer < uiDiff) + if (m_uiHolySpellTimer < uiDiff) { - m_uiTargetsInRangeCount = 0; - for(uint8 i = 0; i < 10; ++i) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO,i)) - if (m_creature->CanReachWithMeleeAttack(pTarget)) - ++m_uiTargetsInRangeCount; - } + uint8 uiTargetsInRange = 0; - if (m_uiTargetsInRangeCount > 1) + // See how many targets are in melee range + ThreatList const& tList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator iter = tList.begin(); iter != tList.end(); ++iter) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HOLY_NOVA); - m_uiHolyNova_Timer = 1000; + if (Unit* pTempTarget = m_creature->GetMap()->GetUnit((*iter)->getUnitGuid())) + { + if (pTempTarget->GetTypeId() == TYPEID_PLAYER && m_creature->CanReachWithMeleeAttack(pTempTarget)) + ++uiTargetsInRange; + } } + + // If there are more targets in melee range cast holy nova, else holy fire + // not sure which is the minimum targets for holy nova + if (uiTargetsInRange > 3) + DoCastSpellIfCan(m_creature, SPELL_HOLY_NOVA); else { - m_uiHolyNova_Timer = 2000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_HOLY_FIRE); } + + m_uiHolySpellTimer = urand(4000, 8000); } else - m_uiHolyNova_Timer -= uiDiff; + m_uiHolySpellTimer -= uiDiff; - if (m_uiHolyFire_Timer < uiDiff && m_uiTargetsInRangeCount < 3) + // Transform at 50% hp + if (m_creature->GetHealthPercent() < 50.0f) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget, SPELL_HOLY_FIRE); - - m_uiHolyFire_Timer = 8000; + if (DoCastSpellIfCan(m_creature, SPELL_SNAKE_FORM, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_PARASITIC_SERPENT, CAST_TRIGGERED); + DoScriptText(SAY_TRANSFORM, m_creature); + DoResetThreat(); + m_bPhaseTwo = true; + } } - else - m_uiHolyFire_Timer -= uiDiff; } + // Snake phase else { - if (m_uiPoisonCloud_Timer < uiDiff) + if (m_uiPoisonCloudTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_POISON_CLOUD); - m_uiPoisonCloud_Timer = 15000; + if (DoCastSpellIfCan(m_creature, SPELL_POISON_CLOUD) == CAST_OK) + m_uiPoisonCloudTimer = 15000; } else - m_uiPoisonCloud_Timer -= uiDiff; + m_uiPoisonCloudTimer -= uiDiff; - if (m_uiVenomSpit_Timer < uiDiff) + if (m_uiVenomSpitTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget, SPELL_VENOMSPIT); - - m_uiVenomSpit_Timer = urand(15000, 20000); - } - else - m_uiVenomSpit_Timer -= uiDiff; - - if (m_uiParasitic_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget, SPELL_PARASITIC); - - m_uiParasitic_Timer = 10000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_VENOMSPIT) == CAST_OK) + m_uiVenomSpitTimer = urand(15000, 20000); + } } else - m_uiParasitic_Timer -= uiDiff; + m_uiVenomSpitTimer -= uiDiff; } - if (m_uiTrash_Timer < uiDiff) + if (m_uiTrashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH); - m_uiTrash_Timer = urand(10000, 20000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiTrashTimer = urand(10000, 20000); } else - m_uiTrash_Timer -= uiDiff; + m_uiTrashTimer -= uiDiff; + + if (!m_bInBerserk && m_creature->GetHealthPercent() < 11.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + m_bInBerserk = true; + } DoMeleeAttackIfReady(); } diff --git a/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp b/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp deleted file mode 100644 index 4ffba6247..000000000 --- a/scripts/eastern_kingdoms/zulgurub/boss_wushoolay.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Wushoolay -SD%Complete: 100 -SDComment: -SDCategory: Zul'Gurub -EndScriptData */ - -#include "precompiled.h" -#include "zulgurub.h" - -#define SPELL_LIGHTNINGCLOUD 25033 -#define SPELL_LIGHTNINGWAVE 24819 - -struct MANGOS_DLL_DECL boss_wushoolayAI : public ScriptedAI -{ - boss_wushoolayAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 LightningCloud_Timer; - uint32 LightningWave_Timer; - - void Reset() - { - LightningCloud_Timer = urand(5000, 10000); - LightningWave_Timer = urand(8000, 16000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //LightningCloud_Timer - if (LightningCloud_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_LIGHTNINGCLOUD); - LightningCloud_Timer = urand(15000, 20000); - }else LightningCloud_Timer -= diff; - - //LightningWave_Timer - if (LightningWave_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) DoCastSpellIfCan(target,SPELL_LIGHTNINGWAVE); - - LightningWave_Timer = urand(12000, 16000); - }else LightningWave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_wushoolay(Creature* pCreature) -{ - return new boss_wushoolayAI(pCreature); -} - -void AddSC_boss_wushoolay() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_wushoolay"; - pNewScript->GetAI = &GetAI_boss_wushoolay; - pNewScript->RegisterSelf(); -} diff --git a/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp b/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp index 62de98485..56b8efd29 100644 --- a/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp +++ b/scripts/eastern_kingdoms/zulgurub/instance_zulgurub.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -52,13 +52,15 @@ void instance_zulgurub::DoYellAtTriggerIfCan(uint32 uiTriggerId) void instance_zulgurub::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_LORKHAN: case NPC_ZATH: case NPC_THEKAL: case NPC_JINDO: case NPC_HAKKAR: + case NPC_BLOODLORD_MANDOKIR: + case NPC_MARLI: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; case NPC_PANTHER_TRIGGER: @@ -77,6 +79,9 @@ void instance_zulgurub::OnObjectCreate(GameObject* pGo) case GO_GONG_OF_BETHEKK: case GO_FORCEFIELD: break; + case GO_SPIDER_EGG: + m_lSpiderEggGUIDList.push_back(pGo->GetObjectGuid()); + return; } m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); @@ -84,24 +89,59 @@ void instance_zulgurub::OnObjectCreate(GameObject* pGo) void instance_zulgurub::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_JEKLIK: case TYPE_VENOXIS: - case TYPE_MARLI: case TYPE_THEKAL: m_auiEncounter[uiType] = uiData; if (uiData == DONE) DoLowerHakkarHitPoints(); break; + case TYPE_MARLI: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoLowerHakkarHitPoints(); + if (uiData == FAIL) + { + for (GuidList::const_iterator itr = m_lSpiderEggGUIDList.begin(); itr != m_lSpiderEggGUIDList.end(); ++itr) + { + if (GameObject* pEgg = instance->GetGameObject(*itr)) + { + // Note: this type of Gameobject needs to be respawned manually + pEgg->SetRespawnTime(2 * DAY); + pEgg->Respawn(); + } + } + } + break; case TYPE_ARLOKK: m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_FORCEFIELD); if (uiData == DONE) DoLowerHakkarHitPoints(); - // ToDo: Reset the Gong on FAIL + if (uiData == FAIL) + { + // Note: this gameobject should change flags - currently it despawns which isn't correct + if (GameObject* pGong = GetSingleGameObjectFromStorage(GO_GONG_OF_BETHEKK)) + { + pGong->SetRespawnTime(2 * DAY); + pGong->Respawn(); + } + } break; case TYPE_OHGAN: + // Note: SPECIAL instance data is set via ACID! + if (uiData == SPECIAL) + { + if (Creature* pMandokir = GetSingleCreatureFromStorage(NPC_BLOODLORD_MANDOKIR)) + { + pMandokir->SetWalk(false); + pMandokir->GetMotionMaster()->MovePoint(1, aMandokirDownstairsPos[0], aMandokirDownstairsPos[1], aMandokirDownstairsPos[2]); + } + } + m_auiEncounter[uiType] = uiData; + break; case TYPE_LORKHAN: case TYPE_ZATH: m_auiEncounter[uiType] = uiData; @@ -114,8 +154,8 @@ void instance_zulgurub::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7]; m_strInstData = saveStream.str(); @@ -133,8 +173,8 @@ void instance_zulgurub::DoLowerHakkarHitPoints() { pHakkar->SetMaxHealth(pHakkar->GetMaxHealth() - HP_LOSS_PER_PRIEST); pHakkar->SetHealth(pHakkar->GetHealth() - HP_LOSS_PER_PRIEST); - } - } + } + } } void instance_zulgurub::Load(const char* chrIn) @@ -149,9 +189,9 @@ void instance_zulgurub::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -160,7 +200,7 @@ void instance_zulgurub::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_zulgurub::GetData(uint32 uiType) +uint32 instance_zulgurub::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -170,11 +210,11 @@ uint32 instance_zulgurub::GetData(uint32 uiType) Creature* instance_zulgurub::SelectRandomPantherTrigger(bool bIsLeft) { - GUIDList* plTempList = bIsLeft ? &m_lLeftPantherTriggerGUIDList : &m_lRightPantherTriggerGUIDList; + GuidList* plTempList = bIsLeft ? &m_lLeftPantherTriggerGUIDList : &m_lRightPantherTriggerGUIDList; std::vector vTriggers; vTriggers.reserve(plTempList->size()); - for (GUIDList::const_iterator itr = plTempList->begin(); itr != plTempList->end(); ++itr) + for (GuidList::const_iterator itr = plTempList->begin(); itr != plTempList->end(); ++itr) { if (Creature* pTemp = instance->GetCreature(*itr)) vTriggers.push_back(pTemp); @@ -183,7 +223,7 @@ Creature* instance_zulgurub::SelectRandomPantherTrigger(bool bIsLeft) if (vTriggers.empty()) return NULL; - return vTriggers[urand(0, vTriggers.size()-1)]; + return vTriggers[urand(0, vTriggers.size() - 1)]; } InstanceData* GetInstanceData_instance_zulgurub(Map* pMap) diff --git a/scripts/eastern_kingdoms/zulgurub/zulgurub.h b/scripts/eastern_kingdoms/zulgurub/zulgurub.h index b37eab7eb..4d58001a3 100644 --- a/scripts/eastern_kingdoms/zulgurub/zulgurub.h +++ b/scripts/eastern_kingdoms/zulgurub/zulgurub.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -25,7 +25,10 @@ enum NPC_JINDO = 11380, NPC_HAKKAR = 14834, NPC_PANTHER_TRIGGER = 15091, + NPC_BLOODLORD_MANDOKIR = 11382, + NPC_MARLI = 14510, + GO_SPIDER_EGG = 179985, GO_GONG_OF_BETHEKK = 180526, GO_FORCEFIELD = 180497, @@ -38,23 +41,25 @@ enum AREATRIGGER_ALTAR = 3960, }; -class MANGOS_DLL_DECL instance_zulgurub : public ScriptedInstance +static const float aMandokirDownstairsPos[3] = { -12196.30f, -1948.37f, 130.31f}; + +class instance_zulgurub : public ScriptedInstance { public: instance_zulgurub(Map* pMap); ~instance_zulgurub() {} - void Initialize(); - // IsEncounterInProgress() const { return false; } // not active in Zul'Gurub + void Initialize() override; + // IsEncounterInProgress() const override { return false; } // not active in Zul'Gurub - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; void DoYellAtTriggerIfCan(uint32 uiTriggerId); @@ -66,8 +71,9 @@ class MANGOS_DLL_DECL instance_zulgurub : public ScriptedInstance uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; - GUIDList m_lRightPantherTriggerGUIDList; - GUIDList m_lLeftPantherTriggerGUIDList; + GuidList m_lRightPantherTriggerGUIDList; + GuidList m_lLeftPantherTriggerGUIDList; + GuidList m_lSpiderEggGUIDList; bool m_bHasIntroYelled; bool m_bHasAltarYelled; diff --git a/scripts/examples/example_creature.cpp b/scripts/examples/example_creature.cpp index 7957535bc..9d1d41fa6 100644 --- a/scripts/examples/example_creature.cpp +++ b/scripts/examples/example_creature.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -69,7 +69,7 @@ enum // If (and only if) a gossip must be handled within SD2, then it should be moved to SD2-database! #define GOSSIP_ITEM "I'm looking for a fight" -struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI +struct example_creatureAI : public ScriptedAI { // *** HANDLED FUNCTION *** // This is the constructor, called only once when the creature is first created @@ -90,7 +90,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI // *** HANDLED FUNCTION *** // This is called whenever the core decides we need to evade - void Reset() + void Reset() override { m_uiPhase = 1; // Start in phase 1 m_uiPhaseTimer = 60000; // 60 seconds @@ -102,7 +102,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI // *** HANDLED FUNCTION *** // Aggro is called when we enter combat, against an enemy, and haven't been in combat before - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { // Say some stuff DoScriptText(SAY_AGGRO, m_creature, pWho); @@ -110,11 +110,11 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI // *** HANDLED FUNCTION *** // Our Recive emote function - void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) + void ReceiveEmote(Player* /*pPlayer*/, uint32 uiTextEmote) override { m_creature->HandleEmote(uiTextEmote); - switch(uiTextEmote) + switch (uiTextEmote) { case TEXTEMOTE_DANCE: DoScriptText(SAY_DANCE, m_creature); @@ -127,7 +127,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI // *** HANDLED FUNCTION *** // Update AI is called Every single map update (roughly once every 100ms if a player is within the grid) - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Out of combat timers if (!m_creature->getVictim()) @@ -136,7 +136,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI if (m_uiSayTimer < uiDiff) { // Random switch between 5 outcomes - switch(urand(0, 4)) + switch (urand(0, 4)) { case 0: DoScriptText(SAY_RANDOM_0, m_creature); break; case 1: DoScriptText(SAY_RANDOM_1, m_creature); break; @@ -145,7 +145,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI case 4: DoScriptText(SAY_RANDOM_4, m_creature); break; } - m_uiSayTimer = 45*IN_MILLISECONDS; // Say something agian in 45 seconds + m_uiSayTimer = 45 * IN_MILLISECONDS; // Say something agian in 45 seconds } else m_uiSayTimer -= uiDiff; @@ -155,7 +155,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI { DoCastSpellIfCan(m_creature, SPELL_BUFF); // Rebuff agian in 15 minutes - m_uiRebuffTimer = 15*MINUTE*IN_MILLISECONDS; + m_uiRebuffTimer = 15 * MINUTE * IN_MILLISECONDS; } else m_uiRebuffTimer -= uiDiff; @@ -170,7 +170,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI if (m_uiSpellOneTimer < uiDiff) { // Cast spell one on our current target. - if (rand()%50 > 10) + if (rand() % 50 > 10) DoCastSpellIfCan(m_creature->getVictim(), SPELL_ONE_ALT); else if (m_creature->IsWithinDist(m_creature->getVictim(), 25.0f)) DoCastSpellIfCan(m_creature->getVictim(), SPELL_ONE); @@ -185,7 +185,7 @@ struct MANGOS_DLL_DECL example_creatureAI : public ScriptedAI { // Cast spell two on self (AoE spell with only self-target) if we can if (DoCastSpellIfCan(m_creature, SPELL_TWO) == CAST_OK) - m_uiSpellTwoTimer = 37*IN_MILLISECONDS; // Only Update Timer, if we could start casting + m_uiSpellTwoTimer = 37 * IN_MILLISECONDS; // Only Update Timer, if we could start casting } else m_uiSpellTwoTimer -= uiDiff; @@ -263,13 +263,13 @@ bool GossipHello_example_creature(Player* pPlayer, Creature* pCreature) // This function is called when the player clicks an option on the gossip menu // In this case here the faction change could be handled by world-DB gossip, hence it should be handled there! -bool GossipSelect_example_creature(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_example_creature(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->CLOSE_GOSSIP_MENU(); // Set our faction to hostile towards all - pCreature->setFaction(FACTION_WORGEN); + pCreature->SetFactionTemporary(FACTION_WORGEN, TEMPFACTION_RESTORE_RESPAWN); pCreature->AI()->AttackStart(pPlayer); } diff --git a/scripts/examples/example_escort.cpp b/scripts/examples/example_escort.cpp index 4153366e5..e77a291f4 100644 --- a/scripts/examples/example_escort.cpp +++ b/scripts/examples/example_escort.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum #define GOSSIP_ITEM_2 "Click to Test Escort(NoAttack, Walk)" #define GOSSIP_ITEM_3 "Click to Test Escort(NoAttack, Run)" -struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI +struct example_escortAI : public npc_escortAI { // CreatureAI functions example_escortAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } @@ -59,19 +59,19 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI uint32 m_uiChatTimer; // Is called after each combat, so usally only reset combat-stuff here - void Reset() + void Reset() override { m_uiDeathCoilTimer = 4000; m_uiChatTimer = 4000; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } // Pure Virtual Functions (Have to be implemented) - void WaypointReached(uint32 uiWP) + void WaypointReached(uint32 uiWP) override { switch (uiWP) { @@ -80,21 +80,21 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI break; case 3: DoScriptText(SAY_WP_2, m_creature); - m_creature->SummonCreature(NPC_FELBOAR, m_creature->GetPositionX()+5.0f, m_creature->GetPositionY()+7.0f, m_creature->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000); + m_creature->SummonCreature(NPC_FELBOAR, m_creature->GetPositionX() + 5.0f, m_creature->GetPositionY() + 7.0f, m_creature->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 3000); break; case 4: if (Player* pTmpPlayer = GetPlayerForEscort()) { - //pTmpPlayer is the target of the text + // pTmpPlayer is the target of the text DoScriptText(SAY_WP_3, m_creature, pTmpPlayer); - //pTmpPlayer is the source of the text + // pTmpPlayer is the source of the text DoScriptText(SAY_WP_4, pTmpPlayer); } break; } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -106,7 +106,7 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI } // Only overwrite if there is something special - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -115,7 +115,7 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI // not a likely case, code here for the sake of example if (pKiller == m_creature) { - //This is actually a whisper. You control the text type in database + // This is actually a whisper. You control the text type in database DoScriptText(SAY_DEATH_1, m_creature, pTemp); } else @@ -129,7 +129,7 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI npc_escortAI::JustDied(pKiller); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { // Combat check if (m_creature->SelectHostileTarget() && m_creature->getVictim()) @@ -147,7 +147,7 @@ struct MANGOS_DLL_DECL example_escortAI : public npc_escortAI } else { - //Out of combat but being escorted + // Out of combat but being escorted if (HasEscortState(STATE_ESCORT_ESCORTING)) { if (m_uiChatTimer < uiDiff) @@ -182,20 +182,20 @@ bool GossipHello_example_escort(Player* pPlayer, Creature* pCreature) pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); pPlayer->PrepareGossipMenu(pCreature, pPlayer->GetDefaultGossipMenuForSource(pCreature)); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); pPlayer->SendPreparedGossip(pCreature); return true; } -bool GossipSelect_example_escort(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_example_escort(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { example_escortAI* pEscortAI = dynamic_cast(pCreature->AI()); - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: pPlayer->CLOSE_GOSSIP_MENU(); diff --git a/scripts/examples/example_gossip_codebox.cpp b/scripts/examples/example_gossip_codebox.cpp index 5b6e55a93..4c2028810 100644 --- a/scripts/examples/example_gossip_codebox.cpp +++ b/scripts/examples/example_gossip_codebox.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,8 +41,8 @@ enum // This function is called when the player opens the gossip menubool bool GossipHello_example_gossip_codebox(Player* pPlayer, Creature* pCreature) { - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1, "", 0, true); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1, "", 0, true); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->PlayerTalkClass->SendGossipMenu(907, pCreature->GetObjectGuid()); @@ -50,9 +50,9 @@ bool GossipHello_example_gossip_codebox(Player* pPlayer, Creature* pCreature) } // This function is called when the player clicks an option on the gossip menubool -bool GossipSelect_example_gossip_codebox(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_example_gossip_codebox(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 2) { DoScriptText(SAY_NOT_INTERESTED, pCreature); pPlayer->CLOSE_GOSSIP_MENU(); @@ -67,20 +67,20 @@ bool GossipSelectWithCode_example_gossip_codebox(Player* pPlayer, Creature* pCre { switch (uiAction) { - case GOSSIP_ACTION_INFO_DEF+1: - if (std::strcmp(sCode, pPlayer->GetName()) != 0) - { - DoScriptText(SAY_WRONG, pCreature); - pCreature->CastSpell(pPlayer, SPELL_POLYMORPH, true); - } - else - { - DoScriptText(SAY_CORRECT, pCreature); - pCreature->CastSpell(pPlayer, SPELL_MARK_OF_THE_WILD, true); - } - pPlayer->CLOSE_GOSSIP_MENU(); + case GOSSIP_ACTION_INFO_DEF+1: + if (std::strcmp(sCode, pPlayer->GetName()) != 0) + { + DoScriptText(SAY_WRONG, pCreature); + pCreature->CastSpell(pPlayer, SPELL_POLYMORPH, true); + } + else + { + DoScriptText(SAY_CORRECT, pCreature); + pCreature->CastSpell(pPlayer, SPELL_MARK_OF_THE_WILD, true); + } + pPlayer->CLOSE_GOSSIP_MENU(); - return true; + return true; } } diff --git a/scripts/examples/example_misc.cpp b/scripts/examples/example_misc.cpp index e9bd36723..26dc5b5b3 100644 --- a/scripts/examples/example_misc.cpp +++ b/scripts/examples/example_misc.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -28,20 +28,20 @@ enum SAY_HI = -1999925 }; -bool AreaTrigger_at_example(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_example(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { DoScriptText(SAY_HI, pPlayer); return true; } extern void LoadDatabase(); -bool ItemUse_example_item(Player* pPlayer, Item* pItem, SpellCastTargets const& scTargets) +bool ItemUse_example_item(Player* /*pPlayer*/, Item* /*pItem*/, SpellCastTargets const& /*scTargets*/) { LoadDatabase(); return true; } -bool GOUse_example_go_teleporter(Player* pPlayer, GameObject* pGo) +bool GOUse_example_go_teleporter(Player* pPlayer, GameObject* /*pGo*/) { pPlayer->TeleportTo(0, 1807.07f, 336.105f, 70.3975f, 0.0f); return false; diff --git a/scripts/kalimdor/ashenvale.cpp b/scripts/kalimdor/ashenvale.cpp index f0cbe4a13..35cc4838a 100644 --- a/scripts/kalimdor/ashenvale.cpp +++ b/scripts/kalimdor/ashenvale.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -64,14 +64,14 @@ enum NPC_VORSHA = 12940 }; -static float m_afFirstNagaCoord[3][3]= +static float m_afFirstNagaCoord[3][3] = { {3603.504150f, 1122.631104f, 1.635f}, // rider {3589.293945f, 1148.664063f, 5.565f}, // sorceress {3609.925537f, 1168.759521f, -1.168f} // razortail }; -static float m_afSecondNagaCoord[3][3]= +static float m_afSecondNagaCoord[3][3] = { {3609.925537f, 1168.759521f, -1.168f}, // witch {3645.652100f, 1139.425415f, 1.322f}, // priest @@ -80,7 +80,7 @@ static float m_afSecondNagaCoord[3][3]= static float m_fVorshaCoord[] = {3633.056885f, 1172.924072f, -5.388f}; -struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI +struct npc_muglashAI : public npc_escortAI { npc_muglashAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -94,7 +94,7 @@ struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI uint32 m_uiWaveId; uint32 m_uiEventTimer; - void Reset() + void Reset() override { m_uiEventTimer = 10000; @@ -105,7 +105,7 @@ struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (HasEscortState(STATE_ESCORT_PAUSED)) { @@ -117,9 +117,9 @@ struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: if (Player* pPlayer = GetPlayerForEscort()) @@ -129,9 +129,9 @@ struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI if (Player* pPlayer = GetPlayerForEscort()) DoScriptText(SAY_MUG_BRAZIER, m_creature, pPlayer); - if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_NAGA_BRAZIER, INTERACTION_DISTANCE*2)) + if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_NAGA_BRAZIER, INTERACTION_DISTANCE * 2)) { - //some kind of event flag? Update to player/group only? + // some kind of event flag? Update to player/group only? pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); SetEscortPaused(true); } @@ -153,20 +153,20 @@ struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI void DoWaveSummon() { - switch(m_uiWaveId) + switch (m_uiWaveId) { case 1: - m_creature->SummonCreature(NPC_WRATH_RIDER, m_afFirstNagaCoord[0][0], m_afFirstNagaCoord[0][1], m_afFirstNagaCoord[0][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - m_creature->SummonCreature(NPC_WRATH_SORCERESS, m_afFirstNagaCoord[1][0], m_afFirstNagaCoord[1][1], m_afFirstNagaCoord[1][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - m_creature->SummonCreature(NPC_WRATH_RAZORTAIL, m_afFirstNagaCoord[2][0], m_afFirstNagaCoord[2][1], m_afFirstNagaCoord[2][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(NPC_WRATH_RIDER, m_afFirstNagaCoord[0][0], m_afFirstNagaCoord[0][1], m_afFirstNagaCoord[0][2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + m_creature->SummonCreature(NPC_WRATH_SORCERESS, m_afFirstNagaCoord[1][0], m_afFirstNagaCoord[1][1], m_afFirstNagaCoord[1][2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + m_creature->SummonCreature(NPC_WRATH_RAZORTAIL, m_afFirstNagaCoord[2][0], m_afFirstNagaCoord[2][1], m_afFirstNagaCoord[2][2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); break; case 2: - m_creature->SummonCreature(NPC_WRATH_PRIESTESS, m_afSecondNagaCoord[0][0], m_afSecondNagaCoord[0][1], m_afSecondNagaCoord[0][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - m_creature->SummonCreature(NPC_WRATH_MYRMIDON, m_afSecondNagaCoord[1][0], m_afSecondNagaCoord[1][1], m_afSecondNagaCoord[1][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - m_creature->SummonCreature(NPC_WRATH_SEAWITCH, m_afSecondNagaCoord[2][0], m_afSecondNagaCoord[2][1], m_afSecondNagaCoord[2][2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(NPC_WRATH_PRIESTESS, m_afSecondNagaCoord[0][0], m_afSecondNagaCoord[0][1], m_afSecondNagaCoord[0][2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + m_creature->SummonCreature(NPC_WRATH_MYRMIDON, m_afSecondNagaCoord[1][0], m_afSecondNagaCoord[1][1], m_afSecondNagaCoord[1][2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); + m_creature->SummonCreature(NPC_WRATH_SEAWITCH, m_afSecondNagaCoord[2][0], m_afSecondNagaCoord[2][1], m_afSecondNagaCoord[2][2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); break; case 3: - m_creature->SummonCreature(NPC_VORSHA, m_fVorshaCoord[0], m_fVorshaCoord[1], m_fVorshaCoord[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(NPC_VORSHA, m_fVorshaCoord[0], m_fVorshaCoord[1], m_fVorshaCoord[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); break; case 4: SetEscortPaused(false); @@ -175,12 +175,12 @@ struct MANGOS_DLL_DECL npc_muglashAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -210,7 +210,7 @@ bool QuestAccept_npc_muglash(Player* pPlayer, Creature* pCreature, const Quest* if (npc_muglashAI* pEscortAI = dynamic_cast(pCreature->AI())) { DoScriptText(SAY_MUG_START1, pCreature); - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); pEscortAI->Start(false, pPlayer, pQuest); } @@ -224,9 +224,9 @@ CreatureAI* GetAI_npc_muglash(Creature* pCreature) return new npc_muglashAI(pCreature); } -bool GOUse_go_naga_brazier(Player* pPlayer, GameObject* pGo) +bool GOUse_go_naga_brazier(Player* /*pPlayer*/, GameObject* pGo) { - if (Creature* pCreature = GetClosestCreatureWithEntry(pGo, NPC_MUGLASH, INTERACTION_DISTANCE*2)) + if (Creature* pCreature = GetClosestCreatureWithEntry(pGo, NPC_MUGLASH, INTERACTION_DISTANCE * 2)) { if (npc_muglashAI* pEscortAI = dynamic_cast(pCreature->AI())) { @@ -252,15 +252,15 @@ enum NPC_T_PATHFINDER = 3926 }; -struct MANGOS_DLL_DECL npc_ruul_snowhoofAI : public npc_escortAI +struct npc_ruul_snowhoofAI : public npc_escortAI { npc_ruul_snowhoofAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 13: m_creature->SummonCreature(NPC_T_TOTEMIC, 3449.218018f, -587.825073f, 174.978867f, 4.714445f, TEMPSUMMON_DEAD_DESPAWN, 60000); @@ -279,7 +279,7 @@ struct MANGOS_DLL_DECL npc_ruul_snowhoofAI : public npc_escortAI } } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* summoned) override { summoned->AI()->AttackStart(m_creature); } @@ -289,7 +289,7 @@ bool QuestAccept_npc_ruul_snowhoof(Player* pPlayer, Creature* pCreature, const Q { if (pQuest->GetQuestId() == QUEST_FREEDOM_TO_RUUL) { - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); pCreature->SetStandState(UNIT_STAND_STATE_STAND); if (npc_ruul_snowhoofAI* pEscortAI = dynamic_cast(pCreature->AI())) @@ -326,27 +326,27 @@ enum NPC_SILVERWING_WARRIOR = 12897 }; -struct MANGOS_DLL_DECL npc_torekAI : public npc_escortAI +struct npc_torekAI : public npc_escortAI { npc_torekAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} uint32 m_uiRend_Timer; uint32 m_uiThunderclap_Timer; - void Reset() + void Reset() override { m_uiRend_Timer = 5000; m_uiThunderclap_Timer = 8000; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(uiPointId) + switch (uiPointId) { case 1: DoScriptText(SAY_MOVE, m_creature, pPlayer); @@ -355,10 +355,10 @@ struct MANGOS_DLL_DECL npc_torekAI : public npc_escortAI DoScriptText(SAY_PREPARE, m_creature, pPlayer); break; case 19: - //TODO: verify location and creatures amount. - m_creature->SummonCreature(NPC_DURIEL, 1776.73f, -2049.06f, 109.83f, 1.54f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,25000); - m_creature->SummonCreature(NPC_SILVERWING_SENTINEL, 1774.64f, -2049.41f, 109.83f, 1.40f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,25000); - m_creature->SummonCreature(NPC_SILVERWING_WARRIOR, 1778.73f, -2049.50f, 109.83f, 1.67f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,25000); + // TODO: verify location and creatures amount. + m_creature->SummonCreature(NPC_DURIEL, 1776.73f, -2049.06f, 109.83f, 1.54f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_SILVERWING_SENTINEL, 1774.64f, -2049.41f, 109.83f, 1.40f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_SILVERWING_WARRIOR, 1778.73f, -2049.50f, 109.83f, 1.67f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 20: DoScriptText(SAY_WIN, m_creature, pPlayer); @@ -370,12 +370,12 @@ struct MANGOS_DLL_DECL npc_torekAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -404,7 +404,7 @@ bool QuestAccept_npc_torek(Player* pPlayer, Creature* pCreature, const Quest* pQ { if (pQuest->GetQuestId() == QUEST_TOREK_ASSULT) { - //TODO: find companions, make them follow Torek, at any time (possibly done by mangos/database in future?) + // TODO: find companions, make them follow Torek, at any time (possibly done by mangos/database in future?) DoScriptText(SAY_READY, pCreature, pPlayer); if (npc_torekAI* pEscortAI = dynamic_cast(pCreature->AI())) @@ -466,7 +466,7 @@ static const float aEliteSummonPositions[3][4] = {4235.78f, 118.09f, 38.08f, 4.12f} }; -struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI +struct npc_feero_ironhandAI : public npc_escortAI { npc_feero_ironhandAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -476,7 +476,7 @@ struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI uint8 m_uiCreaturesCount; bool m_bIsAttacked; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -485,28 +485,28 @@ struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 14: // Prepare the first ambush DoScriptText(SAY_FIRST_AMBUSH_START, m_creature); for (uint8 i = 0; i < 4; ++i) - DoSpawnMob(NPC_DARK_STRAND_ASSASSIN, aSummonPositions[0][0], aSummonPositions[0][1] - M_PI_F/4 * i); + DoSpawnMob(NPC_DARK_STRAND_ASSASSIN, aSummonPositions[0][0], aSummonPositions[0][1] - M_PI_F / 4 * i); break; case 20: // Prepare the second ambush DoScriptText(SAY_SECOND_AMBUSH_START, m_creature); for (uint8 i = 0; i < 3; ++i) - DoSpawnMob(NPC_FORSAKEN_SCOUT, aSummonPositions[1][0], aSummonPositions[1][1] - M_PI_F/3 * i); + DoSpawnMob(NPC_FORSAKEN_SCOUT, aSummonPositions[1][0], aSummonPositions[1][1] - M_PI_F / 3 * i); break; case 29: // Final ambush DoScriptText(SAY_FINAL_AMBUSH_START, m_creature); - m_creature->SummonCreature(NPC_BALIZAR_THE_UMBRAGE, aEliteSummonPositions[0][0], aEliteSummonPositions[0][1], aEliteSummonPositions[0][2], aEliteSummonPositions[0][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); - m_creature->SummonCreature(NPC_ALIGAR_THE_TORMENTOR, aEliteSummonPositions[1][0], aEliteSummonPositions[1][1], aEliteSummonPositions[1][2], aEliteSummonPositions[1][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); - m_creature->SummonCreature(NPC_CAEDAKAR_THE_VICIOUS, aEliteSummonPositions[2][0], aEliteSummonPositions[2][1], aEliteSummonPositions[2][2], aEliteSummonPositions[2][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + m_creature->SummonCreature(NPC_BALIZAR_THE_UMBRAGE, aEliteSummonPositions[0][0], aEliteSummonPositions[0][1], aEliteSummonPositions[0][2], aEliteSummonPositions[0][3], TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_ALIGAR_THE_TORMENTOR, aEliteSummonPositions[1][0], aEliteSummonPositions[1][1], aEliteSummonPositions[1][2], aEliteSummonPositions[1][3], TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_CAEDAKAR_THE_VICIOUS, aEliteSummonPositions[2][0], aEliteSummonPositions[2][1], aEliteSummonPositions[2][2], aEliteSummonPositions[2][3], TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); break; case 30: // Complete the quest @@ -516,7 +516,7 @@ struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI } } - void AttackedBy(Unit* pWho) + void AttackedBy(Unit* pWho) override { // Yell only at the first attack if (!m_bIsAttacked) @@ -535,16 +535,16 @@ struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI float fX, fY, fZ; m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, fDistance, fAngle); - m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { --m_uiCreaturesCount; if (!m_uiCreaturesCount) { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_DARK_STRAND_ASSASSIN: DoScriptText(SAY_FIRST_AMBUSH_END, m_creature); @@ -561,7 +561,7 @@ struct MANGOS_DLL_DECL npc_feero_ironhandAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FORSAKEN_SCOUT) { @@ -587,7 +587,7 @@ bool QuestAccept_npc_feero_ironhand(Player* pPlayer, Creature* pCreature, const if (pQuest->GetQuestId() == QUEST_SUPPLIES_TO_AUBERDINE) { DoScriptText(SAY_QUEST_START, pCreature, pPlayer); - pCreature->setFaction(FACTION_ESCORT_A_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_feero_ironhandAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(true, pPlayer, pQuest, true); diff --git a/scripts/kalimdor/azshara.cpp b/scripts/kalimdor/azshara.cpp index 72d8d2788..778255659 100644 --- a/scripts/kalimdor/azshara.cpp +++ b/scripts/kalimdor/azshara.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -49,27 +49,27 @@ enum NPC_DEPTH_CHARGE = 23025, SPELL_SUMMON_RIZZLE = 39866, - SPELL_BLACKJACK = 39865, //stuns player - SPELL_ESCAPE = 39871, //teleports to water + SPELL_BLACKJACK = 39865, // stuns player + SPELL_ESCAPE = 39871, // teleports to water SPELL_SWIM_SPEED = 40596, - SPELL_FROST_TRAP = 39902, //not used? + SPELL_FROST_TRAP = 39902, // not used? - SPELL_PERIODIC_GRENADE = 40553, //cannot tell who are supposed to have this aura - SPELL_FROST_GRENADE = 40525, //triggered by periodic grenade + SPELL_PERIODIC_GRENADE = 40553, // cannot tell who are supposed to have this aura + SPELL_FROST_GRENADE = 40525, // triggered by periodic grenade - SPELL_SUMMON_DEPTH_CHARGE = 39907, //summons the bomb creature - SPELL_TRAP = 39899, //knockback + SPELL_SUMMON_DEPTH_CHARGE = 39907, // summons the bomb creature + SPELL_TRAP = 39899, // knockback SPELL_PERIODIC_CHECK = 39888, - SPELL_SURRENDER = 39889, //should be triggered by periodic check, if player comes in certain distance with quest incomplete + SPELL_SURRENDER = 39889, // should be triggered by periodic check, if player comes in certain distance with quest incomplete SPELL_GIVE_MOONSTONE = 39886 }; #define GOSSIP_ITEM_MOONSTONE "Hand over the Southfury moonstone and I'll let you go." -struct MANGOS_DLL_DECL npc_rizzle_sprysprocketAI : public npc_escortAI +struct npc_rizzle_sprysprocketAI : public npc_escortAI { npc_rizzle_sprysprocketAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -86,7 +86,7 @@ struct MANGOS_DLL_DECL npc_rizzle_sprysprocketAI : public npc_escortAI uint32 m_uiIntroTimer; uint32 m_uiDepthChargeTimer; - void MoveInLineOfSight(Unit* pUnit) + void MoveInLineOfSight(Unit* pUnit) override { if (HasEscortState(STATE_ESCORT_ESCORTING) && pUnit->GetTypeId() == TYPEID_PLAYER) { @@ -100,19 +100,19 @@ struct MANGOS_DLL_DECL npc_rizzle_sprysprocketAI : public npc_escortAI npc_escortAI::MoveInLineOfSight(pUnit); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: - m_creature->CastSpell(m_creature,SPELL_PERIODIC_CHECK,true); + m_creature->CastSpell(m_creature, SPELL_PERIODIC_CHECK, true); break; } } - void Reset() { } + void Reset() override { } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_SURRENDER) { @@ -122,20 +122,20 @@ struct MANGOS_DLL_DECL npc_rizzle_sprysprocketAI : public npc_escortAI } } - //this may be wrong (and doesn't work) - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + // this may be wrong (and doesn't work) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_FROST_GRENADE) DoScriptText(SAY_WHISPER_CHILL, m_creature, pTarget); } - //this may be wrong - void JustSummoned(Creature* pSummoned) + // this may be wrong + void JustSummoned(Creature* /*pSummoned*/) override { - //pSummoned->CastSpell(pSummoned,SPELL_PERIODIC_GRENADE,false,NULL,NULL,m_creature->GetObjectGuid()); + // pSummoned->CastSpell(pSummoned,SPELL_PERIODIC_GRENADE,false,NULL,NULL,m_creature->GetObjectGuid()); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_bIsIntro) { @@ -147,14 +147,14 @@ struct MANGOS_DLL_DECL npc_rizzle_sprysprocketAI : public npc_escortAI return; } - switch(m_uiIntroPhase) + switch (m_uiIntroPhase) { case 0: DoScriptText(SAY_START, m_creature); DoScriptText(EMOTE_START, m_creature); break; case 1: - //teleports to water _before_ we Start() + // teleports to water _before_ we Start() m_creature->CastSpell(m_creature, SPELL_ESCAPE, false); break; case 2: @@ -188,15 +188,15 @@ CreatureAI* GetAI_npc_rizzle_sprysprocket(Creature* pCreature) bool GossipHello_npc_rizzle_sprysprocket(Player* pPlayer, Creature* pCreature) { if (pPlayer->GetQuestStatus(QUEST_MOONSTONE) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MOONSTONE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MOONSTONE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_rizzle_sprysprocket(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_rizzle_sprysprocket(Player* pPlayer, Creature* /*pCreature*/, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->CLOSE_GOSSIP_MENU(); pPlayer->CastSpell(pPlayer, SPELL_GIVE_MOONSTONE, false); @@ -205,11 +205,11 @@ bool GossipSelect_npc_rizzle_sprysprocket(Player* pPlayer, Creature* pCreature, return true; } -struct MANGOS_DLL_DECL npc_depth_chargeAI : public ScriptedAI +struct npc_depth_chargeAI : public ScriptedAI { npc_depth_chargeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void MoveInLineOfSight(Unit* pUnit) + void MoveInLineOfSight(Unit* pUnit) override { if (pUnit->GetTypeId() != TYPEID_PLAYER) return; @@ -218,7 +218,7 @@ struct MANGOS_DLL_DECL npc_depth_chargeAI : public ScriptedAI m_creature->CastSpell(pUnit, SPELL_TRAP, false); } - void Reset() { } + void Reset() override { } }; CreatureAI* GetAI_npc_depth_charge(Creature* pCreature) @@ -230,10 +230,10 @@ CreatureAI* GetAI_npc_depth_charge(Creature* pCreature) ## go_southfury_moonstone ######*/ -bool GOUse_go_southfury_moonstone(Player* pPlayer, GameObject* pGo) +bool GOUse_go_southfury_moonstone(Player* pPlayer, GameObject* /*pGo*/) { - //implicitTarget=48 not implemented as of writing this code, and manual summon may be just ok for our purpose - //pPlayer->CastSpell(pPlayer,SPELL_SUMMON_RIZZLE,false); + // implicitTarget=48 not implemented as of writing this code, and manual summon may be just ok for our purpose + // pPlayer->CastSpell(pPlayer,SPELL_SUMMON_RIZZLE,false); if (Creature* pCreature = pPlayer->SummonCreature(NPC_RIZZLE, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0)) pCreature->CastSpell(pPlayer, SPELL_BLACKJACK, false); @@ -250,7 +250,6 @@ enum SPELL_POLYMORPH_BACKFIRE = 28406, // summons npc 16479 QUEST_FRAGMENTED_MAGIC = 9364, - // npc spells SPELL_DISARM = 6713, // warrior SPELL_SCREECH = 3589, // screamer @@ -292,11 +291,11 @@ static SpitelashAbilityStruct m_aSpitelashAbility[8] = {NPC_SPITELASH_MYRMIDON, SPELL_STRIKE, TARGET_TYPE_VICTIM, 3000, 7000} }; -struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI +struct mobs_spitelashesAI : public ScriptedAI { mobs_spitelashesAI(Creature* pCreature) : ScriptedAI(pCreature) { - for (uint8 i = 0; i < sizeof(m_aSpitelashAbility); ++i) + for (uint8 i = 0; i < countof(m_aSpitelashAbility); ++i) { if (m_aSpitelashAbility[i].m_uiCreatureEntry == m_creature->GetEntry()) m_mSpellTimers[i] = m_aSpitelashAbility[i].m_uiInitialTimer; @@ -309,7 +308,7 @@ struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI UNORDERED_MAP m_mSpellTimers; - void Reset() + void Reset() override { m_uiMorphTimer = 0; @@ -317,7 +316,7 @@ struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI itr->second = m_aSpitelashAbility[itr->first].m_uiInitialTimer; } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { // If already hit by the polymorph return if (m_uiMorphTimer) @@ -325,7 +324,7 @@ struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI // Creature get polymorphed into a sheep and after 5 secs despawns if (pCaster->GetTypeId() == TYPEID_PLAYER && ((Player*)pCaster)->GetQuestStatus(QUEST_FRAGMENTED_MAGIC) == QUEST_STATUS_INCOMPLETE && - (pSpell->Id==118 || pSpell->Id== 12824 || pSpell->Id== 12825 || pSpell->Id== 12826)) + (pSpell->Id == 118 || pSpell->Id == 12824 || pSpell->Id == 12825 || pSpell->Id == 12826)) m_uiMorphTimer = 5000; } @@ -333,7 +332,7 @@ struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI { Unit* pTarget = NULL; - switch(m_aSpitelashAbility[uiIndex].m_uiTargetType) + switch (m_aSpitelashAbility[uiIndex].m_uiTargetType) { case TARGET_TYPE_SELF: pTarget = m_creature; @@ -358,7 +357,7 @@ struct MANGOS_DLL_DECL mobs_spitelashesAI : public ScriptedAI return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -410,19 +409,19 @@ bool GossipHello_npc_loramus_thalipedes(Player* pPlayer, Creature* pCreature) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(2744) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Can you help me?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Can you help me?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); if (pPlayer->GetQuestStatus(3141) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Tell me your story", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_loramus_thalipedes(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_loramus_thalipedes(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: pPlayer->CLOSE_GOSSIP_MENU(); diff --git a/scripts/kalimdor/azuremyst_isle.cpp b/scripts/kalimdor/azuremyst_isle.cpp index 87caf51d2..6fab7de04 100644 --- a/scripts/kalimdor/azuremyst_isle.cpp +++ b/scripts/kalimdor/azuremyst_isle.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -51,7 +51,7 @@ enum SPELL_STUNNED = 28630 }; -struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI +struct npc_draenei_survivorAI : public ScriptedAI { npc_draenei_survivorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -63,7 +63,7 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI bool m_bCanSayHelp; - void Reset() + void Reset() override { m_casterGuid.Clear(); @@ -81,13 +81,13 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (m_bCanSayHelp && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsFriendlyTo(pWho) && - m_creature->IsWithinDistInMap(pWho, 25.0f)) + m_creature->IsWithinDistInMap(pWho, 25.0f)) { - //Random switch between 4 texts - switch(urand(0, 3)) + // Random switch between 4 texts + switch (urand(0, 3)) { case 0: DoScriptText(SAY_HELP1, m_creature, pWho); break; case 1: DoScriptText(SAY_HELP2, m_creature, pWho); break; @@ -100,7 +100,7 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pSpell->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x080000000)) { @@ -115,7 +115,7 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiSayThanksTimer) { @@ -128,7 +128,7 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI if (pPlayer->GetTypeId() != TYPEID_PLAYER) return; - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_HEAL1, m_creature, pPlayer); break; case 1: DoScriptText(SAY_HEAL2, m_creature, pPlayer); break; @@ -144,7 +144,8 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI m_uiRunAwayTimer = 10000; m_uiSayThanksTimer = 0; - }else m_uiSayThanksTimer -= uiDiff; + } + else m_uiSayThanksTimer -= uiDiff; return; } @@ -163,7 +164,8 @@ struct MANGOS_DLL_DECL npc_draenei_survivorAI : public ScriptedAI { m_bCanSayHelp = true; m_uiSayHelpTimer = 20000; - }else m_uiSayHelpTimer -= uiDiff; + } + else m_uiSayHelpTimer -= uiDiff; } }; @@ -191,11 +193,10 @@ enum #define GOSSIP_FIGHT "Traitor! You will be brought to justice!" -struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI +struct npc_engineer_spark_overgrindAI : public ScriptedAI { npc_engineer_spark_overgrindAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiNormFaction = pCreature->getFaction(); m_uiNpcFlags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS); Reset(); @@ -204,16 +205,14 @@ struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI } uint32 m_uiNpcFlags; - uint32 m_uiNormFaction; uint32 m_uiDynamiteTimer; uint32 m_uiEmoteTimer; bool m_bIsTreeEvent; - void Reset() + void Reset() override { - m_creature->setFaction(m_uiNormFaction); m_creature->SetUInt32Value(UNIT_NPC_FLAGS, m_uiNpcFlags); m_uiDynamiteTimer = 8000; @@ -222,12 +221,12 @@ struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI m_bIsTreeEvent = false; } - void Aggro(Unit *who) + void Aggro(Unit* who) override { DoScriptText(SAY_ATTACK, m_creature, who); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { if (!m_creature->isInCombat() && !m_bIsTreeEvent) { @@ -241,7 +240,7 @@ struct MANGOS_DLL_DECL npc_engineer_spark_overgrindAI : public ScriptedAI } else if (m_bIsTreeEvent) { - //nothing here yet + // nothing here yet return; } @@ -273,12 +272,12 @@ bool GossipHello_npc_engineer_spark_overgrind(Player* pPlayer, Creature* pCreatu return true; } -bool GossipSelect_npc_engineer_spark_overgrind(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_engineer_spark_overgrind(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF) { pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->setFaction(FACTION_HOSTILE); + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN); pCreature->AI()->AttackStart(pPlayer); } return true; @@ -288,32 +287,26 @@ bool GossipSelect_npc_engineer_spark_overgrind(Player* pPlayer, Creature* pCreat ## npc_injured_draenei ######*/ -struct MANGOS_DLL_DECL npc_injured_draeneiAI : public ScriptedAI +struct npc_injured_draeneiAI : public ScriptedAI { npc_injured_draeneiAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() + void Reset() override { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); m_creature->SetHealth(int(m_creature->GetMaxHealth()*.15)); - switch(urand(0, 1)) + switch (urand(0, 1)) { case 0: m_creature->SetStandState(UNIT_STAND_STATE_SIT); break; case 1: m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); break; } } - void MoveInLineOfSight(Unit *who) - { - return; //ignore everyone around them (won't aggro anything) - } - - void UpdateAI(const uint32 diff) - { - return; - } + void MoveInLineOfSight(Unit* /*pWho*/) override {} // ignore everyone around them (won't aggro anything) + void UpdateAI(const uint32 /*uiDiff*/) override {} }; + CreatureAI* GetAI_npc_injured_draenei(Creature* pCreature) { return new npc_injured_draeneiAI(pCreature); @@ -323,27 +316,30 @@ CreatureAI* GetAI_npc_injured_draenei(Creature* pCreature) ## npc_magwin ######*/ -#define SAY_START -1000111 -#define SAY_AGGRO -1000112 -#define SAY_PROGRESS -1000113 -#define SAY_END1 -1000114 -#define SAY_END2 -1000115 -#define EMOTE_HUG -1000116 - -#define QUEST_A_CRY_FOR_HELP 9528 +enum +{ + SAY_START = -1000111, + SAY_AGGRO = -1000112, + SAY_PROGRESS = -1000113, + SAY_END1 = -1000114, + SAY_END2 = -1000115, + EMOTE_HUG = -1000116, + + QUEST_A_CRY_FOR_HELP = 9528 +}; -struct MANGOS_DLL_DECL npc_magwinAI : public npc_escortAI +struct npc_magwinAI : public npc_escortAI { - npc_magwinAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} + npc_magwinAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(i) + switch (uiPointId) { case 0: DoScriptText(SAY_START, m_creature, pPlayer); @@ -362,19 +358,19 @@ struct MANGOS_DLL_DECL npc_magwinAI : public npc_escortAI } } - void Aggro(Unit* who) + void Aggro(Unit* pWho) override { - DoScriptText(SAY_AGGRO, m_creature, who); + DoScriptText(SAY_AGGRO, m_creature, pWho); } - void Reset() { } + void Reset() override { } }; bool QuestAccept_npc_magwin(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_A_CRY_FOR_HELP) { - pCreature->setFaction(10); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_magwinAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); diff --git a/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h b/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h index e316c5812..063d8d558 100644 --- a/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h +++ b/scripts/kalimdor/blackfathom_deeps/blackfathom_deeps.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,14 +7,16 @@ enum { - MAX_ENCOUNTER = 2, + MAX_ENCOUNTER = 3, MAX_FIRES = 4, MAX_COUNT_POS = 3, TYPE_KELRIS = 1, TYPE_SHRINE = 2, + TYPE_AQUANIS = 3, NPC_KELRIS = 4832, + NPC_BARON_AQUANIS = 12876, // Shrine event NPC_AKUMAI_SERVANT = 4978, @@ -27,25 +29,26 @@ enum GO_SHRINE_2 = 21119, GO_SHRINE_3 = 21120, GO_SHRINE_4 = 21121, + GO_FATHOM_STONE = 177964, }; - /* This is the spawn pattern for the event mobs - * D - * 0 3 - * 1 S 4 - * 2 5 - * E +/* This is the spawn pattern for the event mobs +* D +* 0 3 +* 1 S 4 +* 2 5 +* E - * This event spawns 4 sets of mobs - * The order in whitch the fires are lit doesn't matter +* This event spawns 4 sets of mobs +* The order in whitch the fires are lit doesn't matter - * First: 3 Snapjaws: Positions 0, 1, 5 - * Second: 2 Servants: Positions 1, 4 - * Third: 4 Crabs: Positions 0, 2, 3, 4 - * Fourth: 10 Murkshallows: Positions 2*0, 1, 2*2; 3, 2*4, 2*5 +* First: 3 Snapjaws: Positions 0, 1, 5 +* Second: 2 Servants: Positions 1, 4 +* Third: 4 Crabs: Positions 0, 2, 3, 4 +* Fourth: 10 Murkshallows: Positions 2*0, 1, 2*2; 3, 2*4, 2*5 - * On wipe the mobs don't despawn; they stay there until player returns - */ +* On wipe the mobs don't despawn; they stay there until player returns +*/ struct Locations { @@ -54,12 +57,12 @@ struct Locations static const Locations aSpawnLocations[6] = // Should be near the correct positions { - {-768.949f, -174.413f, -25.87f, 3.09f}, // Left side - {-768.888f, -164.238f, -25.87f, 3.09f}, - {-768.951f, -153.911f, -25.88f, 3.09f}, - {-867.782f, -174.352f, -25.87f, 6.27f}, // Right side - {-867.875f, -164.089f, -25.87f, 6.27f}, - {-867.859f, -153.927f, -25.88f, 6.27f} + { -768.949f, -174.413f, -25.87f, 3.09f}, // Left side + { -768.888f, -164.238f, -25.87f, 3.09f}, + { -768.951f, -153.911f, -25.88f, 3.09f}, + { -867.782f, -174.352f, -25.87f, 6.27f}, // Right side + { -867.875f, -164.089f, -25.87f, 6.27f}, + { -867.859f, -153.927f, -25.88f, 6.27f} }; struct PosCount @@ -85,25 +88,27 @@ static const SummonInformation aWaveSummonInformation[] = {3, NPC_MURKSHALLOW_SOFTSHELL, {{1, 3}, {2, 4}, {2, 5}}} }; -class MANGOS_DLL_DECL instance_blackfathom_deeps : public ScriptedInstance +static const float afAquanisPos[4] = { -782.21f, -63.26f, -42.43f, 2.36f }; + +class instance_blackfathom_deeps : public ScriptedInstance { public: instance_blackfathom_deeps(Map* pMap); ~instance_blackfathom_deeps() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureDeath(Creature* pCreature) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: void DoSpawnMobs(uint8 uiWaveIndex); diff --git a/scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp b/scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp index d017e66fd..d2d25e135 100644 --- a/scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp +++ b/scripts/kalimdor/blackfathom_deeps/instance_blackfathom_deeps.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Instance_Blackfathom_Deeps SD%Complete: 50 -SDComment: +SDComment: Quest support: 6921 SDCategory: Blackfathom Deeps EndScriptData */ @@ -27,6 +27,7 @@ EndScriptData */ /* Encounter 0 = Twilight Lord Kelris Encounter 1 = Shrine event Must kill twilight lord for shrine event to be possible + Encounter 2 = Baron Aquanis (spawned by GO use but should only spawn once per instance) */ instance_blackfathom_deeps::instance_blackfathom_deeps(Map* pMap) : ScriptedInstance(pMap), @@ -49,7 +50,7 @@ void instance_blackfathom_deeps::OnCreatureCreate(Creature* pCreature) void instance_blackfathom_deeps::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_PORTAL_DOOR: if (m_auiEncounter[1] == DONE) @@ -77,7 +78,7 @@ void instance_blackfathom_deeps::DoSpawnMobs(uint8 uiWaveIndex) pKelris->GetRespawnCoord(fX_resp, fY_resp, fZ_resp); - for (uint8 i = 0; i < sizeof(aWaveSummonInformation) / sizeof(SummonInformation); ++i) + for (uint8 i = 0; i < countof(aWaveSummonInformation); ++i) { if (aWaveSummonInformation[i].m_uiWaveIndex != uiWaveIndex) continue; @@ -109,7 +110,7 @@ void instance_blackfathom_deeps::DoSpawnMobs(uint8 uiWaveIndex) void instance_blackfathom_deeps::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_KELRIS: // EventAI must set instance data (1,3) at his death if (m_auiEncounter[0] != DONE && uiData == DONE) @@ -125,6 +126,9 @@ void instance_blackfathom_deeps::SetData(uint32 uiType, uint32 uiData) else if (uiData == DONE) DoUseDoorOrButton(GO_PORTAL_DOOR); break; + case TYPE_AQUANIS: + m_auiEncounter[2] = uiData; + break; } if (uiData == DONE) @@ -133,7 +137,7 @@ void instance_blackfathom_deeps::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1]; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; m_strInstData = saveStream.str(); SaveToDB(); @@ -141,12 +145,13 @@ void instance_blackfathom_deeps::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_blackfathom_deeps::GetData(uint32 uiType) +uint32 instance_blackfathom_deeps::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_KELRIS: return m_auiEncounter[0]; case TYPE_SHRINE: return m_auiEncounter[1]; + case TYPE_AQUANIS: return m_auiEncounter[2]; default: return 0; } @@ -163,9 +168,9 @@ void instance_blackfathom_deeps::Load(const char* chrIn) OUT_LOAD_INST_DATA(chrIn); std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -176,6 +181,9 @@ void instance_blackfathom_deeps::Load(const char* chrIn) void instance_blackfathom_deeps::OnCreatureDeath(Creature* pCreature) { + if (pCreature->GetEntry() == NPC_BARON_AQUANIS) + SetData(TYPE_AQUANIS, DONE); + // Only use this function if shrine event is in progress if (m_auiEncounter[1] != IN_PROGRESS) return; @@ -243,7 +251,7 @@ InstanceData* GetInstanceData_instance_blackfathom_deeps(Map* pMap) return new instance_blackfathom_deeps(pMap); } -bool GOUse_go_fire_of_akumai(Player* pPlayer, GameObject* pGo) +bool GOUse_go_fire_of_akumai(Player* /*pPlayer*/, GameObject* pGo) { instance_blackfathom_deeps* pInstance = (instance_blackfathom_deeps*)pGo->GetInstanceData(); @@ -262,6 +270,21 @@ bool GOUse_go_fire_of_akumai(Player* pPlayer, GameObject* pGo) return true; } +bool GOUse_go_fathom_stone(Player* pPlayer, GameObject* pGo) +{ + instance_blackfathom_deeps* pInstance = (instance_blackfathom_deeps*)pGo->GetInstanceData(); + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_AQUANIS) == NOT_STARTED) + { + pPlayer->SummonCreature(NPC_BARON_AQUANIS, afAquanisPos[0], afAquanisPos[1], afAquanisPos[2], afAquanisPos[3], TEMPSUMMON_DEAD_DESPAWN, 0); + pInstance->SetData(TYPE_AQUANIS, IN_PROGRESS); + } + + return false; +} + void AddSC_instance_blackfathom_deeps() { Script* pNewScript; @@ -275,4 +298,9 @@ void AddSC_instance_blackfathom_deeps() pNewScript->Name = "go_fire_of_akumai"; pNewScript->pGOUse = &GOUse_go_fire_of_akumai; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_fathom_stone"; + pNewScript->pGOUse = &GOUse_go_fathom_stone; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/bloodmyst_isle.cpp b/scripts/kalimdor/bloodmyst_isle.cpp index 74cee8ef0..949252ae0 100644 --- a/scripts/kalimdor/bloodmyst_isle.cpp +++ b/scripts/kalimdor/bloodmyst_isle.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,36 +31,41 @@ EndContentData */ ## mob_webbed_creature ######*/ -//possible creatures to be spawned +enum +{ + NPC_EXPEDITION_RESEARCHER = 17681, +}; + +// possible creatures to be spawned (too many to be added to enum) const uint32 possibleSpawns[31] = {17322, 17661, 17496, 17522, 17340, 17352, 17333, 17524, 17654, 17348, 17339, 17345, 17359, 17353, 17336, 17550, 17330, 17701, 17321, 17325, 17320, 17683, 17342, 17715, 17334, 17341, 17338, 17337, 17346, 17344, 17327}; -struct MANGOS_DLL_DECL mob_webbed_creatureAI : public ScriptedAI +struct mob_webbed_creatureAI : public Scripted_NoMovementAI { - mob_webbed_creatureAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + mob_webbed_creatureAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - void Reset() - { - } + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void JustDied(Unit* Killer) + void JustDied(Unit* pKiller) override { - uint32 spawnCreatureID = 0; + uint32 uiSpawnCreatureEntry = 0; - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: - spawnCreatureID = 17681; - if (Killer->GetTypeId() == TYPEID_PLAYER) - ((Player*)Killer)->KilledMonsterCredit(spawnCreatureID, m_creature->GetObjectGuid()); + uiSpawnCreatureEntry = NPC_EXPEDITION_RESEARCHER; + if (pKiller->GetTypeId() == TYPEID_PLAYER) + ((Player*)pKiller)->KilledMonsterCredit(uiSpawnCreatureEntry, m_creature->GetObjectGuid()); break; case 1: case 2: - spawnCreatureID = possibleSpawns[urand(0, 30)]; + uiSpawnCreatureEntry = possibleSpawns[urand(0, 30)]; break; } - if (spawnCreatureID) - m_creature->SummonCreature(spawnCreatureID, 0.0f, 0.0f, 0.0f, m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + if (uiSpawnCreatureEntry) + m_creature->SummonCreature(uiSpawnCreatureEntry, 0.0f, 0.0f, 0.0f, m_creature->GetOrientation(), TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); } }; diff --git a/scripts/kalimdor/boss_azuregos.cpp b/scripts/kalimdor/boss_azuregos.cpp index a792c814a..c2b5d5733 100644 --- a/scripts/kalimdor/boss_azuregos.cpp +++ b/scripts/kalimdor/boss_azuregos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ enum SPELL_ENRAGE = 23537, }; -struct MANGOS_DLL_DECL boss_azuregosAI : public ScriptedAI +struct boss_azuregosAI : public ScriptedAI { boss_azuregosAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -50,7 +50,7 @@ struct MANGOS_DLL_DECL boss_azuregosAI : public ScriptedAI uint32 m_uiCleaveTimer; bool m_bEnraged; - void Reset() + void Reset() override { m_uiManaStormTimer = urand(5000, 17000); m_uiChillTimer = urand(10000, 30000); @@ -61,20 +61,20 @@ struct MANGOS_DLL_DECL boss_azuregosAI : public ScriptedAI m_bEnraged = false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { // Mark killed players with Mark of Frost if (pVictim->GetTypeId() == TYPEID_PLAYER) pVictim->CastSpell(pVictim, SPELL_MARK_OF_FROST_PLAYER, true, NULL, NULL, m_creature->GetObjectGuid()); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { // Boss aura which triggers the stun effect on dead players who resurrect DoCastSpellIfCan(m_creature, SPELL_MARK_OF_FROST_AURA); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp index eba264466..36f2b456d 100644 --- a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,14 @@ /* ScriptData SDName: culling_of_stratholme -SD%Complete: 5% -SDComment: Placeholder +SD%Complete: 80% +SDComment: Zombies spawns partially implemented SDCategory: Culling of Stratholme EndScriptData */ #include "precompiled.h" #include "culling_of_stratholme.h" +#include "escort_ai.h" /* ************* ** npc_chromie (gossip, quest-accept) @@ -47,14 +48,19 @@ enum GOSSIP_ITEM_INN_1 = -3595003, GOSSIP_ITEM_INN_2 = -3595004, GOSSIP_ITEM_INN_3 = -3595005, + GOSSIP_ITEM_INN_SKIP = -3595006, // used to skip the intro; requires research + GOSSIP_ITEM_INN_TELEPORT = -3595007, // teleport to stratholme - used after the main event has started TEXT_ID_INN_1 = 12939, TEXT_ID_INN_2 = 12949, TEXT_ID_INN_3 = 12950, TEXT_ID_INN_4 = 12952, + TEXT_ID_INN_TELEPORT = 13470, + + SPELL_TELEPORT_COT_P4 = 53435, // triggers 53436 }; -bool GossipHello_npc_chromie(Player *pPlayer, Creature *pCreature) +bool GossipHello_npc_chromie(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); @@ -67,13 +73,15 @@ bool GossipHello_npc_chromie(Player *pPlayer, Creature *pCreature) if (m_pInstance->GetData(TYPE_GRAIN_EVENT) != DONE) { if (pPlayer->GetQuestRewardStatus(QUEST_DISPELLING_ILLUSIONS) && !pPlayer->HasItemCount(ITEM_ARCANE_DISRUPTOR, 1)) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INN_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INN_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); } + // intro skip option is available since 3.3.x + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INN_SKIP, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN_1, pCreature->GetObjectGuid()); break; case NPC_CHROMIE_ENTRANCE: if (m_pInstance->GetData(TYPE_GRAIN_EVENT) == DONE && m_pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == NOT_STARTED && pPlayer->GetQuestRewardStatus(QUEST_A_ROYAL_ESCORT)) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ENTRANCE_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ENTRANCE_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(TEXT_ID_ENTRANCE_1, pCreature->GetObjectGuid()); break; } @@ -81,7 +89,7 @@ bool GossipHello_npc_chromie(Player *pPlayer, Creature *pCreature) return true; } -bool GossipSelect_npc_chromie(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 uiAction) +bool GossipSelect_npc_chromie(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) { switch (pCreature->GetEntry()) { @@ -111,6 +119,27 @@ bool GossipSelect_npc_chromie(Player* pPlayer, Creature* pCreature, uint32 sende } } break; + case GOSSIP_ACTION_INFO_DEF+4: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INN_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN_TELEPORT, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF+5: + pCreature->CastSpell(pPlayer, SPELL_TELEPORT_COT_P4, true); + if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) + { + // only skip intro if not already started; + if (pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == NOT_STARTED && pInstance->GetData(TYPE_GRAIN_EVENT) == NOT_STARTED) + { + pInstance->SetData(TYPE_ARTHAS_INTRO_EVENT, DONE); + pInstance->SetData(TYPE_GRAIN_EVENT, DONE); + + // spawn Arthas and Chromie + pInstance->DoSpawnChromieIfNeeded(pPlayer); + pInstance->DoSpawnArthasIfNeeded(pPlayer); + } + } + pPlayer->CLOSE_GOSSIP_MENU(); + break; } break; case NPC_CHROMIE_ENTRANCE: @@ -129,7 +158,10 @@ bool GossipSelect_npc_chromie(Player* pPlayer, Creature* pCreature, uint32 sende if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) { if (pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == NOT_STARTED) - pInstance->DoSpawnArthasIfNeeded(); + { + pInstance->SetData(TYPE_ARTHAS_INTRO_EVENT, IN_PROGRESS); + pInstance->DoSpawnArthasIfNeeded(pPlayer); + } } break; } @@ -153,7 +185,10 @@ bool QuestAccept_npc_chromie(Player* pPlayer, Creature* pCreature, const Quest* if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) { if (pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == NOT_STARTED) - pInstance->DoSpawnArthasIfNeeded(); + { + pInstance->SetData(TYPE_ARTHAS_INTRO_EVENT, IN_PROGRESS); + pInstance->DoSpawnArthasIfNeeded(pPlayer); + } } break; } @@ -166,6 +201,8 @@ bool QuestAccept_npc_chromie(Player* pPlayer, Creature* pCreature, const Quest* enum { + SAY_SOLDIERS_REPORT = -1595000, + SPELL_ARCANE_DISRUPTION = 49590, SPELL_CRATES_KILL_CREDIT = 58109, }; @@ -176,6 +213,9 @@ bool EffectAuraDummy_spell_aura_dummy_npc_crates_dummy(const Aura* pAura, bool b { if (Creature* pTarget = (Creature*)pAura->GetTarget()) { + if (pTarget->GetEntry() != NPC_GRAIN_CRATE_HELPER) + return true; + std::list lCrateBunnyList; if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pTarget->GetInstanceData()) { @@ -185,46 +225,751 @@ bool EffectAuraDummy_spell_aura_dummy_npc_crates_dummy(const Aura* pAura, bool b { ++i; if (*itr == pTarget) + { + // check if the event can proceed + if (!pInstance->CanGrainEventProgress(pTarget)) + return true; + break; + } } switch (i) { case 1: // Start NPC_ROGER_OWENS Event + if (Creature* pRoger = pInstance->GetSingleCreatureFromStorage(NPC_ROGER_OWENS)) + { + pRoger->SetStandState(UNIT_STAND_STATE_STAND); + pRoger->GetMotionMaster()->MoveWaypoint(); + } break; case 2: // Start NPC_SERGEANT_MORIGAN Event + if (Creature* pMorigan = pInstance->GetSingleCreatureFromStorage(NPC_SERGEANT_MORIGAN)) + pMorigan->GetMotionMaster()->MoveWaypoint(); break; case 3: // Start NPC_JENA_ANDERSON Event + if (Creature* pJena = pInstance->GetSingleCreatureFromStorage(NPC_JENA_ANDERSON)) + pJena->GetMotionMaster()->MoveWaypoint(); break; case 4: // Start NPC_MALCOM_MOORE Event + pTarget->SummonCreature(NPC_MALCOM_MOORE, 1605.452f, 804.9279f, 122.961f, 5.19f, TEMPSUMMON_DEAD_DESPAWN, 0); break; case 5: // Start NPC_BARTLEBY_BATTSON Event + if (Creature* pBartleby = pInstance->GetSingleCreatureFromStorage(NPC_BARTLEBY_BATTSON)) + pBartleby->GetMotionMaster()->MoveWaypoint(); break; } - if (pInstance->GetData(TYPE_GRAIN_EVENT) != DONE) + // Finished event, give killcredit + if (pInstance->GetData(TYPE_GRAIN_EVENT) == DONE) { - pInstance->SetData(TYPE_GRAIN_EVENT, IN_PROGRESS); + pTarget->CastSpell(pTarget, SPELL_CRATES_KILL_CREDIT, true); + pInstance->DoOrSimulateScriptTextForThisInstance(SAY_SOLDIERS_REPORT, NPC_LORDAERON_CRIER); + } - // Finished event, give killcredit - if (pInstance->GetData(TYPE_GRAIN_EVENT) == DONE) - pTarget->CastSpell(pTarget, SPELL_CRATES_KILL_CREDIT, true); + // despawn the GO visuals and spanw the plague crate + if (GameObject* pCrate = GetClosestGameObjectWithEntry(pTarget, GO_SUSPICIOUS_GRAIN_CRATE, 5.0f)) + pCrate->SetLootState(GO_JUST_DEACTIVATED); + if (GameObject* pHighlight = GetClosestGameObjectWithEntry(pTarget, GO_CRATE_HIGHLIGHT, 5.0f)) + pHighlight->SetLootState(GO_JUST_DEACTIVATED); + if (GameObject* pCrate = GetClosestGameObjectWithEntry(pTarget, GO_PLAGUE_GRAIN_CRATE, 5.0f)) + { + pCrate->SetRespawnTime(6 * HOUR * IN_MILLISECONDS); + pCrate->Refresh(); } + } + } + } + return true; +} + +/* ************* +** npc_arthas +************* */ + +enum +{ + // texts + SAY_ARTHAS_FOLLOW = -1595009, + SAY_CITIZEN_ARRIVED = -1595010, + SAY_ARTHAS_BEFORE_PLAGUE = -1595011, + SAY_ARTHAS_SORCERY = -1595012, + SAY_CITIZEN_NO_UNDERSTAD = -1595013, + SAY_ARTHAS_MORE_SCOURGE = -1595014, + SAY_ARTHAS_MORE_SORCERY = -1595015, + SAY_ARTHAS_MOVE_ON = -1595016, + SAY_ARTHAS_WATCH_BACK = -1595017, + SAY_ARTHAS_NOT_EASY = -1595018, + SAY_ARTHAS_PERSISTENT = -1595019, + SAY_ARTHAS_WHAT_ELSE = -1595020, + SAY_EPOCH_DARKNESS = -1595021, + SAY_ARTHAS_DO_WHAT_MUST = -1595022, + + SAY_ARTHAS_QUICK_PATH = -1595023, + SAY_ARTHAS_TAKE_A_MOMENT = -1595024, + SAY_ARTHAS_PASSAGE = -1595025, + + SAY_ARTHAS_MOVE_QUICKLY = -1595026, + SAY_ARTHAS_REST = -1595027, + SAY_ARTHAS_REST_COMPLETE = -1595028, + SAY_ARTHAS_CRUSADER_SQUARE = -1595029, + + SAY_ARTHAS_JUSTICE_DONE = -1595030, + SAY_ARTHAS_MALGANIS = -1595031, + SAY_MALGANIS_JOURNEY = -1595032, + SAY_ARTHAS_HUNT_MALGANIS = -1595033, // play music 14951 + SAY_ARTHAS_EVENT_COMPLETE = -1595034, + + SAY_ARTHAS_HALF_HP = -1595035, + SAY_ARTHAS_LOW_HP = -1595036, + SAY_ARTHAS_SLAY_1 = -1595037, + SAY_ARTHAS_SLAY_2 = -1595038, + SAY_ARTHAS_SLAY_3 = -1595039, + SAY_ARTHAS_DEATH = -1595040, + + MUSIC_ID_EVENT_COMPLETE = 14951, + + // gossips + GOSSIP_ITEM_CITY_GATES = -3595008, + GOSSIP_ITEM_TOWN_HALL_1 = -3595009, + GOSSIP_ITEM_TOWN_HALL_2 = -3595010, + GOSSIP_ITEM_EPOCH = -3595011, + GOSSIP_ITEM_ESCORT = -3595012, + GOSSIP_ITEM_DREADLORD = -3595013, + + TEXT_ID_CITY_GATES = 13076, + TEXT_ID_TOWN_HALL_1 = 13125, + TEXT_ID_TOWN_HALL_2 = 13126, + TEXT_ID_EPOCH = 13177, + TEXT_ID_ESCORT = 13179, + TEXT_ID_DREADLORD = 13287, + + // spells + SPELL_HOLY_LIGHT = 52444, + SPELL_EXORCISM = 52445, + SPELL_EXORCISM_H = 58822, + SPELL_DEVOTION_AURA = 52442, + SPELL_CRUSADER_STRIKE = 50773, // dummy used on citizens + + SPELL_MALGANIS_KILL_CREDIT = 58124, + SPELL_MALGANIS_ACHIEVEMENT = 58630, // server side spell + + SPELL_TRANSFORM = 33133, + SPELL_SHADOWSTEP_COSMETIC = 51908, + + // FACTION_ARTHAS_1 = 2076, // default faction + FACTION_ARTHAS_2 = 2077, // burning city + // FACTION_ARTHAS_3 = 2079, // use unk + + POINT_ID_INTRO_COMPLETE = 31, // intro completion WP - handled by dbscript + POINT_ID_ESCORT_CITY = 47, // escort point before burning city + POINT_ID_MARKET_ROW = 70, // escort point before Malganis +}; + +static const DialogueEntry aArthasDialogue[] = +{ + {NPC_TOWNHALL_CITIZEN, 0, 2000}, + {TEXT_ID_TOWN_HALL_1, 0, 0}, + // transform citizens + {SPELL_CRUSADER_STRIKE, 0, 2000}, + {NPC_TOWNHALL_RESIDENT, 0, 1000}, + {SAY_ARTHAS_SORCERY, NPC_ARTHAS, 3000}, + {TEXT_ID_TOWN_HALL_2, 0, 1000}, + {NPC_INFINITE_HUNTER, 0, 1000}, + {NPC_INFINITE_AGENT, 0, 1000}, + {NPC_INFINITE_ADVERSARY, 0, 0}, + // start Epoch fight + {SAY_ARTHAS_WHAT_ELSE, NPC_ARTHAS, 5000}, + {SAY_EPOCH_DARKNESS, NPC_LORD_EPOCH, 13000}, + {SAY_ARTHAS_DO_WHAT_MUST, NPC_ARTHAS, 5000}, + {NPC_ARTHAS, 0, 2000}, + {NPC_LORD_EPOCH, 0, 0}, + // open bookcase door + {SAY_ARTHAS_TAKE_A_MOMENT, NPC_ARTHAS, 2000}, + {GO_DOOR_BOOKCASE, 0, 0}, + // reach crusader square + {SAY_ARTHAS_CRUSADER_SQUARE, NPC_ARTHAS, 10000}, + {SPELL_TRANSFORM, 0, 0}, + // start Malganis fight + {SAY_ARTHAS_MALGANIS, NPC_ARTHAS, 5000}, + {NPC_MALGANIS, 0, 0}, + // Malganis epilog + {SAY_MALGANIS_JOURNEY, NPC_MALGANIS, 18000}, + {SAY_ARTHAS_HUNT_MALGANIS, NPC_ARTHAS, 5000}, + {TEXT_ID_DREADLORD, 0, 2000}, + {SAY_ARTHAS_EVENT_COMPLETE, NPC_ARTHAS, 0}, + {0, 0, 0}, +}; + +struct npc_arthasAI : public npc_escortAI, private DialogueHelper +{ + npc_arthasAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aArthasDialogue) + { + m_pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_culling_of_stratholme* m_pInstance; + + bool m_bIsRegularMode; + + bool m_bYell50Pct; + bool m_bYell20Pct; + + uint32 m_uiHolyLightTimer; + uint32 m_uiExorcismTimer; + + ObjectGuid m_firstCitizenGuid; + ObjectGuid m_secondCitizenGuid; + ObjectGuid m_thirdCitizenGuid; + + GuidList m_lSummonedGuidsList; + + void Reset() override + { + m_uiExorcismTimer = urand(5000, 10000); + m_uiHolyLightTimer = urand(5000, 10000); + m_bYell50Pct = false; + m_bYell20Pct = false; + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_DEVOTION_AURA); + } - // pTarget->ForcedDespawn(); // direct despawn has influence on visual effects, - // but despawning makes it impossible to multi-use the spell at the same place - // perhaps some add. GO-Visual + void KilledUnit(Unit* /*pVictim*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_ARTHAS_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_ARTHAS_SLAY_2, m_creature); break; + case 2: DoScriptText(SAY_ARTHAS_SLAY_3, m_creature); break; + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_ARTHAS_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ARTHAS_ESCORT_EVENT, FAIL); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 uiMiscValue) override + { + // on Malganis encounter finished -> evade + if (pSender->GetEntry() == NPC_MALGANIS && eventType == AI_EVENT_CUSTOM_EVENTAI_B) + { + EnterEvadeMode(); + SetEscortPaused(false); + return; + } + + if (pInvoker->GetTypeId() != TYPEID_PLAYER) + return; + + if (eventType == AI_EVENT_START_ESCORT) + { + DoScriptText(SAY_ARTHAS_FOLLOW, m_creature); + Start(true, (Player*)pInvoker); + } + else if (eventType == AI_EVENT_CUSTOM_A) + { + DoScriptText(SAY_ARTHAS_QUICK_PATH, m_creature); + SetEscortPaused(false); + } + else if (eventType == AI_EVENT_START_ESCORT_B) + { + // start and set WP + Start(true, (Player*)pInvoker); + SetEscortPaused(true); + SetCurrentWaypoint(POINT_ID_ESCORT_CITY); + SetEscortPaused(false); + + DoScriptText(SAY_ARTHAS_MOVE_QUICKLY, m_creature); + m_creature->SetFactionTemporary(FACTION_ARTHAS_2, TEMPFACTION_RESTORE_REACH_HOME); + + if (m_pInstance) + m_pInstance->DoSpawnBurningCityUndead(m_creature); + } + else if (eventType == AI_EVENT_CUSTOM_B) + { + // resume escort or start on point if start from reset + if (HasEscortState(STATE_ESCORT_PAUSED)) + SetEscortPaused(false); + else + { + Start(true, (Player*)pInvoker); + SetEscortPaused(true); + SetCurrentWaypoint(POINT_ID_MARKET_ROW); + SetEscortPaused(false); } + + DoScriptText(SAY_ARTHAS_JUSTICE_DONE, m_creature); + m_creature->SetFactionTemporary(FACTION_ARTHAS_2, TEMPFACTION_RESTORE_REACH_HOME); + + // spawn Malganis if required + if (m_pInstance && !m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS, true)) + m_creature->SummonCreature(NPC_MALGANIS, 2296.862F, 1501.015F, 128.445F, 5.13f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType == WAYPOINT_MOTION_TYPE) + { + // set the intro event as done and start the undead waves + if (uiPointId == POINT_ID_INTRO_COMPLETE && m_pInstance) + m_pInstance->SetData(TYPE_ARTHAS_INTRO_EVENT, DONE); } + else + npc_escortAI::MovementInform(uiType, uiPointId); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_INFINITE_ADVERSARY: + case NPC_INFINITE_AGENT: + case NPC_INFINITE_HUNTER: + pSummoned->AI()->AttackStart(m_creature); + // no break; + case NPC_TOWNHALL_CITIZEN: + case NPC_TOWNHALL_RESIDENT: + m_lSummonedGuidsList.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_LORD_EPOCH: + pSummoned->GetMotionMaster()->MovePoint(0, 2450.874f, 1113.122f, 149.008f); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_INFINITE_ADVERSARY: + case NPC_INFINITE_AGENT: + case NPC_INFINITE_HUNTER: + m_lSummonedGuidsList.remove(pSummoned->GetObjectGuid()); + + if (m_lSummonedGuidsList.empty()) + SetEscortPaused(false); + break; + case NPC_LORD_EPOCH: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + // spawn citizens - ground floor + case 1: + if (Creature* pCitizen = m_creature->SummonCreature(NPC_TOWNHALL_CITIZEN, 2401.265f, 1202.789f, 134.103f, 1.466f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000)) + m_firstCitizenGuid = pCitizen->GetObjectGuid(); + if (Creature* pCitizen = m_creature->SummonCreature(NPC_TOWNHALL_RESIDENT, 2402.654f, 1205.786f, 134.122f, 2.89f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000)) + m_secondCitizenGuid = pCitizen->GetObjectGuid(); + if (Creature* pCitizen = m_creature->SummonCreature(NPC_TOWNHALL_CITIZEN, 2398.715f, 1207.334f, 134.122f, 5.27f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000)) + m_thirdCitizenGuid = pCitizen->GetObjectGuid(); + break; + case 3: + StartNextDialogueText(NPC_TOWNHALL_CITIZEN); + break; + case 4: + DoScriptText(SAY_ARTHAS_BEFORE_PLAGUE, m_creature); + SetRun(false); + break; + case 5: + SetEscortPaused(true); + StartNextDialogueText(SPELL_CRUSADER_STRIKE); + break; + case 6: + m_creature->SetFacingTo(0.30f); + break; + case 7: + DoScriptText(SAY_ARTHAS_MORE_SCOURGE, m_creature); + SetRun(); + break; + + // spawn second wave - on the first floor + case 13: + DoScriptText(SAY_ARTHAS_MORE_SORCERY, m_creature); + SetRun(false); + m_creature->SummonCreature(NPC_TIME_RIFT, 2433.357f, 1192.168f, 148.159f, 3.00f, TEMPSUMMON_TIMED_DESPAWN, 5000); + break; + case 14: + m_creature->SummonCreature(NPC_INFINITE_AGENT, 2433.041f, 1191.158f, 148.128f, 4.99f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_HUNTER, 2433.176f, 1193.429f, 148.114f, 1.21f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_AGENT, 2433.396f, 1192.912f, 148.123f, 0.04f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_ADVERSARY, 2433.626f, 1192.069f, 148.117f, 5.48f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + SetEscortPaused(true); + break; + case 15: + m_creature->SetFacingTo(2.94f); + break; + case 16: + DoScriptText(SAY_ARTHAS_MOVE_ON, m_creature); + SetRun(); + break; + + // spawn third wave - ambush + case 21: + DoScriptText(SAY_ARTHAS_WATCH_BACK, m_creature); + + m_creature->SummonCreature(NPC_INFINITE_HUNTER, 2404.375f, 1179.395f, 148.138f, 5.14f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_AGENT, 2403.785f, 1179.004f, 148.138f, 4.58f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_HUNTER, 2413.933f, 1136.93f, 148.111f, 2.40f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_ADVERSARY, 2414.964f, 1136.857f, 148.088f, 0.90f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_TIME_RIFT, 2404.311f, 1178.306f, 148.158f, 1.60f, TEMPSUMMON_TIMED_DESPAWN, 5000); + m_creature->SummonCreature(NPC_TIME_RIFT, 2414.041f, 1136.068f, 148.159f, 2.23f, TEMPSUMMON_TIMED_DESPAWN, 5000); + SetEscortPaused(true); + break; + case 22: + m_creature->SetFacingTo(1.85f); + break; + case 23: + DoScriptText(SAY_ARTHAS_NOT_EASY, m_creature); + break; + + // spawn forth wave - main hall + case 26: + DoScriptText(SAY_ARTHAS_PERSISTENT, m_creature); + + m_creature->SummonCreature(NPC_INFINITE_HUNTER, 2431.417f, 1105.167f, 148.075f, 1.26f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_AGENT, 2438.808f, 1113.769f, 148.075f, 3.11f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_ADVERSARY, 2440.917f, 1116.085f, 148.080f, 2.18f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_INFINITE_ADVERSARY, 2428.905f, 1102.929f, 148.125f, 1.97f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_TIME_RIFT, 2429.296f, 1102.007f, 148.159f, 6.21f, TEMPSUMMON_TIMED_DESPAWN, 5000); + m_creature->SummonCreature(NPC_TIME_RIFT, 2440.057f, 1114.226f, 148.159f, 6.10f, TEMPSUMMON_TIMED_DESPAWN, 5000); + SetEscortPaused(true); + break; + case 27: + m_creature->SetFacingTo(5.98f); + break; + case 28: + StartNextDialogueText(SAY_ARTHAS_WHAT_ELSE); + SetEscortPaused(true); + break; + + // open passage + case 32: + StartNextDialogueText(SAY_ARTHAS_TAKE_A_MOMENT); + break; + case 33: + DoScriptText(SAY_ARTHAS_PASSAGE, m_creature); + break; + + // townhall escort complete + case 46: + if (m_pInstance) + m_pInstance->SetData(TYPE_ARTHAS_TOWNHALL_EVENT, DONE); + break; + + // burning stratholme + case 57: + DoScriptText(SAY_ARTHAS_REST, m_creature); + m_creature->SetFacingTo(5.04f); + break; + case 58: + DoScriptText(SAY_ARTHAS_REST_COMPLETE, m_creature); + break; + case 69: + StartNextDialogueText(SAY_ARTHAS_CRUSADER_SQUARE); + SetEscortPaused(true); + if (m_pInstance) + m_pInstance->SetData(TYPE_ARTHAS_ESCORT_EVENT, DONE); + break; + + // malganis fight + case 74: + StartNextDialogueText(SAY_ARTHAS_MALGANIS); + SetEscortPaused(true); + break; + + // event epilog + case 75: + StartNextDialogueText(SAY_MALGANIS_JOURNEY); + break; + case 76: + SetRun(false); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + // townhall entrance dialogue + case NPC_TOWNHALL_CITIZEN: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_firstCitizenGuid)) + pCitizen->SetFacingToObject(m_creature); + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_secondCitizenGuid)) + pCitizen->SetFacingToObject(m_creature); + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_thirdCitizenGuid)) + pCitizen->SetFacingToObject(m_creature); + break; + case TEXT_ID_TOWN_HALL_1: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_thirdCitizenGuid)) + DoScriptText(SAY_CITIZEN_ARRIVED, pCitizen); + break; + case SPELL_CRUSADER_STRIKE: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_thirdCitizenGuid)) + DoCastSpellIfCan(pCitizen, SPELL_CRUSADER_STRIKE); + break; + case NPC_TOWNHALL_RESIDENT: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_thirdCitizenGuid)) + pCitizen->HandleEmote(EMOTE_ONESHOT_LAUGH); + break; + case TEXT_ID_TOWN_HALL_2: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_thirdCitizenGuid)) + DoScriptText(SAY_CITIZEN_NO_UNDERSTAD, pCitizen); + break; + case NPC_INFINITE_HUNTER: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_firstCitizenGuid)) + { + pCitizen->CastSpell(pCitizen, SPELL_TRANSFORM, true); + pCitizen->UpdateEntry(NPC_INFINITE_HUNTER); + } + break; + case NPC_INFINITE_AGENT: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_secondCitizenGuid)) + { + pCitizen->CastSpell(pCitizen, SPELL_TRANSFORM, true); + pCitizen->UpdateEntry(NPC_INFINITE_AGENT); + } + break; + case NPC_INFINITE_ADVERSARY: + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(m_thirdCitizenGuid)) + { + pCitizen->CastSpell(pCitizen, SPELL_TRANSFORM, true); + pCitizen->UpdateEntry(NPC_INFINITE_ADVERSARY); + } + break; + + // epoch event dialogue + case SAY_ARTHAS_WHAT_ELSE: + m_creature->SummonCreature(NPC_LORD_EPOCH, 2456.396f, 1113.969f, 150.032f, 3.15f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_TIME_RIFT_BIG, 2456.058f, 1113.838f, 150.091f, 1.74f, TEMPSUMMON_TIMED_DESPAWN, 5000); + break; + case NPC_ARTHAS: + m_creature->HandleEmote(EMOTE_ONESHOT_POINT_NOSHEATHE); + break; + case NPC_LORD_EPOCH: + if (!m_pInstance) + return; + + if (Creature* pEpoch = m_pInstance->GetSingleCreatureFromStorage(NPC_LORD_EPOCH)) + { + pEpoch->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + pEpoch->AI()->AttackStart(m_creature); + } + break; + + // bookcase passage delay + case GO_DOOR_BOOKCASE: + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_DOOR_BOOKCASE); + break; + + // burning city complete delay + case SPELL_TRANSFORM: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + + // malganis attack + case NPC_MALGANIS: + if (!m_pInstance) + return; + + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + { + pMalganis->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + pMalganis->AI()->AttackStart(m_creature); + } + break; + + // malganis event complete + case SAY_ARTHAS_HUNT_MALGANIS: + m_creature->PlayMusic(MUSIC_ID_EVENT_COMPLETE); + + if (!m_pInstance) + return; + + if (Creature* pMalganis = m_pInstance->GetSingleCreatureFromStorage(NPC_MALGANIS)) + { + pMalganis->CastSpell(pMalganis, SPELL_SHADOWSTEP_COSMETIC, true); + pMalganis->CastSpell(pMalganis, SPELL_MALGANIS_ACHIEVEMENT, true); + pMalganis->ForcedDespawn(1000); + } + break; + case TEXT_ID_DREADLORD: + m_creature->HandleEmote(EMOTE_ONESHOT_EXCLAMATION); + break; + case SAY_ARTHAS_EVENT_COMPLETE: + m_creature->SetFacingTo(5.13f); + DoCastSpellIfCan(m_creature, SPELL_MALGANIS_KILL_CREDIT, CAST_TRIGGERED); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MALGANIS_EVENT, DONE); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiExorcismTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_EXORCISM : SPELL_EXORCISM_H) == CAST_OK) + m_uiExorcismTimer = urand(9000, 13000); + } + else + m_uiExorcismTimer -= uiDiff; + + if (m_uiHolyLightTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(40.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HOLY_LIGHT) == CAST_OK) + m_uiHolyLightTimer = urand(18000, 25000); + } + } + else + m_uiHolyLightTimer -= uiDiff; + + if (!m_bYell50Pct && m_creature->GetHealthPercent() < 50.0f) + { + DoScriptText(SAY_ARTHAS_HALF_HP, m_creature); + m_bYell50Pct = true; + } + + if (!m_bYell20Pct && m_creature->GetHealthPercent() < 20.0f) + { + DoScriptText(SAY_ARTHAS_LOW_HP, m_creature); + m_bYell20Pct = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_arthas(Creature* pCreature) +{ + return new npc_arthasAI(pCreature); +} + +bool GossipHello_npc_arthas(Player* pPlayer, Creature* pCreature) +{ + if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pCreature->GetInstanceData()) + { + // city gate gossip + if (pInstance->GetData(TYPE_ARTHAS_INTRO_EVENT) == IN_PROGRESS) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CITY_GATES, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_CITY_GATES, pCreature->GetObjectGuid()); + } + // town hall entrance gossip + else if (pInstance->GetData(TYPE_SALRAMM_EVENT) == DONE && pInstance->GetData(TYPE_EPOCH_EVENT) != DONE) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TOWN_HALL_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_TOWN_HALL_1, pCreature->GetObjectGuid()); + } + // town hall epoch gossip + else if (pInstance->GetData(TYPE_EPOCH_EVENT) == DONE && pInstance->GetData(TYPE_ARTHAS_TOWNHALL_EVENT) != DONE) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_EPOCH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_EPOCH, pCreature->GetObjectGuid()); + } + // burning city gossip + else if (pInstance->GetData(TYPE_ARTHAS_TOWNHALL_EVENT) == DONE && pInstance->GetData(TYPE_ARTHAS_ESCORT_EVENT) != DONE) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ESCORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_ESCORT, pCreature->GetObjectGuid()); + } + // crusader square gossip + else if (pInstance->GetData(TYPE_ARTHAS_ESCORT_EVENT) == DONE && pInstance->GetData(TYPE_MALGANIS_EVENT) != DONE) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DREADLORD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_DREADLORD, pCreature->GetObjectGuid()); + } + } + return true; +} + +bool GossipSelect_npc_arthas(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: // resume WP movement - rest is handled by DB + pCreature->clearUnitState(UNIT_STAT_WAYPOINT_PAUSED); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TOWN_HALL_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_TOWN_HALL_2, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF+3: // start initial town hall escort event + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF+4: // continue escort after Epoch + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pCreature); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF+5: // start burning city event + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT_B, pPlayer, pCreature); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + break; + case GOSSIP_ACTION_INFO_DEF+6: // start Malganis event + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, pPlayer, pCreature); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + break; } return true; } +/* ************* +** npc_spell_dummy_crusader_strike +************* */ + +bool EffectDummyCreature_npc_spell_dummy_crusader_strike(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_CRUSADER_STRIKE && uiEffIndex == EFFECT_INDEX_0) + { + // only apply this for certain citizens + if (pCreatureTarget->GetEntry() == NPC_STRATHOLME_RESIDENT || pCreatureTarget->GetEntry() == NPC_STRATHOLME_CITIZEN) + pCreatureTarget->DealDamage(pCreatureTarget, pCreatureTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + void AddSC_culling_of_stratholme() { Script* pNewScript; @@ -240,4 +985,16 @@ void AddSC_culling_of_stratholme() pNewScript->Name = "spell_dummy_npc_crates_bunny"; pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_npc_crates_dummy; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_arthas"; + pNewScript->GetAI = &GetAI_npc_arthas; + pNewScript->pGossipHello = &GossipHello_npc_arthas; + pNewScript->pGossipSelect = &GossipSelect_npc_arthas; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_spell_dummy_crusader_strike"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_spell_dummy_crusader_strike; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h index 2ae85651b..49ed7e6b1 100644 --- a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/culling_of_stratholme.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,31 +7,34 @@ enum { - MAX_ENCOUNTER = 9, + MAX_ENCOUNTER = 10, + MAX_SCOURGE_WAVES = 10, + MAX_SCOURGE_TYPE_PER_WAVE = 4, TYPE_GRAIN_EVENT = 0, // crates with plagued grain identified TYPE_ARTHAS_INTRO_EVENT = 1, // Arhas Speech and Walk to Gates and short intro with MalGanis TYPE_MEATHOOK_EVENT = 2, // Waves 1-5 TYPE_SALRAMM_EVENT = 3, // Waves 6-10 - TYPE_EPOCH_EVENT = 4, // Townhall Event, Boss Killed - TYPE_ARTHAS_ESCORT_EVENT = 5, // Townhall to Malganis - TYPE_MALGANIS_EVENT = 6, // Malganis - TYPE_INFINITE_CORRUPTER_TIME = 7, // Time for 25min Timer - TYPE_INFINITE_CORRUPTER = 8, + TYPE_ARTHAS_TOWNHALL_EVENT = 4, // Townhall escort event + TYPE_EPOCH_EVENT = 5, // Townhall Event, Boss Killed + TYPE_ARTHAS_ESCORT_EVENT = 6, // Burning city escort event + TYPE_MALGANIS_EVENT = 7, // Malganis + TYPE_INFINITE_CORRUPTER_TIME = 8, // Time for 25min Timer + TYPE_INFINITE_CORRUPTER = 9, // Infinite corruptor event // Main Encounter NPCs NPC_CHROMIE_INN = 26527, NPC_CHROMIE_ENTRANCE = 27915, NPC_CHROMIE_END = 30997, - // NPC_HOURGLASS = 28656, - NPC_ARTHAS = 26499, - // NPC_MEATHOOK = 26529, - // NPC_SALRAMM_THE_FLESHCRAFTER = 26530, - // NPC_CHRONO_LORD_EPOCH = 26532, - // NPC_MALGANIS = 26533, - NPC_INFINITE_CORRUPTER = 32273, + NPC_HOURGLASS = 28656, NPC_LORDAERON_CRIER = 27913, - NPC_ZOMBIE = 27737, + NPC_ARTHAS = 26499, + + // Dungeon bosses + NPC_MEATHOOK = 26529, + NPC_SALRAMM_THE_FLESHCRAFTER = 26530, + NPC_LORD_EPOCH = 26532, + NPC_MALGANIS = 26533, // Inn Event related NPC NPC_MICHAEL_BELFAST = 30571, @@ -47,10 +50,15 @@ enum NPC_JENA_ANDERSON = 27885, NPC_MALCOM_MOORE = 27891, // Not (yet?) spawned NPC_BARTLEBY_BATTSON = 27907, - NPC_CRATES_BUNNY = 30996, + NPC_GRAIN_CRATE_HELPER = 27827, + // NPC_CRATES_BUNNY = 30996, // Intro Event NPCs + NPC_JAINA_PROUDMOORE = 26497, + NPC_UTHER_LIGHTBRINGER = 26528, + NPC_KNIGHT_SILVERHAND = 28612, NPC_LORDAERON_FOOTMAN = 27745, + NPC_HIGH_ELF_MAGE_PRIEST = 27747, NPC_STRATHOLME_CITIZEN = 28167, NPC_STRATHOLME_RESIDENT = 28169, @@ -72,10 +80,41 @@ enum NPC_AGIATED_STRATHOLME_RESIDENT = 31127, NPC_PATRICIA_O_REILLY = 31028, + // Scourge waves + NPC_ENRAGING_GHOUL = 27729, + NPC_ACOLYTE = 27731, + NPC_MASTER_NECROMANCER = 27732, + NPC_CRYPT_FIEND = 27734, + NPC_PATCHWORK_CONSTRUCT = 27736, + NPC_TOMB_STALKER = 28199, + NPC_DARK_NECROMANCER = 28200, + NPC_BILE_GOLEM = 28201, + NPC_DEVOURING_GHOUL = 28249, + NPC_ZOMBIE = 27737, + // NPC_INVISIBLE_STALKER = 20562, + + // Infinite dragons + NPC_TOWNHALL_CITIZEN = 28340, + NPC_TOWNHALL_RESIDENT = 28341, + NPC_INFINITE_ADVERSARY = 27742, + NPC_INFINITE_AGENT = 27744, + NPC_INFINITE_HUNTER = 27743, + NPC_TIME_RIFT = 28409, + NPC_TIME_RIFT_BIG = 28439, + + // Heroic event npcs + NPC_INFINITE_CORRUPTER = 32273, + NPC_GUARDIAN_OF_TIME = 32281, + // Gameobjects GO_DOOR_BOOKCASE = 188686, + GO_CITY_ENTRANCE_GATE = 191788, GO_DARK_RUNED_CHEST = 190663, - GO_DARK_RUNED_CHEST_H = 193597, + GO_DARK_RUNED_CHEST_H = 193597, + + GO_SUSPICIOUS_GRAIN_CRATE = 190094, + GO_CRATE_HIGHLIGHT = 190117, + GO_PLAGUE_GRAIN_CRATE = 190095, // World States WORLD_STATE_CRATES = 3479, @@ -97,6 +136,9 @@ enum 5253 Angelicas boutique 5256 townhall 5291 Inn */ + + // Achievements + ACHIEV_CRIT_ZOMBIEFEST = 7180, // achiev 1872 }; enum eInstancePosition @@ -109,53 +151,99 @@ enum eInstancePosition POS_INSTANCE_FINISHED = 6 }; -class MANGOS_DLL_DECL instance_culling_of_stratholme : public ScriptedInstance +enum eScourgeLocation +{ + POS_FESTIVAL_LANE = 0, + POS_KINGS_SQUARE = 1, + POS_MARKET_ROW = 2, + POS_TOWN_HALL = 3, + POS_ELDERS_SQUARE = 4, +}; + +enum eScourgeType +{ + SCOURGE_TYPE_GHOUL = 1, + SCOURGE_TYPE_NECROMANCER = 2, + SCOURGE_TYPE_FIEND = 3, + SCOURGE_TYPE_GOLEM = 4, + SCOURGE_TYPE_ACOLYTES = 5, + SCOURGE_TYPE_BOSS = 6, +}; + +static const uint32 uiScourgeWaveDef[MAX_SCOURGE_WAVES][MAX_SCOURGE_TYPE_PER_WAVE] = +{ + // first half of scourge waves + {SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL, 0}, + {SCOURGE_TYPE_NECROMANCER, SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL, 0}, + {SCOURGE_TYPE_FIEND, SCOURGE_TYPE_NECROMANCER, SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL}, + {SCOURGE_TYPE_FIEND, SCOURGE_TYPE_NECROMANCER, SCOURGE_TYPE_ACOLYTES, 0}, + {SCOURGE_TYPE_BOSS, 0, 0, 0}, + // second half of scourge waves + {SCOURGE_TYPE_FIEND, SCOURGE_TYPE_FIEND, SCOURGE_TYPE_NECROMANCER, SCOURGE_TYPE_GHOUL}, + {SCOURGE_TYPE_GOLEM, SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL}, + {SCOURGE_TYPE_GOLEM, SCOURGE_TYPE_NECROMANCER, SCOURGE_TYPE_GHOUL, SCOURGE_TYPE_GHOUL}, + {SCOURGE_TYPE_GOLEM, SCOURGE_TYPE_FIEND, SCOURGE_TYPE_NECROMANCER, SCOURGE_TYPE_GHOUL}, + {SCOURGE_TYPE_BOSS, 0, 0, 0} +}; + +class instance_culling_of_stratholme : public ScriptedInstance { public: instance_culling_of_stratholme(Map* pMap); ~instance_culling_of_stratholme() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; - void GetStratAgiatedCitizenList(GUIDList &lList){ lList = m_lAgiatedCitizenGUIDList; }; - void GetStratAgiatedResidentList(GUIDList &lList){ lList = m_lAgiatedResidentGUIDList; }; + void GetCratesBunnyOrderedList(std::list& lList); - void GetCratesBunnyOrderedList(std::list &lList); - Creature* GetStratIntroFootman(); - void GetResidentOrderedList(std::list &lList); - void DoSpawnArthasIfNeeded(); - void DoSpawnChromieIfNeeded(); - uint8 GetInstancePosition(); - void ArthasJustDied(); + void DoSpawnChromieIfNeeded(Unit* pSummoner); + void DoSpawnArthasIfNeeded(Unit* pSummoner); + bool CanGrainEventProgress(Creature* pCrate); + void DoSpawnBurningCityUndead(Unit* pSummoner); + + void DoEventAtTriggerIfCan(uint32 uiTriggerId); protected: - void OnPlayerEnter(Player* pPlayer); - void DoChromieHurrySpeech(); + void DoSetupEntranceSoldiers(Unit* pSummoner); + void DoSpawnCorruptorIfNeeded(Unit* pSummoner); + void DoChromieWhisper(int32 iEntry); + void DoUpdateZombieResidents(); + void DoSpawnNextScourgeWave(); + uint32 GetRandomMobOfType(uint8 uiType); + uint8 GetInstancePosition(); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + bool m_bStartedInnEvent; + uint8 m_uiGrainCrateCount; uint32 m_uiRemoveCrateStateTimer; uint32 m_uiArthasRespawnTimer; - GUIDList m_luiCratesBunnyGUIDs; - GUIDList m_luiFootmanGUIDs; - GUIDList m_luiResidentGUIDs; + uint32 m_uiScourgeWaveTimer; + uint32 m_uiScourgeWaveCount; + uint8 m_uiCurrentUndeadPos; + + GuidList m_luiCratesBunnyGUIDs; + GuidList m_luiResidentGUIDs; + GuidList m_luiGateSoldiersGUIDs; + GuidList m_luiCurrentScourgeWaveGUIDs; - GUIDList m_lAgiatedCitizenGUIDList; - GUIDList m_lAgiatedResidentGUIDList; + GuidSet m_sGrainCratesGuidSet; }; #endif diff --git a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp index 68694ec3c..b015c19a3 100644 --- a/scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp +++ b/scripts/kalimdor/caverns_of_time/culling_of_stratholme/instance_culling_of_stratholme.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,8 +26,25 @@ EndScriptData */ enum { - MAX_ARTHAS_SPAWN_POS = 5, - SAY_CHROMIE_HURRY = -1000000 // TODO + MAX_ARTHAS_SPAWN_POS = 5, + MAX_GRAIN_CRATES = 5, + MAX_SCOURGE_SPAWN_POS = 5, + MAX_BURNING_SCOURGE_POS = 15, + + SAY_SCOURGE_FESTIVAL_LANE = -1595003, + SAY_SCOURGE_KINGS_SQUARE = -1595004, + SAY_SCOURGE_MARKET_ROW = -1595005, + SAY_SCOURGE_TOWN_HALL = -1595006, + SAY_SCOURGE_ELDERS_SQUARE = -1595007, + + SAY_MEET_TOWN_HALL = -1595008, + SAY_CORRUPTOR_DESPAWN = -1595041, + + WHISPER_CHROMIE_CRATES = -1595001, + WHISPER_CHROMIE_GUARDIAN = -1595002, + WHISPER_CHROMIE_HURRY = -1000000, // TODO + + SPELL_CORRUPTION_OF_TIME = 60422, // triggers 60451 }; struct sSpawnLocation @@ -37,25 +54,91 @@ struct sSpawnLocation static sSpawnLocation m_aArthasSpawnLocs[] = // need tuning { - {1969.73f, 1287.12f, 145.48f, 3.14f}, - {2049.43f, 1287.43f, 142.75f, 0.06f}, - {2365.54f, 1194.85f, 131.98f, 0.47f}, - {2534.46f, 1125.99f, 130.75f, 0.27f}, - {2363.77f, 1406.31f, 128.64f, 3.23f} + {1957.13f, 1287.43f, 145.65f, 2.96f}, // bridge + {2091.99f, 1277.25f, 140.47f, 0.43f}, // city entrance + {2366.24f, 1195.25f, 132.04f, 3.15f}, // town hall + {2534.98f, 1126.16f, 130.86f, 2.84f}, // burning stratholme + {2363.44f, 1404.90f, 128.64f, 2.77f}, // crusader square gate +}; + +static sSpawnLocation m_aIntroActorsSpawnLocs[] = +{ + {1876.78f, 1305.72f, 146.24f, 6.07f}, // Jaina + {1786.18f, 1268.63f, 140.02f, 0.42f}, // Uther + {1780.26f, 1261.87f, 139.55f, 0.57f}, // Silverhand knights + {1778.59f, 1265.03f, 139.43f, 0.40f}, + {1777.04f, 1268.16f, 139.35f, 0.59f}, + {2091.47f, 1294.28f, 139.82f, 6.27f}, // High elf priests + {2091.26f, 1281.71f, 139.92f, 6.27f}, + {2096.12f, 1290.53f, 138.81f, 6.27f}, // Footman + {2096.41f, 1284.22f, 138.79f, 6.27f}, + {2096.93f, 1297.57f, 138.96f, 6.27f}, + {2096.32f, 1278.98f, 139.43f, 6.27f} +}; + +static sSpawnLocation m_aChromieSpawnLocs[] = +{ + {1813.298f, 1283.578f, 142.3258f, 3.96f}, // near bridge + {2319.562f, 1506.409f, 152.0499f, 3.78f}, // End + {1810.875f, 1285.035f, 142.4917f, 4.48f}, // Hourglass, near bridge +}; + +static sSpawnLocation m_aHeroicEventSpawnLocs[] = +{ + {2331.642f, 1273.273f, 132.954f, 3.71f}, // Infinite corruptor + {2334.626f, 1280.450f, 133.006f, 1.72f}, // Time rift + {2321.489f, 1268.383f, 132.850f, 0.41f}, // Guardian of time +}; + +struct sScourgeSpawnLoc +{ + uint8 m_uiId; + int32 m_iYellId; + float m_fX, m_fY, m_fZ, m_fO; }; -static sSpawnLocation m_aChromieSpawnLocs[] = // need tuning, escpecially EndPositions! +static sScourgeSpawnLoc m_aScourgeWavesLocs[] = { - {1814.46f, 1283.97f, 142.30f, 4.32f}, // near bridge - {2311.0f, 1502.4f, 127.9f, 0.0f}, // End - {1811.52f, 1285.92f, 142.37f, 4.47f}, // Hourglass, near bridge - {2186.42f, 1323.77f, 129.91f, 0.0f}, // Hourglass, End + {POS_FESTIVAL_LANE, SAY_SCOURGE_FESTIVAL_LANE, 2176.517f, 1244.970f, 136.021f, 1.86f}, + {POS_KINGS_SQUARE, SAY_SCOURGE_KINGS_SQUARE, 2130.760f, 1353.649f, 131.396f, 6.02f}, + {POS_MARKET_ROW, SAY_SCOURGE_MARKET_ROW, 2219.825f, 1331.119f, 127.978f, 3.08f}, + {POS_TOWN_HALL, SAY_SCOURGE_TOWN_HALL, 2351.475f, 1211.893f, 130.361f, 4.50f}, + {POS_ELDERS_SQUARE, SAY_SCOURGE_ELDERS_SQUARE, 2259.153f, 1153.199f, 138.431f, 2.39f}, +}; + +struct sBurningScourgeSpawnLoc +{ + uint8 m_uiType; + float m_fX, m_fY, m_fZ; +}; + +static sBurningScourgeSpawnLoc m_aBurningScourgeLocs[MAX_BURNING_SCOURGE_POS] = +{ + {SCOURGE_TYPE_GHOUL, 2571.570f, 1169.945f, 126.191f}, + {SCOURGE_TYPE_GOLEM, 2560.524f, 1208.296f, 125.613f}, + {SCOURGE_TYPE_GHOUL, 2562.075f, 1182.137f, 126.499f}, + {SCOURGE_TYPE_FIEND, 2552.720f, 1227.233f, 125.620f}, + {SCOURGE_TYPE_GHOUL, 2545.070f, 1245.650f, 125.991f}, + {SCOURGE_TYPE_GHOUL, 2534.250f, 1258.379f, 127.030f}, + {SCOURGE_TYPE_ACOLYTES, 2532.075f, 1271.579f, 127.243f}, + {SCOURGE_TYPE_GHOUL, 2529.144f, 1281.680f, 128.429f}, + {SCOURGE_TYPE_GHOUL, 2491.742f, 1365.169f, 130.827f}, + {SCOURGE_TYPE_FIEND, 2490.869f, 1366.189f, 130.678f}, + {SCOURGE_TYPE_GHOUL, 2479.944f, 1393.666f, 129.975f}, + {SCOURGE_TYPE_GOLEM, 2484.858f, 1380.665f, 130.075f}, + {SCOURGE_TYPE_GHOUL, 2474.965f, 1399.063f, 130.317f}, + {SCOURGE_TYPE_ACOLYTES, 2461.411f, 1416.090f, 130.663f}, + {SCOURGE_TYPE_GHOUL, 2448.391f, 1426.428f, 130.853f}, }; instance_culling_of_stratholme::instance_culling_of_stratholme(Map* pMap) : ScriptedInstance(pMap), + m_bStartedInnEvent(false), m_uiGrainCrateCount(0), m_uiRemoveCrateStateTimer(0), - m_uiArthasRespawnTimer(0) + m_uiArthasRespawnTimer(0), + m_uiScourgeWaveTimer(0), + m_uiScourgeWaveCount(0), + m_uiCurrentUndeadPos(POS_FESTIVAL_LANE) // always the first undead location is Festival Lane { Initialize(); } @@ -65,9 +148,68 @@ void instance_culling_of_stratholme::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_culling_of_stratholme::OnPlayerEnter(Player* pPlayer) +{ + // spawn Chromie + DoSpawnChromieIfNeeded(pPlayer); + + // spawn Arthas if intro is completed / passed + if (GetData(TYPE_ARTHAS_INTRO_EVENT) == DONE) + { + DoSpawnArthasIfNeeded(pPlayer); + + // resume scourge waves if required - this can only happen in case of server reload + if (GetData(TYPE_SALRAMM_EVENT) != DONE) + { + // this will restart the wave event with a delayed timer + if (GetData(TYPE_MEATHOOK_EVENT) == DONE) + { + if (GetData(TYPE_SALRAMM_EVENT) != IN_PROGRESS) + { + SetData(TYPE_SALRAMM_EVENT, IN_PROGRESS); + m_uiScourgeWaveTimer = 30000; + m_uiScourgeWaveCount = 5; + } + } + else + { + if (GetData(TYPE_MEATHOOK_EVENT) != IN_PROGRESS) + { + SetData(TYPE_MEATHOOK_EVENT, IN_PROGRESS); + m_uiScourgeWaveTimer = 30000; + } + } + } + } + + // Show World States if needed + // Grain event world states + if (GetData(TYPE_GRAIN_EVENT) == IN_PROGRESS || GetData(TYPE_GRAIN_EVENT) == SPECIAL) + pPlayer->SendUpdateWorldState(WORLD_STATE_CRATES, 1); // Show Crates Counter + else + pPlayer->SendUpdateWorldState(WORLD_STATE_CRATES, 0); // Remove Crates Counter + + // Scourge waves + if (GetData(TYPE_MEATHOOK_EVENT) == IN_PROGRESS || GetData(TYPE_SALRAMM_EVENT) == IN_PROGRESS) + pPlayer->SendUpdateWorldState(WORLD_STATE_WAVE, m_uiScourgeWaveCount); // Add WaveCounter + else + pPlayer->SendUpdateWorldState(WORLD_STATE_WAVE, 0); // Remove WaveCounter + + // Infinite corruptor + if (GetData(TYPE_INFINITE_CORRUPTER_TIME)) + { + DoSpawnCorruptorIfNeeded(pPlayer); + + pPlayer->SendUpdateWorldState(WORLD_STATE_TIME, 1); // Show Timer + pPlayer->SendUpdateWorldState(WORLD_STATE_TIME_COUNTER, GetData(TYPE_INFINITE_CORRUPTER_TIME) / (MINUTE * IN_MILLISECONDS)); + } + else + pPlayer->SendUpdateWorldState(WORLD_STATE_TIME, 0); // Remove Timer +} + void instance_culling_of_stratholme::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_CHROMIE_ENTRANCE: case NPC_CHROMIE_END: @@ -86,27 +228,48 @@ void instance_culling_of_stratholme::OnCreatureCreate(Creature* pCreature) case NPC_PATRICIA_O_REILLY: case NPC_LORDAERON_CRIER: case NPC_INFINITE_CORRUPTER: + case NPC_LORD_EPOCH: + case NPC_MALGANIS: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; - case NPC_CRATES_BUNNY: m_luiCratesBunnyGUIDs.push_back(pCreature->GetObjectGuid()); break; - case NPC_LORDAERON_FOOTMAN: m_luiFootmanGUIDs.push_back(pCreature->GetObjectGuid()); break; + case NPC_GRAIN_CRATE_HELPER: + m_luiCratesBunnyGUIDs.push_back(pCreature->GetObjectGuid()); + break; + case NPC_LORDAERON_FOOTMAN: + case NPC_HIGH_ELF_MAGE_PRIEST: + if (pCreature->GetPositionX() > 2000.0f) + m_luiGateSoldiersGUIDs.push_back(pCreature->GetObjectGuid()); + break; case NPC_STRATHOLME_CITIZEN: case NPC_STRATHOLME_RESIDENT: + case NPC_AGIATED_STRATHOLME_CITIZEN: + case NPC_AGIATED_STRATHOLME_RESIDENT: if (m_auiEncounter[TYPE_ARTHAS_INTRO_EVENT] == DONE) pCreature->UpdateEntry(NPC_ZOMBIE); else m_luiResidentGUIDs.push_back(pCreature->GetObjectGuid()); break; - case NPC_AGIATED_STRATHOLME_CITIZEN: m_lAgiatedCitizenGUIDList.push_back(pCreature->GetObjectGuid()); break; - case NPC_AGIATED_STRATHOLME_RESIDENT: m_lAgiatedResidentGUIDList.push_back(pCreature->GetObjectGuid()); break; + + case NPC_ENRAGING_GHOUL: + case NPC_ACOLYTE: + case NPC_MASTER_NECROMANCER: + case NPC_CRYPT_FIEND: + case NPC_PATCHWORK_CONSTRUCT: + case NPC_TOMB_STALKER: + case NPC_DARK_NECROMANCER: + case NPC_BILE_GOLEM: + case NPC_DEVOURING_GHOUL: + if (pCreature->IsTemporarySummon() && GetData(TYPE_SALRAMM_EVENT) != DONE) + m_luiCurrentScourgeWaveGUIDs.push_back(pCreature->GetObjectGuid()); + break; } } void instance_culling_of_stratholme::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_DOOR_BOOKCASE: if (m_auiEncounter[TYPE_EPOCH_EVENT] == DONE) @@ -114,6 +277,7 @@ void instance_culling_of_stratholme::OnObjectCreate(GameObject* pGo) break; case GO_DARK_RUNED_CHEST: case GO_DARK_RUNED_CHEST_H: + case GO_CITY_ENTRANCE_GATE: break; default: @@ -122,25 +286,9 @@ void instance_culling_of_stratholme::OnObjectCreate(GameObject* pGo) m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } -void instance_culling_of_stratholme::DoChromieHurrySpeech() -{ - if (Creature* pChromie = GetSingleCreatureFromStorage(NPC_CHROMIE_ENTRANCE)) - { - Map::PlayerList const& players = instance->GetPlayers(); - if (!players.isEmpty()) - { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* pPlayer = itr->getSource()) - DoScriptText(SAY_CHROMIE_HURRY, pChromie, pPlayer); - } - } - } -} - void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_GRAIN_EVENT: m_auiEncounter[uiType] = uiData; @@ -148,13 +296,14 @@ void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData) DoUpdateWorldState(WORLD_STATE_CRATES, 1); else if (uiData == IN_PROGRESS) { - if (m_uiGrainCrateCount >= 5) + // safety check + if (m_uiGrainCrateCount >= MAX_GRAIN_CRATES) return; ++m_uiGrainCrateCount; DoUpdateWorldState(WORLD_STATE_CRATES_COUNT, m_uiGrainCrateCount); - if (m_uiGrainCrateCount == 5) + if (m_uiGrainCrateCount == MAX_GRAIN_CRATES) { m_uiRemoveCrateStateTimer = 20000; SetData(TYPE_GRAIN_EVENT, DONE); @@ -163,29 +312,68 @@ void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData) break; case TYPE_ARTHAS_INTRO_EVENT: m_auiEncounter[uiType] = uiData; - break; - case TYPE_ARTHAS_ESCORT_EVENT: - m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + m_uiScourgeWaveCount = 0; + m_uiScourgeWaveTimer = 1000; + DoUpdateZombieResidents(); + + SetData(TYPE_MEATHOOK_EVENT, IN_PROGRESS); + } break; case TYPE_MEATHOOK_EVENT: m_auiEncounter[uiType] = uiData; if (uiData == DONE) + { + m_uiScourgeWaveTimer = 20000; SetData(TYPE_SALRAMM_EVENT, IN_PROGRESS); + } break; case TYPE_SALRAMM_EVENT: m_auiEncounter[uiType] = uiData; if (uiData == DONE) - DoUpdateWorldState(WORLD_STATE_WAVE, 0); // Remove WaveCounter + m_uiScourgeWaveTimer = 5000; + break; + case TYPE_ARTHAS_TOWNHALL_EVENT: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + // despawn arthas and spawn him in the next point + if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS)) + pArthas->ForcedDespawn(); + + if (Player* pPlayer = GetPlayerInMap()) + DoSpawnArthasIfNeeded(pPlayer); + } break; case TYPE_EPOCH_EVENT: m_auiEncounter[uiType] = uiData; break; + case TYPE_ARTHAS_ESCORT_EVENT: + // use fail in order to respawn Arthas + if (uiData == FAIL) + { + m_uiArthasRespawnTimer = 10000; + + // despawn the bosses if Arthas dies in order to avoid exploits + if (Creature* pEpoch = GetSingleCreatureFromStorage(NPC_LORD_EPOCH, true)) + pEpoch->ForcedDespawn(); + if (Creature* pMalganis = GetSingleCreatureFromStorage(NPC_MALGANIS, true)) + pMalganis->ForcedDespawn(); + } + else + m_auiEncounter[uiType] = uiData; + break; case TYPE_MALGANIS_EVENT: m_auiEncounter[uiType] = uiData; if (uiData == DONE) { - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_DARK_RUNED_CHEST : GO_DARK_RUNED_CHEST_H, 30*MINUTE); - DoSpawnChromieIfNeeded(); + DoUseDoorOrButton(GO_CITY_ENTRANCE_GATE); + DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_DARK_RUNED_CHEST : GO_DARK_RUNED_CHEST_H, GO_FLAG_NO_INTERACT, false); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_DARK_RUNED_CHEST : GO_DARK_RUNED_CHEST_H, 30 * MINUTE); + + if (Player* pPlayer = GetPlayerInMap()) + DoSpawnChromieIfNeeded(pPlayer); } break; case TYPE_INFINITE_CORRUPTER_TIME: @@ -196,41 +384,55 @@ void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData) DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, 0); } else - DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, uiData/(MINUTE*IN_MILLISECONDS)); + DoUpdateWorldState(WORLD_STATE_TIME_COUNTER, uiData / (MINUTE * IN_MILLISECONDS)); break; case TYPE_INFINITE_CORRUPTER: m_auiEncounter[uiType] = uiData; - switch(uiData) + switch (uiData) { case IN_PROGRESS: - if (!m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]) - SetData(TYPE_INFINITE_CORRUPTER_TIME, MINUTE*25*IN_MILLISECONDS); - DoUpdateWorldState(WORLD_STATE_TIME, 1);// Show Timer + if (!GetData(TYPE_INFINITE_CORRUPTER_TIME)) + { + SetData(TYPE_INFINITE_CORRUPTER_TIME, MINUTE * 25 * IN_MILLISECONDS); + DoUpdateWorldState(WORLD_STATE_TIME, 1); + DoChromieWhisper(WHISPER_CHROMIE_GUARDIAN); + + // spawn the corruptor for the first time + if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS)) + DoSpawnCorruptorIfNeeded(pArthas); + } break; case DONE: + // event completed - epilog handled by dbscript SetData(TYPE_INFINITE_CORRUPTER_TIME, 0); break; case SPECIAL: - DoChromieHurrySpeech(); + DoChromieWhisper(WHISPER_CHROMIE_HURRY); break; case FAIL: + // event failed - despawn the corruptor SetData(TYPE_INFINITE_CORRUPTER_TIME, 0); if (Creature* pCorrupter = GetSingleCreatureFromStorage(NPC_INFINITE_CORRUPTER)) + { + DoOrSimulateScriptTextForThisInstance(SAY_CORRUPTOR_DESPAWN, NPC_INFINITE_CORRUPTER); + if (pCorrupter->isAlive()) pCorrupter->ForcedDespawn(); + } break; } break; } - if (uiData == DONE || (uiType == TYPE_INFINITE_CORRUPTER && uiData == FAIL)) + if (uiData == DONE || uiType == TYPE_INFINITE_CORRUPTER_TIME) { OUT_SAVE_INST_DATA; std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9]; m_strInstData = saveStream.str(); @@ -239,6 +441,44 @@ void instance_culling_of_stratholme::SetData(uint32 uiType, uint32 uiData) } } +uint32 instance_culling_of_stratholme::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_culling_of_stratholme::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_MEATHOOK: SetData(TYPE_MEATHOOK_EVENT, DONE); break; + case NPC_SALRAMM_THE_FLESHCRAFTER: SetData(TYPE_SALRAMM_EVENT, DONE); break; + case NPC_LORD_EPOCH: SetData(TYPE_EPOCH_EVENT, DONE); break; + case NPC_INFINITE_CORRUPTER: SetData(TYPE_INFINITE_CORRUPTER, DONE); break; + + case NPC_ENRAGING_GHOUL: + case NPC_ACOLYTE: + case NPC_MASTER_NECROMANCER: + case NPC_CRYPT_FIEND: + case NPC_PATCHWORK_CONSTRUCT: + case NPC_TOMB_STALKER: + case NPC_DARK_NECROMANCER: + case NPC_BILE_GOLEM: + case NPC_DEVOURING_GHOUL: + if (pCreature->IsTemporarySummon() && GetData(TYPE_SALRAMM_EVENT) != DONE) + { + m_luiCurrentScourgeWaveGUIDs.remove(pCreature->GetObjectGuid()); + + // send next scourge wave + if (m_luiCurrentScourgeWaveGUIDs.empty()) + m_uiScourgeWaveTimer = 2000; + } + break; + } +} + void instance_culling_of_stratholme::Load(const char* chrIn) { if (!chrIn) @@ -251,9 +491,10 @@ void instance_culling_of_stratholme::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (i != TYPE_INFINITE_CORRUPTER_TIME) { @@ -269,41 +510,24 @@ void instance_culling_of_stratholme::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -void instance_culling_of_stratholme::OnPlayerEnter(Player* pPlayer) +// Function that will make Chromie to send a whisper to all players in map +void instance_culling_of_stratholme::DoChromieWhisper(int32 iEntry) { - if (instance->GetPlayersCountExceptGMs() == 0) + if (Creature* pChromie = GetSingleCreatureFromStorage(NPC_CHROMIE_ENTRANCE)) { - DoSpawnArthasIfNeeded(); - DoSpawnChromieIfNeeded(); - - // Show World States if needed, TODO verify if needed and if this is the right way - if (m_auiEncounter[TYPE_GRAIN_EVENT] == IN_PROGRESS || m_auiEncounter[TYPE_GRAIN_EVENT] == SPECIAL) - DoUpdateWorldState(WORLD_STATE_CRATES, 1); // Show Crates Counter - else - DoUpdateWorldState(WORLD_STATE_CRATES, 0); // Remove Crates Counter - - if (m_auiEncounter[TYPE_MEATHOOK_EVENT] == IN_PROGRESS) - DoUpdateWorldState(WORLD_STATE_WAVE, 1); // Add WaveCounter - else if (m_auiEncounter[TYPE_SALRAMM_EVENT] == IN_PROGRESS) - DoUpdateWorldState(WORLD_STATE_WAVE, 6); // Add WaveCounter - else - DoUpdateWorldState(WORLD_STATE_WAVE, 0); // Remove WaveCounter - - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]) - DoUpdateWorldState(WORLD_STATE_TIME, 1); // Show Timer - else - DoUpdateWorldState(WORLD_STATE_TIME, 0); // Remove Timer + Map::PlayerList const& players = instance->GetPlayers(); + if (!players.isEmpty()) + { + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + DoScriptText(iEntry, pChromie, pPlayer); + } + } } } -uint32 instance_culling_of_stratholme::GetData(uint32 uiType) -{ - if (uiType < MAX_ENCOUNTER) - return m_auiEncounter[uiType]; - - return 0; -} - +// Function that returns the current position for Arthas event uint8 instance_culling_of_stratholme::GetInstancePosition() { if (m_auiEncounter[TYPE_MALGANIS_EVENT] == DONE) @@ -324,20 +548,17 @@ uint8 instance_culling_of_stratholme::GetInstancePosition() return 0; } +// Sorting function static bool sortFromEastToWest(Creature* pFirst, Creature* pSecond) { return pFirst && pSecond && pFirst->GetPositionY() < pSecond->GetPositionY(); } -static bool sortFromSouthToNorth(Creature* pFirst, Creature* pSecond) -{ - return pFirst && pSecond && pFirst->GetPositionX() < pSecond->GetPositionX(); -} - -void instance_culling_of_stratholme::GetCratesBunnyOrderedList(std::list &lList) +// return the ordered list of Grain Crate Helpers +void instance_culling_of_stratholme::GetCratesBunnyOrderedList(std::list& lList) { std::list lCratesBunnyList; - for (GUIDList::const_iterator itr = m_luiCratesBunnyGUIDs.begin(); itr != m_luiCratesBunnyGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiCratesBunnyGUIDs.begin(); itr != m_luiCratesBunnyGUIDs.end(); ++itr) { if (Creature* pBunny = instance->GetCreature(*itr)) lCratesBunnyList.push_back(pBunny); @@ -349,80 +570,289 @@ void instance_culling_of_stratholme::GetCratesBunnyOrderedList(std::list lFootmanList; - for (GUIDList::const_iterator itr = m_luiFootmanGUIDs.begin(); itr != m_luiFootmanGUIDs.end(); ++itr) + if (!pSummoner) + return; + + Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS, true); + if (pArthas && pArthas->isAlive()) + return; + + uint8 uiPosition = GetInstancePosition(); + if (uiPosition && uiPosition <= MAX_ARTHAS_SPAWN_POS) + pSummoner->SummonCreature(NPC_ARTHAS, m_aArthasSpawnLocs[uiPosition - 1].m_fX, m_aArthasSpawnLocs[uiPosition - 1].m_fY, m_aArthasSpawnLocs[uiPosition - 1].m_fZ, m_aArthasSpawnLocs[uiPosition - 1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000, true); + + // no gossip flag in the following positions + if (uiPosition == POS_ARTHAS_INTRO || uiPosition == POS_ARTHAS_WAVES) { - if (Creature* pFootman = instance->GetCreature(*itr)) - lFootmanList.push_back(pFootman); + if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS)) + pArthas->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - if (lFootmanList.empty()) - return NULL; - else + // summon the other intro actors + if (uiPosition == POS_ARTHAS_INTRO) { - lFootmanList.sort(sortFromSouthToNorth); - return *lFootmanList.begin(); + // start intro event by dbscripts + if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS)) + { + pArthas->SetWalk(false); + pArthas->GetMotionMaster()->MoveWaypoint(); + } + // spawn Jaina and Uther + if (Creature* pJaina = pSummoner->SummonCreature(NPC_JAINA_PROUDMOORE, m_aIntroActorsSpawnLocs[0].m_fX, m_aIntroActorsSpawnLocs[0].m_fY, m_aIntroActorsSpawnLocs[0].m_fZ, m_aIntroActorsSpawnLocs[0].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) + pJaina->GetMotionMaster()->MoveWaypoint(); + if (Creature* pUther = pSummoner->SummonCreature(NPC_UTHER_LIGHTBRINGER, m_aIntroActorsSpawnLocs[1].m_fX, m_aIntroActorsSpawnLocs[1].m_fY, m_aIntroActorsSpawnLocs[1].m_fZ, m_aIntroActorsSpawnLocs[1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) + { + pUther->SetWalk(false); + pUther->GetMotionMaster()->MoveWaypoint(); + + // spawn the knights + if (Creature* pKnight = pSummoner->SummonCreature(NPC_KNIGHT_SILVERHAND, m_aIntroActorsSpawnLocs[2].m_fX, m_aIntroActorsSpawnLocs[2].m_fY, m_aIntroActorsSpawnLocs[2].m_fZ, m_aIntroActorsSpawnLocs[2].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) + pKnight->GetMotionMaster()->MoveFollow(pUther, pKnight->GetDistance(pUther), 2 * M_PI_F - pKnight->GetAngle(pUther)); + if (Creature* pKnight = pSummoner->SummonCreature(NPC_KNIGHT_SILVERHAND, m_aIntroActorsSpawnLocs[3].m_fX, m_aIntroActorsSpawnLocs[3].m_fY, m_aIntroActorsSpawnLocs[3].m_fZ, m_aIntroActorsSpawnLocs[3].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) + pKnight->GetMotionMaster()->MoveFollow(pUther, pKnight->GetDistance(pUther), 2 * M_PI_F - pKnight->GetAngle(pUther)); + if (Creature* pKnight = pSummoner->SummonCreature(NPC_KNIGHT_SILVERHAND, m_aIntroActorsSpawnLocs[4].m_fX, m_aIntroActorsSpawnLocs[4].m_fY, m_aIntroActorsSpawnLocs[4].m_fZ, m_aIntroActorsSpawnLocs[4].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000)) + pKnight->GetMotionMaster()->MoveFollow(pUther, pKnight->GetDistance(pUther), 2 * M_PI_F - pKnight->GetAngle(pUther)); + } } + // setup the entrance soldiers in case of reload or intro skip + else if (uiPosition == POS_ARTHAS_WAVES) + DoSetupEntranceSoldiers(pSummoner); } -void instance_culling_of_stratholme::GetResidentOrderedList(std::list &lList) +// Atm here only new Chromies are spawned +void instance_culling_of_stratholme::DoSpawnChromieIfNeeded(Unit* pSummoner) { - std::list lResidentList; - for (GUIDList::const_iterator itr = m_luiResidentGUIDs.begin(); itr != m_luiResidentGUIDs.end(); ++itr) + if (!pSummoner) + return; + + if (GetInstancePosition() == POS_INSTANCE_FINISHED) { - if (Creature* pResident = instance->GetCreature(*itr)) - lResidentList.push_back(pResident); + Creature* pChromie = GetSingleCreatureFromStorage(NPC_CHROMIE_END, true); + if (!pChromie) + pSummoner->SummonCreature(NPC_CHROMIE_END, m_aChromieSpawnLocs[1].m_fX, m_aChromieSpawnLocs[1].m_fY, m_aChromieSpawnLocs[1].m_fZ, m_aChromieSpawnLocs[1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + } + else if (GetInstancePosition() >= POS_ARTHAS_INTRO) + { + Creature* pChromie = GetSingleCreatureFromStorage(NPC_CHROMIE_ENTRANCE, true); + if (!pChromie) + { + pSummoner->SummonCreature(NPC_CHROMIE_ENTRANCE, m_aChromieSpawnLocs[0].m_fX, m_aChromieSpawnLocs[0].m_fY, m_aChromieSpawnLocs[0].m_fZ, m_aChromieSpawnLocs[0].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + pSummoner->SummonCreature(NPC_HOURGLASS, m_aChromieSpawnLocs[2].m_fX, m_aChromieSpawnLocs[2].m_fY, m_aChromieSpawnLocs[2].m_fZ, m_aChromieSpawnLocs[2].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + } + } +} + +// Function that sets up the city entrance soldiers in case of reload or if the intro is skipped +void instance_culling_of_stratholme::DoSetupEntranceSoldiers(Unit* pSummoner) +{ + if (!pSummoner) + return; + + // despawn the current set of soldiers + for (GuidList::const_iterator itr = m_luiGateSoldiersGUIDs.begin(); itr != m_luiGateSoldiersGUIDs.end(); ++itr) + { + if (Creature* pSoldier = instance->GetCreature(*itr)) + pSoldier->ForcedDespawn(); } - if (lResidentList.empty()) + + // spawn others in the right spot + pSummoner->SummonCreature(NPC_HIGH_ELF_MAGE_PRIEST, m_aIntroActorsSpawnLocs[5].m_fX, m_aIntroActorsSpawnLocs[5].m_fY, m_aIntroActorsSpawnLocs[5].m_fZ, m_aIntroActorsSpawnLocs[5].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 10000); + pSummoner->SummonCreature(NPC_HIGH_ELF_MAGE_PRIEST, m_aIntroActorsSpawnLocs[6].m_fX, m_aIntroActorsSpawnLocs[6].m_fY, m_aIntroActorsSpawnLocs[6].m_fZ, m_aIntroActorsSpawnLocs[6].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 10000); + pSummoner->SummonCreature(NPC_LORDAERON_FOOTMAN, m_aIntroActorsSpawnLocs[7].m_fX, m_aIntroActorsSpawnLocs[7].m_fY, m_aIntroActorsSpawnLocs[7].m_fZ, m_aIntroActorsSpawnLocs[7].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 10000); + pSummoner->SummonCreature(NPC_LORDAERON_FOOTMAN, m_aIntroActorsSpawnLocs[8].m_fX, m_aIntroActorsSpawnLocs[8].m_fY, m_aIntroActorsSpawnLocs[8].m_fZ, m_aIntroActorsSpawnLocs[8].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 10000); + pSummoner->SummonCreature(NPC_LORDAERON_FOOTMAN, m_aIntroActorsSpawnLocs[9].m_fX, m_aIntroActorsSpawnLocs[9].m_fY, m_aIntroActorsSpawnLocs[9].m_fZ, m_aIntroActorsSpawnLocs[9].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 10000); + pSummoner->SummonCreature(NPC_LORDAERON_FOOTMAN, m_aIntroActorsSpawnLocs[10].m_fX, m_aIntroActorsSpawnLocs[10].m_fY, m_aIntroActorsSpawnLocs[10].m_fZ, m_aIntroActorsSpawnLocs[10].m_fO, TEMPSUMMON_CORPSE_DESPAWN, 10000); +} + +// Function that will spawn the infinite corruptor if requires +void instance_culling_of_stratholme::DoSpawnCorruptorIfNeeded(Unit* pSummoner) +{ + if (!pSummoner) + return; + + Creature* pCorruptor = GetSingleCreatureFromStorage(NPC_INFINITE_CORRUPTER, true); + if (pCorruptor) return; - lResidentList.sort(sortFromSouthToNorth); - lList = lResidentList; + pSummoner->SummonCreature(NPC_TIME_RIFT, m_aHeroicEventSpawnLocs[1].m_fX, m_aHeroicEventSpawnLocs[1].m_fY, m_aHeroicEventSpawnLocs[1].m_fZ, m_aHeroicEventSpawnLocs[1].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + pSummoner->SummonCreature(NPC_GUARDIAN_OF_TIME, m_aHeroicEventSpawnLocs[2].m_fX, m_aHeroicEventSpawnLocs[2].m_fY, m_aHeroicEventSpawnLocs[2].m_fZ, m_aHeroicEventSpawnLocs[2].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + + if (Creature* pCorruptor = pSummoner->SummonCreature(NPC_INFINITE_CORRUPTER, m_aHeroicEventSpawnLocs[0].m_fX, m_aHeroicEventSpawnLocs[0].m_fY, m_aHeroicEventSpawnLocs[0].m_fZ, m_aHeroicEventSpawnLocs[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + pCorruptor->CastSpell(pCorruptor, SPELL_CORRUPTION_OF_TIME, false); } -void instance_culling_of_stratholme::ArthasJustDied() +// Function that updates all the stratholme humans to zombies +void instance_culling_of_stratholme::DoUpdateZombieResidents() { - m_uiArthasRespawnTimer = 10000; // TODO, could be instant + // update all residents + for (GuidList::const_iterator itr = m_luiResidentGUIDs.begin(); itr != m_luiResidentGUIDs.end(); ++itr) + { + if (Creature* pResident = instance->GetCreature(*itr)) + pResident->UpdateEntry(NPC_ZOMBIE); + } } -void instance_culling_of_stratholme::DoSpawnArthasIfNeeded() +// Function to check if the grain event can progress +bool instance_culling_of_stratholme::CanGrainEventProgress(Creature* pCrate) { - Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS, true); - if (pArthas && pArthas->isAlive()) - return; + if (!pCrate) + return false; - uint8 uiPosition = GetInstancePosition(); - if (uiPosition && uiPosition <= MAX_ARTHAS_SPAWN_POS) + if (m_sGrainCratesGuidSet.find(pCrate->GetObjectGuid()) != m_sGrainCratesGuidSet.end()) + return false; + + if (GetData(TYPE_GRAIN_EVENT) != DONE) + SetData(TYPE_GRAIN_EVENT, IN_PROGRESS); + + m_sGrainCratesGuidSet.insert(pCrate->GetObjectGuid()); + return true; +} + +// Function that handles instance area trigger scripts +void instance_culling_of_stratholme::DoEventAtTriggerIfCan(uint32 uiTriggerId) +{ + switch (uiTriggerId) { - if (Player* pPlayer = GetPlayerInMap()) - pPlayer->SummonCreature(NPC_ARTHAS, m_aArthasSpawnLocs[uiPosition-1].m_fX, m_aArthasSpawnLocs[uiPosition-1].m_fY, m_aArthasSpawnLocs[uiPosition-1].m_fZ, m_aArthasSpawnLocs[uiPosition-1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + case AREATRIGGER_INN: + if (m_bStartedInnEvent) + return; + + // start dialogue + if (Creature* pMichael = GetSingleCreatureFromStorage(NPC_MICHAEL_BELFAST)) + { + pMichael->SetStandState(UNIT_STAND_STATE_STAND); + pMichael->GetMotionMaster()->MoveWaypoint(); + } + m_bStartedInnEvent = true; + break; } } -// Atm here only new Chromies are spawned - despawning depends on Mangos featuring such a thing -// The hourglass also is not yet spawned/ relocated. -void instance_culling_of_stratholme::DoSpawnChromieIfNeeded() +// Function that spawns next scourge wave +void instance_culling_of_stratholme::DoSpawnNextScourgeWave() { - Player* pPlayer = GetPlayerInMap(); - if (!pPlayer) + Creature* pSummoner = GetSingleCreatureFromStorage(NPC_ARTHAS); + if (!pSummoner) return; - if (GetInstancePosition() == POS_INSTANCE_FINISHED) + DoOrSimulateScriptTextForThisInstance(m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_iYellId, NPC_LORDAERON_CRIER); + + for (uint8 i = 0; i < MAX_SCOURGE_TYPE_PER_WAVE; ++i) { - Creature* pChromie = GetSingleCreatureFromStorage(NPC_CHROMIE_END, true); - if (!pChromie) - pPlayer->SummonCreature(NPC_CHROMIE_END, m_aChromieSpawnLocs[1].m_fX, m_aChromieSpawnLocs[1].m_fY, m_aChromieSpawnLocs[1].m_fZ, m_aChromieSpawnLocs[1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + // get the mob entry + uint32 uiEntry = GetRandomMobOfType(uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i]); + if (!uiEntry) + continue; + + float fX, fY, fZ, fO; + fO = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fO; + + // bosses get exact location + if (uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i] == SCOURGE_TYPE_BOSS || uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i] == SCOURGE_TYPE_ACOLYTES) + { + fX = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fX; + fY = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fY; + fZ = m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fZ; + } + // random position around point + else + pSummoner->GetRandomPoint(m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fX, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fY, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fZ, 5.0f, fX, fY, fZ); + + // special requirement for acolytes - spawn a pack of 4 + if (uiScourgeWaveDef[m_uiScourgeWaveCount - 1][i] == SCOURGE_TYPE_ACOLYTES) + { + for (uint8 j = 0; j < 4; ++j) + { + pSummoner->GetRandomPoint(m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fX, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fY, m_aScourgeWavesLocs[m_uiCurrentUndeadPos].m_fZ, 5.0f, fX, fY, fZ); + pSummoner->SummonCreature(uiEntry, fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + // spawn the selected mob + else + pSummoner->SummonCreature(uiEntry, fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0); } - else if (GetInstancePosition() >= POS_ARTHAS_INTRO) + + // start infinite curruptor event on the first wave + if (m_uiScourgeWaveCount == 1 && !instance->IsRegularDifficulty() && GetData(TYPE_INFINITE_CORRUPTER) != DONE) + SetData(TYPE_INFINITE_CORRUPTER, IN_PROGRESS); + + // get a random position that is different from the previous one for the next round + uint8 uiCurrentPos = urand(POS_FESTIVAL_LANE, POS_ELDERS_SQUARE); + + while (uiCurrentPos == m_uiCurrentUndeadPos) + uiCurrentPos = urand(POS_FESTIVAL_LANE, POS_ELDERS_SQUARE); + + m_uiCurrentUndeadPos = uiCurrentPos; +} + +// function that spawns all the scourge elites in burning stratholme +void instance_culling_of_stratholme::DoSpawnBurningCityUndead(Unit* pSummoner) +{ + for (uint8 i = 0; i < MAX_BURNING_SCOURGE_POS; ++i) { - Creature* pChromie = GetSingleCreatureFromStorage(NPC_CHROMIE_ENTRANCE, true); - if (!pChromie) - pPlayer->SummonCreature(NPC_CHROMIE_ENTRANCE, m_aChromieSpawnLocs[0].m_fX, m_aChromieSpawnLocs[0].m_fY, m_aChromieSpawnLocs[0].m_fZ, m_aChromieSpawnLocs[0].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); + uint32 uiEntry = GetRandomMobOfType(m_aBurningScourgeLocs[i].m_uiType); + if (!uiEntry) + continue; + + float fX, fY, fZ; + + // special requirement for acolytes - spawn a pack of 3 + if (m_aBurningScourgeLocs[i].m_uiType == SCOURGE_TYPE_ACOLYTES) + { + for (uint8 j = 0; j < 3; ++j) + { + pSummoner->GetRandomPoint(m_aBurningScourgeLocs[i].m_fX, m_aBurningScourgeLocs[i].m_fY, m_aBurningScourgeLocs[i].m_fZ, 5.0f, fX, fY, fZ); + + if (Creature* pUndead = pSummoner->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + pUndead->GetMotionMaster()->MoveRandomAroundPoint(pUndead->GetPositionX(), pUndead->GetPositionY(), pUndead->GetPositionZ(), 10.0f); + } + } + // spawn the selected mob + else + { + if (Creature* pUndead = pSummoner->SummonCreature(uiEntry, m_aBurningScourgeLocs[i].m_fX, m_aBurningScourgeLocs[i].m_fY, m_aBurningScourgeLocs[i].m_fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + pUndead->GetMotionMaster()->MoveRandomAroundPoint(pUndead->GetPositionX(), pUndead->GetPositionY(), pUndead->GetPositionZ(), 10.0f); + } + + // spawn a few random zombies + for (uint8 j = 0; j < 5; ++j) + { + pSummoner->GetRandomPoint(m_aBurningScourgeLocs[i].m_fX, m_aBurningScourgeLocs[i].m_fY, m_aBurningScourgeLocs[i].m_fZ, 20.0f, fX, fY, fZ); + + if (Creature* pUndead = pSummoner->SummonCreature(NPC_ZOMBIE, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + pUndead->GetMotionMaster()->MoveRandomAroundPoint(pUndead->GetPositionX(), pUndead->GetPositionY(), pUndead->GetPositionZ(), 10.0f); + } } } +// function that returns a random scourge mob of a specified type +uint32 instance_culling_of_stratholme::GetRandomMobOfType(uint8 uiType) +{ + switch (uiType) + { + case SCOURGE_TYPE_ACOLYTES: + return NPC_ACOLYTE; + case SCOURGE_TYPE_GHOUL: + return urand(0, 1) ? NPC_DEVOURING_GHOUL : NPC_ENRAGING_GHOUL; + case SCOURGE_TYPE_NECROMANCER: + return urand(0, 1) ? NPC_MASTER_NECROMANCER : NPC_DARK_NECROMANCER; + case SCOURGE_TYPE_FIEND: + return urand(0, 1) ? NPC_CRYPT_FIEND : NPC_TOMB_STALKER; + case SCOURGE_TYPE_GOLEM: + return urand(0, 1) ? NPC_BILE_GOLEM : NPC_PATCHWORK_CONSTRUCT; + case SCOURGE_TYPE_BOSS: + if (GetData(TYPE_MEATHOOK_EVENT) == IN_PROGRESS) + return NPC_MEATHOOK; + else if (GetData(TYPE_SALRAMM_EVENT) == IN_PROGRESS) + return NPC_SALRAMM_THE_FLESHCRAFTER; + } + + return 0; +} + void instance_culling_of_stratholme::Update(uint32 uiDiff) { // 25min Run - decrease time, update worldstate every ~20s @@ -434,12 +864,12 @@ void instance_culling_of_stratholme::Update(uint32 uiDiff) else { m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] -= uiDiff; - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]/IN_MILLISECONDS % 20 == 0) + if (m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] / IN_MILLISECONDS % 20 == 0) SetData(TYPE_INFINITE_CORRUPTER_TIME, m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME]); } // This part is needed for a small "hurry up guys" note, TODO, verify 20min - if (m_auiEncounter[TYPE_INFINITE_CORRUPTER] == IN_PROGRESS && m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] <= 24*MINUTE*IN_MILLISECONDS) + if (m_auiEncounter[TYPE_INFINITE_CORRUPTER] == IN_PROGRESS && m_auiEncounter[TYPE_INFINITE_CORRUPTER_TIME] <= 24 * MINUTE * IN_MILLISECONDS) SetData(TYPE_INFINITE_CORRUPTER, SPECIAL); } @@ -448,8 +878,11 @@ void instance_culling_of_stratholme::Update(uint32 uiDiff) { if (m_uiRemoveCrateStateTimer <= uiDiff) { + if (Player* pPlayer = GetPlayerInMap()) + DoSpawnChromieIfNeeded(pPlayer); + DoUpdateWorldState(WORLD_STATE_CRATES, 0); - DoSpawnChromieIfNeeded(); + DoChromieWhisper(WHISPER_CHROMIE_CRATES); m_uiRemoveCrateStateTimer = 0; } else @@ -461,12 +894,43 @@ void instance_culling_of_stratholme::Update(uint32 uiDiff) { if (m_uiArthasRespawnTimer <= uiDiff) { - DoSpawnArthasIfNeeded(); + if (Player* pPlayer = GetPlayerInMap()) + DoSpawnArthasIfNeeded(pPlayer); + m_uiArthasRespawnTimer = 0; } else m_uiArthasRespawnTimer -= uiDiff; } + + // Handle undead waves + if (m_uiScourgeWaveTimer) + { + if (m_uiScourgeWaveTimer <= uiDiff) + { + if (GetData(TYPE_SALRAMM_EVENT) == DONE) + { + DoOrSimulateScriptTextForThisInstance(SAY_MEET_TOWN_HALL, NPC_ARTHAS); + DoUpdateWorldState(WORLD_STATE_WAVE, 0); // Remove WaveCounter + + // despawn and respawn Arthas in the new location + if (Creature* pArthas = GetSingleCreatureFromStorage(NPC_ARTHAS)) + pArthas->ForcedDespawn(); + if (Player* pPlayer = GetPlayerInMap()) + DoSpawnArthasIfNeeded(pPlayer); + } + else + { + ++m_uiScourgeWaveCount; + DoUpdateWorldState(WORLD_STATE_WAVE, m_uiScourgeWaveCount); + DoSpawnNextScourgeWave(); + } + + m_uiScourgeWaveTimer = 0; + } + else + m_uiScourgeWaveTimer -= uiDiff; + } } InstanceData* GetInstanceData_instance_culling_of_stratholme(Map* pMap) @@ -474,6 +938,20 @@ InstanceData* GetInstanceData_instance_culling_of_stratholme(Map* pMap) return new instance_culling_of_stratholme(pMap); } +bool AreaTrigger_at_culling_of_stratholme(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_INN) + { + if (pPlayer->isGameMaster() || pPlayer->isDead()) + return false; + + if (instance_culling_of_stratholme* pInstance = (instance_culling_of_stratholme*)pPlayer->GetInstanceData()) + pInstance->DoEventAtTriggerIfCan(pAt->id); + } + + return false; +} + void AddSC_instance_culling_of_stratholme() { Script* pNewScript; @@ -482,4 +960,9 @@ void AddSC_instance_culling_of_stratholme() pNewScript->Name = "instance_culling_of_stratholme"; pNewScript->GetInstanceData = &GetInstanceData_instance_culling_of_stratholme; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_culling_of_stratholme"; + pNewScript->pAreaTrigger = &AreaTrigger_at_culling_of_stratholme; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp b/scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp index 1672289ea..31be7cf67 100644 --- a/scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp +++ b/scripts/kalimdor/caverns_of_time/dark_portal/boss_aeonus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,6 @@ EndScriptData */ enum { - SAY_ENTER = -1269012, SAY_AGGRO = -1269013, SAY_BANISH = -1269014, SAY_SLAY1 = -1269015, @@ -41,7 +40,7 @@ enum SPELL_SAND_BREATH_H = 39049 }; -struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI +struct boss_aeonusAI : public ScriptedAI { boss_aeonusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -58,7 +57,7 @@ struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI uint32 m_uiFrenzyTimer; uint32 m_uiCleaveTimer; - void Reset() + void Reset() override { m_uiSandBreathTimer = urand(15000, 30000); m_uiTimeStopTimer = urand(10000, 15000); @@ -66,12 +65,12 @@ struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI m_uiCleaveTimer = urand(5000, 9000); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // Despawn Time Keeper if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_TIME_KEEPER) @@ -86,20 +85,17 @@ struct MANGOS_DLL_DECL boss_aeonusAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RIFT, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp b/scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp index 7014e9d69..7cab5098c 100644 --- a/scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp +++ b/scripts/kalimdor/caverns_of_time/dark_portal/boss_chrono_lord_deja.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,6 @@ EndScriptData */ enum { - SAY_ENTER = -1269006, SAY_AGGRO = -1269007, SAY_BANISH = -1269008, SAY_SLAY1 = -1269009, @@ -41,7 +40,7 @@ enum SPELL_ATTRACTION = 38540 }; -struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI +struct boss_chrono_lord_dejaAI : public ScriptedAI { boss_chrono_lord_dejaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -58,7 +57,7 @@ struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI uint32 m_uiAttractionTimer; uint32 m_uiArcaneDischargeTimer; - void Reset() + void Reset() override { m_uiArcaneBlastTimer = urand(18000, 23000); m_uiTimeLapseTimer = urand(10000, 15000); @@ -66,12 +65,12 @@ struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI m_uiAttractionTimer = urand(25000, 35000); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // Despawn Time Keeper if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_TIME_KEEPER) @@ -86,20 +85,17 @@ struct MANGOS_DLL_DECL boss_chrono_lord_dejaAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RIFT, SPECIAL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp b/scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp index 2ee135973..55275e981 100644 --- a/scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp +++ b/scripts/kalimdor/caverns_of_time/dark_portal/boss_temporus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,6 @@ EndScriptData */ enum { - SAY_ENTER = -1269000, SAY_AGGRO = -1269001, SAY_BANISH = -1269002, SAY_SLAY1 = -1269003, @@ -40,7 +39,7 @@ enum SPELL_REFLECT = 38592 }; -struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI +struct boss_temporusAI : public ScriptedAI { boss_temporusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -57,7 +56,7 @@ struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI uint32 m_uiMortalWoundTimer; uint32 m_uiWingBuffetTimer; - void Reset() + void Reset() override { m_uiHasteTimer = urand(15000, 23000); m_uiSpellReflectionTimer = 30000; @@ -65,30 +64,27 @@ struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI m_uiWingBuffetTimer = urand(25000, 35000); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_RIFT, SPECIAL); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // Despawn Time Keeper if (pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_TIME_KEEPER) { - if (m_creature->IsWithinDistInMap(pWho,20.0f)) + if (m_creature->IsWithinDistInMap(pWho, 20.0f)) { if (DoCastSpellIfCan(pWho, SPELL_BANISH_HELPER) == CAST_OK) DoScriptText(SAY_BANISH, m_creature); @@ -98,7 +94,7 @@ struct MANGOS_DLL_DECL boss_temporusAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp b/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp index 5fc50ecbe..52a7b8e96 100644 --- a/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp +++ b/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Dark_Portal -SD%Complete: 30 -SDComment: Misc NPC's and mobs for instance. Most here far from complete. +SD%Complete: 80 +SDComment: Some things may be still missing from here SDCategory: Caverns of Time, The Dark Portal EndScriptData */ @@ -29,33 +29,20 @@ EndContentData */ #include "precompiled.h" #include "dark_portal.h" -#define SAY_ENTER -1269020 //where does this belong? -#define SAY_INTRO -1269021 -#define SAY_WEAK75 -1269022 -#define SAY_WEAK50 -1269023 -#define SAY_WEAK25 -1269024 -#define SAY_DEATH -1269025 -#define SAY_WIN -1269026 -#define SAY_ORCS_ENTER -1269027 -#define SAY_ORCS_ANSWER -1269028 +/*###### +## npc_medivh_black_morass +######*/ -#define SPELL_CHANNEL 31556 -#define SPELL_PORTAL_RUNE 32570 //aura(portal on ground effect) - -#define SPELL_BLACK_CRYSTAL 32563 //aura -#define SPELL_PORTAL_CRYSTAL 32564 //summon - -#define SPELL_BANISH_PURPLE 32566 //aura -#define SPELL_BANISH_GREEN 32567 //aura - -#define SPELL_CORRUPT 31326 -#define SPELL_CORRUPT_AEONUS 37853 +enum +{ + SAY_DEATH = -1269025, -#define C_COUNCIL_ENFORCER 17023 + SPELL_CORRUPT = 31326, +}; -struct MANGOS_DLL_DECL npc_medivh_bmAI : public ScriptedAI +struct npc_medivh_black_morassAI : public ScriptedAI { - npc_medivh_bmAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_medivh_black_morassAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -63,291 +50,282 @@ struct MANGOS_DLL_DECL npc_medivh_bmAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 SpellCorrupt_Timer; - uint32 Check_Timer; - - bool Life75; - bool Life50; - bool Life25; - - void Reset() - { - SpellCorrupt_Timer = 0; - Check_Timer = 0; - - Life75 = true; - Life50 = true; - Life25 = true; - - if (!m_pInstance) - return; - - if (m_pInstance->GetData(TYPE_MEDIVH) == IN_PROGRESS) - m_creature->CastSpell(m_creature, SPELL_CHANNEL, true); - else if (m_creature->HasAura(SPELL_CHANNEL, EFFECT_INDEX_0)) - m_creature->RemoveAurasDueToSpell(SPELL_CHANNEL); + void Reset() override { } - m_creature->CastSpell(m_creature, SPELL_PORTAL_RUNE, true); - } + void AttackStart(Unit* /*pWho*/) override { } - void MoveInLineOfSight(Unit *who) + void JustSummoned(Creature* pSummoned) override { - if (!m_pInstance) - return; - - if (who->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(who, 10.0f)) + // The rift trash mobs are summoned by Medivh, so we can control the movement + if (pSummoned->GetEntry() != NPC_TIME_RIFT && pSummoned->GetEntry() != NPC_COUNCIL_ENFORCER) { - if (m_pInstance->GetData(TYPE_MEDIVH) == IN_PROGRESS || m_pInstance->GetData(TYPE_MEDIVH) == DONE) - return; - - DoScriptText(SAY_INTRO, m_creature); - m_pInstance->SetData(TYPE_MEDIVH, IN_PROGRESS); - m_creature->CastSpell(m_creature, SPELL_CHANNEL, false); - Check_Timer = 5000; + float fX, fY, fZ; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 20.0f, m_creature->GetAngle(pSummoned)); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } - else if (who->GetTypeId() == TYPEID_UNIT && m_creature->IsWithinDistInMap(who, 15.0f)) - { - if (m_pInstance->GetData(TYPE_MEDIVH) != IN_PROGRESS) - return; - - uint32 entry = who->GetEntry(); - if (entry == NPC_ASSAS || entry == NPC_WHELP || entry == NPC_CHRON || entry == NPC_EXECU || entry == NPC_VANQU) - { - who->StopMoving(); - who->CastSpell(m_creature, SPELL_CORRUPT, false); - } - else if (entry == NPC_AEONUS) - { - who->StopMoving(); - who->CastSpell(m_creature, SPELL_CORRUPT_AEONUS, false); - } - } - } - - void AttackStart(Unit *who) - { - //if (m_pInstance && m_pInstance->GetData(TYPE_MEDIVH) == IN_PROGRESS) - //return; - - //ScriptedAI::AttackStart(who); } - void SpellHit(Unit* caster, const SpellEntry* spell) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override { - if (SpellCorrupt_Timer) + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) return; - if (spell->Id == SPELL_CORRUPT_AEONUS) - SpellCorrupt_Timer = 1000; - - if (spell->Id == SPELL_CORRUPT) - SpellCorrupt_Timer = 3000; + pSummoned->CastSpell(m_creature, SPELL_CORRUPT, false); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { - if (Killer->GetEntry() == m_creature->GetEntry()) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_MEDIVH, FAIL); DoScriptText(SAY_DEATH, m_creature); } - void UpdateAI(const uint32 diff) - { - if (!m_pInstance) - return; - - if (SpellCorrupt_Timer) - { - if (SpellCorrupt_Timer <= diff) - { - m_pInstance->SetData(TYPE_MEDIVH, SPECIAL); - - if (m_creature->HasAura(SPELL_CORRUPT_AEONUS, EFFECT_INDEX_0)) - SpellCorrupt_Timer = 1000; - else if (m_creature->HasAura(SPELL_CORRUPT, EFFECT_INDEX_0)) - SpellCorrupt_Timer = 3000; - else - SpellCorrupt_Timer = 0; - } - else - SpellCorrupt_Timer -= diff; - } - - if (Check_Timer) - { - if (Check_Timer <= diff) - { - uint32 pct = m_pInstance->GetData(DATA_SHIELD); - - Check_Timer = 5000; + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; - if (Life25 && pct <= 25) - { - DoScriptText(SAY_WEAK25, m_creature); - Life25 = false; - } - else if (Life50 && pct <= 50) - { - DoScriptText(SAY_WEAK50, m_creature); - Life50 = false; - } - else if (Life75 && pct <= 75) - { - DoScriptText(SAY_WEAK75, m_creature); - Life75 = false; - } +CreatureAI* GetAI_npc_medivh_black_morass(Creature* pCreature) +{ + return new npc_medivh_black_morassAI(pCreature); +} - //if we reach this it means event was running but at some point reset. - if (m_pInstance->GetData(TYPE_MEDIVH) == NOT_STARTED) - { - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_creature->RemoveCorpse(); - m_creature->Respawn(); - return; - } +bool EffectDummyCreature_npc_medivh_black_morass(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if ((uiSpellId == SPELL_CORRUPT && uiEffIndex == EFFECT_INDEX_0) || (uiSpellId == SPELL_CORRUPT_AEONUS && uiEffIndex == EFFECT_INDEX_0)) + { + if (instance_dark_portal* pInstance = (instance_dark_portal*)pCreatureTarget->GetInstanceData()) + pInstance->SetData(TYPE_SHIELD, SPECIAL); - if (m_pInstance->GetData(TYPE_RIFT) == DONE) - { - DoScriptText(SAY_WIN, m_creature); - Check_Timer = 0; + // always return true when we are handling this spell and effect + return true; + } - if (m_creature->HasAura(SPELL_CHANNEL, EFFECT_INDEX_0)) - m_creature->RemoveAurasDueToSpell(SPELL_CHANNEL); + return false; +} - //TODO: start the post-event here - m_pInstance->SetData(TYPE_MEDIVH,DONE); - } - } - else - Check_Timer -= diff; - } +/*###### +## npc_time_rift +######*/ - //if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - //return; +enum +{ + SPELL_RIFT_PERIODIC = 31320, // should trigger 31388 - //DoMeleeAttackIfReady(); - } + // Boss spawn yells + SAY_CHRONO_LORD_ENTER = -1269006, + SAY_TEMPORUS_ENTER = -1269000, + SAY_AEONUS_ENTER = -1269012, }; -CreatureAI* GetAI_npc_medivh_bm(Creature* pCreature) -{ - return new npc_medivh_bmAI(pCreature); -} - -struct Wave +struct RiftWaveData { - uint32 PortalMob[4]; //spawns for portal waves (in order) + uint32 uiPortalMob[4]; // spawns for portal waves (in order) }; -static Wave PortalWaves[]= +static const RiftWaveData aPortalWaves[] = { - {NPC_ASSAS, NPC_WHELP, NPC_CHRON, 0}, - {NPC_EXECU, NPC_CHRON, NPC_WHELP, NPC_ASSAS}, - {NPC_EXECU, NPC_VANQU, NPC_CHRON, NPC_ASSAS} + {{NPC_ASSASSIN, NPC_WHELP, NPC_CHRONOMANCER, 0}}, + {{NPC_EXECUTIONER, NPC_CHRONOMANCER, NPC_WHELP, NPC_ASSASSIN}}, + {{NPC_EXECUTIONER, NPC_VANQUISHER, NPC_CHRONOMANCER, NPC_ASSASSIN}} }; -struct MANGOS_DLL_DECL npc_time_riftAI : public ScriptedAI +struct npc_time_riftAI : public ScriptedAI { npc_time_riftAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_dark_portal*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bIsFirstSummon = true; + m_uiRiftNumber = 0; + m_uiRiftWaveId = 0; Reset(); } - ScriptedInstance* m_pInstance; + instance_dark_portal* m_pInstance; - uint32 TimeRiftWave_Timer; - uint8 mRiftWaveCount; - uint8 mPortalCount; - uint8 mWaveId; + bool m_bIsRegularMode; + bool m_bIsFirstSummon; - void Reset() - { - TimeRiftWave_Timer = 15000; - mRiftWaveCount = 0; + uint8 m_uiRiftWaveCount; + uint8 m_uiRiftNumber; + uint8 m_uiRiftWaveId; - if (!m_pInstance) - return; + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_RIFT_PERIODIC); - mPortalCount = m_pInstance->GetData(DATA_PORTAL_COUNT); + m_uiRiftWaveCount = 0; + m_uiRiftNumber = 0; - if (mPortalCount < 6) - mWaveId = 0; - else if (mPortalCount > 12) - mWaveId = 2; - else - mWaveId = 1; + if (m_pInstance) + { + m_uiRiftNumber = m_pInstance->GetCurrentRiftId(); + if (m_uiRiftNumber < 6) + m_uiRiftWaveId = 0; + else if (m_uiRiftNumber > 12) + m_uiRiftWaveId = 2; + else + m_uiRiftWaveId = 1; + } } - void DoSummonAtRift(uint32 creature_entry) + void DoSummonCreatureAtRift(uint32 uiCreatureEntry, Creature* pSummoner) { - if (!creature_entry) + if (!uiCreatureEntry) return; - if (m_pInstance->GetData(TYPE_MEDIVH) != IN_PROGRESS) - { - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, fX, fY, fZ); + pSummoner->SummonCreature(uiCreatureEntry, fX, fY, fZ, m_creature->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void DoSummon() + { + if (!m_pInstance) return; - } - float x, y, z; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, x, y, z); - // uncomment the following if something doesn't work correctly, otherwise just delete - // m_creature->UpdateAllowedPositionZ(x, y, z); + uint32 uiSummonEntry = 0; - if (Unit* pSummon = m_creature->SummonCreature(creature_entry, x, y, z, m_creature->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + if (m_bIsFirstSummon) { - if (Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_MEDIVH)) - pSummon->AddThreat(pMedivh); - } - } + // Select portal keeper / boss to summon + // On Heroic Mode if Chrono Lord and Temporus are already killed, we need to summon the replacement + switch (m_uiRiftNumber) + { + case 6: + uiSummonEntry = (m_pInstance->GetData(TYPE_CHRONO_LORD) == DONE && !m_bIsRegularMode) ? NPC_CHRONO_LORD : NPC_CHRONO_LORD_DEJA; + break; + case 12: + uiSummonEntry = (m_pInstance->GetData(TYPE_TEMPORUS) == DONE && !m_bIsRegularMode) ? NPC_TIMEREAVER : NPC_TEMPORUS; + break; + case 18: + uiSummonEntry = NPC_AEONUS; + break; + default: + uiSummonEntry = urand(0, 1) ? NPC_RIFT_KEEPER : NPC_RIFT_LORD; + break; + } - void DoSelectSummon() - { - uint32 entry = 0; + // Set the next rift delay + if (uiSummonEntry != NPC_AEONUS) + m_pInstance->SetData(TYPE_TIME_RIFT, SPECIAL); + + DoSummonCreatureAtRift(uiSummonEntry, m_creature); + m_bIsFirstSummon = false; + } + else + { + // Some creatures are summoned by Medivh, because we can better handle the movement this way + Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_MEDIVH); + if (!pMedivh) + return; - if ((mRiftWaveCount > 2 && mWaveId < 1) || mRiftWaveCount > 3) - mRiftWaveCount = 0; + // Reset the RiftWaveCount if we reached the maximum number of the currentRiftWave is 0 + if ((m_uiRiftWaveCount > 2 && !m_uiRiftWaveId) || m_uiRiftWaveCount > 3) + m_uiRiftWaveCount = 0; - entry = PortalWaves[mWaveId].PortalMob[mRiftWaveCount]; - debug_log("SD2: npc_time_rift: summoning wave creature (Wave %u, Entry %u).", mRiftWaveCount, entry); + uiSummonEntry = aPortalWaves[m_uiRiftWaveId].uiPortalMob[m_uiRiftWaveCount]; + ++m_uiRiftWaveCount; - ++mRiftWaveCount; + // Summon the trash waves by Medivh, so we can better handle the movement + // For Whelps we need to summon them in packs of 3 + if (uiSummonEntry == NPC_WHELP) + { + for (uint8 i = 0; i < 3; ++i) + DoSummonCreatureAtRift(uiSummonEntry, pMedivh); + } + else + DoSummonCreatureAtRift(uiSummonEntry, pMedivh); + } + } - if (entry == NPC_WHELP) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - for(uint8 i = 0; i < 3; ++i) - DoSummonAtRift(entry); + case NPC_CHRONO_LORD_DEJA: + DoCastSpellIfCan(pSummoned, SPELL_RIFT_CHANNEL); + DoScriptText(SAY_CHRONO_LORD_ENTER, pSummoned); + break; + case NPC_TEMPORUS: + DoCastSpellIfCan(pSummoned, SPELL_RIFT_CHANNEL); + DoScriptText(SAY_TEMPORUS_ENTER, pSummoned); + break; + case NPC_CHRONO_LORD: + case NPC_TIMEREAVER: + case NPC_RIFT_KEEPER: + case NPC_RIFT_LORD: + DoCastSpellIfCan(pSummoned, SPELL_RIFT_CHANNEL); + break; + case NPC_AEONUS: + DoScriptText(SAY_AEONUS_ENTER, pSummoned); + // Remove Time Rift aura so it won't spawn other mobs + m_creature->RemoveAurasDueToSpell(SPELL_RIFT_PERIODIC); + // Move to Medivh and cast Corrupt on him + pSummoned->SetWalk(false); + if (m_pInstance) + { + if (Creature* pMedivh = m_pInstance->GetSingleCreatureFromStorage(NPC_MEDIVH)) + { + float fX, fY, fZ; + pMedivh->GetNearPoint(pMedivh, fX, fY, fZ, 0, 20.0f, pMedivh->GetAngle(pSummoned)); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + } + break; } - else - DoSummonAtRift(entry); } - void UpdateAI(const uint32 diff) + void SummonedCreatureJustDied(Creature* pSummoned) override { - if (!m_pInstance) - return; + switch (pSummoned->GetEntry()) + { + case NPC_AEONUS: + m_creature->ForcedDespawn(); + break; + case NPC_CHRONO_LORD_DEJA: + case NPC_TEMPORUS: + case NPC_CHRONO_LORD: + case NPC_TIMEREAVER: + case NPC_RIFT_KEEPER: + case NPC_RIFT_LORD: + m_creature->ForcedDespawn(3000); + // No need to set the data to DONE if there is a new portal spawned already + if (m_pInstance && m_uiRiftNumber == m_pInstance->GetCurrentRiftId()) + m_pInstance->SetData(TYPE_TIME_RIFT, DONE); + break; + } + } - if (TimeRiftWave_Timer < diff) + void SummonedCreatureDespawn(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - DoSelectSummon(); - TimeRiftWave_Timer = 15000; + case NPC_AEONUS: + case NPC_CHRONO_LORD_DEJA: + case NPC_TEMPORUS: + case NPC_CHRONO_LORD: + case NPC_TIMEREAVER: + case NPC_RIFT_KEEPER: + case NPC_RIFT_LORD: + // Despawn in case of event reset + m_creature->ForcedDespawn(); + break; } - else - TimeRiftWave_Timer -= diff; + } - if (m_creature->IsNonMeleeSpellCasted(false)) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId || pSummoned->GetEntry() != NPC_AEONUS) return; - debug_log("SD2: npc_time_rift: not casting anylonger, i need to die."); - m_creature->SetDeathState(JUST_DIED); - - if (m_pInstance->GetData(TYPE_RIFT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_RIFT, SPECIAL); + pSummoned->CastSpell(pSummoned, SPELL_CORRUPT_AEONUS, false); } + + void UpdateAI(const uint32 /*uiDiff*/) override { } }; CreatureAI* GetAI_npc_time_rift(Creature* pCreature) @@ -355,17 +333,34 @@ CreatureAI* GetAI_npc_time_rift(Creature* pCreature) return new npc_time_riftAI(pCreature); } +bool EffectDummyCreature_npc_time_rift_channel(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_RIFT_PERIODIC && uiEffIndex == EFFECT_INDEX_0) + { + if (npc_time_riftAI* pTimeRiftAI = dynamic_cast(pCreatureTarget->AI())) + pTimeRiftAI->DoSummon(); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + void AddSC_dark_portal() { Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "npc_medivh_bm"; - pNewScript->GetAI = &GetAI_npc_medivh_bm; + pNewScript->Name = "npc_medivh_black_morass"; + pNewScript->GetAI = &GetAI_npc_medivh_black_morass; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_medivh_black_morass; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_time_rift"; pNewScript->GetAI = &GetAI_npc_time_rift; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_time_rift_channel; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h b/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h index 7c29fdb97..474aa5c5d 100644 --- a/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h +++ b/scripts/kalimdor/caverns_of_time/dark_portal/dark_portal.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,69 +7,138 @@ enum { - MAX_ENCOUNTER = 2, + MAX_ENCOUNTER = 6, - TYPE_MEDIVH = 1, - TYPE_RIFT = 2, + TYPE_MEDIVH = 0, + TYPE_SHIELD = 1, + TYPE_TIME_RIFT = 2, + TYPE_CHRONO_LORD = 3, + TYPE_TEMPORUS = 4, + TYPE_AEONUS = 5, - DATA_PORTAL_COUNT = 11, - DATA_SHIELD = 12, - - WORLD_STATE_BM = 2541, - WORLD_STATE_BM_SHIELD = 2540, - WORLD_STATE_BM_RIFT = 2784, + WORLD_STATE_ID = 2541, + WORLD_STATE_SHIELD = 2540, + WORLD_STATE_RIFT = 2784, QUEST_OPENING_PORTAL = 10297, QUEST_MASTER_TOUCH = 9836, - NPC_TIME_KEEPER = 17918, - NPC_RKEEP = 21104, - NPC_RLORD = 17839, - NPC_DEJA = 17879, - NPC_TEMPO = 17880, + // event controlers + NPC_TIME_RIFT = 17838, + NPC_MEDIVH = 15608, + + // main bosses + NPC_CHRONO_LORD_DEJA = 17879, + NPC_TEMPORUS = 17880, NPC_AEONUS = 17881, - NPC_ASSAS = 17835, + + // boss replacements for heroic + NPC_CHRONO_LORD = 21697, + NPC_TIMEREAVER = 21698, + + // portal guardians + NPC_RIFT_KEEPER = 21104, + NPC_RIFT_LORD = 17839, + + // portal summons + NPC_ASSASSIN = 17835, NPC_WHELP = 21818, - NPC_CHRON = 17892, - NPC_EXECU = 18994, - NPC_VANQU = 18995, - NPC_MEDIVH = 15608, - NPC_TIME_RIFT = 17838, + NPC_CHRONOMANCER = 17892, + NPC_EXECUTIONER = 18994, + NPC_VANQUISHER = 18995, + + // additional npcs + NPC_COUNCIL_ENFORCER = 17023, + NPC_TIME_KEEPER = 17918, + NPC_SAAT = 20201, + NPC_DARK_PORTAL_DUMMY = 18625, // cast spell 32564 on coordinates + NPC_DARK_PORTAL_BEAM = 18555, // purple beams which travel from Medivh to the Dark Portal + + // event spells + SPELL_RIFT_CHANNEL = 31387, // Aura channeled by the Time Rifts on the Rift Keepers + + SPELL_BANISH_HELPER = 31550, // used by the main bosses to banish the time keeprs + SPELL_CORRUPT_AEONUS = 37853, // used by Aeonus to corrupt Medivh + + // cosmetic spells + SPELL_PORTAL_CRYSTAL = 32564, // summons 18553 - Dark Portal Crystal stalker + SPELL_BANISH_GREEN = 32567, + + // yells during the event + SAY_SAAT_WELCOME = -1269019, + + SAY_MEDIVH_INTRO = -1269021, + SAY_MEDIVH_ENTER = -1269020, + SAY_MEDIVH_WIN = -1269026, + SAY_MEDIVH_WEAK75 = -1269022, + SAY_MEDIVH_WEAK50 = -1269023, + SAY_MEDIVH_WEAK25 = -1269024, + SAY_ORCS_ENTER = -1269027, + SAY_ORCS_ANSWER = -1269028, + + AREATRIGGER_MEDIVH = 4288, + AREATRIGGER_ENTER = 4485, +}; - SPELL_RIFT_CHANNEL = 31387, - SPELL_BANISH_HELPER = 31550, +struct PortalData +{ + float fX, fY, fZ, fOrient; +}; - RIFT_BOSS = 1 +static const PortalData afPortalLocation[] = +{ + { -2030.832f, 7024.944f, 23.07182f, 3.141593f}, + { -1961.734f, 7029.528f, 21.8114f, 2.129302f}, + { -1887.695f, 7106.557f, 22.0495f, 4.956735f}, + { -1930.911f, 7183.597f, 23.00764f, 3.595378f} }; -class MANGOS_DLL_DECL instance_dark_portal : public ScriptedInstance +// Dark Crystal summon location +static const float fDarkPortalCrystalLoc[3] = { -2024.31f, 7127.75f, 22.65419f}; + +static const int32 uiMedivhWeakYell[3] = {SAY_MEDIVH_WEAK75, SAY_MEDIVH_WEAK50, SAY_MEDIVH_WEAK25}; + +class instance_dark_portal : public ScriptedInstance { public: instance_dark_portal(Map* pMap); - void Initialize(); - void OnPlayerEnter(Player* pPlayer); - void OnCreatureCreate(Creature* pCreature); + void Initialize() override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; - void Update(uint32 uiDiff); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void DoHandleAreaTrigger(uint32 uiTriggerId); + + uint32 GetCurrentRiftId() { return m_uiWorldStateRiftCount; } + + void Update(uint32 uiDiff) override; private: - Creature* SummonedPortalBoss(Creature* pSource); - void DoSpawnPortal(); - bool CanProgressEvent(); - uint8 GetRiftWaveId(); - void Clear(); - void InitWorldState(bool bEnable = true); + bool IsBossTimeRift() { return m_uiWorldStateRiftCount == 6 || m_uiWorldStateRiftCount == 12; } + void UpdateWorldState(bool bEnable = true); + void DoSpawnNextPortal(); + void DoResetEvent(); uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiWorldState; + uint32 m_uiWorldStateRiftCount; + uint32 m_uiWorldStateShieldCount; - uint32 m_uiRiftPortalCount; - uint32 m_uiShieldPercent; - uint8 m_uiRiftWaveCount; - uint8 m_uiRiftWaveId; + bool m_bHasIntroYelled; + uint32 m_uiMedivhYellCount; uint32 m_uiNextPortalTimer; uint8 m_uiCurrentRiftId; diff --git a/scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp b/scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp index af0dbecdf..a1de8f7f0 100644 --- a/scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp +++ b/scripts/kalimdor/caverns_of_time/dark_portal/instance_dark_portal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,272 +16,359 @@ /* ScriptData SDName: Instance_Dark_Portal -SD%Complete: 50 -SDComment: Quest support: 9836, 10297. Currently in progress. +SD%Complete: 75 +SDComment: Quest support: 9836, 10297. Some visuals for the event are missing; Event epilogue NYI. SDCategory: Caverns of Time, The Dark Portal EndScriptData */ #include "precompiled.h" #include "dark_portal.h" -inline uint32 RandRiftBoss() { return (urand(0, 1) ? NPC_RKEEP : NPC_RLORD); } +instance_dark_portal::instance_dark_portal(Map* pMap) : ScriptedInstance(pMap), + m_uiWorldState(0), + m_uiWorldStateRiftCount(0), + m_uiWorldStateShieldCount(100), -float PortalLocation[4][4]= -{ - {-2041.06f, 7042.08f, 29.99f, 1.30f}, - {-1968.18f, 7042.11f, 21.93f, 2.12f}, - {-1885.82f, 7107.36f, 22.32f, 3.07f}, - {-1928.11f, 7175.95f, 22.11f, 3.44f} -}; - -struct Wave -{ - uint32 PortalBoss; // protector of current portal - uint32 NextPortalTime; // time to next portal, or 0 if portal boss need to be killed -}; + m_bHasIntroYelled(false), + m_uiMedivhYellCount(1), -static Wave RiftWaves[]= -{ - {RIFT_BOSS, 0}, - {NPC_DEJA, 0}, - {RIFT_BOSS, 120000}, - {NPC_TEMPO, 140000}, - {RIFT_BOSS, 120000}, - {NPC_AEONUS, 0} -}; - -instance_dark_portal::instance_dark_portal(Map* pMap) : ScriptedInstance(pMap) + m_uiNextPortalTimer(0), + m_uiCurrentRiftId(0) { Initialize(); } void instance_dark_portal::Initialize() { - Clear(); + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } -void instance_dark_portal::Clear() +void instance_dark_portal::DoResetEvent() { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + UpdateWorldState(false); - m_uiRiftPortalCount = 0; - m_uiShieldPercent = 100; - m_uiRiftWaveCount = 0; - m_uiRiftWaveId = 0; + m_uiWorldStateShieldCount = 100; + m_uiWorldStateRiftCount = 0; m_uiCurrentRiftId = 0; - - m_uiNextPortalTimer = 0; + m_uiNextPortalTimer = 0; + m_uiMedivhYellCount = 1; } -void instance_dark_portal::InitWorldState(bool bEnable /*= true*/) +void instance_dark_portal::UpdateWorldState(bool bEnable) { - DoUpdateWorldState(WORLD_STATE_BM, bEnable ? 1 : 0); - DoUpdateWorldState(WORLD_STATE_BM_SHIELD, 100); - DoUpdateWorldState(WORLD_STATE_BM_RIFT, 0); -} + m_uiWorldState = bEnable ? 1 : 0; -void instance_dark_portal::OnPlayerEnter(Player* pPlayer) -{ - if (m_auiEncounter[0] == IN_PROGRESS) - return; - - pPlayer->SendUpdateWorldState(WORLD_STATE_BM, 0); + DoUpdateWorldState(WORLD_STATE_ID, m_uiWorldState); + DoUpdateWorldState(WORLD_STATE_SHIELD, m_uiWorldStateShieldCount); + DoUpdateWorldState(WORLD_STATE_RIFT, m_uiWorldStateRiftCount); } -void instance_dark_portal::OnCreatureCreate(Creature* pCreature) +void instance_dark_portal::OnPlayerEnter(Player* /*pPlayer*/) { - if (pCreature->GetEntry() == NPC_MEDIVH) - m_mNpcEntryGuidStore[NPC_MEDIVH] = pCreature->GetObjectGuid(); + UpdateWorldState(m_auiEncounter[TYPE_MEDIVH] == IN_PROGRESS ? true : false); } -// what other conditions to check? -bool instance_dark_portal::CanProgressEvent() +void instance_dark_portal::DoHandleAreaTrigger(uint32 uiTriggerId) { - if (instance->GetPlayers().isEmpty()) - return false; - - return true; + if (uiTriggerId == AREATRIGGER_ENTER) + { + // Yell at instance entrance + if (!m_bHasIntroYelled) + { + if (Creature* pSaat = GetSingleCreatureFromStorage(NPC_SAAT)) + DoScriptText(SAY_SAAT_WELCOME, pSaat); + m_bHasIntroYelled = true; + } + } + else if (uiTriggerId == AREATRIGGER_MEDIVH) + { + // Start Dark Portal event + if (GetData(TYPE_MEDIVH) == NOT_STARTED || GetData(TYPE_MEDIVH) == FAIL) + SetData(TYPE_MEDIVH, IN_PROGRESS); + // Start Epilogue + else if (GetData(TYPE_AEONUS) == DONE && GetData(TYPE_MEDIVH) != DONE) + SetData(TYPE_MEDIVH, DONE); + } } -uint8 instance_dark_portal::GetRiftWaveId() +void instance_dark_portal::OnCreatureCreate(Creature* pCreature) { - switch(m_uiRiftPortalCount) + switch (pCreature->GetEntry()) { - case 6: - m_uiRiftWaveId = 2; - return 1; - case 12: - m_uiRiftWaveId = 4; - return 3; - case 18: - return 5; - default: - return m_uiRiftWaveId; + case NPC_MEDIVH: + case NPC_SAAT: + case NPC_DARK_PORTAL_DUMMY: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; } } void instance_dark_portal::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_MEDIVH: - if (uiData == SPECIAL && m_auiEncounter[0] == IN_PROGRESS) + { + if (uiData == IN_PROGRESS) { - --m_uiShieldPercent; + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) + { + if (pMedivh->isAlive()) + DoScriptText(SAY_MEDIVH_ENTER, pMedivh); + // If Medivh is not available the do not store the uiData; + else + return; + } - DoUpdateWorldState(WORLD_STATE_BM_SHIELD, m_uiShieldPercent); + // ToDo: + // Start the Portal Crystal casting - by the Dark Portal Dumm Npc + // Also Start summoning the Dark Portal Beams - if (!m_uiShieldPercent) + UpdateWorldState(); + m_uiNextPortalTimer = 3000; + } + if (uiData == DONE) + { + // Yell for event finished + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) { - if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) + DoScriptText(SAY_MEDIVH_WIN, pMedivh); + pMedivh->SetFacingTo(6.15f); + pMedivh->InterruptNonMeleeSpells(false); + pMedivh->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + } + + // this may be completed further out in the post-event + Map::PlayerList const& players = instance->GetPlayers(); + + if (!players.isEmpty()) + { + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) { - if (pMedivh->isAlive()) + if (Player* pPlayer = itr->getSource()) { - pMedivh->DealDamage(pMedivh, pMedivh->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_auiEncounter[0] = FAIL; - m_auiEncounter[1] = NOT_STARTED; + if (pPlayer->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE) + pPlayer->AreaExploredOrEventHappens(QUEST_OPENING_PORTAL); + + if (pPlayer->GetQuestStatus(QUEST_MASTER_TOUCH) == QUEST_STATUS_INCOMPLETE) + pPlayer->AreaExploredOrEventHappens(QUEST_MASTER_TOUCH); } } } } - else + if (uiData == FAIL) + DoResetEvent(); + m_auiEncounter[uiType] = uiData; + break; + } + case TYPE_SHIELD: + if (uiData == SPECIAL) { - if (uiData == IN_PROGRESS) + --m_uiWorldStateShieldCount; + DoUpdateWorldState(WORLD_STATE_SHIELD, m_uiWorldStateShieldCount); + + // Yell at 75%, 50% and 25% shield + if (m_uiWorldStateShieldCount < 100 - 25 * m_uiMedivhYellCount) { - debug_log("SD2: Instance Dark Portal: Starting event."); - InitWorldState(); - m_auiEncounter[1] = IN_PROGRESS; - m_uiNextPortalTimer = 15000; + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) + { + DoScriptText(uiMedivhWeakYell[m_uiMedivhYellCount - 1], pMedivh); + ++m_uiMedivhYellCount; + } } - if (uiData == DONE) + // Kill the npc when the shield is broken + if (!m_uiWorldStateShieldCount) { - // this may be completed further out in the post-event - debug_log("SD2: Instance Dark Portal: Event completed."); - - Map::PlayerList const& players = instance->GetPlayers(); - - if (!players.isEmpty()) + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - { - if (Player* pPlayer = itr->getSource()) - { - if (pPlayer->GetQuestStatus(QUEST_OPENING_PORTAL) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(QUEST_OPENING_PORTAL); - - if (pPlayer->GetQuestStatus(QUEST_MASTER_TOUCH) == QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(QUEST_MASTER_TOUCH); - } - } + if (pMedivh->isAlive()) + pMedivh->DealDamage(pMedivh, pMedivh->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } } - - m_auiEncounter[0] = uiData; } + m_auiEncounter[uiType] = uiData; + return; + case TYPE_TIME_RIFT: + { + // Set the delay to the next time rift from the point the rift despawns + if (uiData == DONE) + m_uiNextPortalTimer = IsBossTimeRift() ? 125000 : 3000; + // Set the delay to the next time rift from the point the rift summons it's guardian + // ToDo: research if these timers are correct + else if (uiData == SPECIAL) + m_uiNextPortalTimer = IsBossTimeRift() ? 0 : m_uiWorldStateRiftCount > 12 ? 90000 : 2 * MINUTE * IN_MILLISECONDS; + + m_auiEncounter[uiType] = uiData; + return; + } + case TYPE_CHRONO_LORD: + case TYPE_TEMPORUS: + if (m_auiEncounter[uiType] != DONE) // Keep the DONE-information stored + m_auiEncounter[uiType] = uiData; break; - case TYPE_RIFT: - if (uiData == SPECIAL) - { - if (m_uiRiftPortalCount < 7) - m_uiNextPortalTimer = 5000; - } - else - m_auiEncounter[1] = uiData; + case TYPE_AEONUS: + if (uiData == DONE) + UpdateWorldState(false); + m_auiEncounter[uiType] = uiData; break; + default: + return; } -} -uint32 instance_dark_portal::GetData(uint32 uiType) -{ - switch(uiType) + if (uiData == DONE) { - case TYPE_MEDIVH: return m_auiEncounter[0]; - case TYPE_RIFT: return m_auiEncounter[1]; - case DATA_PORTAL_COUNT: return m_uiRiftPortalCount; - case DATA_SHIELD: return m_uiShieldPercent; + OUT_SAVE_INST_DATA; - default: - return 0; + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; } } -Creature* instance_dark_portal::SummonedPortalBoss(Creature* pSource) +uint32 instance_dark_portal::GetData(uint32 uiType) const { - uint32 uiEntry = RiftWaves[GetRiftWaveId()].PortalBoss; + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} - if (uiEntry == RIFT_BOSS) - uiEntry = RandRiftBoss(); +void instance_dark_portal::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } - float x, y, z; - pSource->GetRandomPoint(pSource->GetPositionX(), pSource->GetPositionY(), pSource->GetPositionZ(), 10.0f, x, y, z); - // uncomment the following if something doesn't work correctly, otherwise just delete - // pSource->UpdateAllowedPositionZ(x, y, z); + OUT_LOAD_INST_DATA(chrIn); - debug_log("SD2: Instance Dark Portal: Summoning rift boss uiEntry %u.", uiEntry); + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5]; - if (Creature* pSummoned = pSource->SummonCreature(uiEntry, x, y, z, pSource->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000)) - return pSummoned; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_dark_portal::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_CHRONO_LORD_DEJA: + case NPC_CHRONO_LORD: + SetData(TYPE_CHRONO_LORD, IN_PROGRESS); + break; + case NPC_TEMPORUS: + case NPC_TIMEREAVER: + SetData(TYPE_TEMPORUS, IN_PROGRESS); + break; + case NPC_AEONUS: + SetData(TYPE_AEONUS, IN_PROGRESS); + // no break + case NPC_ASSASSIN: + case NPC_WHELP: + case NPC_CHRONOMANCER: + case NPC_EXECUTIONER: + case NPC_VANQUISHER: + pCreature->InterruptNonMeleeSpells(false); + break; + } +} + +void instance_dark_portal::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_CHRONO_LORD_DEJA: + case NPC_CHRONO_LORD: + SetData(TYPE_CHRONO_LORD, FAIL); + break; + case NPC_TEMPORUS: + case NPC_TIMEREAVER: + SetData(TYPE_TEMPORUS, FAIL); + break; + case NPC_AEONUS: + SetData(TYPE_AEONUS, FAIL); + // no break; + // Allow these guys to go and finish off Medivh + case NPC_ASSASSIN: + case NPC_WHELP: + case NPC_CHRONOMANCER: + case NPC_EXECUTIONER: + case NPC_VANQUISHER: + if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) + { + float fX, fY, fZ; + pMedivh->GetNearPoint(pMedivh, fX, fY, fZ, 0, 20.0f, pMedivh->GetAngle(pCreature)); + pCreature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + break; + } +} - debug_log("SD2: Instance Dark Portal: what just happened there? No boss, no loot, no fun..."); - return NULL; +void instance_dark_portal::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_CHRONO_LORD_DEJA: + case NPC_CHRONO_LORD: + SetData(TYPE_CHRONO_LORD, DONE); + break; + case NPC_TEMPORUS: + case NPC_TIMEREAVER: + SetData(TYPE_TEMPORUS, DONE); + break; + case NPC_AEONUS: + SetData(TYPE_AEONUS, DONE); + break; + } } -void instance_dark_portal::DoSpawnPortal() +void instance_dark_portal::DoSpawnNextPortal() { if (Creature* pMedivh = GetSingleCreatureFromStorage(NPC_MEDIVH)) { + // Randomize portal locations uint8 uiTmp = urand(0, 2); if (uiTmp >= m_uiCurrentRiftId) ++uiTmp; - debug_log("SD2: Instance Dark Portal: Creating Time Rift at locationId %i (old locationId was %u).", uiTmp, m_uiCurrentRiftId); + debug_log("SD2: instance_dark_portal: SetRiftId %u, old was id %u.", uiTmp, m_uiCurrentRiftId); m_uiCurrentRiftId = uiTmp; - if (Creature* pTemp = pMedivh->SummonCreature(NPC_TIME_RIFT, PortalLocation[uiTmp][0], PortalLocation[uiTmp][1], PortalLocation[uiTmp][2], PortalLocation[uiTmp][3], TEMPSUMMON_CORPSE_DESPAWN, 0)) - { - pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if (Creature* pBoss = SummonedPortalBoss(pTemp)) - { - if (pBoss->GetEntry() == NPC_AEONUS) - pBoss->AddThreat(pMedivh); - else - { - pBoss->AddThreat(pTemp); - pTemp->CastSpell(pBoss, SPELL_RIFT_CHANNEL, false); - } - } - } + // Summon next portal + pMedivh->SummonCreature(NPC_TIME_RIFT, afPortalLocation[uiTmp].fX, afPortalLocation[uiTmp].fY, afPortalLocation[uiTmp].fZ, afPortalLocation[uiTmp].fOrient, TEMPSUMMON_CORPSE_DESPAWN, 0); } } void instance_dark_portal::Update(uint32 uiDiff) { - if (m_auiEncounter[1] != IN_PROGRESS) + if (GetData(TYPE_MEDIVH) != IN_PROGRESS) return; - //add delay timer? - if (!CanProgressEvent()) - { - Clear(); - return; - } - if (m_uiNextPortalTimer) { if (m_uiNextPortalTimer <= uiDiff) { - ++m_uiRiftPortalCount; - - DoUpdateWorldState(WORLD_STATE_BM_RIFT, m_uiRiftPortalCount); + DoUpdateWorldState(WORLD_STATE_RIFT, ++m_uiWorldStateRiftCount); - DoSpawnPortal(); - m_uiNextPortalTimer = RiftWaves[GetRiftWaveId()].NextPortalTime; + DoSpawnNextPortal(); + m_uiNextPortalTimer = 0; } else m_uiNextPortalTimer -= uiDiff; @@ -293,6 +380,20 @@ InstanceData* GetInstanceData_instance_dark_portal(Map* pMap) return new instance_dark_portal(pMap); } +bool AreaTrigger_at_dark_portal(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_MEDIVH || pAt->id == AREATRIGGER_ENTER) + { + if (pPlayer->isGameMaster() || pPlayer->isDead()) + return false; + + if (instance_dark_portal* pInstance = (instance_dark_portal*)pPlayer->GetInstanceData()) + pInstance->DoHandleAreaTrigger(pAt->id); + } + + return false; +} + void AddSC_instance_dark_portal() { Script* pNewScript; @@ -301,4 +402,9 @@ void AddSC_instance_dark_portal() pNewScript->Name = "instance_dark_portal"; pNewScript->GetInstanceData = &GetInstanceData_instance_dark_portal; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_dark_portal"; + pNewScript->pAreaTrigger = &AreaTrigger_at_dark_portal; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp b/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp index 4d8257d4b..66219d790 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp +++ b/scripts/kalimdor/caverns_of_time/hyjal/boss_archimonde.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,154 +17,60 @@ /* ScriptData SDName: Boss_Archimonde SD%Complete: 85 -SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented. +SDComment: Timers; Some details may need adjustments. SDCategory: Caverns of Time, Mount Hyjal EndScriptData */ #include "precompiled.h" #include "hyjal.h" -#include "SpellAuras.h" - -//text id -1534018 are the text used when previous events complete. Not part of this script. -#define SAY_AGGRO -1534019 -#define SAY_DOOMFIRE1 -1534020 -#define SAY_DOOMFIRE2 -1534021 -#define SAY_AIR_BURST1 -1534022 -#define SAY_AIR_BURST2 -1534023 -#define SAY_SLAY1 -1534024 -#define SAY_SLAY2 -1534025 -#define SAY_SLAY3 -1534026 -#define SAY_ENRAGE -1534027 -#define SAY_DEATH -1534028 -#define SAY_SOUL_CHARGE1 -1534029 -#define SAY_SOUL_CHARGE2 -1534030 - -#define SPELL_DENOUEMENT_WISP 32124 -#define SPELL_ANCIENT_SPARK 39349 -#define SPELL_PROTECTION_OF_ELUNE 38528 - -#define SPELL_DRAIN_WORLD_TREE 39140 -#define SPELL_DRAIN_WORLD_TREE_2 39141 - -#define SPELL_FINGER_OF_DEATH 31984 -#define SPELL_HAND_OF_DEATH 35354 -#define SPELL_AIR_BURST 32014 -#define SPELL_GRIP_OF_THE_LEGION 31972 -#define SPELL_DOOMFIRE_STRIKE 31903 //summons two creatures -#define SPELL_DOOMFIRE_SPAWN 32074 -#define SPELL_DOOMFIRE 31945 -#define SPELL_SOUL_CHARGE_YELLOW 32045 -#define SPELL_SOUL_CHARGE_GREEN 32051 -#define SPELL_SOUL_CHARGE_RED 32052 -#define SPELL_UNLEASH_SOUL_YELLOW 32054 -#define SPELL_UNLEASH_SOUL_GREEN 32057 -#define SPELL_UNLEASH_SOUL_RED 32053 -#define SPELL_FEAR 31970 - -#define CREATURE_ARCHIMONDE 17968 -#define CREATURE_DOOMFIRE 18095 -#define CREATURE_DOOMFIRE_SPIRIT 18104 -#define CREATURE_ANCIENT_WISP 17946 -#define CREATURE_CHANNEL_TARGET 22418 - -#define NORDRASSIL_X 5503.713f -#define NORDRASSIL_Y -3523.436f -#define NORDRASSIL_Z 1608.781f - -struct mob_ancient_wispAI : public ScriptedAI -{ - mob_ancient_wispAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - uint32 CheckTimer; - - void Reset() - { - CheckTimer = 1000; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - - void DamageTaken(Unit* done_by, uint32 &damage) { damage = 0; } - void UpdateAI(const uint32 diff) - { - if (!m_pInstance) - return; - - if (CheckTimer < diff) - { - if (Creature* Archimonde = m_pInstance->GetSingleCreatureFromStorage(NPC_ARCHIMONDE)) - { - if (Archimonde->GetHealthPercent() < 2.0f || !Archimonde->isAlive()) - DoCastSpellIfCan(m_creature, SPELL_DENOUEMENT_WISP); - else - DoCastSpellIfCan(Archimonde, SPELL_ANCIENT_SPARK); - } - CheckTimer = 1000; - }else CheckTimer -= diff; - } -}; - -/* This script is merely a placeholder for the Doomfire that triggers Doomfire spell. It will - MoveChase the Doomfire Spirit always, until despawn (AttackStart is called upon it's spawn) */ -struct MANGOS_DLL_DECL mob_doomfireAI : public ScriptedAI +enum { - mob_doomfireAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - void Reset() { } - - void MoveInLineOfSight(Unit* who) { } - void DamageTaken(Unit *done_by, uint32 &damage) { damage = 0; } -}; - -/* This is the script for the Doomfire Spirit Mob. This mob simply follow players or - travels in random directions if target cannot be found. */ -struct MANGOS_DLL_DECL mob_doomfire_targettingAI : public ScriptedAI -{ - mob_doomfire_targettingAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - ObjectGuid m_targetGuid; - uint32 m_uiChangeTargetTimer; - - void Reset() - { - m_targetGuid.Clear(); - m_uiChangeTargetTimer = 5000; - } - - void MoveInLineOfSight(Unit* pWwho) - { - //will update once m_targetGuid is 0. In case noone actually moves(not likely) and this is 0 - //when UpdateAI needs it, it will be forced to select randomPoint - if (!m_targetGuid && pWwho->GetTypeId() == TYPEID_PLAYER) - m_targetGuid = pWwho->GetObjectGuid(); - } - - void DamageTaken(Unit* pDealer, uint32& uiDamage) { uiDamage = 0; } - - void UpdateAI(const uint32 uiDiff) - { - if (m_uiChangeTargetTimer < uiDiff) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_targetGuid)) - { - m_creature->GetMotionMaster()->MoveFollow(pPlayer, 0.0f, 0.0f); - m_targetGuid.Clear(); - } - else - { - float x,y,z = 0.0; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 40, x, y, z); - m_creature->GetMotionMaster()->MovePoint(0, x, y, z); - } - - m_uiChangeTargetTimer = 5000; - }else m_uiChangeTargetTimer -= uiDiff; - } + SAY_INTRO = -1534018, + SAY_AGGRO = -1534019, + SAY_DOOMFIRE1 = -1534020, + SAY_DOOMFIRE2 = -1534021, + SAY_AIR_BURST1 = -1534022, + SAY_AIR_BURST2 = -1534023, + SAY_SLAY1 = -1534024, + SAY_SLAY2 = -1534025, + SAY_SLAY3 = -1534026, + SAY_ENRAGE = -1534027, + SAY_EPILOGUE = -1534028, + SAY_SOUL_CHARGE1 = -1534029, + SAY_SOUL_CHARGE2 = -1534030, + + // spells + SPELL_DRAIN_TREE = 39140, // intro cosmetic spell + // SPELL_DRAIN_TREE_DUMMY = 39141, // purpose unk + + SPELL_FINGER_DEATH = 31984, + SPELL_FINGER_DEATH_SCRIPT = 32111, // targets whisps + SPELL_FINGER_DEATH_DUMMY = 39369, // epilogue spell + SPELL_HAND_OF_DEATH = 35354, // hard enrage spell + SPELL_AIR_BURST = 32014, + SPELL_GRIP_OF_THE_LEGION = 31972, + SPELL_DOOMFIRE_STRIKE = 31903, // summons 18095 and 18104 + SPELL_SOUL_CHARGE_YELLOW = 32045, // procs 32054 + SPELL_SOUL_CHARGE_GREEN = 32051, // procs 32057 + SPELL_SOUL_CHARGE_RED = 32052, // procs 32053 + SPELL_FEAR = 31970, + + SPELL_PROTECTION_OF_ELUNE = 38528, // protect the players on epilogue + + // summoned creatures + NPC_DOOMFIRE = 18095, + // NPC_DOOMFIRE_SPIRIT = 18104, + NPC_ANCIENT_WISP = 17946, + NPC_CHANNEL_TARGET = 22418, // if he gets in range of 75.0f, then he gets enraged + + // doomfire spells + SPELL_DOOMFIRE_SPAWN = 32074, + SPELL_DOOMFIRE = 31945, // fire damage spell + + // wisp spells + SPELL_DENOUEMENT_WISP = 32124, + SPELL_ANCIENT_SPARK = 39349, }; /* Finally, Archimonde's script. His script isn't extremely complex, most are simply spells on timers. @@ -173,79 +79,83 @@ struct MANGOS_DLL_DECL mob_doomfire_targettingAI : public ScriptedAI select a random target and cast the spell on them. However, if someone IS in melee range, and this is NOT the main tank (creature's victim), then we aggro that player and they become the new victim. For Doomfire, we summon a mob (Doomfire Spirit) for the Doomfire mob to follow. It's spirit will - randomly select it's target to follow and then we create the random movement making it unpredictable. */ + randomly select it's target to follow and then we create the random movement making it unpredictable. +*/ -struct MANGOS_DLL_DECL boss_archimondeAI : public ScriptedAI +struct boss_archimondeAI : public ScriptedAI { boss_archimondeAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bHasIntro = false; Reset(); } ScriptedInstance* m_pInstance; - ObjectGuid m_doomfireSpiritGuid; - ObjectGuid m_worldTreeGuid; - - uint32 DrainNordrassilTimer; - uint32 FearTimer; - uint32 AirBurstTimer; - uint32 GripOfTheLegionTimer; - uint32 DoomfireTimer; - uint32 MeleeRangeCheckTimer; - uint32 HandOfDeathTimer; - uint32 SummonWispTimer; - uint32 WispCount; - uint32 EnrageTimer; - uint32 CheckDistanceTimer; - - bool Enraged; - bool BelowTenPercent; - bool HasProtected; - bool IsChanneling; - - void Reset() + uint32 m_uiDrainNordrassilTimer; + uint32 m_uiFearTimer; + uint32 m_uiAirBurstTimer; + uint32 m_uiGripOfTheLegionTimer; + uint32 m_uiDoomfireTimer; + uint32 m_uiFingerOfDeathTimer; + uint32 m_uiHandOfDeathTimer; + uint32 m_uiSummonWispTimer; + uint32 m_uiWispCount; + uint32 m_uiEnrageTimer; + + bool m_bHasIntro; + bool m_bIsEnraged; + bool m_bIsEpilogue; + bool m_bStartEpilogue; + + void Reset() override { - m_doomfireSpiritGuid.Clear(); - m_worldTreeGuid.Clear(); - - DrainNordrassilTimer = 0; - FearTimer = 42000; - AirBurstTimer = 30000; - GripOfTheLegionTimer = urand(5000, 25000); - DoomfireTimer = 20000; - MeleeRangeCheckTimer = 15000; - HandOfDeathTimer = 2000; - WispCount = 0; // When ~30 wisps are summoned, Archimonde dies - EnrageTimer = 600000; // 10 minutes - CheckDistanceTimer = 30000; // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage - - Enraged = false; - BelowTenPercent = false; - HasProtected = false; - IsChanneling = false; + m_uiDrainNordrassilTimer = 10000; + m_uiFearTimer = 40000; + m_uiAirBurstTimer = 30000; + m_uiGripOfTheLegionTimer = urand(5000, 25000); + m_uiDoomfireTimer = 15000; + m_uiFingerOfDeathTimer = 15000; + m_uiHandOfDeathTimer = 2000; + m_uiWispCount = 0; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_bIsEnraged = false; + m_bIsEpilogue = false; + m_bStartEpilogue = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - m_creature->InterruptSpell(CURRENT_CHANNELED_SPELL); DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void MoveInLineOfSight(Unit* pWho) override { - switch(urand(0, 2)) + // If the boss reaches the tree during the fight, then he enrages - the distance is not very clear + if (!m_bIsEnraged && pWho->GetEntry() == NPC_CHANNEL_TARGET && pWho->IsWithinDistInMap(m_creature, 75.0f)) { - case 0: DoScriptText(SAY_SLAY1, m_creature); break; - case 1: DoScriptText(SAY_SLAY2, m_creature); break; - case 2: DoScriptText(SAY_SLAY3, m_creature); break; + m_uiEnrageTimer = 1000; + m_bIsEnraged = true; } + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pVictim) override + { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; - switch(pVictim->getClass()) + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_SLAY1, m_creature); break; + case 1: DoScriptText(SAY_SLAY2, m_creature); break; + case 2: DoScriptText(SAY_SLAY3, m_creature); break; + } + + switch (pVictim->getClass()) { case CLASS_PRIEST: case CLASS_PALADIN: @@ -265,265 +175,220 @@ struct MANGOS_DLL_DECL boss_archimondeAI : public ScriptedAI } } - void JustDied(Unit *victim) - { - DoScriptText(SAY_DEATH, m_creature); - } - - bool CanUseFingerOfDeath() + void JustReachedHome() override { - // First we check if our current victim is in melee range or not. - Unit* victim = m_creature->getVictim(); - if (victim && m_creature->IsWithinDistInMap(victim, m_creature->GetAttackDistance(victim))) - return false; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - if (tList.empty()) - return false; - - std::list targets; - - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + // Start epilogue at 10% hp + if (m_bIsEpilogue) { - Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (pUnit && pUnit->isAlive()) - targets.push_back(pUnit); - } - - if (targets.empty()) - return false; - - targets.sort(ObjectDistanceOrder(m_creature)); - Unit* target = targets.front(); - if (target) - { - if (!m_creature->IsWithinDistInMap(target, m_creature->GetAttackDistance(target))) - return true; // Cast Finger of Death - else // This target is closest, he is our new tank - m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); + if (DoCastSpellIfCan(m_creature, SPELL_PROTECTION_OF_ELUNE) == CAST_OK) + { + m_uiFingerOfDeathTimer = 5000; + m_bStartEpilogue = true; + } } - - return false; + else if (m_pInstance) + m_pInstance->SetData(TYPE_ARCHIMONDE, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (pSummoned->GetEntry() == CREATURE_ANCIENT_WISP) - pSummoned->AI()->AttackStart(m_creature); - else + if (pSummoned->GetEntry() == NPC_ANCIENT_WISP) { - pSummoned->setFaction(m_creature->getFaction()); - pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } + pSummoned->AI()->AttackStart(m_creature); + ++m_uiWispCount; - if (pSummoned->GetEntry() == CREATURE_DOOMFIRE_SPIRIT) - { - m_doomfireSpiritGuid = pSummoned->GetObjectGuid(); + // When enough wisps have gathered or boss is low hp, then kill him + if (m_uiWispCount >= 45 || m_creature->GetHealthPercent() <= 1.0f) + pSummoned->CastSpell(pSummoned, SPELL_DENOUEMENT_WISP, false); } - - if (pSummoned->GetEntry() == CREATURE_DOOMFIRE) + else if (pSummoned->GetEntry() == NPC_DOOMFIRE) { - pSummoned->CastSpell(pSummoned,SPELL_DOOMFIRE_SPAWN,false); + pSummoned->CastSpell(pSummoned, SPELL_DOOMFIRE_SPAWN, true); pSummoned->CastSpell(pSummoned, SPELL_DOOMFIRE, true, NULL, NULL, m_creature->GetObjectGuid()); - - if (Creature* pDoomfireSpirit = m_creature->GetMap()->GetCreature(m_doomfireSpiritGuid)) - { - pSummoned->GetMotionMaster()->MoveFollow(pDoomfireSpirit,0.0f,0.0f); - m_doomfireSpiritGuid.Clear(); - } } } - //this is code doing close to what the summoning spell would do (spell 31903) - void SummonDoomfire(Unit* target) - { - m_creature->SummonCreature(CREATURE_DOOMFIRE_SPIRIT, - target->GetPositionX()+15.0,target->GetPositionY()+15.0,target->GetPositionZ(),0, - TEMPSUMMON_TIMED_DESPAWN, 27000); - - m_creature->SummonCreature(CREATURE_DOOMFIRE, - target->GetPositionX()-15.0,target->GetPositionY()-15.0,target->GetPositionZ(),0, - TEMPSUMMON_TIMED_DESPAWN, 27000); - } - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_creature->isInCombat()) + // Intro timer + if (m_uiDrainNordrassilTimer) { - if (m_pInstance) + if (m_uiDrainNordrassilTimer <= uiDiff) { - // Do not let the raid skip straight to Archimonde. Visible and hostile ONLY if Azagalor is finished. - if ((m_pInstance->GetData(TYPE_AZGALOR) < DONE) && ((m_creature->GetVisibility() != VISIBILITY_OFF) || (m_creature->getFaction() != 35))) + if (DoCastSpellIfCan(m_creature, SPELL_DRAIN_TREE) == CAST_OK) { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->setFaction(35); - } - else if ((m_pInstance->GetData(TYPE_AZGALOR) >= DONE) && ((m_creature->GetVisibility() != VISIBILITY_ON) || (m_creature->getFaction() == 35))) - { - m_creature->setFaction(1720); - m_creature->SetVisibility(VISIBILITY_ON); + if (!m_bHasIntro) + { + DoScriptText(SAY_INTRO, m_creature); + m_bHasIntro = true; + } + m_uiDrainNordrassilTimer = 0; } } + else + m_uiDrainNordrassilTimer -= uiDiff; + } - if (DrainNordrassilTimer < diff) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Start epilogue - fight was won! + if (m_creature->GetHealthPercent() < 10.0f) + { + if (!m_bIsEpilogue) { - if (!IsChanneling) - { - Creature *temp = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1200000); + DoScriptText(SAY_EPILOGUE, m_creature); - if (temp) - m_worldTreeGuid = temp->GetObjectGuid(); + // move at home position and start outro + m_creature->GetMotionMaster()->MoveTargetedHome(); + SetCombatMovement(false); + m_bIsEpilogue = true; + } - if (Creature *Nordrassil = m_creature->GetMap()->GetCreature(m_worldTreeGuid)) - { - Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Nordrassil->SetDisplayId(11686); - DoCastSpellIfCan(Nordrassil, SPELL_DRAIN_WORLD_TREE); - IsChanneling = true; - } + if (m_bStartEpilogue) + { + // Spam Finger of Death on players and Wisps + if (m_uiFingerOfDeathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_FINGER_DEATH_DUMMY : SPELL_FINGER_DEATH_SCRIPT) == CAST_OK) + m_uiFingerOfDeathTimer = 1000; } + else + m_uiFingerOfDeathTimer -= uiDiff; - if (Creature *Nordrassil = m_creature->GetMap()->GetCreature(m_worldTreeGuid)) + if (m_uiSummonWispTimer < uiDiff) { - Nordrassil->CastSpell(m_creature, SPELL_DRAIN_WORLD_TREE_2, true); - DrainNordrassilTimer = 1000; + float fX, fY, fZ; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 75.0f, urand(0, 1) ? frand(0, 2.8f) : frand(4.3f, M_PI_F * 2)); + m_creature->SummonCreature(NPC_ANCIENT_WISP, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 15000); + m_uiSummonWispTimer = urand(1000, 1500); } - }else DrainNordrassilTimer -= diff; - } + else + m_uiSummonWispTimer -= uiDiff; + } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Stop using the other spells return; + } - if (m_creature->GetHealthPercent() < 10.0f && !BelowTenPercent && !Enraged) - BelowTenPercent = true; - - if (!Enraged) + if (m_uiEnrageTimer) { - if (EnrageTimer < diff) + if (m_uiEnrageTimer <= uiDiff) { - if (m_creature->GetHealthPercent() > 10.0f) + if (DoCastSpellIfCan(m_creature, SPELL_HAND_OF_DEATH) == CAST_OK) { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - Enraged = true; DoScriptText(SAY_ENRAGE, m_creature); + m_uiEnrageTimer = 0; } - }else EnrageTimer -= diff; - - if (CheckDistanceTimer < diff) - { - // To simplify the check, we simply summon a creature in the location and then check how far we are from the creature - Creature* Check = m_creature->SummonCreature(CREATURE_CHANNEL_TARGET, NORDRASSIL_X, NORDRASSIL_Y, NORDRASSIL_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 2000); - if (Check) - { - Check->SetVisibility(VISIBILITY_OFF); - - if (m_creature->IsWithinDistInMap(Check, 75)) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - Enraged = true; - DoScriptText(SAY_ENRAGE, m_creature); - } - } - CheckDistanceTimer = 5000; - }else CheckDistanceTimer -= diff; + } + else + m_uiEnrageTimer -= uiDiff; } - if (BelowTenPercent) + if (m_uiGripOfTheLegionTimer < uiDiff) { - if (!HasProtected) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); - - //all members of raid must get this buff - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PROTECTION_OF_ELUNE); - HasProtected = true; - Enraged = true; + if (DoCastSpellIfCan(pTarget, SPELL_GRIP_OF_THE_LEGION) == CAST_OK) + m_uiGripOfTheLegionTimer = urand(5000, 25000); } - - if (SummonWispTimer < diff) - { - DoSpawnCreature(CREATURE_ANCIENT_WISP, rand()%40, rand()%40, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - SummonWispTimer = 1500; - ++WispCount; - }else SummonWispTimer -= diff; - - if (WispCount >= 30) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } + else + m_uiGripOfTheLegionTimer -= uiDiff; - if (Enraged) + if (m_uiAirBurstTimer < uiDiff) { - if (HandOfDeathTimer < diff) + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_AIR_BURST) == CAST_OK) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAND_OF_DEATH); - HandOfDeathTimer = 2000; - }else HandOfDeathTimer -= diff; - return; // Don't do anything after this point. + DoScriptText(urand(0, 1) ? SAY_AIR_BURST1 : SAY_AIR_BURST2, m_creature); + m_uiAirBurstTimer = urand(25000, 40000); + } } + else + m_uiAirBurstTimer -= uiDiff; - if (GripOfTheLegionTimer < diff) + if (m_uiFearTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_GRIP_OF_THE_LEGION); - - GripOfTheLegionTimer = urand(5000, 25000); - }else GripOfTheLegionTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = 42000; + } + else + m_uiFearTimer -= uiDiff; - if (AirBurstTimer < diff) + if (m_uiDoomfireTimer < uiDiff) { - if (!urand(0, 1)) - DoScriptText(SAY_AIR_BURST1, m_creature); - else - DoScriptText(SAY_AIR_BURST2, m_creature); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - DoCastSpellIfCan(pTarget, SPELL_AIR_BURST); - AirBurstTimer = urand(25000, 40000); - }else AirBurstTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_DOOMFIRE_STRIKE) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_DOOMFIRE1 : SAY_DOOMFIRE2, m_creature); + m_uiDoomfireTimer = urand(10000, 15000); + } + } + else + m_uiDoomfireTimer -= uiDiff; - if (FearTimer < diff) + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + // Else spam Finger of Death + else { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEAR); - FearTimer = 42000; - }else FearTimer -= diff; + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_FINGER_DEATH); + } + } + } +}; - if (DoomfireTimer < diff) - { - if (!urand(0, 1)) - DoScriptText(SAY_DOOMFIRE1, m_creature); - else - DoScriptText(SAY_DOOMFIRE2, m_creature); +/* This is the script for the Doomfire Spirit Mob. This mob controls the doomfire npc and allows it to move randomly around the map. */ +struct npc_doomfire_spiritAI : public ScriptedAI +{ + npc_doomfire_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - Unit *temp = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (!temp) - temp = m_creature->getVictim(); + ObjectGuid m_doomfireGuid; - //replace with spell cast 31903 once implicitTarget 73 implemented - SummonDoomfire(temp); + uint32 m_uiDoomfireLoadTimer; + uint32 m_uiChangeTargetTimer; + float m_fAngle; - //supposedly three doomfire can be up at the same time - DoomfireTimer = 20000; - }else DoomfireTimer -= diff; + void Reset() override + { + m_uiDoomfireLoadTimer = 1000; + m_uiChangeTargetTimer = 1500; + m_fAngle = urand(0, M_PI_F * 2); + } - if (MeleeRangeCheckTimer < diff) + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDoomfireLoadTimer) { - if (CanUseFingerOfDeath()) + if (m_uiDoomfireLoadTimer <= uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_FINGER_OF_DEATH); + // Get the closest doomfire + if (Creature* pTemp = GetClosestCreatureWithEntry(m_creature, NPC_DOOMFIRE, 5.0f)) + m_doomfireGuid = pTemp->GetObjectGuid(); - MeleeRangeCheckTimer = 1000; + m_uiDoomfireLoadTimer = 0; } + else + m_uiDoomfireLoadTimer -= uiDiff; + } - MeleeRangeCheckTimer = 5000; - }else MeleeRangeCheckTimer -= diff; + // It's not very clear how should this one move. For the moment just move to random points around on timer + if (m_uiChangeTargetTimer < uiDiff) + { + if (Creature* pDoomfire = m_creature->GetMap()->GetCreature(m_doomfireGuid)) + { + float fX, fY, fZ; + pDoomfire->GetNearPoint(pDoomfire, fX, fY, fZ, 0, 30.0f, m_fAngle + frand(0, M_PI_F * .5)); + pDoomfire->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } - DoMeleeAttackIfReady(); + m_uiChangeTargetTimer = 4000; + } + else + m_uiChangeTargetTimer -= uiDiff; } }; @@ -532,19 +397,9 @@ CreatureAI* GetAI_boss_archimonde(Creature* pCreature) return new boss_archimondeAI(pCreature); } -CreatureAI* GetAI_mob_doomfire(Creature* pCreature) +CreatureAI* GetAI_npc_doomfire_spirit(Creature* pCreature) { - return new mob_doomfireAI(pCreature); -} - -CreatureAI* GetAI_mob_doomfire_targetting(Creature* pCreature) -{ - return new mob_doomfire_targettingAI(pCreature); -} - -CreatureAI* GetAI_mob_ancient_wisp(Creature* pCreature) -{ - return new mob_ancient_wispAI(pCreature); + return new npc_doomfire_spiritAI(pCreature); } void AddSC_boss_archimonde() @@ -557,17 +412,7 @@ void AddSC_boss_archimonde() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_doomfire"; - pNewScript->GetAI = &GetAI_mob_doomfire; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_doomfire_targetting"; - pNewScript->GetAI = &GetAI_mob_doomfire_targetting; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_ancient_wisp"; - pNewScript->GetAI = &GetAI_mob_ancient_wisp; + pNewScript->Name = "npc_doomfire_spirit"; + pNewScript->GetAI = &GetAI_npc_doomfire_spirit; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp b/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp index f65823a69..b1730ca71 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp +++ b/scripts/kalimdor/caverns_of_time/hyjal/hyjal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,14 +30,21 @@ EndContentData */ #include "precompiled.h" #include "hyjalAI.h" -#define GOSSIP_ITEM_BEGIN_ALLY "My companions and I are with you, Lady Proudmoore." -#define GOSSIP_ITEM_ANETHERON "We are ready for whatever Archimonde might send our way, Lady Proudmoore." -#define GOSSIP_ITEM_BEGIN_HORDE "I am with you, Thrall." -#define GOSSIP_ITEM_AZGALOR "We have nothing to fear." +enum +{ + GOSSIP_ITEM_JAINA_BEGIN = -3534000, + GOSSIP_ITEM_JAINA_ANATHERON = -3534001, + GOSSIP_ITEM_JAINA_SUCCCESS = -3534002, + + GOSSIP_ITEM_THRALL_BEGIN = -3534003, + GOSSIP_ITEM_THRALL_AZGALOR = -3534004, + GOSSIP_ITEM_THRALL_SUCCESS = -3534005, -#define GOSSIP_ITEM_RETREAT "We can't keep this up. Let's retreat!" + GOSSIP_ITEM_TYRANDE_AID = -3534006, -#define GOSSIP_ITEM_TYRANDE "Aid us in defending Nordrassil" + // Note: additional menu items include 9230 and 9398. + GOSSIP_MENU_ID_DEFAULT = 907, // this is wrong, but currently we don't know which are the right ids +}; CreatureAI* GetAI_npc_jaina_proudmoore(Creature* pCreature) { @@ -64,17 +71,17 @@ bool GossipHello_npc_jaina_proudmoore(Player* pPlayer, Creature* pCreature) { if (hyjalAI* pJainaAI = dynamic_cast(pCreature->AI())) { - if (!pJainaAI->m_bIsEventInProgress) + if (!pJainaAI->IsEventInProgress()) { // Should not happen that jaina is here now, but for safe we check if (pInstance->GetData(TYPE_KAZROGAL) != DONE) { - if (pInstance->GetData(TYPE_WINTERCHILL) == NOT_STARTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN_ALLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - else if (pInstance->GetData(TYPE_WINTERCHILL) == DONE && pInstance->GetData(TYPE_ANETHERON) == NOT_STARTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ANETHERON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + if (pInstance->GetData(TYPE_WINTERCHILL) == NOT_STARTED || pInstance->GetData(TYPE_WINTERCHILL) == FAIL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JAINA_BEGIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + else if (pInstance->GetData(TYPE_WINTERCHILL) == DONE && (pInstance->GetData(TYPE_ANETHERON) == NOT_STARTED || pInstance->GetData(TYPE_ANETHERON) == FAIL)) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JAINA_ANATHERON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); else if (pInstance->GetData(TYPE_ANETHERON) == DONE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_JAINA_SUCCCESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); if (pPlayer->isGameMaster()) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "[GM] Toggle Debug Timers", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); @@ -83,15 +90,15 @@ bool GossipHello_npc_jaina_proudmoore(Player* pPlayer, Creature* pCreature) } } - pPlayer->SEND_GOSSIP_MENU(907, pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_DEFAULT, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_jaina_proudmoore(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_jaina_proudmoore(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (hyjalAI* pJainaAI = dynamic_cast(pCreature->AI())) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF + 1: pJainaAI->StartEvent(); @@ -106,7 +113,7 @@ bool GossipSelect_npc_jaina_proudmoore(Player* pPlayer, Creature* pCreature, uin break; case GOSSIP_ACTION_INFO_DEF: pJainaAI->m_bDebugMode = !pJainaAI->m_bDebugMode; - debug_log("SD2: HyjalAI - Debug mode has been toggled"); + debug_log("SD2: HyjalAI - Debug mode has been toggled %s", pJainaAI->m_bDebugMode ? "on" : "off"); break; } } @@ -136,17 +143,17 @@ bool GossipHello_npc_thrall(Player* pPlayer, Creature* pCreature) { if (hyjalAI* pThrallAI = dynamic_cast(pCreature->AI())) { - if (!pThrallAI->m_bIsEventInProgress) + if (!pThrallAI->IsEventInProgress()) { // Only let them start the Horde phases if Anetheron is dead. - if (pInstance->GetData(TYPE_ANETHERON) == DONE) + if (pInstance->GetData(TYPE_ANETHERON) == DONE && pInstance->GetData(TYPE_ARCHIMONDE) != DONE) { - if (pInstance->GetData(TYPE_KAZROGAL) == NOT_STARTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN_HORDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - else if (pInstance->GetData(TYPE_KAZROGAL) == DONE && pInstance->GetData(TYPE_AZGALOR) == NOT_STARTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AZGALOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + if (pInstance->GetData(TYPE_KAZROGAL) == NOT_STARTED || pInstance->GetData(TYPE_KAZROGAL) == FAIL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THRALL_BEGIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + else if (pInstance->GetData(TYPE_KAZROGAL) == DONE && (pInstance->GetData(TYPE_AZGALOR) == NOT_STARTED || pInstance->GetData(TYPE_AZGALOR) == FAIL)) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THRALL_AZGALOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); else if (pInstance->GetData(TYPE_AZGALOR) == DONE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RETREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THRALL_SUCCESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); if (pPlayer->isGameMaster()) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_DOT, "[GM] Toggle Debug Timers", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); @@ -155,15 +162,15 @@ bool GossipHello_npc_thrall(Player* pPlayer, Creature* pCreature) } } - pPlayer->SEND_GOSSIP_MENU(907, pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_DEFAULT, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_thrall(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_thrall(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (hyjalAI* pThrallAI = dynamic_cast(pCreature->AI())) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF + 1: pThrallAI->StartEvent(); @@ -178,7 +185,7 @@ bool GossipSelect_npc_thrall(Player* pPlayer, Creature* pCreature, uint32 uiSend break; case GOSSIP_ACTION_INFO_DEF: pThrallAI->m_bDebugMode = !pThrallAI->m_bDebugMode; - debug_log("SD2: HyjalAI - Debug mode has been toggled"); + debug_log("SD2: HyjalAI - Debug mode has been toggled %s", pThrallAI->m_bDebugMode ? "on" : "off"); break; } } @@ -193,14 +200,14 @@ bool GossipHello_npc_tyrande_whisperwind(Player* pPlayer, Creature* pCreature) { // Only let them get item if Azgalor is dead. if (pInstance->GetData(TYPE_AZGALOR) == DONE && !pPlayer->HasItemCount(ITEM_TEAR_OF_GODDESS, 1)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TYRANDE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TYRANDE_AID, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); } - pPlayer->SEND_GOSSIP_MENU(907, pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_DEFAULT, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_tyrande_whisperwind(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_tyrande_whisperwind(Player* pPlayer, Creature* /*pCreature*/, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF) { diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h b/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h index dc6d933aa..53f09edb3 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h +++ b/scripts/kalimdor/caverns_of_time/hyjal/hyjal.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -50,32 +50,38 @@ enum GO_ANCIENT_GEM = 185557, }; -class MANGOS_DLL_DECL instance_mount_hyjal : public ScriptedInstance +static const float aArchimondeSpawnLoc[4] = {5581.49f, -3445.63f, 1575.1f, 3.905f}; + +class instance_mount_hyjal : public ScriptedInstance { public: instance_mount_hyjal(Map* pMap); - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnPlayerEnter(Player* pPlayer) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strSaveData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strSaveData.c_str(); } + void Load(const char* chrIn) override; private: + void DoSpawnArchimonde(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strSaveData; - GUIDList lAncientGemGUIDList; + GuidList lAncientGemGUIDList; uint32 m_uiTrashCount; }; diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp b/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp index d2b8f4008..6af4ce03e 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp +++ b/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -32,7 +32,7 @@ struct HyjalLocation // Locations for summoning waves // Must be even number -static const HyjalLocation aHyjalSpawnLoc[]= +static const HyjalLocation aHyjalSpawnLoc[] = { {BASE_ALLY, 4979.010f, -1709.134f, 1339.674f}, {BASE_ALLY, 4969.123f, -1705.904f, 1341.363f}, @@ -45,7 +45,7 @@ static const HyjalLocation aHyjalSpawnLoc[]= }; // used to inform the wave where to move -static const HyjalLocation aHyjalWaveMoveTo[]= +static const HyjalLocation aHyjalWaveMoveTo[] = { {BASE_ALLY, 5018.654f, -1752.074f, 1322.203f}, {BASE_HORDE, 5504.569f, -2688.489f, 1479.991f} @@ -58,7 +58,7 @@ struct HyjalYells int32 m_iTextId; // The text id to be yelled }; -static const HyjalYells aHyjalYell[]= +static const HyjalYells aHyjalYell[] = { {NPC_JAINA, ATTACKED, -1534000}, {NPC_JAINA, ATTACKED, -1534001}, @@ -89,7 +89,7 @@ struct HyjalWave }; // Waves that will be summoned in the Alliance Base -static const HyjalWave aHyjalWavesAlliance[]= +static const HyjalWave aHyjalWavesAlliance[] = { // Rage Winterchill Wave 1-8 {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, 0, 0, 0, 0, 0, 0, 0, 0}, 125000, false}, @@ -116,7 +116,7 @@ static const HyjalWave aHyjalWavesAlliance[]= }; // Waves that are summoned in the Horde base -static const HyjalWave aHyjalWavesHorde[]= +static const HyjalWave aHyjalWavesHorde[] = { // Kaz'Rogal Wave 1-8 {{NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_GHOUL, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_ABOMI, NPC_BANSH, NPC_BANSH, NPC_NECRO, NPC_NECRO, 0, 0, 0, 0, 0, 0}, 135000, false}, @@ -144,14 +144,9 @@ static const HyjalWave aHyjalWavesHorde[]= void hyjalAI::Reset() { - // BossGuids - m_aBossGuid[0].Clear(); - m_aBossGuid[1].Clear(); - // Timers m_uiNextWaveTimer = 10000; m_uiWaveMoveTimer = 15000; - m_uiCheckTimer = 0; m_uiRetreatTimer = 25000; // Misc @@ -159,7 +154,7 @@ void hyjalAI::Reset() m_uiEnemyCount = 0; // Set base area based on creature entry - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case NPC_JAINA: m_uiBase = BASE_ALLY; @@ -180,24 +175,40 @@ void hyjalAI::Reset() // Flags m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + if (!m_pInstance) + return; + // Reset World States m_pInstance->DoUpdateWorldState(WORLD_STATE_WAVES, 0); m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 0); m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, 0); - if (!m_pInstance) - return; - - m_bIsFirstBossDead = m_uiBase ? m_pInstance->GetData(TYPE_KAZROGAL) == DONE : m_pInstance->GetData(TYPE_WINTERCHILL) == DONE; - m_bIsSecondBossDead = m_uiBase ? m_pInstance->GetData(TYPE_AZGALOR) == DONE : m_pInstance->GetData(TYPE_ANETHERON) == DONE; - // Reset Instance Data for trash count m_pInstance->SetData(TYPE_TRASH_COUNT, 0); + + m_bIsFirstBossDead = m_pInstance->GetData(m_uiBase ? TYPE_KAZROGAL : TYPE_WINTERCHILL) == DONE; + m_bIsSecondBossDead = m_pInstance->GetData(m_uiBase ? TYPE_AZGALOR : TYPE_ANETHERON) == DONE; +} + +bool hyjalAI::IsEventInProgress() const +{ + if (m_bIsEventInProgress) + return true; + + // The boss might still be around and alive + for (uint8 i = 0; i < 2; ++i) + { + Creature* pBoss = m_creature->GetMap()->GetCreature(m_aBossGuid[i]); + if (pBoss && pBoss->isAlive()) + return true; + } + + return false; } void hyjalAI::EnterEvadeMode() { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); @@ -216,9 +227,9 @@ void hyjalAI::JustReachedHome() m_bIsSecondBossDead = m_uiBase ? m_pInstance->GetData(TYPE_AZGALOR) == DONE : m_pInstance->GetData(TYPE_ANETHERON) == DONE; } -void hyjalAI::Aggro(Unit *who) +void hyjalAI::Aggro(Unit* /*who*/) { - for(uint8 i = 0; i < MAX_SPELL; ++i) + for (uint8 i = 0; i < MAX_SPELL; ++i) if (m_aSpells[i].m_uiCooldown) m_uiSpellTimer[i] = m_aSpells[i].m_uiCooldown; @@ -230,7 +241,7 @@ void hyjalAI::SpawnCreatureForWave(uint32 uiMobEntry) HyjalLocation const* pSpawn = NULL; uint32 uiMaxCount = countof(aHyjalSpawnLoc); - uint32 uiRandId = urand(1, uiMaxCount/2); //unsafe, if array becomes uneven. + uint32 uiRandId = urand(1, uiMaxCount / 2); // unsafe, if array becomes uneven. uint32 uiJ = 0; @@ -249,7 +260,7 @@ void hyjalAI::SpawnCreatureForWave(uint32 uiMobEntry) } if (pSpawn) - m_creature->SummonCreature(uiMobEntry, pSpawn->m_fX, pSpawn->m_fY, pSpawn->m_fZ, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + m_creature->SummonCreature(uiMobEntry, pSpawn->m_fX, pSpawn->m_fY, pSpawn->m_fZ, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 120000); } void hyjalAI::JustSummoned(Creature* pSummoned) @@ -283,18 +294,37 @@ void hyjalAI::JustSummoned(Creature* pSummoned) // Check if creature is a boss. if (pSummoned->IsWorldBoss()) - { - if (!m_bIsFirstBossDead) - m_aBossGuid[0] = pSummoned->GetObjectGuid(); - else - m_aBossGuid[1] = pSummoned->GetObjectGuid(); - - m_uiCheckTimer = 5000; - } + m_aBossGuid[!m_bIsFirstBossDead ? 0 : 1] = pSummoned->GetObjectGuid(); else lWaveMobGUIDList.push_back(pSummoned->GetObjectGuid()); } +void hyjalAI::SummonedCreatureJustDied(Creature* pSummoned) +{ + if (!pSummoned->IsWorldBoss()) // Only do stuff when bosses die + return; + + if (m_aBossGuid[0] == pSummoned->GetObjectGuid()) + { + DoTalk(INCOMING); + m_bIsFirstBossDead = true; + } + else if (m_aBossGuid[1] == pSummoned->GetObjectGuid()) + { + DoTalk(SUCCESS); + m_bIsSecondBossDead = true; + } + + m_bIsEventInProgress = false; + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + // Reset world state for enemies to disable it + m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 0); + + m_creature->SetActiveObjectState(false); +} + void hyjalAI::SummonNextWave() { // 1 in 4 chance we give a rally yell. Not sure if the chance is offilike. @@ -308,13 +338,13 @@ void hyjalAI::SummonNextWave() if (!pWaveData) { - error_log("SD2: hyjalAI not able to obtain wavedata for SummonNextWave."); + script_error_log("hyjalAI not able to obtain wavedata for SummonNextWave."); return; } m_uiEnemyCount = m_pInstance->GetData(TYPE_TRASH_COUNT); - for(uint8 i = 0; i < MAX_WAVE_MOB; ++i) + for (uint8 i = 0; i < MAX_WAVE_MOB; ++i) { if (pWaveData->m_auiMobEntry[i]) SpawnCreatureForWave(pWaveData->m_auiMobEntry[i]); @@ -322,7 +352,7 @@ void hyjalAI::SummonNextWave() if (!pWaveData->m_bIsBoss) { - uint32 stateValue = m_uiWaveCount+1; + uint32 stateValue = m_uiWaveCount + 1; if (m_bIsFirstBossDead) stateValue -= MAX_WAVES; // Subtract 9 from it to give the proper wave number if we are greater than 8 @@ -355,7 +385,6 @@ void hyjalAI::SummonNextWave() } m_uiWaveMoveTimer = 15000; - m_uiCheckTimer = 5000; ++m_uiWaveCount; } @@ -364,13 +393,15 @@ void hyjalAI::StartEvent() if (!m_pInstance) return; + if (IsEventInProgress()) + return; + DoTalk(BEGIN); m_bIsEventInProgress = true; m_bIsSummoningWaves = true; m_uiNextWaveTimer = 10000; - m_uiCheckTimer = 5000; m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); @@ -391,8 +422,8 @@ void hyjalAI::DoTalk(YellType pYellType) { if (aHyjalYell[i].uiCreatureEntry == m_creature->GetEntry() && aHyjalYell[i].m_pYellType == pYellType) { - //this would not be safe unless we knew these had two entries in m_aYell - if (pYellType == ATTACKED || pYellType== RALLY) + // this would not be safe unless we knew these had two entries in m_aYell + if (pYellType == ATTACKED || pYellType == RALLY) { if (!bGetNext && urand(0, 1)) { @@ -410,18 +441,18 @@ void hyjalAI::DoTalk(YellType pYellType) DoScriptText(pYell->m_iTextId, m_creature); } -void hyjalAI::SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) +void hyjalAI::SpellHitTarget(Unit* /*pTarget*/, const SpellEntry* /*pSpell*/) { - //TODO: this spell should cause misc mobs to despawn - //if (pSpell->Id == SPELL_MASS_TELEPORT && pTarget->GetTypeId() != TYPEID_PLAYER) + // TODO: this spell should cause misc mobs to despawn + // if (pSpell->Id == SPELL_MASS_TELEPORT && pTarget->GetTypeId() != TYPEID_PLAYER) //{ - //despawn; + // despawn; //} } void hyjalAI::Retreat() { - //this will trigger ancient gem respawn + // this will trigger ancient gem respawn if (m_pInstance) m_pInstance->SetData(TYPE_RETREAT, SPECIAL); @@ -430,12 +461,12 @@ void hyjalAI::Retreat() m_bIsRetreating = true; } -void hyjalAI::JustDied(Unit* pKiller) +void hyjalAI::JustDied(Unit* /*pKiller*/) { DoTalk(DEATH); m_creature->SetActiveObjectState(false); - //TODO: in case they die during boss encounter, then what? despawn boss? + // TODO: in case they die during boss encounter, then what? despawn boss? } void hyjalAI::UpdateAI(const uint32 uiDiff) @@ -454,7 +485,7 @@ void hyjalAI::UpdateAI(const uint32 uiDiff) m_uiNextWaveTimer = std::min(m_uiNextWaveTimer, (uint32)5000); } - for (GUIDList::const_iterator itr = lWaveMobGUIDList.begin(); itr != lWaveMobGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = lWaveMobGUIDList.begin(); itr != lWaveMobGUIDList.end(); ++itr) { if (Creature* pTemp = m_pInstance->instance->GetCreature(*itr)) { @@ -476,51 +507,10 @@ void hyjalAI::UpdateAI(const uint32 uiDiff) m_uiNextWaveTimer -= uiDiff; } - if (m_uiCheckTimer < uiDiff) - { - for(uint8 i = 0; i < 2; ++i) - { - if (m_aBossGuid[i]) - { - Creature* pBoss = m_creature->GetMap()->GetCreature(m_aBossGuid[i]); - - if (pBoss && !pBoss->isAlive()) - { - if (m_aBossGuid[i] == m_aBossGuid[0]) - { - DoTalk(INCOMING); - m_bIsFirstBossDead = true; - } - else if (m_aBossGuid[i] == m_aBossGuid[1]) - { - DoTalk(SUCCESS); - m_bIsSecondBossDead = true; - } - - m_bIsEventInProgress = false; - m_uiCheckTimer = 0; - - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - m_aBossGuid[i].Clear(); - - // Reset world state for enemies to disable it - m_pInstance->DoUpdateWorldState(WORLD_STATE_ENEMY, 0); - - m_creature->SetActiveObjectState(false); - } - } - } - - m_uiCheckTimer = 5000; - } - else - m_uiCheckTimer -= uiDiff; - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - for(uint8 i = 0; i < MAX_SPELL; ++i) + for (uint8 i = 0; i < MAX_SPELL; ++i) { if (m_aSpells[i].m_uiSpellId) { @@ -531,7 +521,7 @@ void hyjalAI::UpdateAI(const uint32 uiDiff) Unit* pTarget = NULL; - switch(m_aSpells[i].m_pType) + switch (m_aSpells[i].m_pType) { case TARGETTYPE_SELF: pTarget = m_creature; break; case TARGETTYPE_RANDOM: pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); break; @@ -551,3 +541,8 @@ void hyjalAI::UpdateAI(const uint32 uiDiff) DoMeleeAttackIfReady(); } + +void hyjalAI::JustRespawned() +{ + Reset(); +} diff --git a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h b/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h index 3e13ad100..c852dbedb 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h +++ b/scripts/kalimdor/caverns_of_time/hyjal/hyjalAI.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -55,55 +55,60 @@ enum YellType DEATH = 6, // Used on death }; -struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI +struct hyjalAI : public ScriptedAI { - hyjalAI(Creature* pCreature) : ScriptedAI(pCreature) - { - memset(m_aSpells, 0, sizeof(m_aSpells)); - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + hyjalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + memset(m_aSpells, 0, sizeof(m_aSpells)); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } - // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat - void Reset(); + // Generically used to reset our variables. Do *not* call in EnterEvadeMode as this may make problems if the raid is still in combat + void Reset() override; - // Send creature back to spawn location and evade. - void EnterEvadeMode(); + // Send creature back to spawn location and evade. + void EnterEvadeMode() override; - // Called when creature reached home location after evade. - void JustReachedHome(); + // Called when creature reached home location after evade. + void JustReachedHome() override; - // Used to reset cooldowns for our spells and to inform the raid that we're under attack - void Aggro(Unit* pWho); + // Used to reset cooldowns for our spells and to inform the raid that we're under attack + void Aggro(Unit* pWho) override; - // Called to summon waves, check for boss deaths and to cast our spells. - void UpdateAI(const uint32 uiDiff); + // Called to summon waves, check for boss deaths and to cast our spells. + void UpdateAI(const uint32 uiDiff) override; - // Called on death, informs the raid that they have failed. - void JustDied(Unit* pKiller); + // Called on death, informs the raid that they have failed. + void JustDied(Unit* /*pKiller*/) override; - // "Teleport" all friendly creatures away from the base. - void Retreat(); + void JustRespawned() override; - // Summons a creature for that wave in that base - void SpawnCreatureForWave(uint32 uiMobEntry); + // "Teleport" all friendly creatures away from the base. + void Retreat(); - void JustSummoned(Creature*); + // Summons a creature for that wave in that base + void SpawnCreatureForWave(uint32 uiMobEntry); - // Summons the next wave, calls SummonCreature - void SummonNextWave(); + void JustSummoned(Creature*) override; - // Begins the event by gossip click - void StartEvent(); + void SummonedCreatureJustDied(Creature* pSummoned) override; - // Searches for the appropriate yell and sound and uses it to inform the raid of various things - void DoTalk(YellType pYellType); + // Summons the next wave, calls SummonCreature + void SummonNextWave(); - // Used to filter who to despawn after mass teleport - void SpellHitTarget(Unit*, const SpellEntry*); + // Begins the event by gossip click + void StartEvent(); - public: + // Searches for the appropriate yell and sound and uses it to inform the raid of various things + void DoTalk(YellType pYellType); + + // Used to filter who to despawn after mass teleport + void SpellHitTarget(Unit*, const SpellEntry*) override; + bool IsEventInProgress() const; + + public: ScriptedInstance* m_pInstance; ObjectGuid m_aBossGuid[2]; @@ -111,7 +116,6 @@ struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI uint32 m_uiNextWaveTimer; uint32 m_uiWaveCount; uint32 m_uiWaveMoveTimer; - uint32 m_uiCheckTimer; uint32 m_uiEnemyCount; uint32 m_uiRetreatTimer; uint32 m_uiBase; @@ -132,7 +136,7 @@ struct MANGOS_DLL_DECL hyjalAI : public ScriptedAI private: uint32 m_uiSpellTimer[MAX_SPELL]; - GUIDList lWaveMobGUIDList; + GuidList lWaveMobGUIDList; }; #endif diff --git a/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp b/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp index 45b976aef..0d2cb7012 100644 --- a/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp +++ b/scripts/kalimdor/caverns_of_time/hyjal/instance_hyjal.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -45,16 +45,22 @@ void instance_mount_hyjal::Initialize() bool instance_mount_hyjal::IsEncounterInProgress() const { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS) return true; return false; } +void instance_mount_hyjal::OnPlayerEnter(Player* /*pPlayer*/) +{ + if (GetData(TYPE_AZGALOR) == DONE) + DoSpawnArchimonde(); +} + void instance_mount_hyjal::OnCreatureCreate(Creature* pCreature) { if (pCreature->GetEntry() == NPC_ARCHIMONDE) - m_mNpcEntryGuidStore[NPC_ARCHIMONDE] == pCreature->GetObjectGuid(); + m_mNpcEntryGuidStore[NPC_ARCHIMONDE] = pCreature->GetObjectGuid(); } void instance_mount_hyjal::OnObjectCreate(GameObject* pGo) @@ -83,7 +89,6 @@ void instance_mount_hyjal::OnCreatureEvade(Creature* pCreature) case NPC_ANETHERON: SetData(TYPE_ANETHERON, FAIL); break; case NPC_KAZROGAL: SetData(TYPE_KAZROGAL, FAIL); break; case NPC_AZGALOR: SetData(TYPE_AZGALOR, FAIL); break; - case NPC_ARCHIMONDE: SetData(TYPE_ARCHIMONDE, FAIL); break; } } @@ -97,7 +102,7 @@ void instance_mount_hyjal::OnCreatureDeath(Creature* pCreature) case NPC_AZGALOR: SetData(TYPE_AZGALOR, DONE); break; case NPC_ARCHIMONDE: SetData(TYPE_ARCHIMONDE, DONE); break; - // Trash Mobs summoned in waves + // Trash Mobs summoned in waves case NPC_NECRO: case NPC_ABOMI: case NPC_GHOUL: @@ -119,15 +124,17 @@ void instance_mount_hyjal::OnCreatureDeath(Creature* pCreature) void instance_mount_hyjal::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_WINTERCHILL: case TYPE_ANETHERON: case TYPE_KAZROGAL: + m_auiEncounter[uiType] = uiData; + break; case TYPE_AZGALOR: - if (m_auiEncounter[uiType] == DONE) - return; m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoSpawnArchimonde(); break; case TYPE_ARCHIMONDE: m_auiEncounter[uiType] = uiData; @@ -143,9 +150,9 @@ void instance_mount_hyjal::SetData(uint32 uiType, uint32 uiData) { if (!lAncientGemGUIDList.empty()) { - for(GUIDList::const_iterator itr = lAncientGemGUIDList.begin(); itr != lAncientGemGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = lAncientGemGUIDList.begin(); itr != lAncientGemGUIDList.end(); ++itr) { - //don't know how long it expected + // don't know how long it expected DoRespawnGameObject(*itr, DAY); } } @@ -161,7 +168,7 @@ void instance_mount_hyjal::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4]; + << m_auiEncounter[3] << " " << m_auiEncounter[4]; m_strSaveData = saveStream.str(); @@ -170,9 +177,24 @@ void instance_mount_hyjal::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_mount_hyjal::GetData(uint32 uiType) +void instance_mount_hyjal::DoSpawnArchimonde() +{ + // Don't spawn if already killed + if (GetData(TYPE_ARCHIMONDE) == DONE) + return; + + // Don't spawn him twice + if (GetSingleCreatureFromStorage(NPC_ARCHIMONDE, true)) + return; + + // Summon Archimonde + if (Player* pPlayer = GetPlayerInMap()) + pPlayer->SummonCreature(NPC_ARCHIMONDE, aArchimondeSpawnLoc[0], aArchimondeSpawnLoc[1], aArchimondeSpawnLoc[2], aArchimondeSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); +} + +uint32 instance_mount_hyjal::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_WINTERCHILL: case TYPE_ANETHERON: @@ -200,8 +222,8 @@ void instance_mount_hyjal::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as IN_PROGRESS - reset it instead. + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as IN_PROGRESS - reset it instead. m_auiEncounter[i] = NOT_STARTED; OUT_LOAD_INST_DATA_COMPLETE; diff --git a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp b/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp deleted file mode 100644 index cafed2178..000000000 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_captain_skarloc.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Captain_Skarloc -SD%Complete: 75 -SDComment: Missing adds, missing waypoints to move up to Thrall once spawned + speech before enter combat. -SDCategory: Caverns of Time, Old Hillsbrad Foothills -EndScriptData */ - -#include "precompiled.h" -#include "old_hillsbrad.h" - -#define SAY_ENTER -1560000 -#define SAY_TAUNT1 -1560001 -#define SAY_TAUNT2 -1560002 -#define SAY_SLAY1 -1560003 -#define SAY_SLAY2 -1560004 -#define SAY_DEATH -1560005 - -#define SPELL_HOLY_LIGHT 29427 -#define SPELL_CLEANSE 29380 -#define SPELL_HAMMER_OF_JUSTICE 13005 -#define SPELL_HOLY_SHIELD 31904 -#define SPELL_DEVOTION_AURA 8258 -#define SPELL_CONSECRATION 38385 - -struct MANGOS_DLL_DECL boss_captain_skarlocAI : public ScriptedAI -{ - boss_captain_skarlocAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 Holy_Light_Timer; - uint32 Cleanse_Timer; - uint32 HammerOfJustice_Timer; - uint32 HolyShield_Timer; - uint32 DevotionAura_Timer; - uint32 Consecration_Timer; - - void Reset() - { - Holy_Light_Timer = 30000; - Cleanse_Timer = 10000; - HammerOfJustice_Timer = 60000; - HolyShield_Timer = 240000; - DevotionAura_Timer = 3000; - Consecration_Timer = 8000; - } - - void Aggro(Unit *who) - { - //This is not correct. Should taunt Thrall before engage in combat - DoScriptText(SAY_TAUNT1, m_creature); - DoScriptText(SAY_TAUNT2, m_creature); - } - - void KilledUnit(Unit *victim) - { - DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); - } - - void JustDied(Unit *victim) - { - DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance && m_pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_THRALL_PART1, DONE); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Holy_Light - if (Holy_Light_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_HOLY_LIGHT); - Holy_Light_Timer = urand(20000, 30000); - }else Holy_Light_Timer -= diff; - - //Cleanse - if (Cleanse_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_CLEANSE); - Cleanse_Timer = 10000; - } else Cleanse_Timer -= diff; - - //Hammer of Justice - if (HammerOfJustice_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE); - HammerOfJustice_Timer = urand(20000, 35000); - }else HammerOfJustice_Timer -= diff; - - //Holy Shield - if (HolyShield_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_HOLY_SHIELD); - HolyShield_Timer = 240000; - }else HolyShield_Timer -= diff; - - //Devotion_Aura - if (DevotionAura_Timer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_DEVOTION_AURA); - DevotionAura_Timer = urand(45000, 55000); - }else DevotionAura_Timer -= diff; - - //Consecration - if (Consecration_Timer < diff) - { - //DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONSECRATION); - Consecration_Timer = urand(5000, 10000); - }else Consecration_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_captain_skarloc(Creature* pCreature) -{ - return new boss_captain_skarlocAI(pCreature); -} - -void AddSC_boss_captain_skarloc() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_captain_skarloc"; - pNewScript->GetAI = &GetAI_boss_captain_skarloc; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp b/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp deleted file mode 100644 index b97cd6282..000000000 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_epoch_hunter.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Epoch_Hunter -SD%Complete: 60 -SDComment: Missing spawns pre-event, missing speech to be coordinated with rest of escort event. -SDCategory: Caverns of Time, Old Hillsbrad Foothills -EndScriptData */ - -#include "precompiled.h" -#include "old_hillsbrad.h" - -#define SAY_ENTER1 -1560013 -#define SAY_ENTER2 -1560014 -#define SAY_ENTER3 -1560015 -#define SAY_AGGRO1 -1560016 -#define SAY_AGGRO2 -1560017 -#define SAY_SLAY1 -1560018 -#define SAY_SLAY2 -1560019 -#define SAY_BREATH1 -1560020 -#define SAY_BREATH2 -1560021 -#define SAY_DEATH -1560022 - -#define SPELL_SAND_BREATH 31914 -#define SPELL_IMPENDING_DEATH 31916 -#define SPELL_MAGIC_DISRUPTION_AURA 33834 -#define SPELL_WING_BUFFET 31475 - -struct MANGOS_DLL_DECL boss_epoch_hunterAI : public ScriptedAI -{ - boss_epoch_hunterAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 SandBreath_Timer; - uint32 ImpendingDeath_Timer; - uint32 WingBuffet_Timer; - uint32 Mda_Timer; - - void Reset() - { - SandBreath_Timer = urand(8000, 16000); - ImpendingDeath_Timer = urand(25000, 30000); - WingBuffet_Timer = 35000; - Mda_Timer = 40000; - } - - void Aggro(Unit *who) - { - DoScriptText(urand(0, 1) ? SAY_AGGRO1 : SAY_AGGRO2, m_creature); - } - - void KilledUnit(Unit *victim) - { - DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); - } - - void JustDied(Unit *victim) - { - DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance && m_pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_THRALL_PART4, DONE); - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Sand Breath - if (SandBreath_Timer < diff) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SAND_BREATH); - - DoScriptText(urand(0, 1) ? SAY_BREATH1 : SAY_BREATH2, m_creature); - - SandBreath_Timer = urand(10000, 20000); - }else SandBreath_Timer -= diff; - - if (ImpendingDeath_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_IMPENDING_DEATH); - ImpendingDeath_Timer = urand(25000, 30000); - }else ImpendingDeath_Timer -= diff; - - if (WingBuffet_Timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target,SPELL_WING_BUFFET); - WingBuffet_Timer = urand(25000, 35000); - }else WingBuffet_Timer -= diff; - - if (Mda_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_MAGIC_DISRUPTION_AURA); - Mda_Timer = 15000; - }else Mda_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_epoch_hunter(Creature* pCreature) -{ - return new boss_epoch_hunterAI(pCreature); -} - -void AddSC_boss_epoch_hunter() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_epoch_hunter"; - pNewScript->GetAI = &GetAI_boss_epoch_hunter; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp b/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp deleted file mode 100644 index b0d78db4f..000000000 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/boss_leutenant_drake.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Luetenant_Drake -SD%Complete: 70 -SDComment: Missing proper code for patrolling area after being spawned. Script for GO (barrels) quest 10283 -SDCategory: Caverns of Time, Old Hillsbrad Foothills -EndScriptData */ - -#include "precompiled.h" -#include "old_hillsbrad.h" -#include "escort_ai.h" - -/*###### -## go_barrel_old_hillsbrad -######*/ - -bool GOUse_go_barrel_old_hillsbrad(Player* pPlayer, GameObject* pGo) -{ - if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) - { - if (pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE) - return false; - - pInstance->SetData(TYPE_BARREL_DIVERSION, IN_PROGRESS); - } - return false; -} - -/*###### -## boss_lieutenant_drake -######*/ - -#define SAY_ENTER -1560006 -#define SAY_AGGRO -1560007 -#define SAY_SLAY1 -1560008 -#define SAY_SLAY2 -1560009 -#define SAY_MORTAL -1560010 -#define SAY_SHOUT -1560011 -#define SAY_DEATH -1560012 - -#define SPELL_WHIRLWIND 31909 -#define SPELL_HAMSTRING 9080 -#define SPELL_MORTAL_STRIKE 31911 -#define SPELL_FRIGHTENING_SHOUT 33789 - -struct Location -{ - uint32 wpId; - float x; - float y; - float z; -}; - -static Location DrakeWP[]= -{ - {0, 2125.84f, 88.2535f, 54.8830f}, - {1, 2111.01f, 93.8022f, 52.6356f}, - {2, 2106.70f, 114.753f, 53.1965f}, - {3, 2107.76f, 138.746f, 52.5109f}, - {4, 2114.83f, 160.142f, 52.4738f}, - {5, 2125.24f, 178.909f, 52.7283f}, - {6, 2151.02f, 208.901f, 53.1551f}, - {7, 2177.00f, 233.069f, 52.4409f}, - {8, 2190.71f, 227.831f, 53.2742f}, - {9, 2178.14f, 214.219f, 53.0779f}, - {10, 2154.99f, 202.795f, 52.6446f}, - {11, 2132.00f, 191.834f, 52.5709f}, - {12, 2117.59f, 166.708f, 52.7686f}, - {13, 2093.61f, 139.441f, 52.7616f}, - {14, 2086.29f, 104.950f, 52.9246f}, - {15, 2094.23f, 81.2788f, 52.6946f}, - {16, 2108.70f, 85.3075f, 53.3294f}, - {17, 2125.50f, 88.9481f, 54.7953f}, - {18, 2128.20f, 70.9763f, 64.4221f} -}; - -struct MANGOS_DLL_DECL boss_lieutenant_drakeAI : public ScriptedAI -{ - boss_lieutenant_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - bool CanPatrol; - uint32 wpId; - - uint32 Whirlwind_Timer; - uint32 Fear_Timer; - uint32 MortalStrike_Timer; - uint32 ExplodingShout_Timer; - - void Reset() - { - CanPatrol = true; - wpId = 0; - - Whirlwind_Timer = 20000; - Fear_Timer = 30000; - MortalStrike_Timer = 45000; - ExplodingShout_Timer = 25000; - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - void KilledUnit(Unit *victim) - { - DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); - } - - void JustDied(Unit *victim) - { - DoScriptText(SAY_DEATH, m_creature); - } - - void UpdateAI(const uint32 diff) - { - //TODO: make this work - if (CanPatrol && wpId == 0) - { - m_creature->GetMotionMaster()->MovePoint(DrakeWP[0].wpId, DrakeWP[0].x, DrakeWP[0].y, DrakeWP[0].z); - ++wpId; - } - - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Whirlwind - if (Whirlwind_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_WHIRLWIND); - Whirlwind_Timer = urand(20000, 25000); - }else Whirlwind_Timer -= diff; - - //Fear - if (Fear_Timer < diff) - { - DoScriptText(SAY_SHOUT, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FRIGHTENING_SHOUT); - Fear_Timer = urand(25000, 35000); - }else Fear_Timer -= diff; - - //Mortal Strike - if (MortalStrike_Timer < diff) - { - DoScriptText(SAY_MORTAL, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - MortalStrike_Timer = urand(20000, 30000); - }else MortalStrike_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_lieutenant_drake(Creature* pCreature) -{ - return new boss_lieutenant_drakeAI(pCreature); -} - -void AddSC_boss_lieutenant_drake() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "go_barrel_old_hillsbrad"; - pNewScript->pGOUse = &GOUse_go_barrel_old_hillsbrad; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_lieutenant_drake"; - pNewScript->GetAI = &GetAI_boss_lieutenant_drake; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp b/scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp index 5a4d76207..03e2708dd 100644 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp +++ b/scripts/kalimdor/caverns_of_time/old_hillsbrad/instance_old_hillsbrad.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Instance_Old_Hillsbrad SD%Complete: 75 -SDComment: If thrall escort fail, all parts will reset. In future, save sub-parts and continue from last known. +SDComment: Thrall reset on server restart is not supported, because of core limitation. SDCategory: Caverns of Time, Old Hillsbrad Foothills EndScriptData */ @@ -26,7 +26,8 @@ EndScriptData */ instance_old_hillsbrad::instance_old_hillsbrad(Map* pMap) : ScriptedInstance(pMap), m_uiBarrelCount(0), - m_uiThrallEventCount(0) + m_uiThrallEventCount(0), + m_uiThrallResetTimer(0) { Initialize(); } @@ -36,161 +37,266 @@ void instance_old_hillsbrad::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_old_hillsbrad::OnPlayerEnter(Player* pPlayer) +{ + // ToDo: HandleThrallRelocation(); + // Note: this isn't yet supported because of the grid load / unload + + // Spawn Drake if necessary + if (GetData(TYPE_DRAKE) == DONE || GetData(TYPE_BARREL_DIVERSION) != DONE) + return; + + if (GetSingleCreatureFromStorage(NPC_DRAKE, true)) + return; + + pPlayer->SummonCreature(NPC_DRAKE, aDrakeSummonLoc[0], aDrakeSummonLoc[1], aDrakeSummonLoc[2], aDrakeSummonLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); +} + void instance_old_hillsbrad::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_THRALL: case NPC_TARETHA: + case NPC_EROZION: + case NPC_ARMORER: + case NPC_TARREN_MILL_PROTECTOR: + case NPC_TARREN_MILL_LOOKOUT: + case NPC_YOUNG_BLANCHY: + case NPC_DRAKE: + case NPC_SKARLOC: case NPC_EPOCH: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_ORC_PRISONER: + // Sort the orcs which are inside the houses + if (pCreature->GetPositionZ() > 53.4f) + { + if (pCreature->GetPositionY() > 150.0f) + m_lLeftPrisonersList.push_back(pCreature->GetObjectGuid()); + else + m_lRightPrisonersList.push_back(pCreature->GetObjectGuid()); + } + break; } } void instance_old_hillsbrad::OnCreatureDeath(Creature* pCreature) { - if (pCreature->GetEntry() == NPC_EPOCH) + switch (pCreature->GetEntry()) { - // notify thrall so he can continue - if (Creature* pThrall = GetSingleCreatureFromStorage(NPC_THRALL)) - pThrall->AI()->KilledUnit(pCreature); + case NPC_DRAKE: SetData(TYPE_DRAKE, DONE); break; + case NPC_SKARLOC: SetData(TYPE_SKARLOC, DONE); break; + case NPC_EPOCH: SetData(TYPE_EPOCH, DONE); break; } } +void instance_old_hillsbrad::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_DRAKE: + SetData(TYPE_DRAKE, IN_PROGRESS); + DoUpdateWorldState(WORLD_STATE_OH, 0); + break; + case NPC_SKARLOC: SetData(TYPE_SKARLOC, IN_PROGRESS); break; + case NPC_EPOCH: SetData(TYPE_EPOCH, IN_PROGRESS); break; + } +} + +void instance_old_hillsbrad::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_DRAKE: SetData(TYPE_DRAKE, FAIL); break; + case NPC_SKARLOC: SetData(TYPE_SKARLOC, FAIL); break; + case NPC_EPOCH: SetData(TYPE_EPOCH, FAIL); break; + } +} + +void instance_old_hillsbrad::OnObjectCreate(GameObject* pGo) +{ + if (pGo->GetEntry() == GO_ROARING_FLAME) + m_lRoaringFlamesList.push_back(pGo->GetObjectGuid()); + else if (pGo->GetEntry() == GO_PRISON_DOOR) + m_mGoEntryGuidStore[GO_PRISON_DOOR] = pGo->GetObjectGuid(); +} + void instance_old_hillsbrad::HandleThrallRelocation() { + // reset instance data + SetData(TYPE_THRALL_EVENT, IN_PROGRESS); + if (Creature* pThrall = GetSingleCreatureFromStorage(NPC_THRALL)) { debug_log("SD2: Instance Old Hillsbrad: Thrall relocation"); - if (m_auiEncounter[TYPE_THRALL_PART4] == IN_PROGRESS) - { - // boss failed, reloc to inn - pThrall->GetMap()->CreatureRelocation(pThrall, 2660.57f, 659.173f, 61.9370f, 0.0f); - m_auiEncounter[TYPE_THRALL_PART4] = NOT_STARTED; - } - else if (m_auiEncounter[TYPE_THRALL_PART3] == IN_PROGRESS) - { - // barn to inn failed, reloc to inn - pThrall->GetMap()->CreatureRelocation(pThrall, 2660.57f, 659.173f, 61.9370f, 0.0f); - m_auiEncounter[TYPE_THRALL_PART3] = DONE; - } - else if (m_auiEncounter[TYPE_THRALL_PART2] == IN_PROGRESS) - { - // keep to barn failed, reloc to barn - pThrall->GetMap()->CreatureRelocation(pThrall, 2486.91f, 626.356f, 58.0761f, 0.0f); - m_auiEncounter[TYPE_THRALL_PART2] = DONE; - } - else if (m_auiEncounter[TYPE_THRALL_PART1] == IN_PROGRESS) - { - // didn't reach very far, back to the basement using default - m_auiEncounter[TYPE_THRALL_PART1] = NOT_STARTED; - } + if (!pThrall->isAlive()) + pThrall->Respawn(); + + // epoch failed, reloc to inn + if (GetData(TYPE_ESCORT_INN) == DONE) + pThrall->GetMap()->CreatureRelocation(pThrall, 2660.57f, 659.173f, 61.9370f, 5.76f); + // barn to inn failed, reloc to barn + else if (GetData(TYPE_ESCORT_BARN) == DONE) + pThrall->GetMap()->CreatureRelocation(pThrall, 2486.91f, 626.356f, 58.0761f, 4.66f); + // keep to barn failed, reloc to keep + else if (GetData(TYPE_SKARLOC) == DONE) + pThrall->GetMap()->CreatureRelocation(pThrall, 2063.40f, 229.509f, 64.4883f, 2.23f); + // prison to keep failed, reloc to prison + else + pThrall->GetMap()->CreatureRelocation(pThrall, 2231.89f, 119.95f, 82.2979f, 4.21f); } } void instance_old_hillsbrad::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_BARREL_DIVERSION: - { + m_auiEncounter[uiType] = uiData; if (uiData == IN_PROGRESS) { - if (m_uiBarrelCount >= 5) + if (m_uiBarrelCount >= MAX_BARRELS) return; + // Update barrels used and world state ++m_uiBarrelCount; DoUpdateWorldState(WORLD_STATE_OH, m_uiBarrelCount); debug_log("SD2: Instance Old Hillsbrad: go_barrel_old_hillsbrad count %u", m_uiBarrelCount); - m_auiEncounter[TYPE_BARREL_DIVERSION] = IN_PROGRESS; - - if (m_uiBarrelCount == 5) + // Set encounter to done, and spawn Liutenant Drake + if (m_uiBarrelCount == MAX_BARRELS) { UpdateLodgeQuestCredit(); if (Player* pPlayer = GetPlayerInMap()) - pPlayer->SummonCreature(NPC_DRAKE, 2128.43f, 71.01f, 64.42f, 1.74f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 1800000); + { + pPlayer->SummonCreature(NPC_DRAKE, aDrakeSummonLoc[0], aDrakeSummonLoc[1], aDrakeSummonLoc[2], aDrakeSummonLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + + // set the houses on fire + for (GuidList::const_iterator itr = m_lRoaringFlamesList.begin(); itr != m_lRoaringFlamesList.end(); ++itr) + DoRespawnGameObject(*itr, 30 * MINUTE); + + // move the orcs outside the houses + float fX, fY, fZ; + for (GuidList::const_iterator itr = m_lRightPrisonersList.begin(); itr != m_lRightPrisonersList.end(); ++itr) + { + if (Creature* pOrc = instance->GetCreature(*itr)) + { + pOrc->GetRandomPoint(afInstanceLoc[0][0], afInstanceLoc[0][1], afInstanceLoc[0][2], 10.0f, fX, fY, fZ); + pOrc->SetWalk(false); + pOrc->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + for (GuidList::const_iterator itr = m_lLeftPrisonersList.begin(); itr != m_lLeftPrisonersList.end(); ++itr) + { + if (Creature* pOrc = instance->GetCreature(*itr)) + { + pOrc->GetRandomPoint(afInstanceLoc[1][0], afInstanceLoc[1][1], afInstanceLoc[1][2], 10.0f, fX, fY, fZ); + pOrc->SetWalk(false); + pOrc->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + } else debug_log("SD2: Instance Old Hillsbrad: SetData (Type: %u Data %u) cannot find any pPlayer.", uiType, uiData); - m_auiEncounter[TYPE_BARREL_DIVERSION] = DONE; + SetData(TYPE_BARREL_DIVERSION, DONE); } } break; - } case TYPE_THRALL_EVENT: - { // nothing to do if already done and thrall respawn - if (m_auiEncounter[TYPE_THRALL_EVENT] == DONE) + if (GetData(TYPE_THRALL_EVENT) == DONE) return; - + m_auiEncounter[uiType] = uiData; if (uiData == FAIL) { - if (m_uiThrallEventCount <= 20) + // despawn the bosses if necessary + if (Creature* pSkarloc = GetSingleCreatureFromStorage(NPC_SKARLOC, true)) + pSkarloc->ForcedDespawn(); + if (Creature* pEpoch = GetSingleCreatureFromStorage(NPC_EPOCH, true)) + pEpoch->ForcedDespawn(); + + if (m_uiThrallEventCount <= MAX_WIPE_COUNTER) { ++m_uiThrallEventCount; debug_log("SD2: Instance Old Hillsbrad: Thrall event failed %u times.", m_uiThrallEventCount); - HandleThrallRelocation(); + // reset Thrall on timer + m_uiThrallResetTimer = 30000; } - else if (m_uiThrallEventCount > 20) - { - m_auiEncounter[TYPE_THRALL_EVENT] = uiData; - m_auiEncounter[TYPE_THRALL_PART1] = uiData; - m_auiEncounter[TYPE_THRALL_PART2] = uiData; - m_auiEncounter[TYPE_THRALL_PART3] = uiData; - m_auiEncounter[TYPE_THRALL_PART4] = uiData; + // If we already respawned Thrall too many times, the event is failed for good + else if (m_uiThrallEventCount > MAX_WIPE_COUNTER) debug_log("SD2: Instance Old Hillsbrad: Thrall event failed %u times. Reset instance required.", m_uiThrallEventCount); - } } - else - m_auiEncounter[TYPE_THRALL_EVENT] = uiData; - - debug_log("SD2: Instance Old Hillsbrad: Thrall escort event adjusted to data %u.",uiData); break; - } - case TYPE_THRALL_PART1: - m_auiEncounter[TYPE_THRALL_PART1] = uiData; - debug_log("SD2: Instance Old Hillsbrad: Thrall event part I adjusted to data %u.",uiData); - break; - case TYPE_THRALL_PART2: - m_auiEncounter[TYPE_THRALL_PART2] = uiData; - debug_log("SD2: Instance Old Hillsbrad: Thrall event part II adjusted to data %u.",uiData); - break; - case TYPE_THRALL_PART3: - m_auiEncounter[TYPE_THRALL_PART3] = uiData; - debug_log("SD2: Instance Old Hillsbrad: Thrall event part III adjusted to data %u.",uiData); - break; - case TYPE_THRALL_PART4: - m_auiEncounter[TYPE_THRALL_PART4] = uiData; - debug_log("SD2: Instance Old Hillsbrad: Thrall event part IV adjusted to data %u.",uiData); + case TYPE_DRAKE: + case TYPE_SKARLOC: + case TYPE_ESCORT_BARN: + case TYPE_ESCORT_INN: + case TYPE_EPOCH: + m_auiEncounter[uiType] = uiData; + debug_log("SD2: Instance Old Hillsbrad: Thrall event type %u adjusted to data %u.", uiType, uiData); break; } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_old_hillsbrad::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; } -uint32 instance_old_hillsbrad::GetData(uint32 uiData) +void instance_old_hillsbrad::Load(const char* chrIn) { - switch(uiData) + if (!chrIn) { - case TYPE_BARREL_DIVERSION: - return m_auiEncounter[TYPE_BARREL_DIVERSION]; - case TYPE_THRALL_EVENT: - return m_auiEncounter[TYPE_THRALL_EVENT]; - case TYPE_THRALL_PART1: - return m_auiEncounter[TYPE_THRALL_PART1]; - case TYPE_THRALL_PART2: - return m_auiEncounter[TYPE_THRALL_PART2]; - case TYPE_THRALL_PART3: - return m_auiEncounter[TYPE_THRALL_PART3]; - case TYPE_THRALL_PART4: - return m_auiEncounter[TYPE_THRALL_PART4]; - default: - return 0; + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + // custom reload - if the escort event or the Epoch event are not done, then reset the escort + // this is done, because currently we cannot handle Thrall relocation on server reset + if (m_auiEncounter[5] != DONE) + { + m_auiEncounter[2] = NOT_STARTED; + m_auiEncounter[3] = NOT_STARTED; + m_auiEncounter[4] = NOT_STARTED; } + + OUT_LOAD_INST_DATA_COMPLETE; } void instance_old_hillsbrad::UpdateLodgeQuestCredit() @@ -199,7 +305,7 @@ void instance_old_hillsbrad::UpdateLodgeQuestCredit() if (!players.isEmpty()) { - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) { if (Player* pPlayer = itr->getSource()) pPlayer->KilledMonsterCredit(NPC_LODGE_QUEST_TRIGGER); @@ -207,11 +313,46 @@ void instance_old_hillsbrad::UpdateLodgeQuestCredit() } } +void instance_old_hillsbrad::Update(uint32 uiDiff) +{ + if (m_uiThrallResetTimer) + { + if (m_uiThrallResetTimer <= uiDiff) + { + HandleThrallRelocation(); + m_uiThrallResetTimer = 0; + } + else + m_uiThrallResetTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_old_hillsbrad(Map* pMap) { return new instance_old_hillsbrad(pMap); } +bool ProcessEventId_event_go_barrel_old_hillsbrad(uint32 /*uiEventId*/, Object* pSource, Object* pTarget, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + { + if (instance_old_hillsbrad* pInstance = (instance_old_hillsbrad*)((Player*)pSource)->GetInstanceData()) + { + if (pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE) + return true; + + pInstance->SetData(TYPE_BARREL_DIVERSION, IN_PROGRESS); + + // Don't allow players to use same object twice + if (pTarget->GetTypeId() == TYPEID_GAMEOBJECT) + ((GameObject*)pTarget)->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + + return true; + } + } + return false; +} + void AddSC_instance_old_hillsbrad() { Script* pNewScript; @@ -220,4 +361,9 @@ void AddSC_instance_old_hillsbrad() pNewScript->Name = "instance_old_hillsbrad"; pNewScript->GetInstanceData = &GetInstanceData_instance_old_hillsbrad; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_go_barrel_old_hillsbrad"; + pNewScript->pProcessEventId = &ProcessEventId_event_go_barrel_old_hillsbrad; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp b/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp index bb6be5ffd..5dc5d915d 100644 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp +++ b/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,12 @@ /* ScriptData SDName: Old_Hillsbrad -SD%Complete: 60 -SDComment: Quest support: 10283, 10284. All friendly NPC's. Thrall waypoints fairly complete, missing many details, but possible to complete escort. +SD%Complete: 90 +SDComment: Quest support: 10283, 10284. All friendly NPC's. Thrall escort event is complete, possible a few details are still missing. SDCategory: Caverns of Time, Old Hillsbrad Foothills EndScriptData */ /* ContentData -npc_brazen npc_erozion npc_thrall_old_hillsbrad npc_taretha @@ -32,58 +31,6 @@ EndContentData */ #include "old_hillsbrad.h" #include "escort_ai.h" -struct MANGOS_DLL_DECL npc_tarethaAI : public npc_escortAI -{ - npc_tarethaAI(Creature* pCreature); - - instance_old_hillsbrad* m_pInstance; - ObjectGuid m_erozionGuid; - uint32 m_uiErozionEventTimer; - uint32 m_uiErozionPhase; - - void Reset() {} - void JustSummoned(Creature* pSummoned); - void WaypointReached(uint32 uiPoint); - void UpdateEscortAI(const uint32 uiDiff); -}; - -/*###### -## npc_brazen -######*/ - -enum -{ - GOSSIP_ID_UNKNOWN_TEXT = -1000000, - GOSSIP_ITEM_READY = -3560000, - - TEXT_ID_HAS_BOMBS = 9780, - ITEM_ENTRY_BOMBS = 25853, - - TAXI_PATH_ID = 534 -}; - -bool GossipHello_npc_brazen(Player* pPlayer, Creature* pCreature) -{ - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_brazen(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - if (!pPlayer->HasItemCount(ITEM_ENTRY_BOMBS, 1)) - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_HAS_BOMBS, pCreature->GetObjectGuid()); - else - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID); - } - } - return true; -} - /*###### ## npc_erozion ######*/ @@ -93,6 +40,8 @@ enum GOSSIP_ITEM_NEED_BOMBS = -3560001, TEXT_ID_DEFAULT = 9778, TEXT_ID_GOT_ITEM = 9515, + + ITEM_ENTRY_BOMBS = 25853, }; bool GossipHello_npc_erozion(Player* pPlayer, Creature* pCreature) @@ -102,8 +51,8 @@ bool GossipHello_npc_erozion(Player* pPlayer, Creature* pCreature) ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - if (pInstance && pInstance->GetData(TYPE_BARREL_DIVERSION) != DONE && !pPlayer->HasItemCount(ITEM_ENTRY_BOMBS,1)) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEED_BOMBS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (pInstance && pInstance->GetData(TYPE_BARREL_DIVERSION) != DONE && !pPlayer->HasItemCount(ITEM_ENTRY_BOMBS, 1)) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NEED_BOMBS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); // Need info, should have option to teleport or not /*if (!pPlayer->GetQuestRewardStatus(QUEST_ENTRY_RETURN) && pPlayer->GetQuestStatus(QUEST_ENTRY_RETURN) == QUEST_STATUS_COMPLETE) @@ -114,9 +63,9 @@ bool GossipHello_npc_erozion(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_erozion(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_erozion(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_ENTRY_BOMBS, 1)) pPlayer->SendNewItem(pItem, 1, true, false); @@ -124,7 +73,7 @@ bool GossipSelect_npc_erozion(Player* pPlayer, Creature* pCreature, uint32 uiSen pPlayer->SEND_GOSSIP_MENU(TEXT_ID_GOT_ITEM, pCreature->GetObjectGuid()); } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 2) pPlayer->CLOSE_GOSSIP_MENU(); return true; @@ -136,23 +85,51 @@ bool GossipSelect_npc_erozion(Player* pPlayer, Creature* pCreature, uint32 uiSen enum { - // Thrall texts - SAY_TH_START_EVENT_PART1 = -1560023, - SAY_TH_ARMORY = -1560024, + // Thrall texts - part I + SAY_TH_START_EVENT_PART_1 = -1560023, + SAY_ARMORER_CALL_GUARDS = -1560003, + SAY_TH_KILL_ARMORER = -1560050, + SAY_TH_ARMORY_1 = -1560024, + SAY_TH_ARMORY_2 = -1560005, SAY_TH_SKARLOC_MEET = -1560025, + SAY_SKARLOC_ENTER = -1560000, SAY_TH_SKARLOC_TAUNT = -1560026, + + // Thrall texts - part II SAY_TH_START_EVENT_PART2 = -1560027, SAY_TH_MOUNTS_UP = -1560028, + EMOTE_TH_STARTLE_HORSE = -1560006, + + // Thrall texts part III (barn) + SAY_LOOKOUT_BARN_1 = -1560007, + SAY_PROTECTOR_BARN_2 = -1560008, + EMOTE_TH_CALM_HORSE = -1560009, + SAY_PROTECTOR_BARN_3 = -1560010, + SAY_TH_HEAD_TOWN = -1560011, + + // Thrall texts part III (church) + SAY_TH_CHURCH_ENTER = -1560012, + SAY_LOOKOUT_CHURCH = -1560016, SAY_TH_CHURCH_END = -1560029, + + // Thrall texts part III (inn) + SAY_LOOKOUT_INN = -1560017, + SAY_TA_ESCAPED = -1560049, SAY_TH_MEET_TARETHA = -1560030, SAY_EPOCH_ENTER1 = -1560013, + SAY_TH_EPOCH_WONDER = -1560031, SAY_EPOCH_ENTER2 = -1560014, + SAY_TH_EPOCH_KILL_TARETHA = -1560032, SAY_EPOCH_ENTER3 = -1560015, - SAY_TH_EPOCH_WONDER = -1560031, - SAY_TH_EPOCH_KILL_TARETHA = -1560032, + // infinite dragons texts + SAY_INFINITE_DRAGON_AGGRO_1 = -1560004, + SAY_INFINITE_DRAGON_AGGRO_2 = -1560018, + SAY_INFINITE_DRAGON_AGGRO_3 = -1560019, + SAY_INFINITE_DRAGON_AGGRO_4 = -1560020, + // Thrall texts - misc SAY_TH_RANDOM_LOW_HP1 = -1560034, SAY_TH_RANDOM_LOW_HP2 = -1560035, @@ -168,51 +145,64 @@ enum SAY_TH_RANDOM_KILL2 = -1560043, SAY_TH_RANDOM_KILL3 = -1560044, - SAY_TH_KILL_ARMORER = -1560050, - SAY_TH_LEAVE_COMBAT1 = -1560045, SAY_TH_LEAVE_COMBAT2 = -1560046, SAY_TH_LEAVE_COMBAT3 = -1560047, - // Taretha texts - SAY_TA_ESCAPED = -1560049, + // reset texts + SAY_ERONZION_RESET_THRALL = -1560001, + SAY_ERONZION_RESET_LAST = -1560002, - // end event texts - SAY_TA_FREE = -1560048, - SAY_TR_GLAD_SAFE = -1560054, - SAY_TA_NEVER_MET = -1560055, - SAY_TR_THEN_WHO = -1560056, - SAY_PRE_WIPE = -1560057, - SAY_WIPE_MEMORY = -1560051, - SAY_AFTER_WIPE = -1560058, - SAY_ABOUT_TARETHA = -1560052, - SAY_TH_EVENT_COMPLETE = -1560033, - SAY_TA_FAREWELL = -1560053, + // gossip - start item + GOSSIP_ITEM_START = -3560000, // "We are ready to get you out of here, Thrall" + TEXT_ID_START = 9568, + + // gossip - after Skarloc items + GOSSIP_ITEM_SKARLOC_1 = -3560002, // "Taretha cannot see you, Thrall." + TEXT_ID_SKARLOC_1 = 9578, // Thank you friends, I owe my freedom to you. Where is Taretha? I hoped to see her + GOSSIP_ITEM_SKARLOC_2 = -3560003, // "The situation is rather complicated, Thrall. It would be best for you..." + TEXT_ID_SKARLOC_2 = 9579, // What do you mean by this? Is Taretha in danger? + GOSSIP_ITEM_SKARLOC_3 = -3560007, + TEXT_ID_SKARLOC_3 = 9580, // I will do no such thing. I simply cannot leave Taretha... + + // gossip - barn + GOSSIP_ITEM_TARREN_1 = -3560004, // "We're ready, Thrall." + TEXT_ID_TARREN = 9597, // tarren mill is beyond these trees + + TEXT_ID_INN = 9614, // I'm glad Taretha is alive. We now must find a way to free her... - // Misc for Thrall + // spells used by Thrall + SPELL_KNOCKOUT_ARMORER = 32890, // cast on the armorer SPELL_STRIKE = 14516, SPELL_SHIELD_BLOCK = 12169, - SPELL_SUMMON_EROZION_IMAGE = 33954, // if thrall dies during escort? + SPELL_SHADOW_SPIKE = 33125, // used to kill Taretha + SPELL_TRANSFORM = 33133, // transform infinite defilers + SPELL_SUMMON_EROZION_IMAGE = 33954, // if thrall dies during escort + SPELL_SPAWN_EROZION_IMAGE = 33955, + // equipment EQUIP_ID_WEAPON = 927, - EQUIP_ID_SHIELD = 20913, + EQUIP_ID_SHIELD = 1961, + + // display ids MODEL_THRALL_UNEQUIPPED = 17292, MODEL_THRALL_EQUIPPED = 18165, + MODEL_SKARLOC_MOUNT = 8469, // misc creature entries - NPC_ARMORER = 18764, - NPC_SCARLOC = 17862, + NPC_IMAGE_OF_ERONZION = 19438, + NPC_SKARLOC_MOUNT = 18798, + NPC_THRALL_QUEST_TRIGGER = 20156, + // part I and II ambush npcs NPC_RIFLE = 17820, NPC_WARDEN = 17833, NPC_VETERAN = 17860, + NPC_MAGE = 18934, NPC_WATCHMAN = 17814, NPC_SENTRY = 17815, - NPC_BARN_GUARDSMAN = 18092, - NPC_BARN_PROTECTOR = 18093, - NPC_BARN_LOOKOUT = 18094, - + // part III ambush npcs NPC_CHURCH_GUARDSMAN = 23175, NPC_CHURCH_PROTECTOR = 23179, NPC_CHURCH_LOOKOUT = 23177, @@ -221,36 +211,35 @@ enum NPC_INN_PROTECTOR = 23180, NPC_INN_LOOKOUT = 23178, - NPC_SKARLOC_MOUNT = 18798, - MODEL_SKARLOC_MOUNT = 18223, - NPC_EROZION = 18723, - NPC_THRALL_QUEST_TRIGGER = 20156, - - // gossip - TEXT_ID_START = 9568, - TEXT_ID_SKARLOC1 = 9614, // I'm glad Taretha is alive. We now must find a way to free her... - GOSSIP_ITEM_SKARLOC1 = -3560002, // "Taretha cannot see you, Thrall." - TEXT_ID_SKARLOC2 = 9579, // What do you mean by this? Is Taretha in danger? - GOSSIP_ITEM_SKARLOC2 = -3560003, // "The situation is rather complicated, Thrall. It would be best for you to head into the mountains now, before more of Blackmoore's men show up. We'll make sure Taretha is safe." - TEXT_ID_SKARLOC3 = 9580, - - TEXT_ID_TARREN = 9597, // tarren mill is beyond these trees - GOSSIP_ITEM_TARREN = -3560004, // "We're ready, Thrall." - - TEXT_ID_COMPLETE = 9578, // Thank you friends, I owe my freedom to you. Where is Taretha? I hoped to see her + NPC_INFINITE_DEFILER = 18171, + NPC_INFINITE_SABOTEOR = 18172, + NPC_INFINITE_SLAYER = 18170, }; -const float SPEED_WALK = 0.5f; -const float SPEED_RUN = 1.0f; -const float SPEED_MOUNT = 1.6f; +static const DialogueEntry aThrallDialogue[] = +{ + {SAY_LOOKOUT_BARN_1, NPC_TARREN_MILL_LOOKOUT, 5000}, + {SAY_PROTECTOR_BARN_2, NPC_TARREN_MILL_PROTECTOR, 3000}, + {NPC_YOUNG_BLANCHY, 0, 4000}, + {EMOTE_TH_CALM_HORSE, NPC_THRALL, 1000}, + {SAY_PROTECTOR_BARN_3, NPC_TARREN_MILL_LOOKOUT, 0}, + {NPC_EPOCH, 0, 8000}, + {SAY_TH_EPOCH_WONDER, NPC_THRALL, 4000}, + {SAY_EPOCH_ENTER2, NPC_EPOCH, 4000}, + {SAY_TH_EPOCH_KILL_TARETHA, NPC_THRALL, 2000}, + {NPC_THRALL, 0, 0}, + {0, 0, 0}, +}; -struct MANGOS_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI +struct npc_thrall_old_hillsbradAI : public npc_escortAI, private DialogueHelper { - npc_thrall_old_hillsbradAI(Creature* pCreature) : npc_escortAI(pCreature) + npc_thrall_old_hillsbradAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aThrallDialogue) { m_pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData(); - m_bHadMount = false; + InitializeDialogueHelper(m_pInstance); pCreature->SetActiveObjectState(true); // required for proper relocation + m_bHadMount = false; Reset(); } @@ -258,28 +247,181 @@ struct MANGOS_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI bool m_bIsLowHp; bool m_bHadMount; + bool m_bHasChurchYelled; + bool m_bHasInnYelled; + bool m_bHasEpochYelled; - void Reset() + uint8 m_uiEpochWaveId; + + uint32 m_uiStrikeTimer; + uint32 m_uiShieldBlockTimer; + uint32 m_uiEpochAttackTimer; + + ObjectGuid m_skarlocMountGuid; + + GuidList m_lSkarlocAddsGuids; + GuidList m_lTarrenMillSoldiersGuids; + + void Reset() override { - m_bIsLowHp = false; + m_bIsLowHp = false; + m_uiStrikeTimer = urand(3000, 7000); + m_uiShieldBlockTimer = urand(6000, 11000); if (m_bHadMount) - DoMount(); + m_creature->Mount(MODEL_SKARLOC_MOUNT); if (!HasEscortState(STATE_ESCORT_ESCORTING)) { - DoUnmount(); - m_bHadMount = false; + m_bHadMount = false; + m_bHasChurchYelled = false; + m_bHasEpochYelled = false; + + m_uiEpochWaveId = 0; + m_uiEpochAttackTimer = 0; + + m_creature->Unmount(); SetEquipmentSlots(true); m_creature->SetDisplayId(MODEL_THRALL_UNEQUIPPED); } } - void EnterEvadeMode() + void Aggro(Unit* /*pWho*/) override + { + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_TH_RANDOM_AGGRO1, m_creature); break; + case 1: DoScriptText(SAY_TH_RANDOM_AGGRO2, m_creature); break; + case 2: DoScriptText(SAY_TH_RANDOM_AGGRO3, m_creature); break; + case 3: DoScriptText(SAY_TH_RANDOM_AGGRO4, m_creature); break; + } + + if (m_creature->IsMounted()) + { + m_creature->Unmount(); + m_bHadMount = true; + } + } + + void KilledUnit(Unit* /*pVictim*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_TH_RANDOM_KILL1, m_creature); break; + case 1: DoScriptText(SAY_TH_RANDOM_KILL2, m_creature); break; + case 2: DoScriptText(SAY_TH_RANDOM_KILL3, m_creature); break; + } + } + + void JustDied(Unit* /*pKiller*/) override + { + // fail, and relocation handled in instance script + if (m_pInstance) + m_pInstance->SetData(TYPE_THRALL_EVENT, FAIL); + + DoScriptText(urand(0, 1) ? SAY_TH_RANDOM_DIE1 : SAY_TH_RANDOM_DIE2, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_EROZION_IMAGE, CAST_TRIGGERED); + + // despawn the summons which won't self despawn + for (GuidList::const_iterator itr = m_lSkarlocAddsGuids.begin(); itr != m_lSkarlocAddsGuids.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->ForcedDespawn(); + } + for (GuidList::const_iterator itr = m_lTarrenMillSoldiersGuids.begin(); itr != m_lTarrenMillSoldiersGuids.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->ForcedDespawn(); + } + } + + void CorpseRemoved(uint32& uiRespawnDelay) override + { + uiRespawnDelay = 0; + + // if we're done, just set some high so he never really respawn + if (m_pInstance && (m_pInstance->GetData(TYPE_THRALL_EVENT) == DONE || m_pInstance->GetData(TYPE_THRALL_EVENT) == FAIL)) + uiRespawnDelay = 12 * HOUR; + } + + void JustRespawned() override + { + npc_escortAI::JustRespawned(); + + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS) + { + Start(true); + SetEscortPaused(true); + + m_bHadMount = false; + m_creature->Unmount(); + + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + // check current states before fail and set spesific for the part + if (m_pInstance->GetData(TYPE_SKARLOC) != DONE) + { + SetCurrentWaypoint(1); // basement + + SetEquipmentSlots(true); + m_creature->SetDisplayId(MODEL_THRALL_UNEQUIPPED); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_lSkarlocAddsGuids.clear(); + + // reset prison door + m_pInstance->DoUseDoorOrButton(GO_PRISON_DOOR); + // respawn the Armorer + if (Creature* pArmorer = m_pInstance->GetSingleCreatureFromStorage(NPC_ARMORER)) + pArmorer->Respawn(); + // despwn the horse + if (Creature* pHorse = m_creature->GetMap()->GetCreature(m_skarlocMountGuid)) + pHorse->ForcedDespawn(); + } + else if (m_pInstance->GetData(TYPE_ESCORT_BARN) != DONE) + { + SetCurrentWaypoint(35); // keep + + m_creature->SetDisplayId(MODEL_THRALL_EQUIPPED); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + // resummon the mount + m_creature->SummonCreature(NPC_SKARLOC_MOUNT, 2047.775f, 253.4088f, 62.91183f, 5.37f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + else if (m_pInstance->GetData(TYPE_ESCORT_INN) != DONE) + { + SetCurrentWaypoint(67); // barn + m_lTarrenMillSoldiersGuids.clear(); + + m_creature->SetDisplayId(MODEL_THRALL_EQUIPPED); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + else if (m_pInstance->GetData(TYPE_EPOCH) != DONE) + { + SetCurrentWaypoint(108); // inn + m_creature->SetDisplayId(MODEL_THRALL_EQUIPPED); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_lTarrenMillSoldiersGuids.clear(); + m_uiEpochWaveId = 0; + + // Reset Taretha + if (Creature* pTaretha = m_pInstance->GetSingleCreatureFromStorage(NPC_TARETHA)) + { + pTaretha->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pTaretha->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTaretha->SetStandState(UNIT_STAND_STATE_STAND); + } + } + } + } + + void EnterEvadeMode() override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_TH_LEAVE_COMBAT1, m_creature); break; case 1: DoScriptText(SAY_TH_LEAVE_COMBAT2, m_creature); break; @@ -290,311 +432,568 @@ struct MANGOS_DLL_DECL npc_thrall_old_hillsbradAI : public npc_escortAI npc_escortAI::EnterEvadeMode(); } - void WaypointReached(uint32 uiPoint) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + // Barn soldiers - also used for the first wave of Epoch adds + case NPC_TARREN_MILL_GUARDSMAN: + case NPC_TARREN_MILL_PROTECTOR: + case NPC_TARREN_MILL_LOOKOUT: + m_lTarrenMillSoldiersGuids.push_back(pSummoned->GetObjectGuid()); + // For the summons corresponding to the Epoch event, handle movement + if (m_pInstance && m_pInstance->GetData(TYPE_ESCORT_INN) == DONE) + { + pSummoned->GetMotionMaster()->MovePoint(1, pSummoned->GetPositionX(), pSummoned->GetPositionY() - 10.0f, pSummoned->GetPositionZ()); + + // Transform on timer + if (!m_uiEpochAttackTimer) + m_uiEpochAttackTimer = 7000; + } + break; + // Epoch wave spawns + case NPC_INFINITE_DEFILER: + case NPC_INFINITE_SABOTEOR: + case NPC_INFINITE_SLAYER: + m_lTarrenMillSoldiersGuids.push_back(pSummoned->GetObjectGuid()); + pSummoned->AI()->AttackStart(m_creature); + if (!m_bHasEpochYelled) + { + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_1, pSummoned); break; + case 1: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_2, pSummoned); break; + case 2: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_3, pSummoned); break; + case 3: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_4, pSummoned); break; + } + m_bHasEpochYelled = true; + } + break; + case NPC_SKARLOC_MOUNT: + m_skarlocMountGuid = pSummoned->GetObjectGuid(); + break; + // Church solider - used to yell + case NPC_CHURCH_LOOKOUT: + if (!m_bHasChurchYelled) + { + DoScriptText(SAY_LOOKOUT_CHURCH, pSummoned); + m_bHasChurchYelled = true; + } + pSummoned->AI()->AttackStart(m_creature); + break; + // Inn soldier - used to yell + case NPC_INN_LOOKOUT: + if (!m_bHasInnYelled) + { + DoScriptText(SAY_LOOKOUT_INN, pSummoned); + m_bHasInnYelled = true; + } + pSummoned->AI()->AttackStart(m_creature); + break; + // Spawned when Thrall is dead + case NPC_IMAGE_OF_ERONZION: + if (m_pInstance) + DoScriptText(m_pInstance->GetThrallEventCount() < MAX_WIPE_COUNTER ? SAY_ERONZION_RESET_THRALL : SAY_ERONZION_RESET_LAST, pSummoned); + pSummoned->CastSpell(pSummoned, SPELL_SPAWN_EROZION_IMAGE, false); + pSummoned->ForcedDespawn(30000); + break; + case NPC_SKARLOC: + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, 2050.029f, 249.9696f, 63.0313f); + break; + case NPC_EPOCH: + pSummoned->SetLevitate(true); + DoScriptText(SAY_EPOCH_ENTER1, pSummoned); + break; + // Skarloc helpers - they have special behavior + case NPC_WARDEN: + case NPC_VETERAN: + if (m_pInstance && m_pInstance->GetData(TYPE_SKARLOC) == IN_PROGRESS) + { + // Allow these to follow Skarloc and attack only on command + if (Creature* pSkarloc = m_pInstance->GetSingleCreatureFromStorage(NPC_SKARLOC)) + pSummoned->GetMotionMaster()->MoveFollow(pSkarloc, 5.0f, pSummoned->GetAngle(pSkarloc) + M_PI_F); + + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_lSkarlocAddsGuids.push_back(pSummoned->GetObjectGuid()); + } + else + pSummoned->AI()->AttackStart(m_creature); + break; + default: + pSummoned->AI()->AttackStart(m_creature); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_EPOCH: + DoHandleQuestCredit(); + SetEscortPaused(false); + break; + case NPC_SKARLOC: + SetEscortPaused(false); + break; + case NPC_TARREN_MILL_PROTECTOR: + case NPC_TARREN_MILL_LOOKOUT: + case NPC_TARREN_MILL_GUARDSMAN: + // continue escort when all the barn soldiers are dead + m_lTarrenMillSoldiersGuids.remove(pSummoned->GetObjectGuid()); + if (m_lTarrenMillSoldiersGuids.empty()) + { + SetRun(); + SetEscortPaused(false); + } + break; + case NPC_INFINITE_DEFILER: + case NPC_INFINITE_SABOTEOR: + case NPC_INFINITE_SLAYER: + // Handle Epoch event waves - spawn another when the previous is dead + m_lTarrenMillSoldiersGuids.remove(pSummoned->GetObjectGuid()); + if (m_lTarrenMillSoldiersGuids.empty()) + { + m_lTarrenMillSoldiersGuids.clear(); + m_bHasEpochYelled = false; + switch (m_uiEpochWaveId) + { + case 1: + m_creature->SummonCreature(NPC_INFINITE_DEFILER, 2595.477f, 684.3738f, 55.95534f, 6.05f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_SABOTEOR, 2602.208f, 678.2955f, 56.34682f, 6.07f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_SLAYER, 2602.8f, 686.2845f, 55.79315f, 5.95f, TEMPSUMMON_DEAD_DESPAWN, 0); + ++m_uiEpochWaveId; + break; + case 2: + m_creature->SummonCreature(NPC_INFINITE_DEFILER, 2646.289f, 718.5257f, 57.90024f, 4.32f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_SABOTEOR, 2641.788f, 719.7106f, 57.4023f, 4.46f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_SLAYER, 2645.725f, 709.7153f, 56.69411f, 4.38f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_INFINITE_SLAYER, 2639.641f, 710.5246f, 56.23582f, 4.60f, TEMPSUMMON_DEAD_DESPAWN, 0); + ++m_uiEpochWaveId; + break; + case 3: + if (m_pInstance) + { + if (Creature* pEpoch = m_pInstance->GetSingleCreatureFromStorage(NPC_EPOCH)) + { + pEpoch->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pEpoch->AI()->AttackStart(m_creature); + AttackStart(pEpoch); + } + } + break; + } + } + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + switch (pSummoned->GetEntry()) + { + // Handle Skarloc movement for the intro part + case NPC_SKARLOC: + switch (uiPointId) + { + case 1: + // summon mount + pSummoned->Unmount(); + m_creature->SummonCreature(NPC_SKARLOC_MOUNT, 2047.775f, 253.4088f, 62.91183f, 5.37f, TEMPSUMMON_DEAD_DESPAWN, 0); + pSummoned->SetWalk(true); + pSummoned->GetMotionMaster()->MovePoint(2, 2059.899f, 234.2593f, 64.10809f); + break; + case 2: + // taunt Thrall + DoScriptText(SAY_SKARLOC_ENTER, pSummoned); + SetEscortPaused(false); + break; + } + break; + // Handle infinite dragons transform on point reaches + case NPC_TARREN_MILL_GUARDSMAN: + if (uiPointId) + { + pSummoned->CastSpell(pSummoned, SPELL_TRANSFORM, false); + pSummoned->UpdateEntry(NPC_INFINITE_SLAYER); + } + break; + case NPC_TARREN_MILL_PROTECTOR: + if (uiPointId) + { + pSummoned->CastSpell(pSummoned, SPELL_TRANSFORM, false); + pSummoned->UpdateEntry(NPC_INFINITE_SABOTEOR); + } + break; + case NPC_TARREN_MILL_LOOKOUT: + if (uiPointId) + { + pSummoned->CastSpell(pSummoned, SPELL_TRANSFORM, false); + pSummoned->UpdateEntry(NPC_INFINITE_DEFILER); + } + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case NPC_YOUNG_BLANCHY: + // ToDo: deal with the horse animation! + break; + case EMOTE_TH_CALM_HORSE: + if (Creature* pHorse = m_pInstance->GetSingleCreatureFromStorage(NPC_YOUNG_BLANCHY)) + m_creature->SetFacingToObject(pHorse); + break; + case SAY_PROTECTOR_BARN_3: + // Move the soldiers inside + float fX, fY, fZ; + for (GuidList::const_iterator itr = m_lTarrenMillSoldiersGuids.begin(); itr != m_lTarrenMillSoldiersGuids.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + pTemp->SetWalk(false); + pTemp->GetRandomPoint(2480.19f, 696.15f, 55.78f, 5.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + break; + case SAY_TH_EPOCH_WONDER: + m_creature->SetFacingTo(2.69f); + break; + case SAY_EPOCH_ENTER2: + if (Creature* pTaretha = m_pInstance->GetSingleCreatureFromStorage(NPC_TARETHA)) + { + pTaretha->CastSpell(pTaretha, SPELL_SHADOW_SPIKE, true); + pTaretha->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTaretha->SetStandState(UNIT_STAND_STATE_DEAD); + } + break; + case SAY_TH_EPOCH_KILL_TARETHA: + if (Creature* pTaretha = m_pInstance->GetSingleCreatureFromStorage(NPC_TARETHA)) + m_creature->SetFacingToObject(pTaretha); + break; + case NPC_THRALL: + SetRun(); + SetEscortPaused(false); + break; + } + } + + void WaypointReached(uint32 uiPoint) override { if (!m_pInstance) return; - switch(uiPoint) + switch (uiPoint) { + // *** Escort event - Part I - inside the keep *** + case 0: + m_pInstance->DoUseDoorOrButton(GO_PRISON_DOOR); + break; case 8: - SetRun(false); - m_creature->SummonCreature(NPC_ARMORER, 2181.87f, 112.46f, 89.45f, 0.26f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,5000); + if (Creature* pArmorer = m_pInstance->GetSingleCreatureFromStorage(NPC_ARMORER)) + { + DoScriptText(SAY_ARMORER_CALL_GUARDS, pArmorer); + pArmorer->SetFacingToObject(m_creature); + } break; case 9: - DoScriptText(SAY_TH_ARMORY, m_creature); - SetEquipmentSlots(false, EQUIP_ID_WEAPON, EQUIP_ID_SHIELD, EQUIP_NO_CHANGE); + DoScriptText(SAY_TH_KILL_ARMORER, m_creature); + DoCastSpellIfCan(m_creature, SPELL_KNOCKOUT_ARMORER); + // also kill the armorer + if (Creature* pArmorer = m_pInstance->GetSingleCreatureFromStorage(NPC_ARMORER)) + pArmorer->DealDamage(pArmorer, pArmorer->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); break; case 10: + DoScriptText(SAY_TH_ARMORY_1, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); m_creature->SetDisplayId(MODEL_THRALL_EQUIPPED); + SetEquipmentSlots(false, EQUIP_ID_WEAPON, EQUIP_ID_SHIELD, EQUIP_NO_CHANGE); break; case 11: - SetRun(); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + break; + case 12: + if (Creature* pArmorer = m_pInstance->GetSingleCreatureFromStorage(NPC_ARMORER)) + m_creature->SetFacingToObject(pArmorer); + DoScriptText(SAY_TH_ARMORY_2, m_creature); break; - case 15: - m_creature->SummonCreature(NPC_RIFLE, 2200.28f, 137.37f, 87.93f, 5.07f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_WARDEN, 2197.44f, 131.83f, 87.93f, 0.78f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_VETERAN, 2203.62f, 135.40f, 87.93f, 3.70f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_VETERAN, 2200.75f, 130.13f, 87.93f, 1.48f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + // *** Escort event - Part I - outside the keep *** + case 17: + m_creature->SummonCreature(NPC_MAGE, 2186.909f, 139.8108f, 88.21628f, 5.75f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_WARDEN, 2187.943f, 141.6124f, 88.21628f, 5.73f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_VETERAN, 2190.508f, 140.4597f, 88.21628f, 6.04f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_VETERAN, 2189.543f, 139.0996f, 88.23965f, 0.21f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); break; - case 21: - m_creature->SummonCreature(NPC_RIFLE, 2135.80f, 154.01f, 67.45f, 4.98f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_WARDEN, 2144.36f, 151.87f, 67.74f, 4.46f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_VETERAN, 2142.12f, 154.41f, 67.12f, 4.56f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_VETERAN, 2138.08f, 155.38f, 67.24f, 4.60f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + case 20: + m_creature->SummonCreature(NPC_MAGE, 2149.463f, 104.9756f, 73.63239f, 1.71f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_SENTRY, 2147.642f, 105.0251f, 73.99422f, 1.52f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_VETERAN, 2149.212f, 107.2005f, 74.15676f, 1.71f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_WARDEN, 2147.328f, 106.7235f, 74.34447f, 1.69f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + break; + case 23: + m_creature->SummonCreature(NPC_MAGE, 2142.363f, 172.4260f, 66.30494f, 2.54f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_SENTRY, 2138.177f, 168.6046f, 66.30494f, 2.47f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_SENTRY, 2142.372f, 174.2907f, 66.30494f, 2.56f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_VETERAN, 2140.146f, 169.2364f, 66.30494f, 2.49f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); break; case 25: - m_creature->SummonCreature(NPC_RIFLE, 2102.98f, 192.17f, 65.24f, 6.02f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_WARDEN, 2108.48f, 198.75f, 65.18f, 5.15f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_VETERAN, 2106.11f, 197.29f, 65.18f, 5.63f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_VETERAN, 2104.18f, 194.82f, 65.18f, 5.75f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + m_creature->SummonCreature(NPC_MAGE, 2107.938f, 192.0753f, 66.30494f, 2.54f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_MAGE, 2109.852f, 195.1403f, 66.30493f, 2.42f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_VETERAN, 2108.486f, 189.9346f, 66.30494f, 2.68f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_VETERAN, 2112.387f, 195.4947f, 66.30494f, 2.39f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); break; - case 29: + // *** Escort event - Part I - meet Skarloc *** + case 31: + m_pInstance->SetData(TYPE_SKARLOC, IN_PROGRESS); + m_creature->SummonCreature(NPC_SKARLOC, 2000.201f, 277.9190f, 66.4911f, 6.11f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_VETERAN, 1997.969f, 274.4247f, 66.6181f, 5.67f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_WARDEN, 2000.002f, 282.0754f, 66.2986f, 6.02f, TEMPSUMMON_DEAD_DESPAWN, 0); DoScriptText(SAY_TH_SKARLOC_MEET, m_creature); - m_creature->SummonCreature(NPC_SCARLOC, 2036.48f, 271.22f, 63.43f, 5.27f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + SetEscortPaused(true); + break; + case 33: + // Allow the guards and Skarloc to attack + if (Creature* pSkarloc = m_pInstance->GetSingleCreatureFromStorage(NPC_SKARLOC)) + { + pSkarloc->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pSkarloc->AI()->AttackStart(m_creature); + AttackStart(pSkarloc); + } + for (GuidList::const_iterator itr = m_lSkarlocAddsGuids.begin(); itr != m_lSkarlocAddsGuids.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->AI()->AttackStart(m_creature); + } + } break; - case 30: + case 34: + // wait for player input + if (Creature* pMount = m_creature->GetMap()->GetCreature(m_skarlocMountGuid)) + m_creature->SetFacingToObject(pMount); + SetEscortPaused(true); m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - SetRun(false); break; - case 31: - DoScriptText(SAY_TH_MOUNTS_UP, m_creature); - DoMount(); - SetRun(); + // *** Escort event - Part II - road *** + case 35: + if (Creature* pMount = m_creature->GetMap()->GetCreature(m_skarlocMountGuid)) + { + m_creature->SetFacingToObject(pMount); + pMount->ForcedDespawn(4000); + } break; - case 37: - // possibly regular patrollers? If so, remove this and let database handle them - m_creature->SummonCreature(NPC_WATCHMAN, 2124.26f, 522.16f, 56.87f, 3.99f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_WATCHMAN, 2121.69f, 525.37f, 57.11f, 4.01f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_SENTRY, 2124.65f, 524.55f, 56.63f, 3.98f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + case 36: + DoScriptText(SAY_TH_MOUNTS_UP, m_creature); + m_creature->SetFacingTo(5.33f); + m_creature->Mount(MODEL_SKARLOC_MOUNT); break; - case 59: - m_creature->SummonCreature(NPC_SKARLOC_MOUNT, 2488.64f, 625.77f, 58.26f, 4.71f, TEMPSUMMON_TIMED_DESPAWN, 10000); - DoUnmount(); + // *** Escort event - Part II - reached barn *** + case 64: + m_creature->SummonCreature(NPC_SKARLOC_MOUNT, 2488.779f, 623.9724f, 58.07383f, 1.37f, TEMPSUMMON_TIMED_DESPAWN, 30000); + m_creature->Unmount(); m_bHadMount = false; - SetRun(false); break; - case 60: - m_creature->HandleEmote(EMOTE_ONESHOT_EXCLAMATION); - // make horsie run off + case 65: + if (Creature* pMount = m_creature->GetMap()->GetCreature(m_skarlocMountGuid)) + m_creature->SetFacingToObject(pMount); + DoScriptText(EMOTE_TH_STARTLE_HORSE, m_creature); + break; + case 66: + if (Creature* pMount = m_creature->GetMap()->GetCreature(m_skarlocMountGuid)) + { + pMount->SetWalk(false); + pMount->GetMotionMaster()->MovePoint(0, 2517.504f, 506.253f, 42.329f); + } + m_creature->SetFacingTo(4.66f); + // wait for player input SetEscortPaused(true); m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_pInstance->SetData(TYPE_THRALL_PART2, DONE); - SetRun(); + m_pInstance->SetData(TYPE_ESCORT_BARN, DONE); break; - case 64: + // *** Escort event - Part III - barn *** + case 70: SetRun(false); break; - case 68: - m_creature->SummonCreature(NPC_BARN_PROTECTOR, 2500.22f, 692.60f, 55.50f, 2.84f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_BARN_LOOKOUT, 2500.13f, 696.55f, 55.51f, 3.38f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_BARN_GUARDSMAN, 2500.55f, 693.64f, 55.50f, 3.14f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_BARN_GUARDSMAN, 2500.94f, 695.81f, 55.50f, 3.14f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + case 73: + m_creature->SummonCreature(NPC_TARREN_MILL_PROTECTOR, 2500.22f, 692.60f, 55.50f, 2.84f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_TARREN_MILL_LOOKOUT, 2500.13f, 696.55f, 55.51f, 3.38f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_TARREN_MILL_GUARDSMAN, 2500.55f, 693.64f, 55.50f, 3.14f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_TARREN_MILL_GUARDSMAN, 2500.94f, 695.81f, 55.50f, 3.14f, TEMPSUMMON_DEAD_DESPAWN, 0); break; - case 71: - SetRun(); + // *** Escort event - Part III - start barn dialogue *** + case 74: + StartNextDialogueText(SAY_LOOKOUT_BARN_1); + SetEscortPaused(true); break; - case 81: - SetRun(false); + case 75: + DoScriptText(SAY_TH_HEAD_TOWN, m_creature); break; - case 83: - m_creature->SummonCreature(NPC_CHURCH_PROTECTOR, 2627.33f, 646.82f, 56.03f, 4.28f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); - m_creature->SummonCreature(NPC_CHURCH_LOOKOUT, 2624.14f, 648.03f, 56.03f, 4.50f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); - m_creature->SummonCreature(NPC_CHURCH_GUARDSMAN, 2625.32f, 649.60f, 56.03f, 4.38f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); - m_creature->SummonCreature(NPC_CHURCH_GUARDSMAN, 2627.22f, 649.00f, 56.03f, 4.34f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 5000); + // *** Escort event - Part III - church *** + case 92: + DoScriptText(SAY_TH_CHURCH_ENTER, m_creature); + m_creature->SetFacingTo(1.0f); + break; + case 93: + m_creature->SummonCreature(NPC_CHURCH_PROTECTOR, 2627.88f, 657.63f, 55.98f, 4.28f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 5000); + m_creature->SummonCreature(NPC_CHURCH_LOOKOUT, 2627.27f, 655.17f, 56.03f, 4.50f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 5000); + m_creature->SummonCreature(NPC_CHURCH_LOOKOUT, 2629.21f, 654.81f, 56.04f, 4.38f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 5000); + m_creature->SummonCreature(NPC_CHURCH_GUARDSMAN, 2629.98f, 656.96f, 55.96f, 4.34f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 5000); break; - case 84: + case 94: DoScriptText(SAY_TH_CHURCH_END, m_creature); - SetRun(); break; - case 91: + // *** Escort event - Part III - inside the inn *** + case 105: + m_creature->SummonCreature(NPC_INN_PROTECTOR, 2652.71f, 660.31f, 61.93f, 1.67f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_INN_LOOKOUT, 2648.96f, 662.59f, 61.93f, 0.79f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_INN_LOOKOUT, 2657.36f, 662.34f, 61.93f, 2.68f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + m_creature->SummonCreature(NPC_INN_GUARDSMAN, 2656.39f, 659.77f, 61.93f, 2.61f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); SetRun(false); break; - case 93: - m_creature->SummonCreature(NPC_INN_PROTECTOR, 2652.71f, 660.31f, 61.93f, 1.67f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_INN_LOOKOUT, 2648.96f, 662.59f, 61.93f, 0.79f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_INN_GUARDSMAN, 2657.36f, 662.34f, 61.93f, 2.68f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - m_creature->SummonCreature(NPC_INN_GUARDSMAN, 2656.39f, 659.77f, 61.93f, 2.61f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - break; - case 94: - if (Creature* pTaretha = m_pInstance->GetTaretha()) + // *** Escort event - Part III - meet Taretha *** + case 106: + if (Creature* pTaretha = m_pInstance->GetSingleCreatureFromStorage(NPC_TARETHA)) DoScriptText(SAY_TA_ESCAPED, pTaretha, m_creature); - break; - case 95: + case 107: + // wait for player input DoScriptText(SAY_TH_MEET_TARETHA, m_creature); - m_pInstance->SetData(TYPE_THRALL_PART3, DONE); + m_pInstance->SetData(TYPE_ESCORT_INN, DONE); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + if (Creature* pTaretha = m_pInstance->GetSingleCreatureFromStorage(NPC_TARETHA)) + pTaretha->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); SetEscortPaused(true); break; - case 96: - DoScriptText(SAY_TH_EPOCH_WONDER, m_creature); - break; - case 97: - DoScriptText(SAY_TH_EPOCH_KILL_TARETHA, m_creature); - SetRun(); + // *** Escort event - Part IV - Epoch *** + case 108: + m_creature->SummonCreature(NPC_EPOCH, 2639.92f, 700.2587f, 65.13583f, 4.74f, TEMPSUMMON_DEAD_DESPAWN, 0); + StartNextDialogueText(NPC_EPOCH); + SetEscortPaused(true); break; - case 104: - if (Creature* pEpoch = m_pInstance->GetEpoch()) + // *** Escort event - Part IV - Epoch - begin fight *** + case 116: + if (Creature* pEpoch = m_pInstance->GetSingleCreatureFromStorage(NPC_EPOCH)) + { DoScriptText(SAY_EPOCH_ENTER3, pEpoch); - + m_creature->SetFacingToObject(pEpoch); + } break; - case 105: // outside inn, meeting the dragon + case 117: + // begin fight + m_lTarrenMillSoldiersGuids.clear(); + m_creature->SummonCreature(NPC_TARREN_MILL_GUARDSMAN, 2630.318f, 704.3388f, 56.33701f, 4.73f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_TARREN_MILL_LOOKOUT, 2639.1f, 707.3839f, 56.14664f, 4.49f, TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_TARREN_MILL_PROTECTOR, 2653.135f, 698.6548f, 57.56876f, 3.17f, TEMPSUMMON_DEAD_DESPAWN, 0); + ++m_uiEpochWaveId; SetEscortPaused(true); - - if (Creature* pEpoch = m_pInstance->GetEpoch()) - m_creature->SetFacingToObject(pEpoch); - break; - case 106: // epoch is dead, proceeding with cheering - { - // trigger taretha to run down outside - if (Creature* pTaretha = m_pInstance->GetTaretha()) - { - if (npc_tarethaAI* pTarethaAI = dynamic_cast(pTaretha->AI())) - pTarethaAI->Start(true, GetPlayerForEscort()); - } - - // kill credit creature for quest - Map::PlayerList const& lPlayerList = m_pInstance->instance->GetPlayers(); - - if (!lPlayerList.isEmpty()) - { - for(Map::PlayerList::const_iterator itr = lPlayerList.begin(); itr != lPlayerList.end(); ++itr) - { - if (Player* pPlayer = itr->getSource()) - pPlayer->KilledMonsterCredit(NPC_THRALL_QUEST_TRIGGER, m_creature->GetObjectGuid()); - } - } - - // a lot will happen here, thrall and taretha talk, erozion appear at spot to explain - // handled by taretha script + // *** Escort event - Epilogue - run off *** + case 118: + // return to position SetEscortPaused(true); break; - } - case 107: + case 120: m_creature->SetActiveObjectState(false); break; } } - void WaypointStart(uint32 uiPointId) - { - if (!m_pInstance) - return; - - if (uiPointId == 97) - { - if (Creature* pEpoch = m_pInstance->GetEpoch()) - DoScriptText(SAY_EPOCH_ENTER2, pEpoch); - } - } - - void StartWP() + // Wrapper to restart escort + void DoRestartEscortMovement() { m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); SetEscortPaused(false); } - void DoMount() - { - m_creature->Mount(MODEL_SKARLOC_MOUNT); - m_creature->SetSpeedRate(MOVE_RUN, SPEED_MOUNT); - } - - void DoUnmount() - { - m_creature->Unmount(); - m_creature->SetSpeedRate(MOVE_RUN, SPEED_RUN); - } - - void Aggro(Unit* pWho) + // Complete the quest for escorting + void DoHandleQuestCredit() { - switch(urand(0, 3)) - { - case 0: DoScriptText(SAY_TH_RANDOM_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_TH_RANDOM_AGGRO2, m_creature); break; - case 2: DoScriptText(SAY_TH_RANDOM_AGGRO3, m_creature); break; - case 3: DoScriptText(SAY_TH_RANDOM_AGGRO4, m_creature); break; - } + Map::PlayerList const& lPlayerList = m_pInstance->instance->GetPlayers(); - if (m_creature->IsMounted()) + if (!lPlayerList.isEmpty()) { - DoUnmount(); - m_bHadMount = true; + for (Map::PlayerList::const_iterator itr = lPlayerList.begin(); itr != lPlayerList.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->KilledMonsterCredit(NPC_THRALL_QUEST_TRIGGER, m_creature->GetObjectGuid()); + } } } - void JustSummoned(Creature* pSummoned) + // Wrapper to make the dragons attack + void DoStartDragonsAttack() { - switch(pSummoned->GetEntry()) + for (GuidList::const_iterator itr = m_lTarrenMillSoldiersGuids.begin(); itr != m_lTarrenMillSoldiersGuids.end(); ++itr) { - // TODO: make Scarloc start into event instead, and not start attack directly - case NPC_BARN_GUARDSMAN: - case NPC_BARN_PROTECTOR: - case NPC_BARN_LOOKOUT: - case NPC_SKARLOC_MOUNT: - break; - default: - pSummoned->AI()->AttackStart(m_creature); - break; - } - } + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + { + // Only one will yell aggro + if (!m_bHasEpochYelled) + { + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_1, pTemp); break; + case 1: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_2, pTemp); break; + case 2: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_3, pTemp); break; + case 3: DoScriptText(SAY_INFINITE_DRAGON_AGGRO_4, pTemp); break; + } + m_bHasEpochYelled = true; + } - void KilledUnit(Unit* pVictim) - { - switch(urand(0, 2)) - { - case 0: DoScriptText(SAY_TH_RANDOM_KILL1, m_creature); break; - case 1: DoScriptText(SAY_TH_RANDOM_KILL2, m_creature); break; - case 2: DoScriptText(SAY_TH_RANDOM_KILL3, m_creature); break; + // Attack Thrall + pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pTemp->AI()->AttackStart(m_creature); + } } - - // Death called from instance script (or if he has the killing blow of course) - // Thrall should normally always be the one killing, but no support for this yet. - if (pVictim->GetEntry() == NPC_EPOCH) - SetEscortPaused(false); - } - - void JustDied(Unit* pKiller) - { - DoScriptText(urand(0, 1) ? SAY_TH_RANDOM_DIE1 : SAY_TH_RANDOM_DIE2, m_creature); } - void CorpseRemoved(uint32 &uiRespawnDelay) + void UpdateEscortAI(const uint32 uiDiff) override { - uiRespawnDelay = 0; + DialogueUpdate(uiDiff); - // if we're done, just set some high so he never really respawn - if (m_pInstance && m_pInstance->GetData(TYPE_THRALL_EVENT) == DONE) - uiRespawnDelay = 4 * HOUR; - } - - void JustRespawned() - { - if (!m_pInstance) - return; - - Reset(); - - if (m_pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS) + // Handle soldiers tranform to Infinite dragons + if (m_uiEpochAttackTimer) { - SetEscortPaused(true); - - m_bHadMount = false; - DoUnmount(); - - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - - // check current states before fail and set spesific for the part - if (m_pInstance->GetData(TYPE_THRALL_PART1) == IN_PROGRESS) - { - SetCurrentWaypoint(1); // basement - - SetEquipmentSlots(true); - m_creature->SetDisplayId(MODEL_THRALL_UNEQUIPPED); - - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } - else if (m_pInstance->GetData(TYPE_THRALL_PART2) == IN_PROGRESS) + if (m_uiEpochAttackTimer <= uiDiff) { - SetCurrentWaypoint(61); // barn - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + DoStartDragonsAttack(); + m_uiEpochAttackTimer = 0; } - else if (m_pInstance->GetData(TYPE_THRALL_PART3) == IN_PROGRESS || m_pInstance->GetData(TYPE_THRALL_PART4) == IN_PROGRESS) - SetCurrentWaypoint(96); // inn - - // fail, and relocation handled in instance script - m_pInstance->SetData(TYPE_THRALL_EVENT, FAIL); + else + m_uiEpochAttackTimer -= uiDiff; } - } - void UpdateEscortAI(const uint32 uiDiff) - { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // TODO: add his abilities'n-crap here + if (m_uiStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRIKE) == CAST_OK) + m_uiStrikeTimer = urand(4000, 7000); + } + else + m_uiStrikeTimer -= uiDiff; + + if (m_uiShieldBlockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHIELD_BLOCK) == CAST_OK) + m_uiShieldBlockTimer = urand(8000, 15000); + } + else + m_uiShieldBlockTimer -= uiDiff; if (!m_bIsLowHp && m_creature->GetHealthPercent() < 20.0f) { @@ -621,75 +1020,89 @@ bool GossipHello_npc_thrall_old_hillsbrad(Player* pPlayer, Creature* pCreature) if (instance_old_hillsbrad* pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData()) { - if (pInstance->GetData(TYPE_BARREL_DIVERSION) == DONE && !pInstance->GetData(TYPE_THRALL_EVENT)) + // If the inn escort has started, skip the gossip + if (pInstance->GetData(TYPE_ESCORT_INN) == DONE) + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_INN, pCreature->GetObjectGuid()); + // Escort - barn to inn + else if (pInstance->GetData(TYPE_ESCORT_BARN) == DONE) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ID_UNKNOWN_TEXT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_START, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TARREN_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_TARREN, pCreature->GetObjectGuid()); } - - if (pInstance->GetData(TYPE_THRALL_PART1) == DONE && !pInstance->GetData(TYPE_THRALL_PART2)) + // Escort - after Skarloc is defeated + else if (pInstance->GetData(TYPE_SKARLOC) == DONE) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SKARLOC1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SKARLOC1, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SKARLOC_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SKARLOC_1, pCreature->GetObjectGuid()); } - - if (pInstance->GetData(TYPE_THRALL_PART2) == DONE && !pInstance->GetData(TYPE_THRALL_PART3)) + // Event start - after Drake is defeated + else if (pInstance->GetData(TYPE_DRAKE) == DONE) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TARREN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_TARREN, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_START, pCreature->GetObjectGuid()); } } return true; } -bool GossipSelect_npc_thrall_old_hillsbrad(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_thrall_old_hillsbrad(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { instance_old_hillsbrad* pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData(); - switch(uiAction) + switch (uiAction) { + // Event start case GOSSIP_ACTION_INFO_DEF+1: { pPlayer->CLOSE_GOSSIP_MENU(); - pInstance->SetData(TYPE_THRALL_EVENT, IN_PROGRESS); - pInstance->SetData(TYPE_THRALL_PART1, IN_PROGRESS); + DoScriptText(SAY_TH_START_EVENT_PART_1, pCreature); - DoScriptText(SAY_TH_START_EVENT_PART1, pCreature); + if (pInstance) + pInstance->SetData(TYPE_THRALL_EVENT, IN_PROGRESS); if (npc_thrall_old_hillsbradAI* pThrallAI = dynamic_cast(pCreature->AI())) pThrallAI->Start(true, pPlayer); break; } + // Escort - after Skarloc case GOSSIP_ACTION_INFO_DEF+2: { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SKARLOC2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+20); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SKARLOC2, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SKARLOC_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 20); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SKARLOC_2, pCreature->GetObjectGuid()); break; } case GOSSIP_ACTION_INFO_DEF+20: { - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SKARLOC3, pCreature->GetObjectGuid()); - - pCreature->SummonCreature(NPC_SKARLOC_MOUNT, 2038.81f, 270.26f, 63.20f, 5.41f, TEMPSUMMON_TIMED_DESPAWN,12000); - pInstance->SetData(TYPE_THRALL_PART2, IN_PROGRESS); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SKARLOC_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_SKARLOC_3, pCreature->GetObjectGuid()); + break; + } + case GOSSIP_ACTION_INFO_DEF+21: + { + pPlayer->CLOSE_GOSSIP_MENU(); DoScriptText(SAY_TH_START_EVENT_PART2, pCreature); + if (pInstance) + pInstance->SetData(TYPE_ESCORT_BARN, IN_PROGRESS); + if (npc_thrall_old_hillsbradAI* pThrallAI = dynamic_cast(pCreature->AI())) - pThrallAI->StartWP(); + pThrallAI->DoRestartEscortMovement(); break; } + // Escort - barn to inn case GOSSIP_ACTION_INFO_DEF+3: { pPlayer->CLOSE_GOSSIP_MENU(); - pInstance->SetData(TYPE_THRALL_PART3, IN_PROGRESS); + if (pInstance) + pInstance->SetData(TYPE_ESCORT_INN, IN_PROGRESS); if (npc_thrall_old_hillsbradAI* pThrallAI = dynamic_cast(pCreature->AI())) - pThrallAI->StartWP(); + pThrallAI->DoRestartEscortMovement(); break; } @@ -703,110 +1116,155 @@ bool GossipSelect_npc_thrall_old_hillsbrad(Player* pPlayer, Creature* pCreature, enum { - TEXT_ID_EPOCH1 = 9610, // Thank you for helping Thrall escape, friends. Now I only hope - GOSSIP_ITEM_EPOCH1 = -3560005, // "Strange wizard?" - TEXT_ID_EPOCH2 = 9613, // Yes, friends. This man was no wizard of - GOSSIP_ITEM_EPOCH2 = -3560006, // "We'll get you out. Taretha. Don't worry. I doubt the wizard would wander too far away." + // end event texts and spells + SAY_TA_FREE = -1560048, + SAY_TR_GLAD_SAFE = -1560054, + SAY_TA_NEVER_MET = -1560055, + SAY_TR_THEN_WHO = -1560056, + SAY_PRE_WIPE = -1560057, + SAY_WIPE_MEMORY = -1560051, + SAY_ABOUT_TARETHA = -1560052, + SAY_TH_EVENT_COMPLETE = -1560033, + SAY_TA_FAREWELL = -1560053, + SAY_AFTER_WIPE = -1560058, // not sure when to use this one + + GOSSIP_ITEM_EPOCH_1 = -3560005, // "Strange wizard?" + TEXT_ID_EPOCH_1 = 9610, // Thank you for helping Thrall escape, friends. Now I only hope + + GOSSIP_ITEM_EPOCH_2 = -3560006, // "We'll get you out. Taretha. Don't worry. I doubt the wizard would wander too far away." + TEXT_ID_EPOCH_2 = 9613, // Yes, friends. This man was no wizard of + + SPELL_TELEPORT = 7791, + SPELL_MEMORY_WIPE = 33336, // hits Taretha and Thrall + SPELL_MEMORY_WP_RESUME = 33337, + SPELL_SHADOW_PRISON = 33071, // in creature_template_addon - remove from Taretha on event complete }; -npc_tarethaAI::npc_tarethaAI(Creature* pCreature) : npc_escortAI(pCreature) +static const DialogueEntry aTarethaDialogue[] = { - m_pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData(); - m_uiErozionEventTimer = 5000; - m_uiErozionPhase = 0; - Reset(); -} + {SAY_TA_FREE, NPC_TARETHA, 4000}, + {SAY_TR_GLAD_SAFE, NPC_THRALL, 9000}, + {SAY_TA_NEVER_MET, NPC_TARETHA, 3000}, + {SAY_TR_THEN_WHO, NPC_THRALL, 6000}, + {SPELL_MEMORY_WIPE, 0, 3000}, + {SAY_WIPE_MEMORY, NPC_EROZION, 12000}, + {SAY_ABOUT_TARETHA, NPC_EROZION, 6000}, + {SAY_TH_EVENT_COMPLETE, NPC_THRALL, 3000}, + {NPC_THRALL, 0, 2000}, + {SAY_TA_FAREWELL, NPC_TARETHA, 3000}, + {NPC_TARETHA, 0, 0}, + {0, 0, 0}, +}; -void npc_tarethaAI::JustSummoned(Creature* pSummoned) +struct npc_tarethaAI : public npc_escortAI, private DialogueHelper { - if (pSummoned->GetEntry() == NPC_EROZION) - m_erozionGuid = pSummoned->GetObjectGuid(); - else - DoScriptText(SAY_EPOCH_ENTER1, pSummoned); -} + npc_tarethaAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aTarethaDialogue) + { + m_pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } -void npc_tarethaAI::WaypointReached(uint32 uiPoint) -{ - switch(uiPoint) + instance_old_hillsbrad* m_pInstance; + + bool m_bHasStartedEpilogue; + + void Reset() override { - case 6: - DoScriptText(SAY_TA_FREE, m_creature); - break; - case 7: + m_bHasStartedEpilogue = false; + } + + void JustSummoned(Creature* pSummoned) override + { + // Remove flags from the npc - the quest will be handled by the entrance version + if (pSummoned->GetEntry() == NPC_EROZION) + { + DoScriptText(SAY_PRE_WIPE, pSummoned); + pSummoned->CastSpell(pSummoned, SPELL_TELEPORT, false); + pSummoned->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + } + } + + void WaypointReached(uint32 uiPoint) override + { + if (uiPoint == 7) + { + StartNextDialogueText(SAY_TA_FREE); + + if (m_pInstance) + { + if (Creature* pThrall = m_pInstance->GetSingleCreatureFromStorage(NPC_THRALL)) + pThrall->SetFacingToObject(m_creature); + } + m_creature->HandleEmote(EMOTE_ONESHOT_CHEER); - m_creature->SummonCreature(NPC_EROZION, 2646.47f, 680.416f, 55.38f, 4.16f, TEMPSUMMON_TIMED_DESPAWN, 120000); SetEscortPaused(true); SetRun(false); - break; + } } -} - -void npc_tarethaAI::UpdateEscortAI(const uint32 uiDiff) -{ - if (!HasEscortState(STATE_ESCORT_PAUSED)) - return; - if (m_uiErozionEventTimer < uiDiff) + void JustDidDialogueStep(int32 iEntry) override { - ++m_uiErozionPhase; - m_uiErozionEventTimer = 5000; + if (!m_pInstance) + return; - switch(m_uiErozionPhase) + switch (iEntry) { - case 1: - if (Creature* pThrall = m_pInstance->GetThrall()) - { - pThrall->SetFacingToObject(m_creature); - DoScriptText(SAY_TR_GLAD_SAFE, pThrall); - } - break; - case 2: - DoScriptText(SAY_TA_NEVER_MET, m_creature); - break; - case 3: - if (Creature* pThrall = m_pInstance->GetThrall()) - DoScriptText(SAY_TR_THEN_WHO, pThrall); - break; - case 4: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_erozionGuid)) - DoScriptText(SAY_PRE_WIPE, pErozion); - break; - case 5: - //if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_erozionGuid)) - //pErozion->AI()->DoCastSpellIfCan(); - break; - case 6: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_erozionGuid)) - DoScriptText(SAY_WIPE_MEMORY, pErozion); + case SAY_TR_THEN_WHO: + m_creature->SummonCreature(NPC_EROZION, 2646.47f, 680.416f, 55.38f, 4.16f, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS); break; - case 7: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_erozionGuid)) - DoScriptText(SAY_ABOUT_TARETHA, pErozion); + case SPELL_MEMORY_WIPE: + if (Creature* pErozion = m_pInstance->GetSingleCreatureFromStorage(NPC_EROZION)) + pErozion->CastSpell(pErozion, SPELL_MEMORY_WIPE, false); break; - case 8: - if (Creature* pErozion = m_creature->GetMap()->GetCreature(m_erozionGuid)) - DoScriptText(SAY_AFTER_WIPE, pErozion); - break; - case 9: - if (Creature* pThrall = m_pInstance->GetThrall()) - DoScriptText(SAY_TH_EVENT_COMPLETE, pThrall); + case SAY_TH_EVENT_COMPLETE: + if (Creature* pErozion = m_pInstance->GetSingleCreatureFromStorage(NPC_EROZION)) + pErozion->CastSpell(pErozion, SPELL_MEMORY_WP_RESUME, false); + if (Creature* pThrall = m_pInstance->GetSingleCreatureFromStorage(NPC_THRALL)) + pThrall->RemoveAurasDueToSpell(SPELL_MEMORY_WIPE); + m_creature->RemoveAurasDueToSpell(SPELL_MEMORY_WIPE); break; - case 10: - DoScriptText(SAY_TA_FAREWELL, m_creature); - SetEscortPaused(false); - - if (Creature* pThrall = m_pInstance->GetThrall()) + case NPC_THRALL: + if (Creature* pThrall = m_pInstance->GetSingleCreatureFromStorage(NPC_THRALL)) { if (npc_thrall_old_hillsbradAI* pThrallAI = dynamic_cast(pThrall->AI())) pThrallAI->SetEscortPaused(false); } - + break; + case SAY_TA_FAREWELL: + if (Creature* pThrall = m_pInstance->GetSingleCreatureFromStorage(NPC_THRALL)) + m_creature->SetFacingToObject(pThrall); + m_creature->HandleEmote(EMOTE_ONESHOT_WAVE); + break; + case NPC_TARETHA: + if (Creature* pErozion = m_pInstance->GetSingleCreatureFromStorage(NPC_EROZION)) + pErozion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_pInstance->SetData(TYPE_THRALL_EVENT, DONE); + SetEscortPaused(false); break; } } - else - m_uiErozionEventTimer -= uiDiff; -} + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_bHasStartedEpilogue && m_pInstance) + { + // Start epilogue + if (m_pInstance->GetData(TYPE_EPOCH) == DONE && m_pInstance->GetData(TYPE_THRALL_EVENT) != DONE) + { + m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_PRISON); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + Start(true); + m_bHasStartedEpilogue = true; + } + } + } +}; CreatureAI* GetAI_npc_taretha(Creature* pCreature) { @@ -817,38 +1275,37 @@ bool GossipHello_npc_taretha(Player* pPlayer, Creature* pCreature) { instance_old_hillsbrad* pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData(); - if (pInstance && pInstance->GetData(TYPE_THRALL_PART3) == DONE && pInstance->GetData(TYPE_THRALL_PART4) == NOT_STARTED) + if (pInstance && pInstance->GetData(TYPE_ESCORT_INN) == DONE && pInstance->GetData(TYPE_EPOCH) != DONE) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_EPOCH1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_EPOCH1, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_EPOCH_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_EPOCH_1, pCreature->GetObjectGuid()); } return true; } -bool GossipSelect_npc_taretha(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_taretha(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { instance_old_hillsbrad* pInstance = (instance_old_hillsbrad*)pCreature->GetInstanceData(); - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_EPOCH2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_EPOCH2, pCreature->GetObjectGuid()); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_EPOCH_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_EPOCH_2, pCreature->GetObjectGuid()); } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 2) { pPlayer->CLOSE_GOSSIP_MENU(); if (pInstance && pInstance->GetData(TYPE_THRALL_EVENT) == IN_PROGRESS) { - pInstance->SetData(TYPE_THRALL_PART4, IN_PROGRESS); - pCreature->SummonCreature(NPC_EPOCH, 2639.13f, 698.55f, 65.43f, 4.59f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - if (Creature* pThrall = pInstance->GetThrall()) + if (Creature* pThrall = pInstance->GetSingleCreatureFromStorage(NPC_THRALL)) { if (npc_thrall_old_hillsbradAI* pThrallAI = dynamic_cast(pThrall->AI())) - pThrallAI->StartWP(); + pThrallAI->DoRestartEscortMovement(); } } } @@ -856,20 +1313,10 @@ bool GossipSelect_npc_taretha(Player* pPlayer, Creature* pCreature, uint32 uiSen return true; } -/*###### -## AddSC -######*/ - void AddSC_old_hillsbrad() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_brazen"; - pNewScript->pGossipHello = &GossipHello_npc_brazen; - pNewScript->pGossipSelect = &GossipSelect_npc_brazen; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_erozion"; pNewScript->pGossipHello = &GossipHello_npc_erozion; @@ -878,15 +1325,15 @@ void AddSC_old_hillsbrad() pNewScript = new Script; pNewScript->Name = "npc_thrall_old_hillsbrad"; + pNewScript->GetAI = &GetAI_npc_thrall_old_hillsbrad; pNewScript->pGossipHello = &GossipHello_npc_thrall_old_hillsbrad; pNewScript->pGossipSelect = &GossipSelect_npc_thrall_old_hillsbrad; - pNewScript->GetAI = &GetAI_npc_thrall_old_hillsbrad; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "npc_taretha"; + pNewScript->GetAI = &GetAI_npc_taretha; pNewScript->pGossipHello = &GossipHello_npc_taretha; pNewScript->pGossipSelect = &GossipSelect_npc_taretha; - pNewScript->GetAI = &GetAI_npc_taretha; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h b/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h index 59a3b2862..74512c6fd 100644 --- a/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h +++ b/scripts/kalimdor/caverns_of_time/old_hillsbrad/old_hillsbrad.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,21 +7,39 @@ enum { - MAX_ENCOUNTER = 6, - - TYPE_BARREL_DIVERSION = 0, - TYPE_THRALL_EVENT = 1, - TYPE_THRALL_PART1 = 2, // prison to keep - TYPE_THRALL_PART2 = 3, // keep to barn - TYPE_THRALL_PART3 = 4, // barn to inn - TYPE_THRALL_PART4 = 5, // inn to boss - + MAX_ENCOUNTER = 7, + MAX_BARRELS = 5, + MAX_WIPE_COUNTER = 20, + + TYPE_BARREL_DIVERSION = 0, // barrel event + TYPE_DRAKE = 1, // first boss + TYPE_SKARLOC = 2, // prison to keep - boss + TYPE_ESCORT_BARN = 3, // keep to barn + TYPE_ESCORT_INN = 4, // barn to inn + TYPE_EPOCH = 5, // inn event + TYPE_THRALL_EVENT = 6, // global event + + // event npcs NPC_THRALL = 17876, NPC_TARETHA = 18887, - NPC_DRAKE = 17848, + NPC_EROZION = 18723, NPC_LODGE_QUEST_TRIGGER = 20155, + NPC_ARMORER = 18764, + NPC_ORC_PRISONER = 18598, + + NPC_TARREN_MILL_GUARDSMAN = 18092, + NPC_TARREN_MILL_PROTECTOR = 18093, + NPC_TARREN_MILL_LOOKOUT = 18094, + NPC_YOUNG_BLANCHY = 18651, + + // bosses + NPC_DRAKE = 17848, + NPC_SKARLOC = 17862, NPC_EPOCH = 18096, + GO_ROARING_FLAME = 182592, + GO_PRISON_DOOR = 184393, + QUEST_ENTRY_HILLSBRAD = 10282, QUEST_ENTRY_DIVERSION = 10283, QUEST_ENTRY_ESCAPE = 10284, @@ -30,33 +48,54 @@ enum WORLD_STATE_OH = 2436, }; -class MANGOS_DLL_DECL instance_old_hillsbrad : public ScriptedInstance +static const float afInstanceLoc[][4] = +{ + {2104.51f, 91.96f, 53.14f, 0}, // right orcs outside loc + {2192.58f, 238.44f, 52.44f, 0}, // left orcs outside loc +}; + +static const float aDrakeSummonLoc[4] = {2128.43f, 71.01f, 64.42f, 1.74f}; + +class instance_old_hillsbrad : public ScriptedInstance { public: instance_old_hillsbrad(Map* pMap); ~instance_old_hillsbrad() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void HandleThrallRelocation(); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void UpdateLodgeQuestCredit(); + uint32 GetThrallEventCount() { return m_uiThrallEventCount; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - Creature* GetThrall() { return GetSingleCreatureFromStorage(NPC_THRALL); } - Creature* GetTaretha() { return GetSingleCreatureFromStorage(NPC_TARETHA); } - Creature* GetEpoch() { return GetSingleCreatureFromStorage(NPC_EPOCH); } + void Update(uint32 uiDiff) override; protected: + void HandleThrallRelocation(); + void UpdateLodgeQuestCredit(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; uint32 m_uiBarrelCount; uint32 m_uiThrallEventCount; + uint32 m_uiThrallResetTimer; + + GuidList m_lRoaringFlamesList; + GuidList m_lLeftPrisonersList; + GuidList m_lRightPrisonersList; }; #endif diff --git a/scripts/kalimdor/darkshore.cpp b/scripts/kalimdor/darkshore.cpp index d9b9bf7c7..d937805f7 100644 --- a/scripts/kalimdor/darkshore.cpp +++ b/scripts/kalimdor/darkshore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Darkshore SD%Complete: 100 -SDComment: Quest support: 731, 994, 2078, 5321 +SDComment: Quest support: 731, 945, 994, 995, 2078, 2118, 5321 SDCategory: Darkshore EndScriptData */ @@ -26,6 +26,8 @@ npc_kerlonian npc_prospector_remtravel npc_threshwackonator npc_volcor +npc_therylune +npc_rabid_bear EndContentData */ #include "precompiled.h" @@ -59,28 +61,28 @@ enum SPELL_SLEEP_VISUAL = 25148, SPELL_AWAKEN = 17536, QUEST_SLEEPER_AWAKENED = 5321, - NPC_LILADRIS = 11219 //attackers entries unknown + NPC_LILADRIS = 11219 // attackers entries unknown }; -//TODO: make concept similar as "ringo" -escort. Find a way to run the scripted attacks, _if_ player are choosing road. -struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI +// TODO: make concept similar as "ringo" -escort. Find a way to run the scripted attacks, _if_ player are choosing road. +struct npc_kerlonianAI : public FollowerAI { npc_kerlonianAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } uint32 m_uiFallAsleepTimer; - void Reset() + void Reset() override { m_uiFallAsleepTimer = urand(10000, 45000); } - void MoveInLineOfSight(Unit *pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_LILADRIS) { - if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE*5)) + if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE * 5)) { if (Player* pPlayer = GetLeaderForFollower()) { @@ -95,7 +97,7 @@ struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (HasFollowState(STATE_FOLLOW_INPROGRESS | STATE_FOLLOW_PAUSED) && pSpell->Id == SPELL_AWAKEN) ClearSleeping(); @@ -105,14 +107,14 @@ struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI { SetFollowPaused(true); - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(EMOTE_KER_SLEEP_1, m_creature); break; case 1: DoScriptText(EMOTE_KER_SLEEP_2, m_creature); break; case 2: DoScriptText(EMOTE_KER_SLEEP_3, m_creature); break; } - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_KER_SLEEP_1, m_creature); break; case 1: DoScriptText(SAY_KER_SLEEP_2, m_creature); break; @@ -134,7 +136,7 @@ struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI SetFollowPaused(false); } - void UpdateFollowerAI(const uint32 uiDiff) + void UpdateFollowerAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -205,18 +207,18 @@ enum NPC_GRAVEL_GEO = 2160 }; -struct MANGOS_DLL_DECL npc_prospector_remtravelAI : public npc_escortAI +struct npc_prospector_remtravelAI : public npc_escortAI { npc_prospector_remtravelAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(uiPointId) + switch (uiPointId) { case 0: DoScriptText(SAY_REM_START, m_creature, pPlayer); @@ -225,22 +227,22 @@ struct MANGOS_DLL_DECL npc_prospector_remtravelAI : public npc_escortAI DoScriptText(SAY_REM_RAMP1_1, m_creature, pPlayer); break; case 6: - DoSpawnCreature(NPC_GRAVEL_SCOUT, -10.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - DoSpawnCreature(NPC_GRAVEL_BONE, -10.0f, 7.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + DoSpawnCreature(NPC_GRAVEL_SCOUT, -10.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + DoSpawnCreature(NPC_GRAVEL_BONE, -10.0f, 7.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 9: DoScriptText(SAY_REM_RAMP1_2, m_creature, pPlayer); break; case 14: - //depend quest rewarded? + // depend quest rewarded? DoScriptText(SAY_REM_BOOK, m_creature, pPlayer); break; case 15: DoScriptText(SAY_REM_TENT1_1, m_creature, pPlayer); break; case 16: - DoSpawnCreature(NPC_GRAVEL_SCOUT, -10.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - DoSpawnCreature(NPC_GRAVEL_BONE, -10.0f, 7.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + DoSpawnCreature(NPC_GRAVEL_SCOUT, -10.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + DoSpawnCreature(NPC_GRAVEL_BONE, -10.0f, 7.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 17: DoScriptText(SAY_REM_TENT1_2, m_creature, pPlayer); @@ -255,9 +257,9 @@ struct MANGOS_DLL_DECL npc_prospector_remtravelAI : public npc_escortAI DoScriptText(SAY_REM_MOSS_PROGRESS, m_creature, pPlayer); break; case 29: - DoSpawnCreature(NPC_GRAVEL_SCOUT, -15.0f, 3.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - DoSpawnCreature(NPC_GRAVEL_BONE, -15.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - DoSpawnCreature(NPC_GRAVEL_GEO, -15.0f, 7.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + DoSpawnCreature(NPC_GRAVEL_SCOUT, -15.0f, 3.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + DoSpawnCreature(NPC_GRAVEL_BONE, -15.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + DoSpawnCreature(NPC_GRAVEL_GEO, -15.0f, 7.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 31: DoScriptText(SAY_REM_PROGRESS, m_creature, pPlayer); @@ -272,18 +274,18 @@ struct MANGOS_DLL_DECL npc_prospector_remtravelAI : public npc_escortAI } } - void Reset() { } + void Reset() override { } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (urand(0, 1)) DoScriptText(SAY_REM_AGGRO, m_creature, pWho); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* /*pSummoned*/) override { - //unsure if it should be any - //pSummoned->AI()->AttackStart(m_creature); + // unsure if it should be any + // pSummoned->AI()->AttackStart(m_creature); } }; @@ -296,7 +298,7 @@ bool QuestAccept_npc_prospector_remtravel(Player* pPlayer, Creature* pCreature, { if (pQuest->GetQuestId() == QUEST_ABSENT_MINDED_PT2) { - pCreature->setFaction(FACTION_ESCORT_A_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_prospector_remtravelAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest, true); @@ -320,13 +322,13 @@ enum #define GOSSIP_ITEM_INSERT_KEY "[PH] Insert key" -struct MANGOS_DLL_DECL npc_threshwackonatorAI : public FollowerAI +struct npc_threshwackonatorAI : public FollowerAI { npc_threshwackonatorAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); @@ -342,7 +344,7 @@ struct MANGOS_DLL_DECL npc_threshwackonatorAI : public FollowerAI void DoAtEnd() { - m_creature->setFaction(FACTION_HOSTILE); + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN); if (Player* pHolder = GetLeaderForFollower()) m_creature->AI()->AttackStart(pHolder); @@ -359,15 +361,15 @@ CreatureAI* GetAI_npc_threshwackonator(Creature* pCreature) bool GossipHello_npc_threshwackonator(Player* pPlayer, Creature* pCreature) { if (pPlayer->GetQuestStatus(QUEST_GYROMAST_REV) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INSERT_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INSERT_KEY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_threshwackonator(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_threshwackonator(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->CLOSE_GOSSIP_MENU(); @@ -382,22 +384,30 @@ bool GossipSelect_npc_threshwackonator(Player* pPlayer, Creature* pCreature, uin } /*###### -+# npc_volcor -+######*/ +# npc_volcor +######*/ enum { - SAY_START = -1000789, - SAY_END = -1000790, - SAY_FIRST_AMBUSH = -1000791, - SAY_AGGRO_1 = -1000792, - SAY_AGGRO_2 = -1000793, - SAY_AGGRO_3 = -1000794, + SAY_START = -1000789, + SAY_END = -1000790, + SAY_FIRST_AMBUSH = -1000791, + SAY_AGGRO_1 = -1000792, + SAY_AGGRO_2 = -1000793, + SAY_AGGRO_3 = -1000794, + + SAY_ESCAPE = -1000195, + + NPC_BLACKWOOD_SHAMAN = 2171, + NPC_BLACKWOOD_URSA = 2170, - NPC_BLACKWOOD_SHAMAN = 2171, - NPC_BLACKWOOD_URSA = 2170, + SPELL_MOONSTALKER_FORM = 10849, - QUEST_ESCAPE_THROUGH_FORCE = 994 + WAYPOINT_ID_QUEST_STEALTH = 16, + FACTION_FRIENDLY = 35, + + QUEST_ESCAPE_THROUGH_FORCE = 994, + QUEST_ESCAPE_THROUGH_STEALTH = 995, }; struct SummonLocation @@ -416,16 +426,22 @@ static const SummonLocation aVolcorSpawnLocs[] = {4711.7f, 109.1f, 53.5f, 2.4f}, }; -struct MANGOS_DLL_DECL npc_volcorAI : public npc_escortAI +struct npc_volcorAI : public npc_escortAI { npc_volcorAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + uint32 m_uiQuestId; - void Aggro(Unit* pWho) + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_uiQuestId = 0; + } + + void Aggro(Unit* /*pWho*/) override { // shouldn't always use text on agro - switch(urand(0, 4)) + switch (urand(0, 4)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -433,33 +449,83 @@ struct MANGOS_DLL_DECL npc_volcorAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void MoveInLineOfSight(Unit* pWho) override + { + // No combat for this quest + if (m_uiQuestId == QUEST_ESCAPE_THROUGH_STEALTH) + return; + + npc_escortAI::MoveInLineOfSight(pWho); + } + + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void WaypointReached(uint32 uiPointId) + // Wrapper to handle start function for both quests + void StartEscort(Player* pPlayer, const Quest* pQuest) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFacingToObject(pPlayer); + m_uiQuestId = pQuest->GetQuestId(); + + if (pQuest->GetQuestId() == QUEST_ESCAPE_THROUGH_STEALTH) + { + // Note: faction may not be correct, but only this way works fine + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + + Start(true, pPlayer, pQuest); + SetEscortPaused(true); + SetCurrentWaypoint(WAYPOINT_ID_QUEST_STEALTH); + SetEscortPaused(false); + } + else + Start(false, pPlayer, pQuest); + } + + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { - case 4: - m_creature->SummonCreature(NPC_BLACKWOOD_SHAMAN, aVolcorSpawnLocs[0].m_fX, aVolcorSpawnLocs[0].m_fY, aVolcorSpawnLocs[0].m_fZ, aVolcorSpawnLocs[0].m_fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,20000); - m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[1].m_fX, aVolcorSpawnLocs[1].m_fY, aVolcorSpawnLocs[1].m_fZ, aVolcorSpawnLocs[1].m_fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,20000); + case 2: + DoScriptText(SAY_START, m_creature); break; case 5: + m_creature->SummonCreature(NPC_BLACKWOOD_SHAMAN, aVolcorSpawnLocs[0].m_fX, aVolcorSpawnLocs[0].m_fY, aVolcorSpawnLocs[0].m_fZ, aVolcorSpawnLocs[0].m_fO, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[1].m_fX, aVolcorSpawnLocs[1].m_fY, aVolcorSpawnLocs[1].m_fZ, aVolcorSpawnLocs[1].m_fO, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + break; + case 6: DoScriptText(SAY_FIRST_AMBUSH, m_creature); break; - case 10: - m_creature->SummonCreature(NPC_BLACKWOOD_SHAMAN, aVolcorSpawnLocs[2].m_fX, aVolcorSpawnLocs[2].m_fY, aVolcorSpawnLocs[2].m_fZ, aVolcorSpawnLocs[2].m_fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,20000); - m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[3].m_fX, aVolcorSpawnLocs[3].m_fY, aVolcorSpawnLocs[3].m_fZ, aVolcorSpawnLocs[3].m_fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,20000); - case 12: - m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[4].m_fX, aVolcorSpawnLocs[4].m_fY, aVolcorSpawnLocs[4].m_fZ, aVolcorSpawnLocs[4].m_fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); - m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[5].m_fX, aVolcorSpawnLocs[5].m_fY, aVolcorSpawnLocs[5].m_fZ, aVolcorSpawnLocs[5].m_fO, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + case 11: + m_creature->SummonCreature(NPC_BLACKWOOD_SHAMAN, aVolcorSpawnLocs[2].m_fX, aVolcorSpawnLocs[2].m_fY, aVolcorSpawnLocs[2].m_fZ, aVolcorSpawnLocs[2].m_fO, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[3].m_fX, aVolcorSpawnLocs[3].m_fY, aVolcorSpawnLocs[3].m_fZ, aVolcorSpawnLocs[3].m_fO, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + case 13: + m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[4].m_fX, aVolcorSpawnLocs[4].m_fY, aVolcorSpawnLocs[4].m_fZ, aVolcorSpawnLocs[4].m_fO, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); + m_creature->SummonCreature(NPC_BLACKWOOD_URSA, aVolcorSpawnLocs[5].m_fX, aVolcorSpawnLocs[5].m_fY, aVolcorSpawnLocs[5].m_fZ, aVolcorSpawnLocs[5].m_fO, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); break; - case 14: + case 15: DoScriptText(SAY_END, m_creature); if (Player* pPlayer = GetPlayerForEscort()) pPlayer->GroupEventHappens(QUEST_ESCAPE_THROUGH_FORCE, m_creature); + SetEscortPaused(true); + m_creature->ForcedDespawn(10000); + break; + // Quest 995 waypoints + case 16: + m_creature->HandleEmote(EMOTE_ONESHOT_BOW); + break; + case 17: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_ESCAPE, m_creature, pPlayer); + break; + case 18: + DoCastSpellIfCan(m_creature, SPELL_MOONSTALKER_FORM); + break; + case 24: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ESCAPE_THROUGH_STEALTH, m_creature); break; } } @@ -472,20 +538,201 @@ CreatureAI* GetAI_npc_volcor(Creature* pCreature) bool QuestAccept_npc_volcor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - if (pQuest->GetQuestId() == QUEST_ESCAPE_THROUGH_FORCE) + if (pQuest->GetQuestId() == QUEST_ESCAPE_THROUGH_FORCE || pQuest->GetQuestId() == QUEST_ESCAPE_THROUGH_STEALTH) { - pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); - pCreature->SetStandState(UNIT_STAND_STATE_STAND); + if (npc_volcorAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->StartEscort(pPlayer, pQuest); + } - DoScriptText(SAY_START, pCreature); + return true; +} - if (npc_volcorAI* pEscortAI = dynamic_cast(pCreature->AI())) +/*#### +# npc_therylune +####*/ + +enum +{ + SAY_THERYLUNE_START = -1000905, + SAY_THERYLUNE_FINISH = -1000906, + + NPC_THERYSIL = 3585, + + QUEST_ID_THERYLUNE_ESCAPE = 945, +}; + +struct npc_theryluneAI : public npc_escortAI +{ + npc_theryluneAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + + void Reset() override {} + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 17: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_THERYLUNE_ESCAPE, m_creature); + break; + case 19: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_THERYLUNE_FINISH, m_creature, pPlayer); + SetRun(); + break; + } + } +}; + +CreatureAI* GetAI_npc_therylune(Creature* pCreature) +{ + return new npc_theryluneAI(pCreature); +} + +bool QuestAccept_npc_therylune(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_THERYLUNE_ESCAPE) + { + if (npc_theryluneAI* pEscortAI = dynamic_cast(pCreature->AI())) + { pEscortAI->Start(false, pPlayer, pQuest); + DoScriptText(SAY_THERYLUNE_START, pCreature, pPlayer); + } } return true; } +/*###### +## npc_rabid_bear +######*/ + +enum +{ + QUEST_PLAGUED_LANDS = 2118, + + NPC_CAPTURED_RABID_THISTLE_BEAR = 11836, + NPC_THARNARIUN_TREETENDER = 3701, // Npc related to quest-outro + GO_NIGHT_ELVEN_BEAR_TRAP = 111148, // This is actually the (visual) spell-focus GO + + SPELL_RABIES = 3150, // Spell used in comabt +}; + +struct npc_rabid_bearAI : public ScriptedAI +{ + npc_rabid_bearAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + JustRespawned(); + } + + uint32 m_uiCheckTimer; + uint32 m_uiRabiesTimer; + uint32 m_uiDespawnTimer; + + void Reset() override + { + m_uiRabiesTimer = urand(12000, 18000); + } + + void JustRespawned() override + { + m_uiCheckTimer = 1000; + m_uiDespawnTimer = 0; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_uiCheckTimer && pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_THARNARIUN_TREETENDER && + pWho->IsWithinDist(m_creature, 2 * INTERACTION_DISTANCE, false)) + { + // Possible related spell: 9455 9372 + m_creature->ForcedDespawn(1000); + m_creature->GetMotionMaster()->MoveIdle(); + + return; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiCheckTimer && m_creature->isInCombat()) + { + if (m_uiCheckTimer <= uiDiff) + { + // Trap nearby? + if (GameObject* pTrap = GetClosestGameObjectWithEntry(m_creature, GO_NIGHT_ELVEN_BEAR_TRAP, 0.5f)) + { + // Despawn trap + pTrap->Use(m_creature); + // "Evade" + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + Reset(); + // Update Entry and start following player + m_creature->UpdateEntry(NPC_CAPTURED_RABID_THISTLE_BEAR); + // get player + Unit* pTrapOwner = pTrap->GetOwner(); + if (pTrapOwner && pTrapOwner->GetTypeId() == TYPEID_PLAYER && + ((Player*)pTrapOwner)->GetQuestStatus(QUEST_PLAGUED_LANDS) == QUEST_STATUS_INCOMPLETE) + { + ((Player*)pTrapOwner)->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); + m_creature->GetMotionMaster()->MoveFollow(pTrapOwner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + } + else // Something unexpected happened + m_creature->ForcedDespawn(1000); + + // No need to check any more + m_uiCheckTimer = 0; + // Despawn after a while (delay guesswork) + m_uiDespawnTimer = 3 * MINUTE * IN_MILLISECONDS; + + return; + } + else + m_uiCheckTimer = 1000; + } + else + m_uiCheckTimer -= uiDiff; + } + + if (m_uiDespawnTimer && !m_creature->isInCombat()) + { + if (m_uiDespawnTimer <= uiDiff) + { + m_creature->ForcedDespawn(); + return; + } + else + m_uiDespawnTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiRabiesTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, SPELL_RABIES)) + DoCastSpellIfCan(pTarget, SPELL_RABIES); + m_uiRabiesTimer = urand(12000, 18000); + } + else + m_uiRabiesTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_rabid_bear(Creature* pCreature) +{ + return new npc_rabid_bearAI(pCreature); +} + void AddSC_darkshore() { Script* pNewScript; @@ -514,4 +761,15 @@ void AddSC_darkshore() pNewScript->GetAI = &GetAI_npc_volcor; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_volcor; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_therylune"; + pNewScript->GetAI = &GetAI_npc_therylune; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_therylune; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_rabid_bear"; + pNewScript->GetAI = &GetAI_npc_rabid_bear; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/desolace.cpp b/scripts/kalimdor/desolace.cpp index f7d0f77d4..3c3f6f2ce 100644 --- a/scripts/kalimdor/desolace.cpp +++ b/scripts/kalimdor/desolace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -49,24 +49,23 @@ enum NPC_TAMED_KODO = 11627, SPELL_KODO_KOMBO_ITEM = 18153, - SPELL_KODO_KOMBO_PLAYER_BUFF = 18172, //spells here have unclear function, but using them at least for visual parts and checks + SPELL_KODO_KOMBO_PLAYER_BUFF = 18172, // spells here have unclear function, but using them at least for visual parts and checks SPELL_KODO_KOMBO_DESPAWN_BUFF = 18377, SPELL_KODO_KOMBO_GOSSIP = 18362 - }; -struct MANGOS_DLL_DECL npc_aged_dying_ancient_kodoAI : public ScriptedAI +struct npc_aged_dying_ancient_kodoAI : public ScriptedAI { npc_aged_dying_ancient_kodoAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiDespawnTimer; - void Reset() + void Reset() override { m_uiDespawnTimer = 0; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (pWho->GetEntry() == NPC_SMEED) { @@ -75,20 +74,20 @@ struct MANGOS_DLL_DECL npc_aged_dying_ancient_kodoAI : public ScriptedAI if (m_creature->IsWithinDistInMap(pWho, 10.0f)) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SMEED_HOME_1, pWho); break; case 1: DoScriptText(SAY_SMEED_HOME_2, pWho); break; case 2: DoScriptText(SAY_SMEED_HOME_3, pWho); break; } - //spell have no implemented effect (dummy), so useful to notify spellHit - m_creature->CastSpell(m_creature,SPELL_KODO_KOMBO_GOSSIP,true); + // spell have no implemented effect (dummy), so useful to notify spellHit + m_creature->CastSpell(m_creature, SPELL_KODO_KOMBO_GOSSIP, true); } } } - void SpellHit(Unit* pCaster, SpellEntry const* pSpell) + void SpellHit(Unit* /*pCaster*/, SpellEntry const* pSpell) override { if (pSpell->Id == SPELL_KODO_KOMBO_GOSSIP) { @@ -97,9 +96,9 @@ struct MANGOS_DLL_DECL npc_aged_dying_ancient_kodoAI : public ScriptedAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { - //timer should always be == 0 unless we already updated entry of creature. Then not expect this updated to ever be in combat. + // timer should always be == 0 unless we already updated entry of creature. Then not expect this updated to ever be in combat. if (m_uiDespawnTimer && m_uiDespawnTimer <= diff) { if (!m_creature->getVictim() && m_creature->isAlive()) @@ -109,7 +108,8 @@ struct MANGOS_DLL_DECL npc_aged_dying_ancient_kodoAI : public ScriptedAI m_creature->Respawn(); return; } - } else m_uiDespawnTimer -= diff; + } + else m_uiDespawnTimer -= diff; if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -123,23 +123,23 @@ CreatureAI* GetAI_npc_aged_dying_ancient_kodo(Creature* pCreature) return new npc_aged_dying_ancient_kodoAI(pCreature); } -bool EffectDummyCreature_npc_aged_dying_ancient_kodo(Unit *pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature *pCreatureTarget) +bool EffectDummyCreature_npc_aged_dying_ancient_kodo(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (spellId == SPELL_KODO_KOMBO_ITEM && effIndex == EFFECT_INDEX_0) { - //no effect if player/creature already have aura from spells + // no effect if player/creature already have aura from spells if (pCaster->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) || pCreatureTarget->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF)) return true; if (pCreatureTarget->GetEntry() == NPC_AGED_KODO || - pCreatureTarget->GetEntry() == NPC_DYING_KODO || - pCreatureTarget->GetEntry() == NPC_ANCIENT_KODO) + pCreatureTarget->GetEntry() == NPC_DYING_KODO || + pCreatureTarget->GetEntry() == NPC_ANCIENT_KODO) { - pCaster->CastSpell(pCaster,SPELL_KODO_KOMBO_PLAYER_BUFF,true); + pCaster->CastSpell(pCaster, SPELL_KODO_KOMBO_PLAYER_BUFF, true); pCreatureTarget->UpdateEntry(NPC_TAMED_KODO); - pCreatureTarget->CastSpell(pCreatureTarget,SPELL_KODO_KOMBO_DESPAWN_BUFF,false); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_KODO_KOMBO_DESPAWN_BUFF, false); if (pCreatureTarget->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) pCreatureTarget->GetMotionMaster()->MoveIdle(); @@ -147,7 +147,7 @@ bool EffectDummyCreature_npc_aged_dying_ancient_kodo(Unit *pCaster, uint32 spell pCreatureTarget->GetMotionMaster()->MoveFollow(pCaster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } return false; @@ -157,7 +157,7 @@ bool GossipHello_npc_aged_dying_ancient_kodo(Player* pPlayer, Creature* pCreatur { if (pPlayer->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) && pCreature->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF)) { - //the expected quest objective + // the expected quest objective pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); pPlayer->RemoveAurasDueToSpell(SPELL_KODO_KOMBO_PLAYER_BUFF); @@ -177,18 +177,18 @@ enum QUEST_RETURN_TO_VAHLARRIEL = 1440, }; -struct MANGOS_DLL_DECL npc_dalinda_malemAI : public npc_escortAI +struct npc_dalinda_malemAI : public npc_escortAI { npc_dalinda_malemAI(Creature* m_creature) : npc_escortAI(m_creature) { Reset(); } - void Reset() {} + void Reset() override {} - void JustStartedEscort() + void JustStartedEscort() override { m_creature->SetStandState(UNIT_STAND_STATE_STAND); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { if (uiPointId == 18) { @@ -210,7 +210,7 @@ bool QuestAccept_npc_dalinda_malem(Player* pPlayer, Creature* pCreature, const Q if (npc_dalinda_malemAI* pEscortAI = dynamic_cast(pCreature->AI())) { // TODO This faction change needs confirmation, also possible that we need to drop her PASSIVE flag - pCreature->setFaction(FACTION_ESCORT_A_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_PASSIVE); pEscortAI->Start(false, pPlayer, pQuest); } } @@ -265,32 +265,29 @@ struct SummonLocation static const SummonLocation aMarauderSpawn[] = { - {-1291.492f, 2644.650f, 111.556f}, - {-1306.730f, 2675.163f, 111.561f}, + { -1291.492f, 2644.650f, 111.556f}, + { -1306.730f, 2675.163f, 111.561f}, }; -static const SummonLocation aWranglerSpawn[] = {-1393.194f, 2429.465f, 88.689f}; +static const SummonLocation wranglerSpawn = { -1393.194f, 2429.465f, 88.689f }; -struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private DialogueHelper +struct npc_melizza_brimbuzzleAI : public npc_escortAI, private DialogueHelper { npc_melizza_brimbuzzleAI(Creature* m_creature) : npc_escortAI(m_creature), DialogueHelper(aIntroDialogue) { - m_uiNormalFaction = m_creature->getFaction(); Reset(); } - uint32 m_uiNormalFaction; + void Reset() override {} - void Reset() {} - - void JustStartedEscort() + void JustStartedEscort() override { if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_MELIZZAS_CAGE, INTERACTION_DISTANCE)) pCage->UseDoorOrButton(); } - Creature* GetSpeakerByEntry(uint32 uiEntry) + Creature* GetSpeakerByEntry(uint32 uiEntry) override { if (uiEntry == NPC_MELIZZA) return m_creature; @@ -298,15 +295,15 @@ struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private D return NULL; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 1: if (Player* pPlayer = GetPlayerForEscort()) DoScriptText(SAY_MELIZZA_START, m_creature, pPlayer); - m_creature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); break; case 4: for (uint8 i = 0; i < MAX_MARAUDERS; ++i) @@ -324,10 +321,10 @@ struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private D for (uint8 i = 0; i < MAX_WRANGLERS; ++i) { float fX, fY, fZ; - m_creature->GetRandomPoint(aWranglerSpawn[0].m_fX, aWranglerSpawn[0].m_fY, aWranglerSpawn[0].m_fZ, 10.0f, fX, fY, fZ); + m_creature->GetRandomPoint(wranglerSpawn.m_fX, wranglerSpawn.m_fY, wranglerSpawn.m_fZ, 10.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_MARAUDINE_BONEPAW, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); - m_creature->GetRandomPoint(aWranglerSpawn[0].m_fX, aWranglerSpawn[0].m_fY, aWranglerSpawn[0].m_fZ, 10.0f, fX, fY, fZ); + m_creature->GetRandomPoint(wranglerSpawn.m_fX, wranglerSpawn.m_fY, wranglerSpawn.m_fZ, 10.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_MARAUDINE_WRANGLER, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); } break; @@ -338,10 +335,9 @@ struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private D StartNextDialogueText(POINT_ID_EVENT_COMPLETE); break; } - } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { switch (iEntry) { @@ -355,7 +351,7 @@ struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private D pPlayer->GroupEventHappens(QUEST_GET_ME_OUT_OF_HERE, m_creature); } - m_creature->setFaction(m_uiNormalFaction); + m_creature->ClearTemporaryFaction(); SetRun(true); SetEscortPaused(false); break; @@ -369,7 +365,7 @@ struct MANGOS_DLL_DECL npc_melizza_brimbuzzleAI : public npc_escortAI, private D } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); diff --git a/scripts/kalimdor/dire_maul/dire_maul.cpp b/scripts/kalimdor/dire_maul/dire_maul.cpp index 9f7a5b961..e1536d3fb 100644 --- a/scripts/kalimdor/dire_maul/dire_maul.cpp +++ b/scripts/kalimdor/dire_maul/dire_maul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/kalimdor/dire_maul/dire_maul.h b/scripts/kalimdor/dire_maul/dire_maul.h index 793a26c9f..fc3706619 100644 --- a/scripts/kalimdor/dire_maul/dire_maul.h +++ b/scripts/kalimdor/dire_maul/dire_maul.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,7 +7,7 @@ enum { - MAX_ENCOUNTER = 12, + MAX_ENCOUNTER = 16, MAX_GENERATORS = 5, // East @@ -27,6 +27,10 @@ enum // North TYPE_KING_GORDOK = 11, + TYPE_MOLDAR = 12, + TYPE_FENGUS = 13, + TYPE_SLIPKIK = 14, + TYPE_KROMCRUSH = 15, // East GO_CRUMBLE_WALL = 177220, @@ -55,6 +59,7 @@ enum GO_CRYSTAL_GENERATOR_5 = 179505, GO_FORCEFIELD = 179503, GO_WARPWOOD_DOOR = 177221, + GO_WEST_LIBRARY_DOOR = 179550, // North NPC_GUARD_MOLDAR = 14326, @@ -69,34 +74,42 @@ enum GO_KNOTS_CACHE = 179501, GO_KNOTS_BALL_AND_CHAIN = 179511, GO_GORDOK_TRIBUTE = 179564, + GO_NORTH_LIBRARY_DOOR = 179549, SAY_FREE_IMMOLTHAR = -1429000, SAY_KILL_IMMOLTHAR = -1429001, SAY_IRONBARK_REDEEM = -1429002, + SAY_CHORUSH_KING_DEAD = -1429003, FACTION_HOSTILE = 14, - SPELL_KING_OF_GORDOK = 22799, + FACTION_FRIENDLY = 35, }; -class MANGOS_DLL_DECL instance_dire_maul : public ScriptedInstance +static const float afMizzleSpawnLoc[4] = {683.296f, 484.384f, 29.544f, 0.0174f}; + +class instance_dire_maul : public ScriptedInstance { public: instance_dire_maul(Map* pMap); ~instance_dire_maul() {} - void Initialize(); + void Initialize() override; + + void OnPlayerEnter(Player* pPlayer) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnCreatureEnterCombat(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const override; protected: bool CheckAllGeneratorsDestroyed(); @@ -109,14 +122,17 @@ class MANGOS_DLL_DECL instance_dire_maul : public ScriptedInstance // East bool m_bWallDestroyed; - GUIDList m_lFelvineShardGUIDs; + GuidList m_lFelvineShardGUIDs; // West ObjectGuid m_aCrystalGeneratorGuid[MAX_GENERATORS]; - GUIDList m_luiHighborneSummonerGUIDs; - GUIDList m_lGeneratorGuardGUIDs; + GuidList m_luiHighborneSummonerGUIDs; + GuidList m_lGeneratorGuardGUIDs; std::set m_sSortedGeneratorGuards[MAX_GENERATORS]; + + // North + bool m_bDoNorthBeforeWest; }; #endif diff --git a/scripts/kalimdor/dire_maul/instance_dire_maul.cpp b/scripts/kalimdor/dire_maul/instance_dire_maul.cpp index b08fa3656..3d140d63a 100644 --- a/scripts/kalimdor/dire_maul/instance_dire_maul.cpp +++ b/scripts/kalimdor/dire_maul/instance_dire_maul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,7 +25,8 @@ EndScriptData */ #include "dire_maul.h" instance_dire_maul::instance_dire_maul(Map* pMap) : ScriptedInstance(pMap), - m_bWallDestroyed(false) + m_bWallDestroyed(false), + m_bDoNorthBeforeWest(false) { Initialize(); } @@ -35,18 +36,31 @@ void instance_dire_maul::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_dire_maul::OnPlayerEnter(Player* pPlayer) +{ + // figure where to enter to set library doors accordingly + // Enter DM North first + if (pPlayer->IsWithinDist2d(260.0f, -20.0f, 20.0f) && m_auiEncounter[TYPE_WARPWOOD] != DONE) + m_bDoNorthBeforeWest = true; + else + m_bDoNorthBeforeWest = false; + + DoToggleGameObjectFlags(GO_WEST_LIBRARY_DOOR, GO_FLAG_NO_INTERACT, m_bDoNorthBeforeWest); + DoToggleGameObjectFlags(GO_WEST_LIBRARY_DOOR, GO_FLAG_LOCKED, !m_bDoNorthBeforeWest); +} + void instance_dire_maul::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - // East + // East case NPC_OLD_IRONBARK: break; - // West + // West case NPC_PRINCE_TORTHELDRIN: if (m_auiEncounter[TYPE_IMMOLTHAR] == DONE) - pCreature->setFaction(FACTION_HOSTILE); + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_OOC_NOT_ATTACK); break; case NPC_ARCANE_ABERRATION: case NPC_MANA_REMNANT: @@ -58,10 +72,10 @@ void instance_dire_maul::OnCreatureCreate(Creature* pCreature) m_luiHighborneSummonerGUIDs.push_back(pCreature->GetObjectGuid()); return; - // North + // North case NPC_CHORUSH: case NPC_KING_GORDOK: - case NPC_MIZZLE_THE_CRAFTY: + case NPC_CAPTAIN_KROMCRUSH: break; default: @@ -72,9 +86,9 @@ void instance_dire_maul::OnCreatureCreate(Creature* pCreature) void instance_dire_maul::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - // East + // East case GO_CONSERVATORY_DOOR: if (m_auiEncounter[TYPE_IRONBARK] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); @@ -91,7 +105,7 @@ void instance_dire_maul::OnObjectCreate(GameObject* pGo) m_lFelvineShardGUIDs.push_back(pGo->GetObjectGuid()); break; - // West + // West case GO_CRYSTAL_GENERATOR_1: m_aCrystalGeneratorGuid[0] = pGo->GetObjectGuid(); if (m_auiEncounter[TYPE_PYLON_1] == DONE) @@ -127,6 +141,15 @@ void instance_dire_maul::OnObjectCreate(GameObject* pGo) if (m_auiEncounter[TYPE_WARPWOOD] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + case GO_WEST_LIBRARY_DOOR: + pGo->SetFlag(GAMEOBJECT_FLAGS, m_bDoNorthBeforeWest ? GO_FLAG_NO_INTERACT : GO_FLAG_LOCKED); + pGo->RemoveFlag(GAMEOBJECT_FLAGS, m_bDoNorthBeforeWest ? GO_FLAG_LOCKED : GO_FLAG_NO_INTERACT); + break; + + // North + case GO_NORTH_LIBRARY_DOOR: + break; + default: return; } @@ -135,9 +158,9 @@ void instance_dire_maul::OnObjectCreate(GameObject* pGo) void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { - // East + // East case TYPE_ZEVRIM: if (uiData == DONE) { @@ -166,7 +189,7 @@ void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) if (!m_lFelvineShardGUIDs.empty()) { - for(GUIDList::const_iterator itr = m_lFelvineShardGUIDs.begin(); itr != m_lFelvineShardGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lFelvineShardGUIDs.begin(); itr != m_lFelvineShardGUIDs.end(); ++itr) DoRespawnGameObject(*itr); } } @@ -178,7 +201,7 @@ void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; - // West + // West case TYPE_WARPWOOD: if (uiData == DONE) DoUseDoorOrButton(GO_WARPWOOD_DOOR); @@ -190,7 +213,7 @@ void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_PRINCE_TORTHELDRIN)) { DoScriptText(SAY_FREE_IMMOLTHAR, pPrince); - pPrince->setFaction(FACTION_HOSTILE); + pPrince->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_OOC_NOT_ATTACK); // Despawn Chest-Aura if (GameObject* pChestAura = GetSingleGameObjectFromStorage(GO_PRINCES_CHEST_AURA)) pChestAura->Use(pPrince); @@ -215,20 +238,49 @@ void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) } break; - // North + // North case TYPE_KING_GORDOK: m_auiEncounter[uiType] = uiData; if (uiData == DONE) { - // Apply Aura to players in the map - Map::PlayerList const& players = instance->GetPlayers(); - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + // change faction to certian ogres + if (Creature* pOgre = GetSingleCreatureFromStorage(NPC_CAPTAIN_KROMCRUSH)) + { + if (pOgre->isAlive()) + { + pOgre->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + + // only evade if required + if (pOgre->getVictim()) + pOgre->AI()->EnterEvadeMode(); + } + } + + if (Creature* pOgre = GetSingleCreatureFromStorage(NPC_CHORUSH)) { - if (Player* pPlayer = itr->getSource()) - pPlayer->CastSpell(pPlayer, SPELL_KING_OF_GORDOK, true); + // Chorush evades and yells on king death (if alive) + if (pOgre->isAlive()) + { + DoScriptText(SAY_CHORUSH_KING_DEAD, pOgre); + pOgre->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + pOgre->AI()->EnterEvadeMode(); + } + + // start WP movement for Mizzle; event handled by movement and gossip dbscripts + if (Creature* pMizzle = pOgre->SummonCreature(NPC_MIZZLE_THE_CRAFTY, afMizzleSpawnLoc[0], afMizzleSpawnLoc[1], afMizzleSpawnLoc[2], afMizzleSpawnLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0, true)) + { + pMizzle->SetWalk(false); + pMizzle->GetMotionMaster()->MoveWaypoint(); + } } } break; + case TYPE_MOLDAR: + case TYPE_FENGUS: + case TYPE_SLIPKIK: + case TYPE_KROMCRUSH: + m_auiEncounter[uiType] = uiData; + break; } if (uiData == DONE) @@ -239,7 +291,9 @@ void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11]; + << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] << " " + << m_auiEncounter[12] << " " << m_auiEncounter[13] << " " << m_auiEncounter[14] << " " + << m_auiEncounter[15]; m_strInstData = saveStream.str(); @@ -248,7 +302,7 @@ void instance_dire_maul::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_dire_maul::GetData(uint32 uiType) +uint32 instance_dire_maul::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -260,13 +314,13 @@ void instance_dire_maul::OnCreatureEnterCombat(Creature* pCreature) { switch (pCreature->GetEntry()) { - // West - // - Handling of guards of generators + // West + // - Handling of guards of generators case NPC_ARCANE_ABERRATION: case NPC_MANA_REMNANT: SortPylonGuards(); break; - // - Set InstData for ImmolThar + // - Set InstData for ImmolThar case NPC_IMMOLTHAR: SetData(TYPE_IMMOLTHAR, IN_PROGRESS); break; @@ -277,8 +331,8 @@ void instance_dire_maul::OnCreatureDeath(Creature* pCreature) { switch (pCreature->GetEntry()) { - // East - // - Handling Zevrim and Old Ironbark for the door event + // East + // - Handling Zevrim and Old Ironbark for the door event case NPC_ZEVRIM_THORNHOOF: SetData(TYPE_ZEVRIM, DONE); break; @@ -286,13 +340,13 @@ void instance_dire_maul::OnCreatureDeath(Creature* pCreature) SetData(TYPE_IRONBARK, DONE); break; - // West - // - Handling of guards of generators + // West + // - Handling of guards of generators case NPC_ARCANE_ABERRATION: case NPC_MANA_REMNANT: PylonGuardJustDied(pCreature); break; - // - InstData settings + // - InstData settings case NPC_TENDRIS_WARPWOOD: SetData(TYPE_WARPWOOD, DONE); break; @@ -300,11 +354,24 @@ void instance_dire_maul::OnCreatureDeath(Creature* pCreature) SetData(TYPE_IMMOLTHAR, DONE); break; - // North - // - Handling of Ogre Boss (Assume boss can be handled in Acid) + // North + // - Handling of Ogre Boss (Assume boss can be handled in Acid) case NPC_KING_GORDOK: SetData(TYPE_KING_GORDOK, DONE); break; + // Handle Ogre guards for Tribute Run chest + case NPC_GUARD_MOLDAR: + SetData(TYPE_MOLDAR, DONE); + break; + case NPC_GUARD_FENGUS: + SetData(TYPE_FENGUS, DONE); + break; + case NPC_GUARD_SLIPKIK: + SetData(TYPE_SLIPKIK, DONE); + break; + case NPC_CAPTAIN_KROMCRUSH: + SetData(TYPE_KROMCRUSH, DONE); + break; } } @@ -320,14 +387,16 @@ void instance_dire_maul::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> - m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5] >> - m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8] >> - m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11]; + m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5] >> + m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8] >> + m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11] >> + m_auiEncounter[12] >> m_auiEncounter[13] >> m_auiEncounter[14] >> + m_auiEncounter[15]; if (m_auiEncounter[TYPE_ALZZIN] >= DONE) - m_bWallDestroyed = true; + m_bWallDestroyed = true; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -336,6 +405,28 @@ void instance_dire_maul::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } +bool instance_dire_maul::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const +{ + switch (uiInstanceConditionId) + { + case INSTANCE_CONDITION_ID_NORMAL_MODE: // No guards alive + case INSTANCE_CONDITION_ID_HARD_MODE: // One guard alive + case INSTANCE_CONDITION_ID_HARD_MODE_2: // Two guards alive + case INSTANCE_CONDITION_ID_HARD_MODE_3: // Three guards alive + case INSTANCE_CONDITION_ID_HARD_MODE_4: // All guards alive + { + uint8 uiTributeRunAliveBosses = (GetData(TYPE_MOLDAR) != DONE ? 1 : 0) + (GetData(TYPE_FENGUS) != DONE ? 1 : 0) + (GetData(TYPE_SLIPKIK) != DONE ? 1 : 0) + + (GetData(TYPE_KROMCRUSH) != DONE ? 1 : 0); + + return uiInstanceConditionId == uiTributeRunAliveBosses; + } + } + + script_error_log("instance_dire_maul::CheckConditionCriteriaMeet called with unsupported Id %u. Called with param plr %s, src %s, condition source type %u", + uiInstanceConditionId, pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", pConditionSource ? pConditionSource->GetGuidStr().c_str() : "NULL", conditionSourceType); + return false; +} + bool instance_dire_maul::CheckAllGeneratorsDestroyed() { if (m_auiEncounter[TYPE_PYLON_1] != DONE || m_auiEncounter[TYPE_PYLON_2] != DONE || m_auiEncounter[TYPE_PYLON_3] != DONE || m_auiEncounter[TYPE_PYLON_4] != DONE || m_auiEncounter[TYPE_PYLON_5] != DONE) @@ -355,7 +446,7 @@ void instance_dire_maul::ProcessForceFieldOpening() return; bool bHasYelled = false; - for (GUIDList::const_iterator itr = m_luiHighborneSummonerGUIDs.begin(); itr != m_luiHighborneSummonerGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiHighborneSummonerGUIDs.begin(); itr != m_luiHighborneSummonerGUIDs.end(); ++itr) { Creature* pSummoner = instance->GetCreature(*itr); @@ -385,7 +476,7 @@ void instance_dire_maul::SortPylonGuards() continue; // Sort all remaining (alive) NPCs to unfinished generators - for (GUIDList::iterator itr = m_lGeneratorGuardGUIDs.begin(); itr != m_lGeneratorGuardGUIDs.end();) + for (GuidList::iterator itr = m_lGeneratorGuardGUIDs.begin(); itr != m_lGeneratorGuardGUIDs.end();) { Creature* pGuard = instance->GetCreature(*itr); if (!pGuard || pGuard->isDead()) // Remove invalid guids and dead guards @@ -394,7 +485,7 @@ void instance_dire_maul::SortPylonGuards() continue; } - if (pGuard->IsWithinDistInMap(pGenerator, 20.0f)) + if (pGuard->IsWithinDist2d(pGenerator->GetPositionX(), pGenerator->GetPositionY(), 20.0f)) { m_sSortedGeneratorGuards[i].insert(pGuard->GetGUIDLow()); m_lGeneratorGuardGUIDs.erase(itr++); diff --git a/scripts/kalimdor/durotar.cpp b/scripts/kalimdor/durotar.cpp index 496ff4f25..d895b8a54 100644 --- a/scripts/kalimdor/durotar.cpp +++ b/scripts/kalimdor/durotar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,33 +43,65 @@ enum GO_LUMBERPILE = 175784, }; -struct MANGOS_DLL_DECL npc_lazy_peonAI : public ScriptedAI +struct npc_lazy_peonAI : public ScriptedAI { - npc_lazy_peonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset (); } + npc_lazy_peonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + m_uiStopSleepingTimer = urand(30000, 120000); // Set on spawn to a potential small timer, to get nice results for initial case + } - uint32 m_uiResetSleepTimer; + uint32 m_uiResetSleepTimer; // Time, until the npc stops harvesting lumber + uint32 m_uiStopSleepingTimer; // Time, until the npcs (re)starts working on its own - void Reset() + void Reset() override { m_uiResetSleepTimer = 0; + m_uiStopSleepingTimer = urand(90000, 120000); // Sleeping aura has only 2min duration } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + // Can also be self invoked for random working + void StartLumbering(Unit* pInvoker) + { + m_uiStopSleepingTimer = 0; + if (GameObject* pLumber = GetClosestGameObjectWithEntry(m_creature, GO_LUMBERPILE, 15.0f)) + { + m_creature->RemoveAurasDueToSpell(SPELL_PEON_SLEEP); + + float fX, fY, fZ; + m_creature->SetWalk(false); + pLumber->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); + + if (pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_PEON_AWAKE_1, m_creature); + ((Player*)pInvoker)->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + else + m_creature->GetMotionMaster()->MovePoint(2, fX, fY, fZ); + } + else + script_error_log("No GameObject of entry %u was found in range or something really bad happened.", GO_LUMBERPILE); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) return; - // ToDo: check the reset timer m_creature->HandleEmote(EMOTE_STATE_WORK_CHOPWOOD); - m_uiResetSleepTimer = 1*MINUTE*IN_MILLISECONDS; + // TODO - random bevahior for self-invoked awakening guesswork + m_uiResetSleepTimer = uiPointId == 1 ? 80000 : urand(30000, 60000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiResetSleepTimer) { if (m_uiResetSleepTimer <= uiDiff) { + DoScriptText(SAY_PEON_AWAKE_2, m_creature); m_creature->HandleEmote(EMOTE_STATE_NONE); EnterEvadeMode(); m_uiResetSleepTimer = 0; @@ -77,6 +109,14 @@ struct MANGOS_DLL_DECL npc_lazy_peonAI : public ScriptedAI else m_uiResetSleepTimer -= uiDiff; } + + if (m_uiStopSleepingTimer) + { + if (m_uiStopSleepingTimer <= uiDiff) + StartLumbering(m_creature); + else + m_uiStopSleepingTimer -= uiDiff; + } } }; @@ -85,29 +125,18 @@ CreatureAI* GetAI_npc_lazy_peon(Creature* pCreature) return new npc_lazy_peonAI(pCreature); } -bool EffectDummyCreature_lazy_peon_awake(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_lazy_peon_awake(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_AWAKEN_PEON && uiEffIndex == EFFECT_INDEX_0) { if (!pCreatureTarget->HasAura(SPELL_PEON_SLEEP) || pCaster->GetTypeId() != TYPEID_PLAYER || pCreatureTarget->GetEntry() != NPC_SLEEPING_PEON) return true; - if (GameObject* pLumber = GetClosestGameObjectWithEntry(pCreatureTarget, GO_LUMBERPILE, 15.0f)) - { - pCreatureTarget->RemoveAurasDueToSpell(SPELL_PEON_SLEEP); - DoScriptText(urand(0, 1) ? SAY_PEON_AWAKE_1 : SAY_PEON_AWAKE_2, pCreatureTarget); - ((Player*)pCaster)->KilledMonsterCredit(pCreatureTarget->GetEntry()); - - float fX, fY, fZ; - pCreatureTarget->SetWalk(false); - pLumber->GetContactPoint(pCreatureTarget, fX, fY, fZ, CONTACT_DISTANCE); - pCreatureTarget->GetMotionMaster()->MovePoint(1, fX, fY, fZ); - } - else - error_log("SD2: No GameObject of entry %u was found in range or something really bad happened.", GO_LUMBERPILE); + if (npc_lazy_peonAI* pPeonAI = dynamic_cast(pCreatureTarget->AI())) + pPeonAI->StartLumbering(pCaster); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } diff --git a/scripts/kalimdor/dustwallow_marsh.cpp b/scripts/kalimdor/dustwallow_marsh.cpp index 044be6d3d..0eef7ff52 100644 --- a/scripts/kalimdor/dustwallow_marsh.cpp +++ b/scripts/kalimdor/dustwallow_marsh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Dustwallow_Marsh SD%Complete: 95 -SDComment: Quest support: 1173, 1273, 1324, 11209, 11180. +SDComment: Quest support: 1173, 1222, 1270, 1273, 1324, 11180, 11198, 11209. SDCategory: Dustwallow Marsh EndScriptData */ @@ -27,10 +27,14 @@ npc_restless_apparition npc_morokk npc_ogron npc_private_hendel +npc_stinky_ignatz +at_nats_landing +boss_tethyr EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "TemporarySummon.h" /*###### ## mobs_risen_husk_spirit @@ -40,13 +44,13 @@ enum { QUEST_WHATS_HAUNTING_WITCH_HILL = 11180, SPELL_SUMMON_RESTLESS_APPARITION = 42511, - SPELL_CONSUME_FLESH = 37933, //Risen Husk - SPELL_INTANGIBLE_PRESENCE = 43127, //Risen Spirit + SPELL_CONSUME_FLESH = 37933, // Risen Husk + SPELL_INTANGIBLE_PRESENCE = 43127, // Risen Spirit NPC_RISEN_HUSK = 23555, NPC_RISEN_SPIRIT = 23554 }; -struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI +struct mobs_risen_husk_spiritAI : public ScriptedAI { mobs_risen_husk_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -55,7 +59,7 @@ struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI Player* m_pCreditPlayer; - void Reset() + void Reset() override { m_uiConsumeFlesh_Timer = 10000; m_uiIntangiblePresence_Timer = 5000; @@ -63,13 +67,13 @@ struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI m_pCreditPlayer = NULL; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (m_pCreditPlayer) - m_pCreditPlayer->KilledMonsterCredit(pSummoned->GetEntry(), pSummoned->GetObjectGuid()); + m_pCreditPlayer->RewardPlayerAndGroupAtEvent(pSummoned->GetEntry(), pSummoned); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; @@ -84,7 +88,7 @@ struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -92,7 +96,7 @@ struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI if (m_uiConsumeFlesh_Timer < uiDiff) { if (m_creature->GetEntry() == NPC_RISEN_HUSK) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CONSUME_FLESH); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONSUME_FLESH); m_uiConsumeFlesh_Timer = 15000; } @@ -102,7 +106,7 @@ struct MANGOS_DLL_DECL mobs_risen_husk_spiritAI : public ScriptedAI if (m_uiIntangiblePresence_Timer < uiDiff) { if (m_creature->GetEntry() == NPC_RISEN_SPIRIT) - DoCastSpellIfCan(m_creature->getVictim(),SPELL_INTANGIBLE_PRESENCE); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_INTANGIBLE_PRESENCE); m_uiIntangiblePresence_Timer = 20000; } @@ -134,25 +138,25 @@ enum SAY_RAND_8 = -1000550 }; -struct MANGOS_DLL_DECL npc_restless_apparitionAI : public ScriptedAI +struct npc_restless_apparitionAI : public ScriptedAI { npc_restless_apparitionAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint32 m_uiTalk_Timer; - void Reset() + void Reset() override { m_uiTalk_Timer = 1000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_uiTalk_Timer) return; if (m_uiTalk_Timer <= uiDiff) { - switch(urand(0, 7)) + switch (urand(0, 7)) { case 0: DoScriptText(SAY_RAND_1, m_creature); break; case 1: DoScriptText(SAY_RAND_2, m_creature); break; @@ -191,7 +195,7 @@ enum FACTION_MOR_RUNNING = 35 }; -struct MANGOS_DLL_DECL npc_morokkAI : public npc_escortAI +struct npc_morokkAI : public npc_escortAI { npc_morokkAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -201,11 +205,11 @@ struct MANGOS_DLL_DECL npc_morokkAI : public npc_escortAI bool m_bIsSuccess; - void Reset() {} + void Reset() override {} - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: SetEscortPaused(true); @@ -222,7 +226,7 @@ struct MANGOS_DLL_DECL npc_morokkAI : public npc_escortAI } } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -233,7 +237,7 @@ struct MANGOS_DLL_DECL npc_morokkAI : public npc_escortAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -252,7 +256,7 @@ struct MANGOS_DLL_DECL npc_morokkAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 /*uiDiff*/) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -339,10 +343,10 @@ enum PHASE_COMPLETE = 3 }; -static float m_afSpawn[] = {-3383.501953f, -3203.383301f, 36.149f}; -static float m_afMoveTo[] = {-3371.414795f, -3212.179932f, 34.210f}; +static float m_afSpawn[] = { -3383.501953f, -3203.383301f, 36.149f}; +static float m_afMoveTo[] = { -3371.414795f, -3212.179932f, 34.210f}; -struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI +struct npc_ogronAI : public npc_escortAI { npc_ogronAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -358,7 +362,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI uint32 m_uiPhaseCounter; uint32 m_uiGlobalTimer; - void Reset() + void Reset() override { m_uiGlobalTimer = 5000; @@ -373,7 +377,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (HasEscortState(STATE_ESCORT_ESCORTING) && pWho->GetEntry() == NPC_REETHE && lCreatureList.empty()) lCreatureList.push_back((Creature*)pWho); @@ -385,7 +389,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI { if (!lCreatureList.empty()) { - for(std::list::iterator itr = lCreatureList.begin(); itr != lCreatureList.end(); ++itr) + for (std::list::iterator itr = lCreatureList.begin(); itr != lCreatureList.end(); ++itr) { if ((*itr)->GetEntry() == uiCreatureEntry && (*itr)->isAlive()) return (*itr); @@ -395,9 +399,9 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI return NULL; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 9: DoScriptText(SAY_OGR_SPOT, m_creature); @@ -412,7 +416,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { lCreatureList.push_back(pSummoned); @@ -424,9 +428,9 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI { if (Creature* pCaldwell = GetCreature(NPC_CALDWELL)) { - //will this conversion work without compile warning/error? + // will this conversion work without compile warning/error? size_t iSize = lCreatureList.size(); - pSummoned->GetMotionMaster()->MoveFollow(pCaldwell, 0.5f, (M_PI/2)*(int)iSize); + pSummoned->GetMotionMaster()->MoveFollow(pCaldwell, 0.5f, (M_PI / 2) * (int)iSize); } } } @@ -435,7 +439,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI { if (!lCreatureList.empty()) { - for(std::list::iterator itr = lCreatureList.begin(); itr != lCreatureList.end(); ++itr) + for (std::list::iterator itr = lCreatureList.begin(); itr != lCreatureList.end(); ++itr) { if ((*itr)->GetEntry() == NPC_REETHE) continue; @@ -449,7 +453,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -459,11 +463,11 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI { m_uiGlobalTimer = 5000; - switch(m_uiPhase) + switch (m_uiPhase) { case PHASE_INTRO: { - switch(m_uiPhaseCounter) + switch (m_uiPhaseCounter) { case 0: if (Creature* pReethe = GetCreature(NPC_REETHE)) @@ -489,10 +493,10 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI if (Creature* pReethe = GetCreature(NPC_REETHE)) DoScriptText(SAY_OGR_RET_HEAR, pReethe); - m_creature->SummonCreature(NPC_CALDWELL, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); - m_creature->SummonCreature(NPC_HALLAN, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); - m_creature->SummonCreature(NPC_SKIRMISHER, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); - m_creature->SummonCreature(NPC_SKIRMISHER, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); + m_creature->SummonCreature(NPC_CALDWELL, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000); + m_creature->SummonCreature(NPC_HALLAN, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000); + m_creature->SummonCreature(NPC_SKIRMISHER, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000); + m_creature->SummonCreature(NPC_SKIRMISHER, m_afSpawn[0], m_afSpawn[1], m_afSpawn[2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000); m_uiPhase = PHASE_GUESTS; break; @@ -501,7 +505,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI } case PHASE_GUESTS: { - switch(m_uiPhaseCounter) + switch (m_uiPhaseCounter) { case 6: if (Creature* pCaldwell = GetCreature(NPC_CALDWELL)) @@ -542,7 +546,7 @@ struct MANGOS_DLL_DECL npc_ogronAI : public npc_escortAI } case PHASE_COMPLETE: { - switch(m_uiPhaseCounter) + switch (m_uiPhaseCounter) { case 12: if (Player* pPlayer = GetPlayerForEscort()) @@ -585,7 +589,7 @@ bool QuestAccept_npc_ogron(Player* pPlayer, Creature* pCreature, const Quest* pQ if (npc_ogronAI* pEscortAI = dynamic_cast(pCreature->AI())) { pEscortAI->Start(false, pPlayer, pQuest, true); - pCreature->setFaction(FACTION_ESCORT_N_FRIEND_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_FRIEND_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_OGR_START, pCreature, pPlayer); } } @@ -611,25 +615,21 @@ enum EMOTE_SURRENDER = -1000415, QUEST_MISSING_DIPLO_PT16 = 1324, - FACTION_HOSTILE = 168, //guessed, may be different + FACTION_HOSTILE = 168, // guessed, may be different - NPC_SENTRY = 5184, //helps hendel - NPC_JAINA = 4968, //appears once hendel gives up + NPC_SENTRY = 5184, // helps hendel + NPC_JAINA = 4968, // appears once hendel gives up NPC_TERVOSH = 4967 }; -//TODO: develop this further, end event not created -struct MANGOS_DLL_DECL npc_private_hendelAI : public ScriptedAI +// TODO: develop this further, end event not created +struct npc_private_hendelAI : public ScriptedAI { npc_private_hendelAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() - { - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - } + void Reset() override {} - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -640,7 +640,7 @@ struct MANGOS_DLL_DECL npc_private_hendelAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { if (uiDamage > m_creature->GetHealth() || m_creature->GetHealthPercent() < 20.0f) { @@ -655,10 +655,10 @@ struct MANGOS_DLL_DECL npc_private_hendelAI : public ScriptedAI } }; -bool QuestAccept_npc_private_hendel(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool QuestAccept_npc_private_hendel(Player* /*pPlayer*/, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_MISSING_DIPLO_PT16) - pCreature->setFaction(FACTION_HOSTILE); + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN); return true; } @@ -668,6 +668,128 @@ CreatureAI* GetAI_npc_private_hendel(Creature* pCreature) return new npc_private_hendelAI(pCreature); } +/*##### +## npc_stinky_ignatz +## TODO Note: Faction change is guessed +#####*/ + +enum +{ + QUEST_ID_STINKYS_ESCAPE_ALLIANCE = 1222, + QUEST_ID_STINKYS_ESCAPE_HORDE = 1270, + + SAY_STINKY_BEGIN = -1000958, + SAY_STINKY_FIRST_STOP = -1000959, + SAY_STINKY_SECOND_STOP = -1001141, + SAY_STINKY_THIRD_STOP_1 = -1001142, + SAY_STINKY_THIRD_STOP_2 = -1001143, + SAY_STINKY_THIRD_STOP_3 = -1001144, + SAY_STINKY_PLANT_GATHERED = -1001145, + SAY_STINKY_END = -1000962, + SAY_STINKY_AGGRO_1 = -1000960, + SAY_STINKY_AGGRO_2 = -1000961, + SAY_STINKY_AGGRO_3 = -1001146, + SAY_STINKY_AGGRO_4 = -1001147, + + GO_BOGBEAN_PLANT = 20939, +}; + +struct npc_stinky_ignatzAI : public npc_escortAI +{ + npc_stinky_ignatzAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + ObjectGuid m_bogbeanPlantGuid; + + void Reset() override {} + + void Aggro(Unit* pWho) override + { + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_STINKY_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_STINKY_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_STINKY_AGGRO_3, m_creature); break; + case 3: DoScriptText(SAY_STINKY_AGGRO_4, m_creature, pWho); break; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_STINKY_BEGIN, m_creature); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 5: + DoScriptText(SAY_STINKY_FIRST_STOP, m_creature); + break; + case 10: + DoScriptText(SAY_STINKY_SECOND_STOP, m_creature); + break; + case 24: + DoScriptText(SAY_STINKY_THIRD_STOP_1, m_creature); + break; + case 25: + DoScriptText(SAY_STINKY_THIRD_STOP_2, m_creature); + if (GameObject* pBogbeanPlant = GetClosestGameObjectWithEntry(m_creature, GO_BOGBEAN_PLANT, DEFAULT_VISIBILITY_DISTANCE)) + { + m_bogbeanPlantGuid = pBogbeanPlant->GetObjectGuid(); + m_creature->SetFacingToObject(pBogbeanPlant); + } + break; + case 26: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_STINKY_THIRD_STOP_3, m_creature, pPlayer); + break; + case 29: + m_creature->HandleEmote(EMOTE_STATE_USESTANDING); + break; + case 30: + DoScriptText(SAY_STINKY_PLANT_GATHERED, m_creature); + break; + case 39: + if (Player* pPlayer = GetPlayerForEscort()) + { + pPlayer->GroupEventHappens(pPlayer->GetTeam() == ALLIANCE ? QUEST_ID_STINKYS_ESCAPE_ALLIANCE : QUEST_ID_STINKYS_ESCAPE_HORDE, m_creature); + DoScriptText(SAY_STINKY_END, m_creature, pPlayer); + } + break; + } + } + + void WaypointStart(uint32 uiPointId) + { + if (uiPointId == 30) + { + if (GameObject* pBogbeanPlant = m_creature->GetMap()->GetGameObject(m_bogbeanPlantGuid)) + pBogbeanPlant->Use(m_creature); + m_bogbeanPlantGuid.Clear(); + m_creature->HandleEmote(EMOTE_ONESHOT_NONE); + } + } +}; + +CreatureAI* GetAI_npc_stinky_ignatz(Creature* pCreature) +{ + return new npc_stinky_ignatzAI(pCreature); +} + +bool QuestAccept_npc_stinky_ignatz(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_STINKYS_ESCAPE_ALLIANCE || pQuest->GetQuestId() == QUEST_ID_STINKYS_ESCAPE_HORDE) + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + /*###### ## at_nats_landing ######*/ @@ -678,14 +800,14 @@ enum NPC_LURKING_SHARK = 23928 }; -bool AreaTrigger_at_nats_landing(Player* pPlayer, const AreaTriggerEntry* pAt) +bool AreaTrigger_at_nats_landing(Player* pPlayer, const AreaTriggerEntry* /*pAt*/) { if (pPlayer->GetQuestStatus(QUEST_NATS_BARGAIN) == QUEST_STATUS_INCOMPLETE && pPlayer->HasAura(SPELL_FISH_PASTE)) { Creature* pShark = GetClosestCreatureWithEntry(pPlayer, NPC_LURKING_SHARK, 20.0f); if (!pShark) - pShark = pPlayer->SummonCreature(NPC_LURKING_SHARK, -4246.243f, -3922.356f, -7.488f, 5.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 100000); + pShark = pPlayer->SummonCreature(NPC_LURKING_SHARK, -4246.243f, -3922.356f, -7.488f, 5.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 100000); pShark->AI()->AttackStart(pPlayer); return false; @@ -693,6 +815,252 @@ bool AreaTrigger_at_nats_landing(Player* pPlayer, const AreaTriggerEntry* pAt) return true; } +/*###### +## boss_tethyr +######*/ + +enum +{ + SPELL_WATER_BOLT = 42574, + SPELL_SPOUT_LEFT = 42581, // triggers 42584 + SPELL_SPOUT_RIGHT = 42582, + SPELL_CANNON_BLAST = 42578, // triggers 42576 + SPELL_CANNON_BLAST_DMG = 42576, + + NPC_TETHYR = 23899, + NPC_THERAMORE_MARKSMAN = 23900, + NPC_THERAMORE_CANNON = 23907, + + GO_COVE_CANNON = 186432, // cast 42578 + QUEST_ID_TETHYR = 11198, + + WORLD_STATE_TETHYR_SHOW = 3083, + WORLD_STATE_TETHYR_COUNT = 3082, + + MAX_MARKSMEN = 12, + PHASE_NORMAL = 1, + PHASE_SPOUT = 2, +}; + +struct boss_tethyrAI : public Scripted_NoMovementAI +{ + boss_tethyrAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + // send world states to player summoner + if (m_creature->IsTemporarySummon()) + m_summonerGuid = ((TemporarySummon*)m_creature)->GetSummonerGuid(); + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_summonerGuid)) + { + pPlayer->SendUpdateWorldState(WORLD_STATE_TETHYR_SHOW, 1); + pPlayer->SendUpdateWorldState(WORLD_STATE_TETHYR_COUNT, MAX_MARKSMEN); + } + + m_creature->SetSwim(true); + Reset(); + } + + ObjectGuid m_summonerGuid; + + uint8 m_uiPhase; + uint8 m_uiMarksmenKilled; + uint32 m_uiWaterBoltTimer; + uint32 m_uiSpoutEndTimer; + + void Reset() override + { + m_uiPhase = PHASE_NORMAL; + m_uiMarksmenKilled = 0; + m_uiWaterBoltTimer = urand(0, 1000); + m_uiSpoutEndTimer = 7000; + } + + void JustReachedHome() override + { + // cleanup + DoEncounterCleanup(); + m_creature->ForcedDespawn(5000); + } + + void JustDied(Unit* /*pVictim*/) override + { + // quest complete and cleanup + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(m_summonerGuid)) + pSummoner->GroupEventHappens(QUEST_ID_TETHYR, m_creature); + + // ToDo: trigger some fireworks! + DoEncounterCleanup(); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType == WAYPOINT_MOTION_TYPE) + { + // start attacking + if (uiPointId == 12) + { + // make cannons usable + std::list lCannonsInRange; + GetGameObjectListWithEntryInGrid(lCannonsInRange, m_creature, GO_COVE_CANNON, 100.0f); + + for (std::list::const_iterator itr = lCannonsInRange.begin(); itr != lCannonsInRange.end(); ++itr) + (*itr)->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + + // attack all marksmen + std::list lMarksmenInRange; + GetCreatureListWithEntryInGrid(lMarksmenInRange, m_creature, NPC_THERAMORE_MARKSMAN, 100.0f); + + for (std::list::const_iterator itr = lMarksmenInRange.begin(); itr != lMarksmenInRange.end(); ++itr) + { + (*itr)->AI()->AttackStart(m_creature); + AttackStart(*itr); + } + } + } + else if (uiMotionType == POINT_MOTION_TYPE) + { + // Spout on cannon point reach + if (uiPointId) + { + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SPOUT_LEFT : SPELL_SPOUT_RIGHT, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + // Remove the target focus + m_creature->SetTargetGuid(ObjectGuid()); + m_uiPhase = PHASE_SPOUT; + } + } + } + } + + void KilledUnit(Unit* pVictim) override + { + // count the marksmen + if (pVictim->GetEntry() != NPC_THERAMORE_MARKSMAN) + return; + + ++m_uiMarksmenKilled; + + // update world state + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(m_summonerGuid)) + { + pSummoner->SendUpdateWorldState(WORLD_STATE_TETHYR_COUNT, MAX_MARKSMEN - m_uiMarksmenKilled); + + // fail quest if all marksmen are killed + if (m_uiMarksmenKilled == MAX_MARKSMEN) + { + pSummoner->FailQuest(QUEST_ID_TETHYR); + EnterEvadeMode(); + } + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // spout on cannon + if (pCaster->GetEntry() == NPC_THERAMORE_CANNON && pSpell->Id == SPELL_CANNON_BLAST_DMG) + { + if (m_uiPhase == PHASE_SPOUT) + return; + + // not all cannons have same distance range + uint8 uiDistMod = pCaster->GetPositionY() > -4650.0f ? 6 : 5; + + float fX, fY, fZ; + pCaster->GetContactPoint(m_creature, fX, fY, fZ, uiDistMod * ATTACK_DISTANCE); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, m_creature->GetPositionZ()); + + m_uiWaterBoltTimer = 10000; + } + } + + // function to cleanup the world states and GO flags + void DoEncounterCleanup() + { + // remove world state + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(m_summonerGuid)) + pSummoner->SendUpdateWorldState(WORLD_STATE_TETHYR_SHOW, 0); + + // reset all cannons + std::list lCannonsInRange; + GetGameObjectListWithEntryInGrid(lCannonsInRange, m_creature, GO_COVE_CANNON, 100.0f); + + for (std::list::const_iterator itr = lCannonsInRange.begin(); itr != lCannonsInRange.end(); ++itr) + (*itr)->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + + // despawn all marksmen + std::list lMarksmenInRange; + GetCreatureListWithEntryInGrid(lMarksmenInRange, m_creature, NPC_THERAMORE_MARKSMAN, 100.0f); + + for (std::list::const_iterator itr = lMarksmenInRange.begin(); itr != lMarksmenInRange.end(); ++itr) + (*itr)->ForcedDespawn(30000); + } + + // Custom threat management + bool SelectCustomHostileTarget() + { + // Not started combat or evading prevented + if (!m_creature->isInCombat() || m_creature->HasAuraType(SPELL_AURA_MOD_TAUNT)) + return false; + + // Check if there are still enemies (marksmen) in the threatList + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if ((*itr)->getUnitGuid().IsCreature()) + return true; + } + + EnterEvadeMode(); + return false; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectCustomHostileTarget()) + return; + + if (m_uiPhase == PHASE_SPOUT) + { + if (m_uiSpoutEndTimer < uiDiff) + { + // Remove rotation auras + m_creature->RemoveAurasDueToSpell(SPELL_SPOUT_LEFT); + m_creature->RemoveAurasDueToSpell(SPELL_SPOUT_RIGHT); + + m_uiPhase = PHASE_NORMAL; + m_uiSpoutEndTimer = 7000; + m_uiWaterBoltTimer = urand(0, 1000); + } + else + m_uiSpoutEndTimer -= uiDiff; + } + else if (m_uiPhase == PHASE_NORMAL) + { + if (m_uiWaterBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_WATER_BOLT) == CAST_OK) + { + // mimic boss turning because of the missing threat system + m_creature->SetTargetGuid(pTarget->GetObjectGuid()); + m_creature->SetInFront(pTarget); + + m_uiWaterBoltTimer = urand(0, 1000); + } + } + } + else + m_uiWaterBoltTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_tethyr(Creature* pCreature) +{ + return new boss_tethyrAI(pCreature); +} + void AddSC_dustwallow_marsh() { Script* pNewScript; @@ -725,8 +1093,19 @@ void AddSC_dustwallow_marsh() pNewScript->pQuestAcceptNPC = &QuestAccept_npc_private_hendel; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_stinky_ignatz"; + pNewScript->GetAI = &GetAI_npc_stinky_ignatz; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_stinky_ignatz; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "at_nats_landing"; pNewScript->pAreaTrigger = &AreaTrigger_at_nats_landing; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_tethyr"; + pNewScript->GetAI = &GetAI_boss_tethyr; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/felwood.cpp b/scripts/kalimdor/felwood.cpp index e4f9e7060..daeca821a 100644 --- a/scripts/kalimdor/felwood.cpp +++ b/scripts/kalimdor/felwood.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,19 +17,21 @@ /* ScriptData SDName: Felwood SD%Complete: 95 -SDComment: Quest support: related to 4101/4102 (To obtain Cenarion Beacon), 4506, 7603, 7603 (Summon Pollo Grande) +SDComment: Quest support: 4261, 4506, 5203, 7603, 7603 (Summon Pollo Grande) SDCategory: Felwood EndScriptData */ /* ContentData npc_kitten -npcs_riverbreeze_and_silversky npc_niby_the_almighty npc_kroshius +npc_captured_arkonarin +npc_arei EndContentData */ #include "precompiled.h" #include "follower_ai.h" +#include "escort_ai.h" #include "ObjectMgr.h" /*#### @@ -50,7 +52,7 @@ enum #define GOSSIP_ITEM_RELEASE "I want to release the corrupted saber to Winna." -struct MANGOS_DLL_DECL npc_kittenAI : public FollowerAI +struct npc_kittenAI : public FollowerAI { npc_kittenAI(Creature* pCreature) : FollowerAI(pCreature) { @@ -62,7 +64,7 @@ struct MANGOS_DLL_DECL npc_kittenAI : public FollowerAI pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - //find a decent way to move to center of moonwell + // find a decent way to move to center of moonwell } m_uiMoonwellCooldown = 7500; @@ -71,11 +73,11 @@ struct MANGOS_DLL_DECL npc_kittenAI : public FollowerAI uint32 m_uiMoonwellCooldown; - void Reset() { } + void Reset() override { } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - //should not have npcflag by default, so set when expected + // should not have npcflag by default, so set when expected if (!m_creature->getVictim() && !m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && HasFollowState(STATE_FOLLOW_INPROGRESS) && pWho->GetEntry() == NPC_WINNA) { if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) @@ -83,7 +85,7 @@ struct MANGOS_DLL_DECL npc_kittenAI : public FollowerAI } } - void UpdateFollowerAI(const uint32 uiDiff) + void UpdateFollowerAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -110,9 +112,9 @@ CreatureAI* GetAI_npc_kitten(Creature* pCreature) return new npc_kittenAI(pCreature); } -bool EffectDummyCreature_npc_kitten(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_kitten(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_CORRUPT_SABER_VISUAL && uiEffIndex == EFFECT_INDEX_0) { // Not nice way, however using UpdateEntry will not be correct. @@ -121,13 +123,13 @@ bool EffectDummyCreature_npc_kitten(Unit* pCaster, uint32 uiSpellId, SpellEffect pCreatureTarget->SetEntry(pTemp->Entry); pCreatureTarget->SetDisplayId(Creature::ChooseDisplayId(pTemp)); pCreatureTarget->SetName(pTemp->Name); - pCreatureTarget->SetFloatValue(OBJECT_FIELD_SCALE_X, pTemp->scale); + pCreatureTarget->SetFloatValue(OBJECT_FIELD_SCALE_X, pTemp->Scale); } if (Unit* pOwner = pCreatureTarget->GetOwner()) DoScriptText(EMOTE_SAB_FOLLOW, pCreatureTarget, pOwner); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } return false; @@ -138,16 +140,16 @@ bool GossipHello_npc_corrupt_saber(Player* pPlayer, Creature* pCreature) if (pPlayer->GetQuestStatus(QUEST_CORRUPT_SABER) == QUEST_STATUS_INCOMPLETE) { if (GetClosestCreatureWithEntry(pCreature, NPC_WINNA, INTERACTION_DISTANCE)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RELEASE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RELEASE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); } pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_corrupt_saber(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_corrupt_saber(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->CLOSE_GOSSIP_MENU(); @@ -160,65 +162,6 @@ bool GossipSelect_npc_corrupt_saber(Player* pPlayer, Creature* pCreature, uint32 return true; } -/*###### -## npcs_riverbreeze_and_silversky -######*/ - -enum -{ - QUEST_CLEANSING_FELWOOD_A = 4101, - QUEST_CLEANSING_FELWOOD_H = 4102, - - NPC_ARATHANDIS_SILVERSKY = 9528, - NPC_MAYBESS_RIVERBREEZE = 9529, - - SPELL_CENARION_BEACON = 15120 -}; - -#define GOSSIP_ITEM_BEACON "Please make me a Cenarion Beacon" - -bool GossipHello_npcs_riverbreeze_and_silversky(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - switch (pCreature->GetEntry()) - { - case NPC_ARATHANDIS_SILVERSKY: - if (pPlayer->GetQuestRewardStatus(QUEST_CLEANSING_FELWOOD_A)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEACON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(2848, pCreature->GetObjectGuid()); - }else if (pPlayer->GetTeam() == HORDE) - pPlayer->SEND_GOSSIP_MENU(2845, pCreature->GetObjectGuid()); - else - pPlayer->SEND_GOSSIP_MENU(2844, pCreature->GetObjectGuid()); - break; - case NPC_MAYBESS_RIVERBREEZE: - if (pPlayer->GetQuestRewardStatus(QUEST_CLEANSING_FELWOOD_H)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEACON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(2849, pCreature->GetObjectGuid()); - }else if (pPlayer->GetTeam() == ALLIANCE) - pPlayer->SEND_GOSSIP_MENU(2843, pCreature->GetObjectGuid()); - else - pPlayer->SEND_GOSSIP_MENU(2842, pCreature->GetObjectGuid()); - break; - } - - return true; -} - -bool GossipSelect_npcs_riverbreeze_and_silversky(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer, SPELL_CENARION_BEACON, false); - } - return true; -} - /*###### ## npc_niby_the_almighty (summons el pollo grande) ######*/ @@ -238,16 +181,16 @@ enum SAY_NIBY_3 = -1000570 }; -struct MANGOS_DLL_DECL npc_niby_the_almightyAI : public ScriptedAI +struct npc_niby_the_almightyAI : public ScriptedAI { - npc_niby_the_almightyAI(Creature* pCreature) : ScriptedAI(pCreature){ Reset(); } + npc_niby_the_almightyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiSummonTimer; uint8 m_uiSpeech; bool m_bEventStarted; - void Reset() + void Reset() override { m_uiSummonTimer = 500; m_uiSpeech = 0; @@ -262,7 +205,7 @@ struct MANGOS_DLL_DECL npc_niby_the_almightyAI : public ScriptedAI m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bEventStarted) { @@ -294,7 +237,7 @@ struct MANGOS_DLL_DECL npc_niby_the_almightyAI : public ScriptedAI } else { - //Skip Speech 5 + // Skip Speech 5 m_uiSummonTimer = 40000; ++m_uiSpeech; } @@ -322,7 +265,7 @@ CreatureAI* GetAI_npc_niby_the_almighty(Creature* pCreature) return new npc_niby_the_almightyAI(pCreature); } -bool QuestRewarded_npc_niby_the_almighty(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool QuestRewarded_npc_niby_the_almighty(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) { if (pQuest->GetQuestId() == QUEST_KROSHIUS) { @@ -347,7 +290,7 @@ enum FACTION_HOSTILE = 16, }; -struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI +struct npc_kroshiusAI : public ScriptedAI { npc_kroshiusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -361,19 +304,13 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI uint8 m_uiPhase; - void Reset() + void Reset() override { m_uiKnockBackTimer = urand(5000, 8000); m_playerGuid.Clear(); if (!m_uiPhase) - { - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - // TODO: Workaround? till better solution - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - } } void DoRevive(Player* pSource) @@ -388,12 +325,12 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI // TODO: A visual Flame Circle around the mob still missing } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { m_uiPhase = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_uiPhase) return; @@ -404,7 +341,7 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI { switch (m_uiPhase) { - case 1: // Revived + case 1: // Revived m_creature->SetStandState(UNIT_STAND_STATE_STAND); m_uiPhaseTimer = 1000; break; @@ -412,11 +349,8 @@ struct MANGOS_DLL_DECL npc_kroshiusAI : public ScriptedAI DoScriptText(SAY_KROSHIUS_REVIVE, m_creature); m_uiPhaseTimer = 3500; break; - case 3: // Attack - m_creature->setFaction(FACTION_HOSTILE); - // TODO workaround will better idea - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + case 3: // Attack + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_COMBAT_STOP | TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_OOC_NOT_ATTACK | TEMPFACTION_TOGGLE_PASSIVE); if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { if (m_creature->IsWithinDistInMap(pPlayer, 30.0f)) @@ -452,7 +386,7 @@ CreatureAI* GetAI_npc_kroshius(Creature* pCreature) return new npc_kroshiusAI(pCreature); } -bool ProcessEventId_npc_kroshius(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_npc_kroshius(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) { if (uiEventId == EVENT_KROSHIUS_REVIVE) { @@ -470,6 +404,379 @@ bool ProcessEventId_npc_kroshius(uint32 uiEventId, Object* pSource, Object* pTar return false; } +/*#### +# npc_captured_arkonarin +####*/ + +enum +{ + SAY_ESCORT_START = -1001148, + SAY_FIRST_STOP = -1001149, + SAY_SECOND_STOP = -1001150, + SAY_AGGRO = -1001151, + SAY_FOUND_EQUIPMENT = -1001152, + SAY_ESCAPE_DEMONS = -1001153, + SAY_FRESH_AIR = -1001154, + SAY_TREY_BETRAYER = -1001155, + SAY_TREY = -1001156, + SAY_TREY_ATTACK = -1001157, + SAY_ESCORT_COMPLETE = -1001158, + + SPELL_STRENGTH_ARKONARIN = 18163, + SPELL_MORTAL_STRIKE = 16856, + SPELL_CLEAVE = 15496, + + QUEST_ID_RESCUE_JAEDENAR = 5203, + NPC_JAEDENAR_LEGIONNAIRE = 9862, + NPC_SPIRT_TREY = 11141, + NPC_ARKONARIN = 11018, + GO_ARKONARIN_CHEST = 176225, + GO_ARKONARIN_CAGE = 176306, +}; + +struct npc_captured_arkonarinAI : public npc_escortAI +{ + npc_captured_arkonarinAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + ObjectGuid m_treyGuid; + + bool m_bCanAttack; + + uint32 m_uiMortalStrikeTimer; + uint32 m_uiCleaveTimer; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + m_bCanAttack = false; + + m_uiMortalStrikeTimer = urand(5000, 7000); + m_uiCleaveTimer = urand(1000, 4000); + } + + void Aggro(Unit* pWho) override + { + if (pWho->GetEntry() == NPC_SPIRT_TREY) + DoScriptText(SAY_TREY_ATTACK, m_creature); + else if (roll_chance_i(25)) + DoScriptText(SAY_AGGRO, m_creature, pWho); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_JAEDENAR_LEGIONNAIRE) + pSummoned->AI()->AttackStart(m_creature); + else if (pSummoned->GetEntry() == NPC_SPIRT_TREY) + { + DoScriptText(SAY_TREY_BETRAYER, pSummoned); + m_treyGuid = pSummoned->GetObjectGuid(); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + + if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_ARKONARIN_CAGE, 5.0f)) + pCage->Use(m_creature); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_ESCORT_START, m_creature, pPlayer); + break; + case 14: + DoScriptText(SAY_FIRST_STOP, m_creature); + break; + case 34: + DoScriptText(SAY_SECOND_STOP, m_creature); + SetRun(); + break; + case 38: + if (GameObject* pChest = GetClosestGameObjectWithEntry(m_creature, GO_ARKONARIN_CHEST, 5.0f)) + pChest->Use(m_creature); + m_creature->HandleEmote(EMOTE_ONESHOT_KNEEL); + break; + case 39: + DoCastSpellIfCan(m_creature, SPELL_STRENGTH_ARKONARIN); + break; + case 40: + m_creature->UpdateEntry(NPC_ARKONARIN); + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + m_bCanAttack = true; + DoScriptText(SAY_FOUND_EQUIPMENT, m_creature); + break; + case 41: + DoScriptText(SAY_ESCAPE_DEMONS, m_creature); + m_creature->SummonCreature(NPC_JAEDENAR_LEGIONNAIRE, 5082.068f, -490.084f, 296.856f, 5.15f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_JAEDENAR_LEGIONNAIRE, 5084.135f, -489.187f, 296.832f, 5.15f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_JAEDENAR_LEGIONNAIRE, 5085.676f, -488.518f, 296.824f, 5.15f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 43: + SetRun(false); + break; + case 104: + DoScriptText(SAY_FRESH_AIR, m_creature); + break; + case 105: + m_creature->SummonCreature(NPC_SPIRT_TREY, 4844.839f, -395.763f, 350.603f, 6.25f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 106: + DoScriptText(SAY_TREY, m_creature); + break; + case 107: + if (Creature* pTrey = m_creature->GetMap()->GetCreature(m_treyGuid)) + AttackStart(pTrey); + break; + case 108: + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + DoScriptText(SAY_ESCORT_COMPLETE, m_creature); + break; + case 109: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_RESCUE_JAEDENAR, m_creature); + SetRun(); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bCanAttack) + { + if (m_uiMortalStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiMortalStrikeTimer = urand(7000, 10000); + } + else + m_uiMortalStrikeTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(3000, 6000); + } + else + m_uiCleaveTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_captured_arkonarin(Creature* pCreature) +{ + return new npc_captured_arkonarinAI(pCreature); +} + +bool QuestAccept_npc_captured_arkonarin(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_RESCUE_JAEDENAR) + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + +/*#### +# npc_arei +####*/ + +enum +{ + SAY_AREI_ESCORT_START = -1001159, + SAY_ATTACK_IRONTREE = -1001160, + SAY_ATTACK_TOXIC_HORROR = -1001161, + SAY_EXIT_WOODS = -1001162, + SAY_CLEAR_PATH = -1001163, + SAY_ASHENVALE = -1001164, + SAY_TRANSFORM = -1001165, + SAY_LIFT_CURSE = -1001166, + SAY_AREI_ESCORT_COMPLETE = -1001167, + + SPELL_WITHER_STRIKE = 5337, + SPELL_AREI_TRANSFORM = 14888, + + NPC_AREI = 9598, + NPC_TOXIC_HORROR = 7132, + NPC_IRONTREE_WANDERER = 7138, + NPC_IRONTREE_STOMPER = 7139, + QUEST_ID_ANCIENT_SPIRIT = 4261, +}; + +static const DialogueEntry aEpilogDialogue[] = +{ + {SAY_CLEAR_PATH, NPC_AREI, 4000}, + {SPELL_WITHER_STRIKE, 0, 5000}, + {SAY_TRANSFORM, NPC_AREI, 3000}, + {SPELL_AREI_TRANSFORM, 0, 7000}, + {QUEST_ID_ANCIENT_SPIRIT, 0, 0}, + {0, 0, 0}, +}; + +struct npc_areiAI : public npc_escortAI, private DialogueHelper +{ + npc_areiAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aEpilogDialogue) + { + m_bAggroIrontree = false; + m_bAggroHorror = false; + Reset(); + } + + uint32 m_uiWitherStrikeTimer; + + bool m_bAggroIrontree; + bool m_bAggroHorror; + + GuidList m_lSummonsGuids; + + void Reset() override + { + m_uiWitherStrikeTimer = urand(1000, 4000); + } + + void Aggro(Unit* pWho) override + { + if ((pWho->GetEntry() == NPC_IRONTREE_WANDERER || pWho->GetEntry() == NPC_IRONTREE_STOMPER) && !m_bAggroIrontree) + { + DoScriptText(SAY_ATTACK_IRONTREE, m_creature); + m_bAggroIrontree = true; + } + else if (pWho->GetEntry() == NPC_TOXIC_HORROR && ! m_bAggroHorror) + { + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_ATTACK_TOXIC_HORROR, m_creature, pPlayer); + m_bAggroHorror = true; + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_IRONTREE_STOMPER: + DoScriptText(SAY_EXIT_WOODS, m_creature, pSummoned); + // no break; + case NPC_IRONTREE_WANDERER: + pSummoned->AI()->AttackStart(m_creature); + m_lSummonsGuids.push_back(pSummoned->GetObjectGuid()); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_IRONTREE_STOMPER || pSummoned->GetEntry() == NPC_IRONTREE_WANDERER) + { + m_lSummonsGuids.remove(pSummoned->GetObjectGuid()); + + if (m_lSummonsGuids.empty()) + StartNextDialogueText(SAY_CLEAR_PATH); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_AREI_ESCORT_START, m_creature, pInvoker); + + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(true, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } + } + + void WaypointReached(uint32 uiPointId) override + { + if (uiPointId == 36) + { + SetEscortPaused(true); + + m_creature->SummonCreature(NPC_IRONTREE_STOMPER, 6573.321f, -1195.213f, 442.489f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_IRONTREE_WANDERER, 6573.240f, -1213.475f, 443.643f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_IRONTREE_WANDERER, 6583.354f, -1209.811f, 444.769f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_AREI) + return m_creature; + + return NULL; + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case SPELL_WITHER_STRIKE: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_ASHENVALE, m_creature, pPlayer); + break; + case SPELL_AREI_TRANSFORM: + DoCastSpellIfCan(m_creature, SPELL_AREI_TRANSFORM); + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_LIFT_CURSE, m_creature, pPlayer); + break; + case QUEST_ID_ANCIENT_SPIRIT: + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_AREI_ESCORT_COMPLETE, m_creature, pPlayer); + pPlayer->GroupEventHappens(QUEST_ID_ANCIENT_SPIRIT, m_creature); + m_creature->ForcedDespawn(10000); + } + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiWitherStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_WITHER_STRIKE) == CAST_OK) + m_uiWitherStrikeTimer = urand(3000, 6000); + } + else + m_uiWitherStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_arei(Creature* pCreature) +{ + return new npc_areiAI(pCreature); +} + +bool QuestAccept_npc_arei(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_ANCIENT_SPIRIT) + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + + return true; +} + void AddSC_felwood() { Script* pNewScript; @@ -486,12 +793,6 @@ void AddSC_felwood() pNewScript->pGossipSelect = &GossipSelect_npc_corrupt_saber; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npcs_riverbreeze_and_silversky"; - pNewScript->pGossipHello = &GossipHello_npcs_riverbreeze_and_silversky; - pNewScript->pGossipSelect = &GossipSelect_npcs_riverbreeze_and_silversky; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_niby_the_almighty"; pNewScript->GetAI = &GetAI_npc_niby_the_almighty; @@ -503,4 +804,16 @@ void AddSC_felwood() pNewScript->GetAI = &GetAI_npc_kroshius; pNewScript->pProcessEventId = &ProcessEventId_npc_kroshius; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_captured_arkonarin"; + pNewScript->GetAI = &GetAI_npc_captured_arkonarin; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_captured_arkonarin; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_arei"; + pNewScript->GetAI = &GetAI_npc_arei; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_arei; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/feralas.cpp b/scripts/kalimdor/feralas.cpp index cf95c078c..11b64d361 100644 --- a/scripts/kalimdor/feralas.cpp +++ b/scripts/kalimdor/feralas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,40 +17,18 @@ /* ScriptData SDName: Feralas SD%Complete: 100 -SDComment: Quest support: 3520, 2767. Special vendor Gregan Brewspewer +SDComment: Quest support: 2767, 2845. SDCategory: Feralas EndScriptData */ +/* ContentData +npc_oox22fe +npc_shay_leafrunner +EndContentData */ + #include "precompiled.h" #include "escort_ai.h" - -/*###### -## npc_gregan_brewspewer -######*/ - -bool GossipHello_npc_gregan_brewspewer(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pCreature->isVendor() && pPlayer->GetQuestStatus(3909) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Buy somethin', will ya?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(2433, pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_gregan_brewspewer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(2434, pCreature->GetObjectGuid()); - } - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - return true; -} +#include "follower_ai.h" /*###### ## npc_oox22fe @@ -74,38 +52,38 @@ enum QUEST_RESCUE_OOX22FE = 2767 }; -struct MANGOS_DLL_DECL npc_oox22feAI : public npc_escortAI +struct npc_oox22feAI : public npc_escortAI { npc_oox22feAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 i) override { switch (i) { - // First Ambush(3 Yetis) + // First Ambush(3 Yetis) case 11: - DoScriptText(SAY_OOX_AMBUSH,m_creature); + DoScriptText(SAY_OOX_AMBUSH, m_creature); m_creature->SummonCreature(NPC_YETI, -4841.01f, 1593.91f, 73.42f, 3.98f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_YETI, -4837.61f, 1568.58f, 78.21f, 3.13f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_YETI, -4841.89f, 1569.95f, 76.53f, 0.68f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; - //Second Ambush(3 Gorillas) + // Second Ambush(3 Gorillas) case 21: - DoScriptText(SAY_OOX_AMBUSH,m_creature); + DoScriptText(SAY_OOX_AMBUSH, m_creature); m_creature->SummonCreature(NPC_GORILLA, -4595.81f, 2005.99f, 53.08f, 3.74f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_GORILLA, -4597.53f, 2008.31f, 52.70f, 3.78f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_GORILLA, -4599.37f, 2010.59f, 52.77f, 3.84f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; - //Third Ambush(4 Gnolls) + // Third Ambush(4 Gnolls) case 30: - DoScriptText(SAY_OOX_AMBUSH,m_creature); + DoScriptText(SAY_OOX_AMBUSH, m_creature); m_creature->SummonCreature(NPC_WOODPAW_REAVER, -4425.14f, 2075.87f, 47.77f, 3.77f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_WOODPAW_BRUTE , -4426.68f, 2077.98f, 47.57f, 3.77f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_WOODPAW_MYSTIC, -4428.33f, 2080.24f, 47.43f, 3.87f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); m_creature->SummonCreature(NPC_WOODPAW_ALPHA , -4430.04f, 2075.54f, 46.83f, 3.81f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; case 37: - DoScriptText(SAY_OOX_END,m_creature); + DoScriptText(SAY_OOX_END, m_creature); // Award quest credit if (Player* pPlayer = GetPlayerForEscort()) pPlayer->GroupEventHappens(QUEST_RESCUE_OOX22FE, m_creature); @@ -113,23 +91,23 @@ struct MANGOS_DLL_DECL npc_oox22feAI : public npc_escortAI } } - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) m_creature->SetStandState(UNIT_STAND_STATE_DEAD); } - void Aggro(Unit* who) + void Aggro(Unit* /*who*/) override { - //For an small probability the npc says something when he get aggro - switch(urand(0, 9)) + // For an small probability the npc says something when he get aggro + switch (urand(0, 9)) { - case 0: DoScriptText(SAY_OOX_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_OOX_AGGRO2, m_creature); break; + case 0: DoScriptText(SAY_OOX_AGGRO1, m_creature); break; + case 1: DoScriptText(SAY_OOX_AGGRO2, m_creature); break; } } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* summoned) override { summoned->AI()->AttackStart(m_creature); } @@ -145,14 +123,14 @@ bool QuestAccept_npc_oox22fe(Player* pPlayer, Creature* pCreature, const Quest* if (pQuest->GetQuestId() == QUEST_RESCUE_OOX22FE) { DoScriptText(SAY_OOX_START, pCreature); - //change that the npc is not lying dead on the ground + // change that the npc is not lying dead on the ground pCreature->SetStandState(UNIT_STAND_STATE_STAND); if (pPlayer->GetTeam() == ALLIANCE) - pCreature->setFaction(FACTION_ESCORT_A_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (pPlayer->GetTeam() == HORDE) - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_oox22feAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -161,32 +139,170 @@ bool QuestAccept_npc_oox22fe(Player* pPlayer, Creature* pCreature, const Quest* } /*###### -## npc_screecher_spirit +## npc_shay_leafrunner ######*/ -bool GossipHello_npc_screecher_spirit(Player* pPlayer, Creature* pCreature) +enum { - pPlayer->SEND_GOSSIP_MENU(2039, pCreature->GetObjectGuid()); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SAY_ESCORT_START = -1001106, + SAY_WANDER_1 = -1001107, + SAY_WANDER_2 = -1001108, + SAY_WANDER_3 = -1001109, + SAY_WANDER_4 = -1001110, + SAY_WANDER_DONE_1 = -1001111, + SAY_WANDER_DONE_2 = -1001112, + SAY_WANDER_DONE_3 = -1001113, + EMOTE_WANDER = -1001114, + SAY_EVENT_COMPLETE_1 = -1001115, + SAY_EVENT_COMPLETE_2 = -1001116, + + SPELL_SHAYS_BELL = 11402, + NPC_ROCKBITER = 7765, + QUEST_ID_WANDERING_SHAY = 2845, +}; +struct npc_shay_leafrunnerAI : public FollowerAI +{ + npc_shay_leafrunnerAI(Creature* pCreature) : FollowerAI(pCreature) + { + m_uiWanderTimer = 0; + Reset(); + } + + uint32 m_uiWanderTimer; + bool m_bIsRecalled; + bool m_bIsComplete; + + void Reset() override + { + m_bIsRecalled = false; + m_bIsComplete = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + FollowerAI::MoveInLineOfSight(pWho); + + if (!m_bIsComplete && pWho->GetEntry() == NPC_ROCKBITER && m_creature->IsWithinDistInMap(pWho, 20.0f)) + { + Player* pPlayer = GetLeaderForFollower(); + if (!pPlayer) + return; + + DoScriptText(SAY_EVENT_COMPLETE_1, m_creature); + DoScriptText(SAY_EVENT_COMPLETE_2, pWho); + + // complete quest + pPlayer->GroupEventHappens(QUEST_ID_WANDERING_SHAY, m_creature); + SetFollowComplete(true); + m_creature->ForcedDespawn(30000); + m_bIsComplete = true; + m_uiWanderTimer = 0; + + // move to Rockbiter + float fX, fY, fZ; + pWho->GetContactPoint(m_creature, fX, fY, fZ, INTERACTION_DISTANCE); + m_creature->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + else if (m_bIsRecalled && pWho->GetTypeId() == TYPEID_PLAYER && pWho->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) + { + m_uiWanderTimer = 60000; + m_bIsRecalled = false; + + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_WANDER_DONE_1, m_creature); break; + case 1: DoScriptText(SAY_WANDER_DONE_2, m_creature); break; + case 2: DoScriptText(SAY_WANDER_DONE_3, m_creature); break; + } + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + // start following + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + StartFollow((Player*)pInvoker, 0, GetQuestTemplateStore(uiMiscValue)); + m_uiWanderTimer = 30000; + } + else if (eventType == AI_EVENT_CUSTOM_A) + { + // resume following + m_bIsRecalled = true; + SetFollowPaused(false); + } + } + + void UpdateFollowerAI(const uint32 uiDiff) + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + if (m_uiWanderTimer) + { + if (m_uiWanderTimer <= uiDiff) + { + // set follow paused and wander in a random point + SetFollowPaused(true); + DoScriptText(EMOTE_WANDER, m_creature); + m_uiWanderTimer = 0; + + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_WANDER_1, m_creature); break; + case 1: DoScriptText(SAY_WANDER_2, m_creature); break; + case 2: DoScriptText(SAY_WANDER_3, m_creature); break; + case 3: DoScriptText(SAY_WANDER_4, m_creature); break; + } + + float fX, fY, fZ; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, frand(25.0f, 40.0f), frand(0, 2 * M_PI_F)); + m_creature->GetMotionMaster()->MoveRandomAroundPoint(fX, fY, fZ, 20.0f); + } + else + m_uiWanderTimer -= uiDiff; + } + + return; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_shay_leafrunner(Creature* pCreature) +{ + return new npc_shay_leafrunnerAI(pCreature); +} + +bool QuestAccept_npc_shay_leafrunner(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_WANDERING_SHAY) + { + DoScriptText(SAY_ESCORT_START, pCreature); + pCreature->AI()->SendAIEvent(AI_EVENT_START_EVENT, pPlayer, pCreature, pQuest->GetQuestId()); + } return true; } -/*###### -## AddSC -######*/ +bool EffectDummyCreature_npc_shay_leafrunner(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_SHAYS_BELL && uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() != TYPEID_PLAYER) + return true; + + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + return true; + } + + return false; +} void AddSC_feralas() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_gregan_brewspewer"; - pNewScript->pGossipHello = &GossipHello_npc_gregan_brewspewer; - pNewScript->pGossipSelect = &GossipSelect_npc_gregan_brewspewer; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_oox22fe"; pNewScript->GetAI = &GetAI_npc_oox22fe; @@ -194,7 +310,9 @@ void AddSC_feralas() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_screecher_spirit"; - pNewScript->pGossipHello = &GossipHello_npc_screecher_spirit; + pNewScript->Name = "npc_shay_leafrunner"; + pNewScript->GetAI = &GetAI_npc_shay_leafrunner; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_shay_leafrunner; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_shay_leafrunner; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp b/scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp deleted file mode 100644 index b2238b811..000000000 --- a/scripts/kalimdor/maraudon/boss_celebras_the_cursed.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Celebras_the_Cursed -SD%Complete: 100 -SDComment: -SDCategory: Maraudon -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_WRATH 21807 -#define SPELL_ENTANGLINGROOTS 12747 -#define SPELL_CORRUPT_FORCES 21968 - -struct MANGOS_DLL_DECL celebras_the_cursedAI : public ScriptedAI -{ - celebras_the_cursedAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Wrath_Timer; - uint32 EntanglingRoots_Timer; - uint32 CorruptForces_Timer; - - void Reset() - { - Wrath_Timer = 8000; - EntanglingRoots_Timer = 2000; - CorruptForces_Timer = 30000; - } - - void JustDied(Unit* Killer) - { - m_creature->SummonCreature(13716, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 600000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Wrath - if (Wrath_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - DoCastSpellIfCan(target,SPELL_WRATH); - Wrath_Timer = 8000; - }else Wrath_Timer -= diff; - - //EntanglingRoots - if (EntanglingRoots_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ENTANGLINGROOTS); - EntanglingRoots_Timer = 20000; - }else EntanglingRoots_Timer -= diff; - - //CorruptForces - if (CorruptForces_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature,SPELL_CORRUPT_FORCES); - CorruptForces_Timer = 20000; - }else CorruptForces_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_celebras_the_cursed(Creature* pCreature) -{ - return new celebras_the_cursedAI(pCreature); -} - -void AddSC_boss_celebras_the_cursed() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "celebras_the_cursed"; - pNewScript->GetAI = &GetAI_celebras_the_cursed; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/maraudon/boss_landslide.cpp b/scripts/kalimdor/maraudon/boss_landslide.cpp deleted file mode 100644 index 47bf75dd8..000000000 --- a/scripts/kalimdor/maraudon/boss_landslide.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Landslide -SD%Complete: 100 -SDComment: -SDCategory: Maraudon -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_KNOCKAWAY 18670 -#define SPELL_TRAMPLE 5568 -#define SPELL_LANDSLIDE 21808 - -struct MANGOS_DLL_DECL boss_landslideAI : public ScriptedAI -{ - boss_landslideAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 KnockAway_Timer; - uint32 Trample_Timer; - uint32 Landslide_Timer; - - void Reset() - { - KnockAway_Timer = 8000; - Trample_Timer = 2000; - Landslide_Timer = 0; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //KnockAway_Timer - if (KnockAway_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCKAWAY); - KnockAway_Timer = 15000; - }else KnockAway_Timer -= diff; - - //Trample_Timer - if (Trample_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_TRAMPLE); - Trample_Timer = 8000; - }else Trample_Timer -= diff; - - //Landslide - if (m_creature->GetHealthPercent() < 50.0f) - { - if (Landslide_Timer < diff) - { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature,SPELL_LANDSLIDE); - Landslide_Timer = 60000; - } else Landslide_Timer -= diff; - } - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_landslide(Creature* pCreature) -{ - return new boss_landslideAI(pCreature); -} - -void AddSC_boss_landslide() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_landslide"; - pNewScript->GetAI = &GetAI_boss_landslide; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/maraudon/boss_noxxion.cpp b/scripts/kalimdor/maraudon/boss_noxxion.cpp index 238744f14..3e4606523 100644 --- a/scripts/kalimdor/maraudon/boss_noxxion.cpp +++ b/scripts/kalimdor/maraudon/boss_noxxion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,7 +31,7 @@ enum SPELL_NOXXION_SPAWNS_SUMMON = 21707, }; -struct MANGOS_DLL_DECL boss_noxxionAI : public ScriptedAI +struct boss_noxxionAI : public ScriptedAI { boss_noxxionAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -39,20 +39,20 @@ struct MANGOS_DLL_DECL boss_noxxionAI : public ScriptedAI uint32 m_uiUppercutTimer; uint32 m_uiSummonTimer; - void Reset() + void Reset() override { m_uiToxicVolleyTimer = 7000; m_uiUppercutTimer = 16000; m_uiSummonTimer = 19000; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/kalimdor/maraudon/boss_princess_theradras.cpp b/scripts/kalimdor/maraudon/boss_princess_theradras.cpp deleted file mode 100644 index 3119cac74..000000000 --- a/scripts/kalimdor/maraudon/boss_princess_theradras.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Princess_Theradras -SD%Complete: 100 -SDComment: -SDCategory: Maraudon -EndScriptData */ - -#include "precompiled.h" - -#define SPELL_DUSTFIELD 21909 -#define SPELL_BOULDER 21832 -#define SPELL_THRASH 3391 -#define SPELL_REPULSIVEGAZE 21869 - -struct MANGOS_DLL_DECL boss_ptheradrasAI : public ScriptedAI -{ - boss_ptheradrasAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Dustfield_Timer; - uint32 Boulder_Timer; - uint32 Thrash_Timer; - uint32 RepulsiveGaze_Timer; - - void Reset() - { - Dustfield_Timer = 8000; - Boulder_Timer = 2000; - Thrash_Timer = 5000; - RepulsiveGaze_Timer = 23000; - } - - void JustDied(Unit* Killer) - { - m_creature->SummonCreature(12238,28.067f, 61.875f, -123.405f, 4.67f, TEMPSUMMON_TIMED_DESPAWN, 600000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Dustfield_Timer - if (Dustfield_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_DUSTFIELD); - Dustfield_Timer = 14000; - }else Dustfield_Timer -= diff; - - //Boulder_Timer - if (Boulder_Timer < diff) - { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - DoCastSpellIfCan(target,SPELL_BOULDER); - Boulder_Timer = 10000; - }else Boulder_Timer -= diff; - - //RepulsiveGaze_Timer - if (RepulsiveGaze_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_REPULSIVEGAZE); - RepulsiveGaze_Timer = 20000; - }else RepulsiveGaze_Timer -= diff; - - //Thrash_Timer - if (Thrash_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_THRASH); - Thrash_Timer = 18000; - }else Thrash_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_ptheradras(Creature* pCreature) -{ - return new boss_ptheradrasAI(pCreature); -} - -void AddSC_boss_ptheradras() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_princess_theradras"; - pNewScript->GetAI = &GetAI_boss_ptheradras; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/moonglade.cpp b/scripts/kalimdor/moonglade.cpp index 3ccf1e020..2a9964eed 100644 --- a/scripts/kalimdor/moonglade.cpp +++ b/scripts/kalimdor/moonglade.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,15 +17,12 @@ /* ScriptData SDName: Moonglade SD%Complete: 100 -SDComment: Quest support: 30, 272, 5929, 5930, 8736, 10965. Special Flight Paths for Druid class. +SDComment: Quest support: 8736, 10965. SDCategory: Moonglade EndScriptData */ /* ContentData -npc_bunthen_plainswind npc_clintar_dw_spirit -npc_great_bear_spirit -npc_silva_filnaveth npc_keeper_remulos boss_eranikus EndContentData */ @@ -35,65 +32,6 @@ EndContentData */ #include "ObjectMgr.h" /*###### -## npc_bunthen_plainswind -######*/ - -enum -{ - QUEST_SEA_LION_HORDE = 30, - QUEST_SEA_LION_ALLY = 272, - TAXI_PATH_ID_ALLY = 315, - TAXI_PATH_ID_HORDE = 316 -}; - -#define GOSSIP_ITEM_THUNDER "I'd like to fly to Thunder Bluff." -#define GOSSIP_ITEM_AQ_END "Do you know where I can find Half Pendant of Aquatic Endurance?" - -bool GossipHello_npc_bunthen_plainswind(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->getClass() != CLASS_DRUID) - pPlayer->SEND_GOSSIP_MENU(4916, pCreature->GetObjectGuid()); - else if (pPlayer->GetTeam() != HORDE) - { - if (pPlayer->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AQ_END, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - pPlayer->SEND_GOSSIP_MENU(4917, pCreature->GetObjectGuid()); - } - else if (pPlayer->getClass() == CLASS_DRUID && pPlayer->GetTeam() == HORDE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_THUNDER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if (pPlayer->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AQ_END, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - pPlayer->SEND_GOSSIP_MENU(4918, pCreature->GetObjectGuid()); - } - return true; -} - -bool GossipSelect_npc_bunthen_plainswind(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->CLOSE_GOSSIP_MENU(); - - if (pPlayer->getClass() == CLASS_DRUID && pPlayer->GetTeam() == HORDE) - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_HORDE); - - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->SEND_GOSSIP_MENU(5373, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(5376, pCreature->GetObjectGuid()); - break; - } - return true; -} - -/*#### # npc_clintar_dw_spirit ####*/ @@ -114,19 +52,19 @@ enum NPC_ASPECT_OF_RAVEN = 22915, }; -struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI +struct npc_clintar_dw_spiritAI : public npc_escortAI { npc_clintar_dw_spiritAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 i) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - //visual details here probably need refinement - switch(i) + // visual details here probably need refinement + switch (i) { case 0: DoScriptText(SAY_START, m_creature, pPlayer); @@ -144,7 +82,7 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI DoScriptText(SAY_RELIC2, m_creature, pPlayer); break; case 31: - m_creature->SummonCreature(NPC_ASPECT_OF_RAVEN, 7465.321f, -3088.515f, 429.006f, 5.550f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); + m_creature->SummonCreature(NPC_ASPECT_OF_RAVEN, 7465.321f, -3088.515f, 429.006f, 5.550f, TEMPSUMMON_TIMED_OOC_DESPAWN, 10000); break; case 35: m_creature->HandleEmote(EMOTE_STATE_USESTANDING_NOSHEATHE); @@ -159,19 +97,19 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI } } - void Aggro(Unit* who) + void Aggro(Unit* /*who*/) override { DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature); } - void Reset() + void Reset() override { if (HasEscortState(STATE_ESCORT_ESCORTING)) return; - //m_creature are expected to always be spawned, but not visible for player - //spell casted from quest_template.SrcSpell require this to be this way - //we handle the triggered spell to get a "hook" to our guy so he can be escorted on quest accept + // m_creature are expected to always be spawned, but not visible for player + // spell casted from quest_template.SrcSpell require this to be this way + // we handle the triggered spell to get a "hook" to our guy so he can be escorted on quest accept if (CreatureInfo const* pTemp = GetCreatureTemplateStore(m_creature->GetEntry())) m_creature->SetDisplayId(Creature::ChooseDisplayId(pTemp)); @@ -180,10 +118,10 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI m_creature->SetVisibility(VISIBILITY_OFF); } - //called only from EffectDummy + // called only from EffectDummy void DoStart(Unit* pStarter) { - //not the best way, maybe check in DummyEffect if this creature are "free" and not in escort. + // not the best way, maybe check in DummyEffect if this creature are "free" and not in escort. if (HasEscortState(STATE_ESCORT_ESCORTING)) return; @@ -192,7 +130,7 @@ struct MANGOS_DLL_DECL npc_clintar_dw_spiritAI : public npc_escortAI Start(false, pStarter && pStarter->GetTypeId() == TYPEID_PLAYER ? (Player*)pStarter : NULL); } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* summoned) override { summoned->AI()->AttackStart(m_creature); } @@ -203,10 +141,10 @@ CreatureAI* GetAI_npc_clintar_dw_spirit(Creature* pCreature) return new npc_clintar_dw_spiritAI(pCreature); } -//we expect this spell to be triggered from spell casted at questAccept -bool EffectDummyCreature_npc_clintar_dw_spirit(Unit *pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature *pCreatureTarget) +// we expect this spell to be triggered from spell casted at questAccept +bool EffectDummyCreature_npc_clintar_dw_spirit(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (spellId == SPELL_EMERALD_DREAM && effIndex == EFFECT_INDEX_0) { if (pCaster->GetTypeId() != TYPEID_PLAYER || pCaster->HasAura(SPELL_EMERALD_DREAM)) @@ -220,117 +158,16 @@ bool EffectDummyCreature_npc_clintar_dw_spirit(Unit *pCaster, uint32 spellId, Sp else return true; - //done here, escort can start + // done here, escort can start if (npc_clintar_dw_spiritAI* pSpiritAI = dynamic_cast(pCreatureTarget->AI())) pSpiritAI->DoStart(pCaster); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } return true; } -/*###### -## npc_great_bear_spirit -######*/ - -#define GOSSIP_BEAR1 "What do you represent, spirit?" -#define GOSSIP_BEAR2 "I seek to understand the importance of strength of the body." -#define GOSSIP_BEAR3 "I seek to understand the importance of strength of the heart." -#define GOSSIP_BEAR4 "I have heard your words, Great Bear Spirit, and I understand. I now seek your blessings to fully learn the way of the Claw." - -bool GossipHello_npc_great_bear_spirit(Player* pPlayer, Creature* pCreature) -{ - //ally or horde quest - if (pPlayer->GetQuestStatus(5929) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(5930) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(4719, pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_GOSSIP_MENU(4718, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_great_bear_spirit(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(4721, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(4733, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BEAR4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(4734, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(4735, pCreature->GetObjectGuid()); - if (pPlayer->GetQuestStatus(5929)==QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(5929); - if (pPlayer->GetQuestStatus(5930)==QUEST_STATUS_INCOMPLETE) - pPlayer->AreaExploredOrEventHappens(5930); - break; - } - return true; -} - -/*###### -## npc_silva_filnaveth -######*/ - -#define GOSSIP_ITEM_RUTHERAN "I'd like to fly to Rut'theran Village." -#define GOSSIP_ITEM_AQ_AGI "Do you know where I can find Half Pendant of Aquatic Agility?" - -bool GossipHello_npc_silva_filnaveth(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->getClass() != CLASS_DRUID) - pPlayer->SEND_GOSSIP_MENU(4913, pCreature->GetObjectGuid()); - else if (pPlayer->GetTeam() != ALLIANCE) - { - if (pPlayer->GetQuestStatus(QUEST_SEA_LION_HORDE) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AQ_AGI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - - pPlayer->SEND_GOSSIP_MENU(4915, pCreature->GetObjectGuid()); - } - else if (pPlayer->getClass() == CLASS_DRUID && pPlayer->GetTeam() == ALLIANCE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTHERAN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - if (pPlayer->GetQuestStatus(QUEST_SEA_LION_ALLY) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_AQ_AGI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - pPlayer->SEND_GOSSIP_MENU(4914, pCreature->GetObjectGuid()); - } - return true; -} - -bool GossipSelect_npc_silva_filnaveth(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->CLOSE_GOSSIP_MENU(); - - if (pPlayer->getClass() == CLASS_DRUID && pPlayer->GetTeam() == ALLIANCE) - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_ALLY); - - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->SEND_GOSSIP_MENU(5374, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->SEND_GOSSIP_MENU(5375, pCreature->GetObjectGuid()); - break; - } - return true; -} - /*###### ## npc_keeper_remulos ######*/ @@ -343,7 +180,7 @@ enum SPELL_REJUVENATION = 20664, SPELL_STARFIRE = 21668, SPELL_ERANIKUS_REDEEMED = 25846, // transform Eranikus - //SPELL_MOONGLADE_TRANQUILITY = unk, // spell which acts as a spotlight over Eranikus after he is redeemed + // SPELL_MOONGLADE_TRANQUILITY = unk, // spell which acts as a spotlight over Eranikus after he is redeemed NPC_ERANIKUS_TYRANT = 15491, NPC_NIGHTMARE_PHANTASM = 15629, // shadows summoned during the event - should cast 17228 and 21307 @@ -410,10 +247,10 @@ enum static const DialogueEntry aIntroDialogue[] = { - {NPC_REMULOS, 0, 14000}, // target player + {NPC_REMULOS, 0, 14000}, // target player {SAY_REMULOS_INTRO_4, NPC_REMULOS, 12000}, {SAY_REMULOS_INTRO_5, NPC_REMULOS, 5000}, - {SPELL_CONJURE_RIFT, 0, 13000}, // conjure rift spell + {SPELL_CONJURE_RIFT, 0, 13000}, // conjure rift spell {SAY_ERANIKUS_SPAWN, NPC_ERANIKUS_TYRANT, 11000}, {SAY_REMULOS_TAUNT_1, NPC_REMULOS, 5000}, {EMOTE_ERANIKUS_LAUGH, NPC_ERANIKUS_TYRANT, 3000}, @@ -421,8 +258,8 @@ static const DialogueEntry aIntroDialogue[] = {SAY_REMULOS_TAUNT_3, NPC_REMULOS, 12000}, {SAY_ERANIKUS_TAUNT_4, NPC_ERANIKUS_TYRANT, 6000}, {EMOTE_ERANIKUS_ATTACK, NPC_ERANIKUS_TYRANT, 7000}, - {NPC_ERANIKUS_TYRANT, 0, 0}, // target player - restart the escort and move Eranikus above the village - {SAY_REMULOS_DEFEND_2, NPC_REMULOS, 6000}, // face Eranikus + {NPC_ERANIKUS_TYRANT, 0, 0}, // target player - restart the escort and move Eranikus above the village + {SAY_REMULOS_DEFEND_2, NPC_REMULOS, 6000}, // face Eranikus {SAY_ERANIKUS_SHADOWS, NPC_ERANIKUS_TYRANT, 4000}, {SAY_REMULOS_DEFEND_3, NPC_REMULOS, 0}, {0, 0, 0}, @@ -461,7 +298,7 @@ static EventLocations aShadowsLocations[] = {7963.00f, -2492.03f, 487.84f} }; -struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private DialogueHelper +struct npc_keeper_remulosAI : public npc_escortAI, private DialogueHelper { npc_keeper_remulosAI(Creature* pCreature) : npc_escortAI(pCreature), DialogueHelper(aIntroDialogue) @@ -481,7 +318,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo bool m_bIsFirstWave; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -499,15 +336,15 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_ERANIKUS_TYRANT: m_eranikusGuid = pSummoned->GetObjectGuid(); // Make Eranikus unattackable first // ToDo: uncomment the fly effect when it will be possible to cancel it properly - //pSummoned->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + // pSummoned->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); pSummoned->SetLevitate(true); break; @@ -519,12 +356,12 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_ERANIKUS_TYRANT) return; - switch(uiPointId) + switch (uiPointId) { case POINT_ID_ERANIKUS_FLIGHT: // Set Eranikus to face Remulos @@ -539,7 +376,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo } } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { // Make Eranikus evade in order to despawn all the summons if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) @@ -548,9 +385,9 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo npc_escortAI::JustDied(pKiller); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: if (Player* pPlayer = GetPlayerForEscort()) @@ -573,7 +410,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo } } - Creature* GetSpeakerByEntry(uint32 uiEntry) + Creature* GetSpeakerByEntry(uint32 uiEntry) override { switch (uiEntry) { @@ -585,9 +422,9 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo } } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { - switch(iEntry) + switch (iEntry) { case NPC_REMULOS: if (Player* pPlayer = GetPlayerForEscort()) @@ -598,7 +435,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo break; case SAY_ERANIKUS_SPAWN: // This big yellow emote was removed at some point in WotLK - //DoScriptText(EMOTE_SUMMON_ERANIKUS, pEranikus); + // DoScriptText(EMOTE_SUMMON_ERANIKUS, pEranikus); break; case NPC_ERANIKUS_TYRANT: if (Player* pPlayer = GetPlayerForEscort()) @@ -626,7 +463,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo m_uiOutroTimer = 3000; } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); @@ -634,7 +471,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo { if (m_uiOutroTimer <= uiDiff) { - switch(m_uiOutroPhase) + switch (m_uiOutroPhase) { case 0: DoScriptText(SAY_REMULOS_OUTRO_1, m_creature); @@ -643,7 +480,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo case 1: // Despawn Remulos after the outro is finished - he will respawn automatically at his home position after a few min DoScriptText(SAY_REMULOS_OUTRO_2, m_creature); - m_creature->SetRespawnDelay(1*MINUTE); + m_creature->SetRespawnDelay(1 * MINUTE); m_creature->ForcedDespawn(3000); m_uiOutroTimer = 0; break; @@ -664,7 +501,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo { // summon 3 shades inside the house for (uint8 i = 0; i < MAX_SHADOWS; ++i) - m_creature->SummonCreature(NPC_NIGHTMARE_PHANTASM, aShadowsLocations[i].m_fX, aShadowsLocations[i].m_fY, aShadowsLocations[i].m_fZ, 0,TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_NIGHTMARE_PHANTASM, aShadowsLocations[i].m_fX, aShadowsLocations[i].m_fY, aShadowsLocations[i].m_fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); if (Creature* pEranikus = m_creature->GetMap()->GetCreature(m_eranikusGuid)) DoScriptText(SAY_ERANIKUS_ATTACK_1, pEranikus); @@ -677,7 +514,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo // Summon 3 shades per turn until the maximum summon turns are reached float fX, fY, fZ; // Randomize the summon point - uint8 uiSummonPoint = roll_chance_i(70) ? MAX_SHADOWS : urand(MAX_SHADOWS + 1, MAX_SHADOWS + 2); + uint8 uiSummonPoint = roll_chance_i(70) ? uint32(MAX_SHADOWS) : urand(MAX_SHADOWS + 1, MAX_SHADOWS + 2); if (m_uiSummonCount < MAX_SUMMON_TURNS) { @@ -718,7 +555,7 @@ struct MANGOS_DLL_DECL npc_keeper_remulosAI : public npc_escortAI, private Dialo { if (Unit* pTarget = DoSelectLowestHpFriendly(DEFAULT_VISIBILITY_DISTANCE)) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoCastSpellIfCan(pTarget, SPELL_HEALING_TOUCH); break; case 1: DoCastSpellIfCan(pTarget, SPELL_REJUVENATION); break; @@ -764,14 +601,14 @@ bool QuestAccept_npc_keeper_remulos(Player* pPlayer, Creature* pCreature, const return false; } -bool EffectDummyCreature_conjure_rift(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_conjure_rift(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* /*pCreatureTarget*/, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_CONJURE_RIFT && uiEffIndex == EFFECT_INDEX_0) { pCaster->SummonCreature(NPC_ERANIKUS_TYRANT, aEranikusLocations[0].m_fX, aEranikusLocations[0].m_fY, aEranikusLocations[0].m_fZ, aEranikusLocations[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } @@ -798,7 +635,7 @@ enum POINT_ID_TYRANDE_ABSOLUTION = 1, }; -struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI +struct boss_eranikusAI : public ScriptedAI { boss_eranikusAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -814,9 +651,9 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI ObjectGuid m_remulosGuid; ObjectGuid m_tyrandeGuid; - GUIDList m_lPriestessList; + GuidList m_lPriestessList; - void Reset() + void Reset() override { m_uiAcidBreathTimer = 10000; m_uiNoxiousBreathTimer = 3000; @@ -834,11 +671,11 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI SetCombatMovement(false); } - void EnterEvadeMode() + void EnterEvadeMode() override { if (m_creature->GetHealthPercent() < 20.0f) { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->LoadCreatureAddon(true); @@ -871,7 +708,7 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -889,9 +726,9 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_TYRANDE_WHISPERWIND: m_tyrandeGuid = pSummoned->GetObjectGuid(); @@ -910,19 +747,19 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI void DoDespawnSummoned() { - for(GUIDList::const_iterator itr = m_lPriestessList.begin(); itr != m_lPriestessList.end(); ++itr) + for (GuidList::const_iterator itr = m_lPriestessList.begin(); itr != m_lPriestessList.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) pTemp->ForcedDespawn(); } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; - switch(uiPointId) + switch (uiPointId) { case POINT_ID_TYRANDE_HEAL: if (pSummoned->GetEntry() == NPC_TYRANDE_WHISPERWIND) @@ -946,7 +783,7 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI } } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE || uiPointId != POINT_ID_ERANIKUS_REDEEMED) return; @@ -955,13 +792,13 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI m_uiEventTimer = 11000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiEventTimer) { if (m_uiEventTimer <= uiDiff) { - switch(m_uiEventPhase) + switch (m_uiEventPhase) { case 0: // Eranikus is redeemed - make Tyrande kneel and stop casting @@ -975,7 +812,7 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI pRemulos->SetFacingToObject(m_creature); // Note: this emote was a world wide yellow emote before WotLK DoScriptText(EMOTE_ERANIKUS_REDEEM, m_creature); - //DoCastSpellIfCan(m_creature, SPELL_MOONGLADE_TRANQUILITY); // spell id unk for the moment + // DoCastSpellIfCan(m_creature, SPELL_MOONGLADE_TRANQUILITY); // spell id unk for the moment m_creature->SetStandState(UNIT_STAND_STATE_DEAD); m_uiEventTimer = 5000; break; @@ -1047,7 +884,7 @@ struct MANGOS_DLL_DECL boss_eranikusAI : public ScriptedAI // Not sure if this should be handled by health percent, but this is the only reasonable way if (m_creature->GetHealthPercent() < m_uiHealthCheck) { - switch(m_uiHealthCheck) + switch (m_uiHealthCheck) { case 85: DoScriptText(SAY_ERANIKUS_ATTACK_3, m_creature); @@ -1133,30 +970,12 @@ void AddSC_moonglade() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_bunthen_plainswind"; - pNewScript->pGossipHello = &GossipHello_npc_bunthen_plainswind; - pNewScript->pGossipSelect = &GossipSelect_npc_bunthen_plainswind; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_clintar_dw_spirit"; pNewScript->GetAI = &GetAI_npc_clintar_dw_spirit; pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_clintar_dw_spirit; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_great_bear_spirit"; - pNewScript->pGossipHello = &GossipHello_npc_great_bear_spirit; - pNewScript->pGossipSelect = &GossipSelect_npc_great_bear_spirit; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_silva_filnaveth"; - pNewScript->pGossipHello = &GossipHello_npc_silva_filnaveth; - pNewScript->pGossipSelect = &GossipSelect_npc_silva_filnaveth; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_keeper_remulos"; pNewScript->GetAI = &GetAI_npc_keeper_remulos; diff --git a/scripts/kalimdor/mulgore.cpp b/scripts/kalimdor/mulgore.cpp index 5de540d54..cda59a27d 100644 --- a/scripts/kalimdor/mulgore.cpp +++ b/scripts/kalimdor/mulgore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,13 +17,12 @@ /* ScriptData SDName: Mulgore SD%Complete: 100 -SDComment: Quest support: 11129. Skorn Whitecloud: Just a story if not rewarded for quest +SDComment: Quest support: 11129. SDCategory: Mulgore EndScriptData */ /* ContentData npc_kyle_the_frenzied -npc_skorn_whitecloud EndContentData */ #include "precompiled.h" @@ -44,7 +43,7 @@ enum POINT_ID = 1 }; -struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI +struct npc_kyle_the_frenziedAI : public ScriptedAI { npc_kyle_the_frenziedAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -54,7 +53,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI uint32 m_uiEventTimer; uint8 m_uiEventPhase; - void Reset() + void Reset() override { m_bEvent = false; m_bIsMovingToLunch = false; @@ -66,7 +65,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI m_creature->UpdateEntry(NPC_KYLE_FRENZIED); } - void SpellHit(Unit* pCaster, SpellEntry const* pSpell) + void SpellHit(Unit* pCaster, SpellEntry const* pSpell) override { if (!m_creature->getVictim() && !m_bEvent && pSpell->Id == SPELL_LUNCH) { @@ -86,7 +85,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI } } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE || !m_bEvent) return; @@ -95,7 +94,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI m_bIsMovingToLunch = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { if (m_bEvent) { @@ -107,7 +106,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI m_uiEventTimer = 5000; ++m_uiEventPhase; - switch(m_uiEventPhase) + switch (m_uiEventPhase) { case 1: if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) @@ -121,7 +120,7 @@ struct MANGOS_DLL_DECL npc_kyle_the_frenziedAI : public ScriptedAI uint32 uiGameobjectEntry = pSpell->EffectMiscValue[EFFECT_INDEX_1]; - pGo = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2*INTERACTION_DISTANCE); + pGo = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2 * INTERACTION_DISTANCE); } if (pGo) @@ -168,31 +167,6 @@ CreatureAI* GetAI_npc_kyle_the_frenzied(Creature* pCreature) return new npc_kyle_the_frenziedAI(pCreature); } -/*###### -# npc_skorn_whitecloud -######*/ - -bool GossipHello_npc_skorn_whitecloud(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (!pPlayer->GetQuestRewardStatus(770)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Tell me a story, Skorn.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(522, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_skorn_whitecloud(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - pPlayer->SEND_GOSSIP_MENU(523, pCreature->GetObjectGuid()); - - return true; -} - void AddSC_mulgore() { Script* pNewScript; @@ -201,10 +175,4 @@ void AddSC_mulgore() pNewScript->Name = "npc_kyle_the_frenzied"; pNewScript->GetAI = &GetAI_npc_kyle_the_frenzied; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_skorn_whitecloud"; - pNewScript->pGossipHello = &GossipHello_npc_skorn_whitecloud; - pNewScript->pGossipSelect = &GossipSelect_npc_skorn_whitecloud; - pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp b/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp index a7f776738..8007d278a 100644 --- a/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp +++ b/scripts/kalimdor/onyxias_lair/boss_onyxia.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Onyxia -SD%Complete: 70 -SDComment: Phase 3 need additional code. The spawning Whelps need GO-Support. Use of spells 22191 and 21131 unknown +SD%Complete: 85 +SDComment: Phase 3 need additional code. The spawning Whelps need GO-Support. SDCategory: Onyxia's Lair EndScriptData */ @@ -43,7 +43,7 @@ enum SPELL_FIREBALL = 18392, SPELL_FIREBALL_H = 68926, - //Not much choise about these. We have to make own defintion on the direction/start-end point + // Not much choise about these. We have to make own defintion on the direction/start-end point SPELL_BREATH_NORTH_TO_SOUTH = 17086, // 20x in "array" SPELL_BREATH_SOUTH_TO_NORTH = 18351, // 11x in "array" @@ -58,57 +58,64 @@ enum SPELL_VISUAL_BREATH_A = 4880, // Only and all of the above Breath spells (and their triggered spells) have these visuals SPELL_VISUAL_BREATH_B = 4919, - //SPELL_BREATH = 21131, // 8x in "array", different initial cast than the other arrays + SPELL_BREATH_ENTRANCE = 21131, // 8x in "array", different initial cast than the other arrays SPELL_BELLOWINGROAR = 18431, - SPELL_HEATED_GROUND = 22191, // TODO + SPELL_HEATED_GROUND = 22191, // Prevent players from hiding in the tunnels when it is time for Onyxia's breath SPELL_SUMMONWHELP = 17646, // TODO this spell is only a summon spell, but would need a spell to activate the eggs SPELL_SUMMON_LAIR_GUARD = 68968, MAX_WHELPS_PER_PACK = 40, - PHASE_START = 1, - PHASE_BREATH = 2, - PHASE_END = 3, - PHASE_BREATH_PRE = 4, - PHASE_BREATH_POST = 5 + POINT_ID_NORTH = 0, + POINT_ID_SOUTH = 4, + NUM_MOVE_POINT = 8, + POINT_ID_LIFTOFF = 1 + NUM_MOVE_POINT, + POINT_ID_IN_AIR = 2 + NUM_MOVE_POINT, + POINT_ID_INIT_NORTH = 3 + NUM_MOVE_POINT, + POINT_ID_LAND = 4 + NUM_MOVE_POINT, + + PHASE_START = 1, // Health above 65%, normal ground abilities + PHASE_BREATH = 2, // Breath phase (while health above 40%) + PHASE_END = 3, // normal ground abilities + some extra abilities + PHASE_BREATH_POST = 4, // Landing and initial fearing + PHASE_TO_LIFTOFF = 5, // Movement to south-entrance of room and liftoff there + PHASE_BREATH_PRE = 6, // lifting off + initial flying to north side (summons also first pack of whelps) + }; struct OnyxiaMove { - uint32 uiLocId; - uint32 uiLocIdEnd; uint32 uiSpellId; float fX, fY, fZ; }; -static OnyxiaMove aMoveData[]= +static const OnyxiaMove aMoveData[NUM_MOVE_POINT] = { - {0, 4, SPELL_BREATH_NORTH_TO_SOUTH, 22.8763f, -217.152f, -60.0548f}, //north - {1, 5, SPELL_BREATH_NE_TO_SW, 10.2191f, -247.912f, -60.896f}, //north-east - {2, 6, SPELL_BREATH_EAST_TO_WEST, -31.4963f, -250.123f, -60.1278f}, //east - {3, 7, SPELL_BREATH_SE_TO_NW, -63.5156f, -240.096f, -60.477f}, //south-east - {4, 0, SPELL_BREATH_SOUTH_TO_NORTH, -65.8444f, -213.809f, -60.2985f}, //south - {5, 1, SPELL_BREATH_SW_TO_NE, -58.2509f, -189.020f, -60.790f}, //south-west - {6, 2, SPELL_BREATH_WEST_TO_EAST, -33.5561f, -182.682f, -60.9457f}, //west - {7, 3, SPELL_BREATH_NW_TO_SE, 6.8951f, -180.246f, -60.896f}, //north-west + {SPELL_BREATH_NORTH_TO_SOUTH, 24.16332f, -216.0808f, -58.98009f}, // north (coords verified in wotlk) + {SPELL_BREATH_NE_TO_SW, 10.2191f, -247.912f, -60.896f}, // north-east + {SPELL_BREATH_EAST_TO_WEST, -15.00505f, -244.4841f, -60.40087f}, // east (coords verified in wotlk) + {SPELL_BREATH_SE_TO_NW, -63.5156f, -240.096f, -60.477f}, // south-east + {SPELL_BREATH_SOUTH_TO_NORTH, -66.3589f, -215.928f, -64.23904f}, // south (coords verified in wotlk) + {SPELL_BREATH_SW_TO_NE, -58.2509f, -189.020f, -60.790f}, // south-west + {SPELL_BREATH_WEST_TO_EAST, -16.70134f, -181.4501f, -61.98513f}, // west (coords verified in wotlk) + {SPELL_BREATH_NW_TO_SE, 12.26687f, -181.1084f, -60.23914f}, // north-west (coords verified in wotlk) }; -static const float afSpawnLocations[3][3]= +static const float afSpawnLocations[3][3] = { - {-30.127f, -254.463f, -89.440f}, // whelps - {-30.817f, -177.106f, -89.258f}, // whelps - {-126.57f, -214.609f, -71.446f} // guardians + { -30.127f, -254.463f, -89.440f}, // whelps + { -30.817f, -177.106f, -89.258f}, // whelps + { -126.57f, -214.609f, -71.446f} // guardians }; -struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI +struct boss_onyxiaAI : public ScriptedAI { boss_onyxiaAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_onyxias_lair*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - m_uiMaxBreathPositions = sizeof(aMoveData)/sizeof(OnyxiaMove); Reset(); } @@ -116,16 +123,15 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI instance_onyxias_lair* m_pInstance; uint8 m_uiPhase; - uint8 m_uiMaxBreathPositions; uint32 m_uiFlameBreathTimer; uint32 m_uiCleaveTimer; uint32 m_uiTailSweepTimer; uint32 m_uiWingBuffetTimer; + uint32 m_uiCheckInLairTimer; uint32 m_uiMovePoint; uint32 m_uiMovementTimer; - OnyxiaMove* m_pPointData; uint32 m_uiFireballTimer; uint32 m_uiSummonWhelpsTimer; @@ -137,7 +143,9 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI bool m_bIsSummoningWhelps; - void Reset() + uint32 m_uiPhaseTimer; + + void Reset() override { if (!IsCombatMovement()) SetCombatMovement(true); @@ -148,23 +156,25 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI m_uiTailSweepTimer = urand(15000, 20000); m_uiCleaveTimer = urand(2000, 5000); m_uiWingBuffetTimer = urand(10000, 20000); + m_uiCheckInLairTimer = 3000; - m_uiMovePoint = urand(0, m_uiMaxBreathPositions - 1); - m_uiMovementTimer = 20000; - m_pPointData = GetMoveData(); + m_uiMovePoint = POINT_ID_NORTH; // First point reached by the flying Onyxia + m_uiMovementTimer = 25000; - m_uiFireballTimer = 15000; - m_uiSummonWhelpsTimer = 15000; - m_uiBellowingRoarTimer = 2000; // Immediately after landing + m_uiFireballTimer = 1000; + m_uiSummonWhelpsTimer = 60000; + m_uiBellowingRoarTimer = 30000; m_uiWhelpTimer = 1000; m_uiSummonGuardTimer = 15000; m_uiSummonCount = 0; m_bIsSummoningWhelps = false; + + m_uiPhaseTimer = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -172,7 +182,7 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI m_pInstance->SetData(TYPE_ONYXIA, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { // in case evade in phase 2, see comments for hack where phase 2 is set m_creature->SetLevitate(false); @@ -182,13 +192,13 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI m_pInstance->SetData(TYPE_ONYXIA, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ONYXIA, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (!m_pInstance) return; @@ -207,7 +217,7 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI ++m_uiSummonCount; } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || uiPointId != 1 || !m_creature->getVictim()) return; @@ -215,52 +225,83 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI pSummoned->SetInCombatWithZone(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_KILL, m_creature); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_BREATH_EAST_TO_WEST || - pSpell->Id == SPELL_BREATH_WEST_TO_EAST || - pSpell->Id == SPELL_BREATH_SE_TO_NW || - pSpell->Id == SPELL_BREATH_NW_TO_SE || - pSpell->Id == SPELL_BREATH_SW_TO_NE || - pSpell->Id == SPELL_BREATH_NE_TO_SW || - pSpell->Id == SPELL_BREATH_SOUTH_TO_NORTH || - pSpell->Id == SPELL_BREATH_NORTH_TO_SOUTH) + pSpell->Id == SPELL_BREATH_WEST_TO_EAST || + pSpell->Id == SPELL_BREATH_SE_TO_NW || + pSpell->Id == SPELL_BREATH_NW_TO_SE || + pSpell->Id == SPELL_BREATH_SW_TO_NE || + pSpell->Id == SPELL_BREATH_NE_TO_SW || + pSpell->Id == SPELL_BREATH_SOUTH_TO_NORTH || + pSpell->Id == SPELL_BREATH_NORTH_TO_SOUTH) { // This was sent with SendMonsterMove - which resulted in better speed than now - if (m_pPointData = GetMoveData()) - m_creature->GetMotionMaster()->MovePoint(m_pPointData->uiLocId, m_pPointData->fX, m_pPointData->fY, m_pPointData->fZ); + m_creature->GetMotionMaster()->MovePoint(m_uiMovePoint, aMoveData[m_uiMovePoint].fX, aMoveData[m_uiMovePoint].fY, aMoveData[m_uiMovePoint].fZ); + DoCastSpellIfCan(m_creature, SPELL_HEATED_GROUND, CAST_TRIGGERED); } } - OnyxiaMove* GetMoveData() + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - for (uint32 i = 0; i < m_uiMaxBreathPositions; ++i) + if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) + return; + + switch (uiPointId) { - if (aMoveData[i].uiLocId == m_uiMovePoint) - return &aMoveData[i]; + case POINT_ID_IN_AIR: + // sort of a hack, it is unclear how this really work but the values are valid + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + m_creature->SetLevitate(true); + m_uiPhaseTimer = 1000; // Movement to Initial North Position is delayed + return; + case POINT_ID_LAND: + // undo flying + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); + m_creature->SetLevitate(false); + m_uiPhaseTimer = 500; // Start PHASE_END shortly delayed + return; + case POINT_ID_LIFTOFF: + m_uiPhaseTimer = 500; // Start Flying shortly delayed + break; + case POINT_ID_INIT_NORTH: // Start PHASE_BREATH + m_uiPhase = PHASE_BREATH; + m_uiSummonCount = 0; + break; } - return NULL; + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER)) + m_creature->SetFacingToObject(pTrigger); } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) + void AttackStart(Unit* pWho) override { - if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) - return; + if (m_uiPhase == PHASE_START || m_uiPhase == PHASE_END) + ScriptedAI::AttackStart(pWho); + } - if (m_uiPhase == PHASE_BREATH) + bool DidSummonWhelps(const uint32 uiDiff) + { + if (m_uiSummonCount >= MAX_WHELPS_PER_PACK) + return true; + + if (m_uiWhelpTimer < uiDiff) { - if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER)) - m_creature->SetFacingToObject(pTrigger); + m_creature->SummonCreature(NPC_ONYXIA_WHELP, afSpawnLocations[0][0], afSpawnLocations[0][1], afSpawnLocations[0][2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS); + m_creature->SummonCreature(NPC_ONYXIA_WHELP, afSpawnLocations[1][0], afSpawnLocations[1][1], afSpawnLocations[1][2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS); + m_uiWhelpTimer = 500; } + else + m_uiWhelpTimer -= uiDiff; + return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -310,25 +351,29 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI else m_uiWingBuffetTimer -= uiDiff; - if (m_uiPhase == PHASE_START && m_creature->GetHealthPercent() < 65.0f) + if (m_uiCheckInLairTimer < uiDiff) { - m_uiPhase = PHASE_BREATH; + if (m_pInstance) + { + Creature* pOnyTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER); + if (pOnyTrigger && !m_creature->IsWithinDistInMap(pOnyTrigger, 90.0f, false)) + DoCastSpellIfCan(m_creature, SPELL_BREATH_ENTRANCE); + } + m_uiCheckInLairTimer = 3000; + } + else + m_uiCheckInLairTimer -= uiDiff; + if (m_uiPhase == PHASE_START && m_creature->GetHealthPercent() < 65.0f) + { + m_uiPhase = PHASE_TO_LIFTOFF; + DoScriptText(SAY_PHASE_2_TRANS, m_creature); SetCombatMovement(false); m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetTargetGuid(ObjectGuid()); - DoScriptText(SAY_PHASE_2_TRANS, m_creature); - - // sort of a hack, it is unclear how this really work but the values appear to be valid - m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); - m_creature->SetLevitate(true); - - if (m_pPointData) - m_creature->GetMotionMaster()->MovePoint(m_pPointData->uiLocId, m_pPointData->fX, m_pPointData->fY, m_pPointData->fZ); - - // TODO - this might not be the correct place to set this setting - if (m_pInstance) - m_pInstance->SetData(TYPE_ONYXIA, DATA_LIFTOFF); + float fGroundZ = m_creature->GetMap()->GetHeight(m_creature->GetPhaseMask(), aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, aMoveData[POINT_ID_SOUTH].fZ); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_LIFTOFF, aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, fGroundZ); return; } @@ -339,47 +384,40 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI { if (m_creature->GetHealthPercent() < 40.0f) { - m_uiPhase = PHASE_END; + m_uiPhase = PHASE_BREATH_POST; DoScriptText(SAY_PHASE_3_TRANS, m_creature); - // undo flying - m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); - m_creature->SetLevitate(false); - - SetCombatMovement(true); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + float fGroundZ = m_creature->GetMap()->GetHeight(m_creature->GetPhaseMask(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + m_creature->GetMotionMaster()->MoveFlyOrLand(POINT_ID_LAND, m_creature->GetPositionX(), m_creature->GetPositionY(), fGroundZ, false); return; } if (m_uiMovementTimer < uiDiff) { - m_uiMovementTimer = 25000; - // 3 possible actions - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: // breath - if (m_pPointData = GetMoveData()) - { - DoScriptText(EMOTE_BREATH, m_creature); - DoCastSpellIfCan(m_creature, m_pPointData->uiSpellId, CAST_INTERRUPT_PREVIOUS); - m_uiMovePoint = m_pPointData->uiLocIdEnd; - } + DoScriptText(EMOTE_BREATH, m_creature); + DoCastSpellIfCan(m_creature, aMoveData[m_uiMovePoint].uiSpellId, CAST_INTERRUPT_PREVIOUS); + m_uiMovePoint += NUM_MOVE_POINT / 2; + m_uiMovePoint %= NUM_MOVE_POINT; + m_uiMovementTimer = 25000; return; case 1: // a point on the left side { // C++ is stupid, so add -1 with +7 - m_uiMovePoint += m_uiMaxBreathPositions - 1; - m_uiMovePoint %= m_uiMaxBreathPositions; + m_uiMovePoint += NUM_MOVE_POINT - 1; + m_uiMovePoint %= NUM_MOVE_POINT; break; } case 2: // a point on the right side - ++m_uiMovePoint %= m_uiMaxBreathPositions; + ++m_uiMovePoint %= NUM_MOVE_POINT; break; } - if (m_pPointData = GetMoveData()) - m_creature->GetMotionMaster()->MovePoint(m_pPointData->uiLocId, m_pPointData->fX, m_pPointData->fY, m_pPointData->fZ); + m_uiMovementTimer = urand(15000, 25000); + m_creature->GetMotionMaster()->MovePoint(m_uiMovePoint, aMoveData[m_uiMovePoint].fX, aMoveData[m_uiMovePoint].fY, aMoveData[m_uiMovePoint].fZ); } else m_uiMovementTimer -= uiDiff; @@ -389,26 +427,15 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FIREBALL : SPELL_FIREBALL_H) == CAST_OK) - m_uiFireballTimer = 8000; + m_uiFireballTimer = urand(3000, 5000); } } else - m_uiFireballTimer -= uiDiff; //engulfingflames is supposed to be activated by a fireball but haven't come by + m_uiFireballTimer -= uiDiff; // engulfingflames is supposed to be activated by a fireball but haven't come by if (m_bIsSummoningWhelps) { - if (m_uiSummonCount < MAX_WHELPS_PER_PACK) - { - if (m_uiWhelpTimer < uiDiff) - { - m_creature->SummonCreature(NPC_ONYXIA_WHELP, afSpawnLocations[0][0], afSpawnLocations[0][1], afSpawnLocations[0][2], 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, MINUTE*IN_MILLISECONDS); - m_creature->SummonCreature(NPC_ONYXIA_WHELP, afSpawnLocations[1][0], afSpawnLocations[1][1], afSpawnLocations[1][2], 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, MINUTE*IN_MILLISECONDS); - m_uiWhelpTimer = 500; - } - else - m_uiWhelpTimer -= uiDiff; - } - else + if (DidSummonWhelps(uiDiff)) { m_bIsSummoningWhelps = false; m_uiSummonCount = 0; @@ -436,10 +463,41 @@ struct MANGOS_DLL_DECL boss_onyxiaAI : public ScriptedAI break; } + case PHASE_BREATH_PRE: // Summon first rounds of whelps + DidSummonWhelps(uiDiff); + // no break here + default: // Phase-switching phases + if (!m_uiPhaseTimer) + break; + if (m_uiPhaseTimer <= uiDiff) + { + switch (m_uiPhase) + { + case PHASE_TO_LIFTOFF: + m_uiPhase = PHASE_BREATH_PRE; + if (m_pInstance) + m_pInstance->SetData(TYPE_ONYXIA, DATA_LIFTOFF); + m_creature->GetMotionMaster()->MoveFlyOrLand(POINT_ID_IN_AIR, aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, aMoveData[POINT_ID_SOUTH].fZ, true); + break; + case PHASE_BREATH_PRE: + m_creature->GetMotionMaster()->MovePoint(POINT_ID_INIT_NORTH, aMoveData[POINT_ID_NORTH].fX, aMoveData[POINT_ID_NORTH].fY, aMoveData[POINT_ID_NORTH].fZ); + break; + case PHASE_BREATH_POST: + m_uiPhase = PHASE_END; + m_creature->SetTargetGuid(m_creature->getVictim()->GetObjectGuid()); + SetCombatMovement(true, true); + DoCastSpellIfCan(m_creature, SPELL_BELLOWINGROAR); + break; + } + m_uiPhaseTimer = 0; + } + else + m_uiPhaseTimer -= uiDiff; + break; } } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { // Check if players are hit by Onyxia's Deep Breath if (pTarget->GetTypeId() != TYPEID_PLAYER || !m_pInstance) diff --git a/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp b/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp index 6772476b5..e08676116 100644 --- a/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp +++ b/scripts/kalimdor/onyxias_lair/instance_onyxias_lair.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,7 +43,7 @@ bool instance_onyxias_lair::IsEncounterInProgress() const void instance_onyxias_lair::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ONYXIA_TRIGGER: m_mNpcEntryGuidStore[NPC_ONYXIA_TRIGGER] = pCreature->GetObjectGuid(); @@ -72,7 +72,7 @@ void instance_onyxias_lair::SetData(uint32 uiType, uint32 uiData) // Currently no reason to save anything } -bool instance_onyxias_lair::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_onyxias_lair::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { diff --git a/scripts/kalimdor/onyxias_lair/onyxias_lair.h b/scripts/kalimdor/onyxias_lair/onyxias_lair.h index 4ecbd7c91..31c4aaf87 100644 --- a/scripts/kalimdor/onyxias_lair/onyxias_lair.h +++ b/scripts/kalimdor/onyxias_lair/onyxias_lair.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -28,21 +28,21 @@ enum ACHIEV_START_ONYXIA_ID = 6601, }; -class MANGOS_DLL_DECL instance_onyxias_lair : public ScriptedInstance +class instance_onyxias_lair : public ScriptedInstance { public: instance_onyxias_lair(Map* pMap); ~instance_onyxias_lair() {} - void Initialize(); + void Initialize() override; - bool IsEncounterInProgress() const; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; protected: uint32 m_uiEncounter; diff --git a/scripts/kalimdor/orgrimmar.cpp b/scripts/kalimdor/orgrimmar.cpp index e87cb84cb..f58c44329 100644 --- a/scripts/kalimdor/orgrimmar.cpp +++ b/scripts/kalimdor/orgrimmar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,60 +37,67 @@ enum QUEST_SHATTERED_SALUTE = 2460 }; -struct MANGOS_DLL_DECL npc_shenthulAI : public ScriptedAI +struct npc_shenthulAI : public ScriptedAI { npc_shenthulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool CanTalk; - bool CanEmote; - uint32 Salute_Timer; - uint32 Reset_Timer; + uint32 m_uiSaluteTimer; + uint32 m_uiResetTimer; + ObjectGuid m_playerGuid; - void Reset() + void Reset() override { - CanTalk = false; - CanEmote = false; - Salute_Timer = 6000; - Reset_Timer = 0; + m_uiSaluteTimer = 0; + m_uiResetTimer = 0; + m_playerGuid.Clear(); } - void ReceiveEmote(Player* pPlayer, uint32 emote) + void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) override { - if (emote == TEXTEMOTE_SALUTE && pPlayer->GetQuestStatus(QUEST_SHATTERED_SALUTE) == QUEST_STATUS_INCOMPLETE) + if (m_uiResetTimer && uiTextEmote == TEXTEMOTE_SALUTE && pPlayer->GetQuestStatus(QUEST_SHATTERED_SALUTE) == QUEST_STATUS_INCOMPLETE) { - if (CanEmote) - { - pPlayer->AreaExploredOrEventHappens(QUEST_SHATTERED_SALUTE); - Reset(); - } + pPlayer->AreaExploredOrEventHappens(QUEST_SHATTERED_SALUTE); + EnterEvadeMode(); } } - void UpdateAI(const uint32 diff) + void DoStartQuestEvent(Player* pPlayer) { - if (CanEmote) + m_playerGuid = pPlayer->GetObjectGuid(); + m_uiSaluteTimer = 6000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiResetTimer) { - if (Reset_Timer < diff) + if (m_uiResetTimer <= uiDiff) { if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { if (pPlayer->GetTypeId() == TYPEID_PLAYER && pPlayer->GetQuestStatus(QUEST_SHATTERED_SALUTE) == QUEST_STATUS_INCOMPLETE) pPlayer->FailQuest(QUEST_SHATTERED_SALUTE); } - Reset(); - } else Reset_Timer -= diff; + + m_uiResetTimer = 0; + EnterEvadeMode(); + } + else + m_uiResetTimer -= uiDiff; } - if (CanTalk && !CanEmote) + if (m_uiSaluteTimer) { - if (Salute_Timer < diff) + if (m_uiSaluteTimer <= uiDiff) { m_creature->HandleEmote(EMOTE_ONESHOT_SALUTE); - CanEmote = true; - Reset_Timer = 60000; - } else Salute_Timer -= diff; + m_uiResetTimer = 60000; + m_uiSaluteTimer = 0; + } + else + m_uiSaluteTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -110,11 +117,9 @@ bool QuestAccept_npc_shenthul(Player* pPlayer, Creature* pCreature, const Quest* if (pQuest->GetQuestId() == QUEST_SHATTERED_SALUTE) { if (npc_shenthulAI* pShenAI = dynamic_cast(pCreature->AI())) - { - pShenAI->CanTalk = true; - pShenAI->m_playerGuid = pPlayer->GetObjectGuid(); - } + pShenAI->DoStartQuestEvent(pPlayer); } + return true; } @@ -122,93 +127,54 @@ bool QuestAccept_npc_shenthul(Player* pPlayer, Creature* pCreature, const Quest* ## npc_thrall_warchief ######*/ -#define QUEST_6566 6566 - -#define SPELL_CHAIN_LIGHTNING 16033 -#define SPELL_SHOCK 16034 - -//TODO: verify abilities/timers -struct MANGOS_DLL_DECL npc_thrall_warchiefAI : public ScriptedAI +enum { - npc_thrall_warchiefAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 ChainLightning_Timer; - uint32 Shock_Timer; - - void Reset() - { - ChainLightning_Timer = 2000; - Shock_Timer = 8000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (ChainLightning_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CHAIN_LIGHTNING); - ChainLightning_Timer = 9000; - }else ChainLightning_Timer -= diff; - - if (Shock_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHOCK); - Shock_Timer = 15000; - }else Shock_Timer -= diff; - - DoMeleeAttackIfReady(); - } + QUEST_ID_WHAT_THE_WIND_CARRIES = 6566, }; -CreatureAI* GetAI_npc_thrall_warchief(Creature* pCreature) -{ - return new npc_thrall_warchiefAI(pCreature); -} bool GossipHello_npc_thrall_warchief(Player* pPlayer, Creature* pCreature) { if (pCreature->isQuestGiver()) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - if (pPlayer->GetQuestStatus(QUEST_6566) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Please share your wisdom with me, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (pPlayer->GetQuestStatus(QUEST_ID_WHAT_THE_WIND_CARRIES) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Please share your wisdom with me, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_thrall_warchief(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_thrall_warchief(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What discoveries?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What discoveries?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(5733, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Usurper?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Usurper?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); pPlayer->SEND_GOSSIP_MENU(5734, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "With all due respect, Warchief - why not allow them to be destroyed? Does this not strengthen our position?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "With all due respect, Warchief - why not allow them to be destroyed? Does this not strengthen our position?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); pPlayer->SEND_GOSSIP_MENU(5735, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I... I did not think of it that way, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I... I did not think of it that way, Warchief.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); pPlayer->SEND_GOSSIP_MENU(5736, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I live only to serve, Warchief! My life is empty and meaningless without your guidance.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I live only to serve, Warchief! My life is empty and meaningless without your guidance.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); pPlayer->SEND_GOSSIP_MENU(5737, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Of course, Warchief!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Of course, Warchief!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); pPlayer->SEND_GOSSIP_MENU(5738, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+7: pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(QUEST_6566); + pPlayer->AreaExploredOrEventHappens(QUEST_ID_WHAT_THE_WIND_CARRIES); break; } return true; @@ -226,7 +192,6 @@ void AddSC_orgrimmar() pNewScript = new Script; pNewScript->Name = "npc_thrall_warchief"; - pNewScript->GetAI = &GetAI_npc_thrall_warchief; pNewScript->pGossipHello = &GossipHello_npc_thrall_warchief; pNewScript->pGossipSelect = &GossipSelect_npc_thrall_warchief; pNewScript->RegisterSelf(); diff --git a/scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp b/scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp deleted file mode 100644 index 2aef7d045..000000000 --- a/scripts/kalimdor/razorfen_downs/boss_amnennar_the_coldbringer.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Amnennar_the_coldbringer -SD%Complete: 100 -SDComment: -SDCategory: Razorfen Downs -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO -1129000 -#define SAY_SUMMON60 -1129001 -#define SAY_SUMMON30 -1129002 -#define SAY_HP -1129003 -#define SAY_KILL -1129004 - -#define SPELL_AMNENNARSWRATH 13009 -#define SPELL_FROSTBOLT 15530 -#define SPELL_FROST_NOVA 15531 -#define SPELL_FROST_SPECTRES 12642 - -struct MANGOS_DLL_DECL boss_amnennar_the_coldbringerAI : public ScriptedAI -{ - boss_amnennar_the_coldbringerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 AmnenarsWrath_Timer; - uint32 FrostBolt_Timer; - uint32 FrostNova_Timer; - bool Spectrals60; - bool Spectrals30; - bool Hp; - - void Reset() - { - AmnenarsWrath_Timer = 8000; - FrostBolt_Timer = 1000; - FrostNova_Timer = urand(10000, 15000); - Spectrals30 = false; - Spectrals60 = false; - Hp = false; - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO, m_creature); - } - - void KilledUnit(Unit* pVictim) - { - DoScriptText(SAY_KILL, m_creature); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //AmnenarsWrath_Timer - if (AmnenarsWrath_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_AMNENNARSWRATH); - AmnenarsWrath_Timer = 12000; - } else AmnenarsWrath_Timer -= diff; - - //FrostBolt_Timer - if (FrostBolt_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLT); - FrostBolt_Timer = 8000; - } else FrostBolt_Timer -= diff; - - if (FrostNova_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_FROST_NOVA); - FrostNova_Timer = 15000; - } else FrostNova_Timer -= diff; - - if (!Spectrals60 && m_creature->GetHealthPercent() < 60.0f) - { - DoScriptText(SAY_SUMMON60, m_creature); - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROST_SPECTRES); - Spectrals60 = true; - } - - if (!Hp && m_creature->GetHealthPercent() < 50.0f) - { - DoScriptText(SAY_HP, m_creature); - Hp = true; - } - - if (!Spectrals30 && m_creature->GetHealthPercent() < 30.0f) - { - DoScriptText(SAY_SUMMON30, m_creature); - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROST_SPECTRES); - Spectrals30 = true; - } - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_amnennar_the_coldbringer(Creature* pCreature) -{ - return new boss_amnennar_the_coldbringerAI(pCreature); -} - -void AddSC_boss_amnennar_the_coldbringer() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_amnennar_the_coldbringer"; - pNewScript->GetAI = &GetAI_boss_amnennar_the_coldbringer; - pNewScript->RegisterSelf(); -} diff --git a/scripts/kalimdor/razorfen_downs/instance_razorfen_downs.cpp b/scripts/kalimdor/razorfen_downs/instance_razorfen_downs.cpp new file mode 100644 index 000000000..04d3453eb --- /dev/null +++ b/scripts/kalimdor/razorfen_downs/instance_razorfen_downs.cpp @@ -0,0 +1,207 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: instance_razorfen_downs +SD%Complete: 90% +SDComment: Spawns coords can be improved +SDCategory: Razorfen Downs +EndScriptData */ + +#include "precompiled.h" +#include "razorfen_downs.h" + +instance_razorfen_downs::instance_razorfen_downs(Map* pMap) : ScriptedInstance(pMap), + m_uiWaveCounter(0) +{ + Initialize(); +} + +void instance_razorfen_downs::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +void instance_razorfen_downs::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_TOMB_FIEND: + case NPC_TOMB_REAVER: + m_lSpawnedMobsList.push_back(pCreature->GetObjectGuid()); + return; + } +} + +void instance_razorfen_downs::OnObjectCreate(GameObject* pGo) +{ + if (pGo->GetEntry() == GO_GONG) + m_mGoEntryGuidStore[GO_GONG] = pGo->GetObjectGuid(); +} + +void instance_razorfen_downs::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_TUTEN_KASH: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + ++m_uiWaveCounter; + break; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + saveStream << m_auiEncounter[0]; + + m_strInstData = saveStream.str(); + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_razorfen_downs::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_razorfen_downs::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_razorfen_downs::OnCreatureDeath(Creature* pCreature) +{ + // Only use this function if gong event is in progress + if (GetData(TYPE_TUTEN_KASH) != IN_PROGRESS) + return; + + switch (pCreature->GetEntry()) + { + case NPC_TOMB_FIEND: + case NPC_TOMB_REAVER: + m_lSpawnedMobsList.remove(pCreature->GetObjectGuid()); + + // No more wave-mobs around, enable the gong for the next wave + if (m_lSpawnedMobsList.empty()) + { + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_GONG)) + { + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + + // Workaround - GO need to be respawned - requires core fix, GO shouldn't despawn in the first place + pGo->Respawn(); + } + } + break; + case NPC_TUTEN_KASH: + SetData(TYPE_TUTEN_KASH, DONE); + break; + } +} + +void instance_razorfen_downs::DoSpawnWaveIfCan(GameObject* pGo) +{ + // safety checks + if (GetData(TYPE_TUTEN_KASH) == DONE) + return; + + if (!m_lSpawnedMobsList.empty()) + return; + + if (m_uiWaveCounter >= MAX_WAVES) + return; + + for (uint8 i = 0; i < aWaveSummonInformation[m_uiWaveCounter].m_uiNPCperWave; ++i) + { + uint8 uiPos = i % 2; // alternate spawn between the left and right corridor + float fPosX, fPosY, fPosZ; + float fTargetPosX, fTargetPosY, fTargetPosZ; + + pGo->GetRandomPoint(aSpawnLocations[uiPos].m_fX, aSpawnLocations[uiPos].m_fY, aSpawnLocations[uiPos].m_fZ, 5.0f, fPosX, fPosY, fPosZ); + + // move the summoned NPC toward the gong + if (Creature* pSummoned = pGo->SummonCreature(aWaveSummonInformation[m_uiWaveCounter].m_uiNpcEntry, fPosX, fPosY, fPosZ, aSpawnLocations[uiPos].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pSummoned->SetWalk(false); + pGo->GetContactPoint(pSummoned, fTargetPosX, fTargetPosY, fTargetPosZ); + pSummoned->GetMotionMaster()->MovePoint(0, fTargetPosX, fTargetPosY, fTargetPosZ); + } + } + + // Will increase m_uiWaveCounter, hence after the wave is summoned + SetData(TYPE_TUTEN_KASH, IN_PROGRESS); + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); +} + +InstanceData* GetInstanceData_instance_razorfen_downs(Map* pMap) +{ + return new instance_razorfen_downs(pMap); +} + +bool ProcessEventId_event_go_tutenkash_gong(uint32 /*uiEventId*/, Object* pSource, Object* pTarget, bool /*bIsStart*/) +{ + if (pSource->GetTypeId() == TYPEID_PLAYER && pTarget->GetTypeId() == TYPEID_GAMEOBJECT) + { + instance_razorfen_downs* pInstance = (instance_razorfen_downs*)((Player*)pSource)->GetInstanceData(); + if (!pInstance) + return true; + + pInstance->DoSpawnWaveIfCan((GameObject*)pTarget); + return true; + } + + return false; +} + +void AddSC_instance_razorfen_downs() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_razorfen_downs"; + pNewScript->GetInstanceData = &GetInstanceData_instance_razorfen_downs; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_go_tutenkash_gong"; + pNewScript->pProcessEventId = &ProcessEventId_event_go_tutenkash_gong; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp b/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp index 87393c94a..da5f97003 100644 --- a/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp +++ b/scripts/kalimdor/razorfen_downs/razorfen_downs.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -60,19 +60,19 @@ enum SPELL_IDOL_SHUTDOWN = 12774, // summon spells only exist in 1.x - //SPELL_SUMMON_1 = 12694, // NPC_WITHERED_BATTLE_BOAR - //SPELL_SUMMON_2 = 14802, // NPC_DEATHS_HEAD_GEOMANCER - //SPELL_SUMMON_3 = 14801, // NPC_WITHERED_QUILGUARD + // SPELL_SUMMON_1 = 12694, // NPC_WITHERED_BATTLE_BOAR + // SPELL_SUMMON_2 = 14802, // NPC_DEATHS_HEAD_GEOMANCER + // SPELL_SUMMON_3 = 14801, // NPC_WITHERED_QUILGUARD }; -static float m_fSpawnerCoord[3][4]= +static float m_fSpawnerCoord[3][4] = { {2582.79f, 954.392f, 52.4821f, 3.78736f}, {2569.42f, 956.380f, 52.2732f, 5.42797f}, {2570.62f, 942.393f, 53.7433f, 0.71558f} }; -struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI +struct npc_belnistraszAI : public npc_escortAI { npc_belnistraszAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -89,19 +89,19 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI uint32 m_uiFireballTimer; uint32 m_uiFrostNovaTimer; - void Reset() + void Reset() override { m_uiFireballTimer = 1000; m_uiFrostNovaTimer = 6000; } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (HasEscortState(STATE_ESCORT_PAUSED)) { if (!m_bAggro) { - DoScriptText(urand(0,1) ? SAY_BELNISTRASZ_AGGRO_1 : SAY_BELNISTRASZ_AGGRO_1, m_creature, pAttacker); + DoScriptText(urand(0, 1) ? SAY_BELNISTRASZ_AGGRO_1 : SAY_BELNISTRASZ_AGGRO_1, m_creature, pAttacker); m_bAggro = true; } @@ -115,11 +115,11 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI { if (m_uiRitualPhase > 7) { - pSummoner->SummonCreature(NPC_PLAGUEMAW_THE_ROTTING, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ(), pSummoner->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + pSummoner->SummonCreature(NPC_PLAGUEMAW_THE_ROTTING, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ(), pSummoner->GetOrientation(), TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); return; } - for(int i = 0; i < 4; ++i) + for (int i = 0; i < 4; ++i) { uint32 uiEntry = 0; @@ -128,7 +128,7 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI float fX, fZ, fY; pSummoner->GetClosePoint(fX, fZ, fY, 0.0f, 2.0f, angle); - switch(i) + switch (i) { case 0: case 1: @@ -142,11 +142,11 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI break; } - pSummoner->SummonCreature(uiEntry, fX, fZ, fY, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + pSummoner->SummonCreature(uiEntry, fX, fZ, fY, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { SpawnerSummon(pSummoned); } @@ -156,7 +156,7 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI m_creature->SummonCreature(NPC_IDOL_ROOM_SPAWNER, m_fSpawnerCoord[iType][0], m_fSpawnerCoord[iType][1], m_fSpawnerCoord[iType][2], m_fSpawnerCoord[iType][3], TEMPSUMMON_TIMED_DESPAWN, 10000); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { if (uiPointId == 24) { @@ -165,13 +165,13 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (HasEscortState(STATE_ESCORT_PAUSED)) { if (m_uiRitualTimer < uiDiff) { - switch(m_uiRitualPhase) + switch (m_uiRitualPhase) { case 0: DoCastSpellIfCan(m_creature, SPELL_IDOL_SHUTDOWN); @@ -224,7 +224,7 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI { if (!pGo->isSpawned()) { - pGo->SetRespawnTime(HOUR*IN_MILLISECONDS); + pGo->SetRespawnTime(HOUR * IN_MILLISECONDS); pGo->Refresh(); } } @@ -250,7 +250,7 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI if (m_uiFireballTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL); - m_uiFireballTimer = urand(2000,3000); + m_uiFireballTimer = urand(2000, 3000); } else m_uiFireballTimer -= uiDiff; @@ -258,7 +258,7 @@ struct MANGOS_DLL_DECL npc_belnistraszAI : public npc_escortAI if (m_uiFrostNovaTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_NOVA); - m_uiFrostNovaTimer = urand(10000,15000); + m_uiFrostNovaTimer = urand(10000, 15000); } else m_uiFrostNovaTimer -= uiDiff; @@ -280,7 +280,7 @@ bool QuestAccept_npc_belnistrasz(Player* pPlayer, Creature* pCreature, const Que { pEscortAI->Start(true, pPlayer, pQuest); DoScriptText(SAY_BELNISTRASZ_READY, pCreature, pPlayer); - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); } } diff --git a/scripts/kalimdor/razorfen_downs/razorfen_downs.h b/scripts/kalimdor/razorfen_downs/razorfen_downs.h new file mode 100644 index 000000000..77fe4731e --- /dev/null +++ b/scripts/kalimdor/razorfen_downs/razorfen_downs.h @@ -0,0 +1,76 @@ +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_RFD_H +#define DEF_RFD_H + +enum +{ + MAX_ENCOUNTER = 1, + MAX_WAVES = 3, + MAX_COUNT_POS = 2, + + TYPE_TUTEN_KASH = 0, + + NPC_TOMB_FIEND = 7349, + NPC_TOMB_REAVER = 7351, + NPC_TUTEN_KASH = 7355, + + GO_GONG = 148917, +}; + +struct Locations +{ + float m_fX, m_fY, m_fZ, m_fO; +}; + +static const Locations aSpawnLocations[MAX_COUNT_POS] = +{ + {2484.83f, 811.11f, 43.40f, 1.67f}, // Right corridor + {2546.03f, 902.77f, 47.16f, 5.04f}, // Left corridor +}; + +struct SummonInformation +{ + uint32 m_uiNpcEntry; + uint8 m_uiNPCperWave; +}; + +static const SummonInformation aWaveSummonInformation[] = +{ + {NPC_TOMB_FIEND, 8}, + {NPC_TOMB_REAVER, 4}, + {NPC_TUTEN_KASH, 1} +}; + +class instance_razorfen_downs : public ScriptedInstance +{ + public: + instance_razorfen_downs(Map* pMap); + ~instance_razorfen_downs() {} + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void DoSpawnWaveIfCan(GameObject* pGo); + + protected: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint8 m_uiWaveCounter; + + GuidList m_lSpawnedMobsList; +}; + +#endif diff --git a/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp b/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp index 7e6f4395c..dfead9b0e 100644 --- a/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp +++ b/scripts/kalimdor/razorfen_kraul/instance_razorfen_kraul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,7 +37,7 @@ void instance_razorfen_kraul::Initialize() void instance_razorfen_kraul::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_AGATHELOS_WARD: m_mGoEntryGuidStore[GO_AGATHELOS_WARD] = pGo->GetObjectGuid(); @@ -45,12 +45,11 @@ void instance_razorfen_kraul::OnObjectCreate(GameObject* pGo) pGo->SetGoState(GO_STATE_ACTIVE); break; } - } void instance_razorfen_kraul::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_WARD_KEEPER: ++m_uiWardKeepersRemaining; @@ -60,7 +59,7 @@ void instance_razorfen_kraul::OnCreatureCreate(Creature* pCreature) void instance_razorfen_kraul::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_AGATHELOS: --m_uiWardKeepersRemaining; @@ -99,7 +98,7 @@ void instance_razorfen_kraul::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -108,9 +107,9 @@ void instance_razorfen_kraul::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_razorfen_kraul::GetData(uint32 uiType) +uint32 instance_razorfen_kraul::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_AGATHELOS: return m_auiEncounter[0]; diff --git a/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp index a1a634d6b..735826bab 100644 --- a/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp +++ b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Razorfen_Kraul SD%Complete: 100 -SDComment: Willix the Importer Escort Event +SDComment: Quest support: 1144, 1221 SDCategory: Razorfen Kraul EndScriptData */ @@ -27,6 +27,11 @@ EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "pet_ai.h" + +/*###### +## npc_willix_the_importer +######*/ enum { @@ -58,16 +63,16 @@ static const float aBoarSpawn[4][3] = {1958.971f, 1599.01f, 81.44f} }; -struct MANGOS_DLL_DECL npc_willix_the_importerAI : public npc_escortAI +struct npc_willix_the_importerAI : public npc_escortAI { npc_willix_the_importerAI(Creature* m_creature) : npc_escortAI(m_creature) { Reset(); } - void Reset() {} + void Reset() override {} // Exact use of these texts remains unknown, it seems that he should only talk when he initiates the attack or he is the first who is attacked by a npc - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { - switch(urand(0, 6)) // Not always said + switch (urand(0, 6)) // Not always said { case 0: DoScriptText(SAY_WILLIX_AGGRO_1, m_creature, pWho); break; case 1: DoScriptText(SAY_WILLIX_AGGRO_2, m_creature, pWho); break; @@ -76,12 +81,12 @@ struct MANGOS_DLL_DECL npc_willix_the_importerAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { @@ -97,8 +102,8 @@ struct MANGOS_DLL_DECL npc_willix_the_importerAI : public npc_escortAI case 14: DoScriptText(SAY_WILLIX_4, m_creature); // Summon 2 boars on the pathway - m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[0][0], aBoarSpawn[0][1], aBoarSpawn[0][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[1][0], aBoarSpawn[1][1], aBoarSpawn[1][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[0][0], aBoarSpawn[0][1], aBoarSpawn[0][2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[1][0], aBoarSpawn[1][1], aBoarSpawn[1][2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 25: DoScriptText(SAY_WILLIX_5, m_creature); @@ -109,8 +114,8 @@ struct MANGOS_DLL_DECL npc_willix_the_importerAI : public npc_escortAI case 44: DoScriptText(SAY_WILLIX_7, m_creature); // Summon 2 boars at the end - m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[2][0], aBoarSpawn[2][1], aBoarSpawn[2][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[3][0], aBoarSpawn[3][1], aBoarSpawn[3][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[2][0], aBoarSpawn[2][1], aBoarSpawn[2][2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_RAGING_AGAMAR, aBoarSpawn[3][0], aBoarSpawn[3][1], aBoarSpawn[3][2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 45: DoScriptText(SAY_WILLIX_END, m_creature); @@ -121,7 +126,6 @@ struct MANGOS_DLL_DECL npc_willix_the_importerAI : public npc_escortAI SetEscortPaused(true); break; } - } }; @@ -139,11 +143,113 @@ bool QuestAccept_npc_willix_the_importer(Player* pPlayer, Creature* pCreature, c // After 4.0.1 set run = true pEscortAI->Start(false, pPlayer, pQuest); DoScriptText(SAY_WILLIX_READY, pCreature, pPlayer); - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + } + } + + return true; +} + +/*###### +## npc_snufflenose_gopher +######*/ + +enum +{ + SPELL_SNUFFLENOSE_COMMAND = 8283, + NPC_SNUFFLENOSE_GOPHER = 4781, + GO_BLUELEAF_TUBBER = 20920, +}; + +struct npc_snufflenose_gopherAI : public ScriptedPetAI +{ + npc_snufflenose_gopherAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + bool m_bIsMovementActive; + + ObjectGuid m_targetTubberGuid; + + void Reset() override + { + m_bIsMovementActive = false; + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (GameObject* pGo = m_creature->GetMap()->GetGameObject(m_targetTubberGuid)) + { + pGo->SetRespawnTime(5 * MINUTE); + pGo->Refresh(); + + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); + } + + m_bIsMovementActive = false; + } + + // Function to search for new tubber in range + void DoFindNewTubber() + { + std::list lTubbersInRange; + GetGameObjectListWithEntryInGrid(lTubbersInRange, m_creature, GO_BLUELEAF_TUBBER, 40.0f); + + if (lTubbersInRange.empty()) + return; + + lTubbersInRange.sort(ObjectDistanceOrder(m_creature)); + GameObject* pNearestTubber = NULL; + + // Always need to find new ones + for (std::list::const_iterator itr = lTubbersInRange.begin(); itr != lTubbersInRange.end(); ++itr) + { + if (!(*itr)->isSpawned() && (*itr)->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND) && (*itr)->IsWithinLOSInMap(m_creature)) + { + pNearestTubber = *itr; + break; + } } + + if (!pNearestTubber) + return; + m_targetTubberGuid = pNearestTubber->GetObjectGuid(); + + float fX, fY, fZ; + pNearestTubber->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_bIsMovementActive = true; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsMovementActive) + ScriptedPetAI::UpdateAI(uiDiff); } +}; +CreatureAI* GetAI_npc_snufflenose_gopher(Creature* pCreature) +{ + return new npc_snufflenose_gopherAI(pCreature); +} + +bool EffectDummyCreature_npc_snufflenose_gopher(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_SNUFFLENOSE_COMMAND && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_SNUFFLENOSE_GOPHER) + { + if (npc_snufflenose_gopherAI* pGopherAI = dynamic_cast(pCreatureTarget->AI())) + pGopherAI->DoFindNewTubber(); + } + + // always return true when we are handling this spell and effect return true; + } + + return false; } void AddSC_razorfen_kraul() @@ -155,4 +261,10 @@ void AddSC_razorfen_kraul() pNewScript->GetAI = &GetAI_npc_willix_the_importer; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_willix_the_importer; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_snufflenose_gopher"; + pNewScript->GetAI = &GetAI_npc_snufflenose_gopher; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_snufflenose_gopher; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h index 613bb3258..2aa4fca94 100644 --- a/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h +++ b/scripts/kalimdor/razorfen_kraul/razorfen_kraul.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -16,22 +16,22 @@ enum NPC_WARD_KEEPER = 4625 }; -class MANGOS_DLL_DECL instance_razorfen_kraul : public ScriptedInstance +class instance_razorfen_kraul : public ScriptedInstance { public: instance_razorfen_kraul(Map* pMap); ~instance_razorfen_kraul() {} - void Initialize(); + void Initialize() override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp index 939c36c68..edfa81910 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/boss_ayamiss.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,8 +29,8 @@ enum EMOTE_GENERIC_FRENZY = -1000002, SPELL_STINGER_SPRAY = 25749, - SPELL_POISON_STINGER = 25748, //only used in phase1 - //SPELL_SUMMON_SWARMER = 25844, //might be 25708 - spells were removed since 2.0.1 + SPELL_POISON_STINGER = 25748, // only used in phase1 + // SPELL_SUMMON_SWARMER = 25844, // might be 25708 - spells were removed since 2.0.1 SPELL_PARALYZE = 25725, SPELL_LASH = 25852, SPELL_FRENZY = 8269, @@ -54,13 +54,13 @@ struct SummonLocation // Spawn locations static const SummonLocation aAyamissSpawnLocs[] = { - {-9674.4707f, 1528.4133f, 22.457f}, // larva - {-9701.6005f, 1566.9993f, 24.118f}, // larva - {-9647.352f, 1578.062f, 55.32f}, // anchor point for swarmers - {-9717.18f, 1517.72f, 27.4677f}, // teleport location - need to be hardcoded because the player is teleported after the larva is summoned + { -9674.4707f, 1528.4133f, 22.457f}, // larva + { -9701.6005f, 1566.9993f, 24.118f}, // larva + { -9647.352f, 1578.062f, 55.32f}, // anchor point for swarmers + { -9717.18f, 1517.72f, 27.4677f}, // teleport location - need to be hardcoded because the player is teleported after the larva is summoned }; -struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI +struct boss_ayamissAI : public ScriptedAI { boss_ayamissAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -76,9 +76,9 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI bool m_bHasFrenzy; ObjectGuid m_paralyzeTarget; - GUIDList m_lSwarmersGuidList; + GuidList m_lSwarmersGuidList; - void Reset() + void Reset() override { m_uiStingerSprayTimer = urand(20000, 30000); m_uiPoisonStingerTimer = 5000; @@ -94,13 +94,13 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI SetCombatMovement(false); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { m_creature->SetLevitate(true); m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 15.0f); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // store the swarmers for a future attack if (pSummoned->GetEntry() == NPC_SWARMER) @@ -118,7 +118,7 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 /*uiMotionType*/, uint32 uiPointId) override { if (uiPointId != 1 || pSummoned->GetEntry() != NPC_LARVA) return; @@ -128,7 +128,7 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI pSummoned->CastSpell(pTarget, SPELL_FEED, true, NULL, NULL, m_creature->GetObjectGuid()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -165,7 +165,7 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI // Summon a larva uint8 uiLoc = urand(0, 1); - m_creature->SummonCreature(NPC_LARVA, aAyamissSpawnLocs[uiLoc].m_fX, aAyamissSpawnLocs[uiLoc].m_fY, aAyamissSpawnLocs[uiLoc].m_fZ, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + m_creature->SummonCreature(NPC_LARVA, aAyamissSpawnLocs[uiLoc].m_fX, aAyamissSpawnLocs[uiLoc].m_fY, aAyamissSpawnLocs[uiLoc].m_fZ, 0, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 30000); } } else @@ -191,7 +191,7 @@ struct MANGOS_DLL_DECL boss_ayamissAI : public ScriptedAI // All the swarmers attack at a certain period of time if (m_uiSwarmerAttackTimer < uiDiff) { - for (GUIDList::const_iterator itr = m_lSwarmersGuidList.begin(); itr != m_lSwarmersGuidList.end(); ++itr) + for (GuidList::const_iterator itr = m_lSwarmersGuidList.begin(); itr != m_lSwarmersGuidList.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) { @@ -256,7 +256,7 @@ CreatureAI* GetAI_boss_ayamiss(Creature* pCreature) return new boss_ayamissAI(pCreature); } -struct MANGOS_DLL_DECL npc_hive_zara_larvaAI : public ScriptedAI +struct npc_hive_zara_larvaAI : public ScriptedAI { npc_hive_zara_larvaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -266,9 +266,9 @@ struct MANGOS_DLL_DECL npc_hive_zara_larvaAI : public ScriptedAI instance_ruins_of_ahnqiraj* m_pInstance; - void Reset() { } + void Reset() override { } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { // don't attack anything during the Ayamiss encounter if (m_pInstance) @@ -280,7 +280,7 @@ struct MANGOS_DLL_DECL npc_hive_zara_larvaAI : public ScriptedAI ScriptedAI::AttackStart(pWho); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // don't attack anything during the Ayamiss encounter if (m_pInstance) @@ -292,7 +292,7 @@ struct MANGOS_DLL_DECL npc_hive_zara_larvaAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 /*uiDiff*/) override { if (m_pInstance) { diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp index 8118174c9..d33089814 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/boss_buru.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Buru -SD%Complete: 50 -SDComment: Timers; Fixate for phase I target NYI; Kill eggs on transform NYI; Egg explode damage and Buru stun are missing +SD%Complete: 70 +SDComment: Timers; Kill eggs on transform NYI; Egg explode damage and Buru stun are missing SDCategory: Ruins of Ahn'Qiraj EndScriptData */ @@ -50,7 +50,7 @@ enum PHASE_TRANSFORM = 2, }; -struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI +struct boss_buruAI : public ScriptedAI { boss_buruAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -60,7 +60,7 @@ struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI uint32 m_uiGatheringSpeedTimer; uint32 m_uiFullSpeedTimer; - void Reset() + void Reset() override { m_uiDismemberTimer = 5000; m_uiGatheringSpeedTimer = 9000; @@ -69,13 +69,14 @@ struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI m_uiPhase = PHASE_EGG; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoScriptText(EMOTE_TARGET, m_creature, pWho); DoCastSpellIfCan(m_creature, SPELL_THORNS); + m_creature->FixateTarget(pWho); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { // Attack a new random target when a player is killed if (pVictim->GetTypeId() == TYPEID_PLAYER) @@ -93,8 +94,7 @@ struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) { - DoResetThreat(); - m_creature->AI()->AttackStart(pTarget); + m_creature->FixateTarget(pTarget); DoScriptText(EMOTE_TARGET, m_creature, pTarget); } @@ -102,7 +102,7 @@ struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI m_uiGatheringSpeedTimer = 9000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -145,6 +145,7 @@ struct MANGOS_DLL_DECL boss_buruAI : public ScriptedAI // Not sure of this but the boss should gain full speed in phase II DoCastSpellIfCan(m_creature, SPELL_FULL_SPEED, CAST_TRIGGERED); m_creature->RemoveAurasDueToSpell(SPELL_THORNS); + m_creature->FixateTarget(NULL); m_uiPhase = PHASE_TRANSFORM; } } @@ -172,7 +173,7 @@ CreatureAI* GetAI_boss_buru(Creature* pCreature) return new boss_buruAI(pCreature); } -struct MANGOS_DLL_DECL npc_buru_eggAI : public Scripted_NoMovementAI +struct npc_buru_eggAI : public Scripted_NoMovementAI { npc_buru_eggAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -182,10 +183,10 @@ struct MANGOS_DLL_DECL npc_buru_eggAI : public Scripted_NoMovementAI ScriptedInstance* m_pInstance; - void Reset() + void Reset() override { } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // The purpose of this is unk for the moment if (pSummoned->GetEntry() == NPC_BURU_EGG_TRIGGER) @@ -204,7 +205,7 @@ struct MANGOS_DLL_DECL npc_buru_eggAI : public Scripted_NoMovementAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { // Explode and Summon hatchling DoCastSpellIfCan(m_creature, SPELL_EXPLODE, CAST_TRIGGERED); @@ -221,7 +222,7 @@ struct MANGOS_DLL_DECL npc_buru_eggAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) { } + void UpdateAI(const uint32 /*uiDiff*/) override { } }; CreatureAI* GetAI_npc_buru_egg(Creature* pCreature) diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp index c3ed80cd6..01f6ca780 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/boss_kurinnaxx.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,7 +35,7 @@ enum GO_SAND_TRAP = 180647, }; -struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI +struct boss_kurinnaxxAI : public ScriptedAI { boss_kurinnaxxAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -48,7 +48,7 @@ struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI ObjectGuid m_sandtrapGuid; - void Reset() + void Reset() override { m_bEnraged = false; @@ -59,7 +59,7 @@ struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI m_uiTrapTriggerTimer = 0; } - void JustSummoned(GameObject* pGo) + void JustSummoned(GameObject* pGo) override { if (pGo->GetEntry() == GO_SAND_TRAP) { @@ -68,7 +68,7 @@ struct MANGOS_DLL_DECL boss_kurinnaxxAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp index f97f6bee4..e21cd7b6b 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/boss_moam.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,7 +41,7 @@ enum PHASE_ENERGIZING = 1 }; -struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI +struct boss_moamAI : public ScriptedAI { boss_moamAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -52,7 +52,7 @@ struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI uint32 m_uiCheckoutManaTimer; uint32 m_uiSummonManaFiendsTimer; - void Reset() + void Reset() override { m_uiTrampleTimer = 9000; m_uiManaDrainTimer = 3000; @@ -63,18 +63,18 @@ struct MANGOS_DLL_DECL boss_moamAI : public ScriptedAI m_creature->SetMaxPower(POWER_MANA, 0); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(EMOTE_AGGRO, m_creature); - m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->maxmana); + m_creature->SetMaxPower(POWER_MANA, m_creature->GetCreatureInfo()->MaxLevelMana); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - switch(m_uiPhase) + switch (m_uiPhase) { case PHASE_ATTACKING: if (m_uiCheckoutManaTimer <= uiDiff) diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp index d61e91d8e..3b8cba0ef 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/boss_ossirian.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Ossirian -SD%Complete: 50% -SDComment: Tornados missing, Crystal handling missing, Weather missing +SD%Complete: 100% +SDComment: SDCategory: Ruins of Ahn'Qiraj EndScriptData */ @@ -40,6 +40,8 @@ enum SPELL_CYCLONE = 25189, SPELL_STOMP = 25188, SPELL_SUPREME = 25176, + SPELL_SUMMON_CRYSTAL = 25192, + SPELL_SAND_STORM = 25160, // tornado spell SPELL_SUMMON = 20477, // TODO NYI MAX_CRYSTAL_POSITIONS = 1, // TODO @@ -49,11 +51,22 @@ enum SPELL_WEAKNESS_NATURE = 25180, SPELL_WEAKNESS_ARCANE = 25181, SPELL_WEAKNESS_SHADOW = 25183, + + NPC_SAND_VORTEX = 15428, // tornado npc + + ZONE_ID_RUINS_AQ = 3429, +}; + +static const float aSandVortexSpawnPos[2][4] = +{ + { -9523.482f, 1880.435f, 85.645f, 5.08f}, + { -9321.39f, 1822.968f, 84.266f, 3.16f}, }; +static const float aCrystalSpawnPos[3] = { -9355.75f, 1905.43f, 85.55f}; static const uint32 aWeaknessSpell[] = {SPELL_WEAKNESS_FIRE, SPELL_WEAKNESS_FROST, SPELL_WEAKNESS_NATURE, SPELL_WEAKNESS_ARCANE, SPELL_WEAKNESS_SHADOW}; -struct MANGOS_DLL_DECL boss_ossirianAI : public ScriptedAI +struct boss_ossirianAI : public ScriptedAI { boss_ossirianAI(Creature* pCreature) : ScriptedAI(pCreature) @@ -73,7 +86,7 @@ struct MANGOS_DLL_DECL boss_ossirianAI : public ScriptedAI bool m_bSaidIntro; - void Reset() + void Reset() override { m_uiCrystalPosition = 0; m_uiCycloneTimer = 20000; @@ -82,19 +95,25 @@ struct MANGOS_DLL_DECL boss_ossirianAI : public ScriptedAI m_uiSupremeTimer = 45000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, SPELL_SUPREME, CAST_TRIGGERED); DoScriptText(SAY_AGGRO, m_creature); DoSpawnNextCrystal(); + + for (uint8 i = 0; i < countof(aSandVortexSpawnPos); ++i) + m_creature->SummonCreature(NPC_SAND_VORTEX, aSandVortexSpawnPos[i][0], aSandVortexSpawnPos[i][1], aSandVortexSpawnPos[i][2], aSandVortexSpawnPos[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0); + + if (m_pInstance) + m_pInstance->instance->SetWeather(ZONE_ID_RUINS_AQ, WEATHER_TYPE_STORM, 1.0f, true); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY, m_creature); } @@ -115,25 +134,41 @@ struct MANGOS_DLL_DECL boss_ossirianAI : public ScriptedAI else { // Summon a new crystal trigger at some position depending on m_uiCrystalPosition + // Note: the summon points seem to be very random; requires additional research + float fX, fY, fZ; + m_creature->GetRandomPoint(aCrystalSpawnPos[0], aCrystalSpawnPos[1], aCrystalSpawnPos[2], 100.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_OSSIRIAN_TRIGGER, fX, fY, fZ, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); } if (!pOssirianTrigger) return; // Respawn GO near crystal trigger if (GameObject* pCrystal = GetClosestGameObjectWithEntry(pOssirianTrigger, GO_OSSIRIAN_CRYSTAL, 10.0f)) - m_pInstance->DoRespawnGameObject(pCrystal->GetObjectGuid(), 5*MINUTE); + m_pInstance->DoRespawnGameObject(pCrystal->GetObjectGuid(), 5 * MINUTE); // Increase position ++m_uiCrystalPosition %= MAX_CRYSTAL_POSITIONS; } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_OSSIRIAN_TRIGGER) + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_CRYSTAL, true); + else if (pSummoned->GetEntry() == NPC_SAND_VORTEX) + { + // The movement of this isn't very clear - may require additional research + pSummoned->CastSpell(pSummoned, SPELL_SAND_STORM, true); + pSummoned->GetMotionMaster()->MoveRandomAroundPoint(aCrystalSpawnPos[0], aCrystalSpawnPos[1], aCrystalSpawnPos[2], 100.0f); + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pCaster->GetTypeId() == TYPEID_UNIT && pCaster->GetEntry() == NPC_OSSIRIAN_TRIGGER) { // Check for proper spell id bool bIsWeaknessSpell = false; - for (uint8 i = 0; i < sizeof(aWeaknessSpell); ++i) + for (uint8 i = 0; i < countof(aWeaknessSpell); ++i) { if (pSpell->Id == aWeaknessSpell[i]) { @@ -152,7 +187,7 @@ struct MANGOS_DLL_DECL boss_ossirianAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // TODO: Range guesswork if (!m_bSaidIntro && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 75.0f, false)) @@ -167,7 +202,7 @@ struct MANGOS_DLL_DECL boss_ossirianAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -228,7 +263,7 @@ CreatureAI* GetAI_boss_ossirian(Creature* pCreature) } // This is actually a hack for a server-side spell -bool GOUse_go_ossirian_crystal(Player* pPlayer, GameObject* pGo) +bool GOUse_go_ossirian_crystal(Player* /*pPlayer*/, GameObject* pGo) { if (Creature* pOssirianTrigger = GetClosestCreatureWithEntry(pGo, NPC_OSSIRIAN_TRIGGER, 10.0f)) pOssirianTrigger->CastSpell(pOssirianTrigger, aWeaknessSpell[urand(0, 4)], false); diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp index a68ab798e..c0170685f 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/boss_rajaxx.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,29 +16,372 @@ /* ScriptData SDName: Boss_Rajaxx -SD%Complete: 0 -SDComment: Place Holder +SD%Complete: 100 +SDComment: General Andorov script SDCategory: Ruins of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "ruins_of_ahnqiraj.h" -#define SAY_ANDOROV_INTRO -1509003 -#define SAY_ANDOROV_ATTACK -1509004 +enum +{ + // Event yells + SAY_ANDOROV_INTRO_1 = -1509004, + SAY_ANDOROV_INTRO_2 = -1509031, + SAY_ANDOROV_INTRO_3 = -1509003, + SAY_ANDOROV_INTRO_4 = -1509029, + SAY_ANDOROV_ATTACK_START = -1509030, -#define SAY_WAVE3 -1509005 -#define SAY_WAVE4 -1509006 -#define SAY_WAVE5 -1509007 -#define SAY_WAVE6 -1509008 -#define SAY_WAVE7 -1509009 -#define SAY_INTRO -1509010 + // Rajaxx kills Andorov + SAY_KILLS_ANDOROV = -1509016, -#define SAY_UNK1 -1509011 -#define SAY_UNK2 -1509012 -#define SAY_UNK3 -1509013 -#define SAY_UNK4 -1509014 + // probably related to the opening of AQ event + SAY_UNK1 = -1509011, + SAY_UNK2 = -1509012, + SAY_UNK3 = -1509013, + SAY_UNK4 = -1509014, -#define SAY_DEAGGRO -1509015 -#define SAY_KILLS_ANDOROV -1509016 + // gossip items + GOSSIP_TEXT_ID_INTRO = 7883, + GOSSIP_TEXT_ID_TRADE = 8305, -#define SAY_COMPLETE_QUEST -1509017 //Yell when realm complete quest 8743 for world event + GOSSIP_ITEM_START = -3509000, + GOSSIP_ITEM_TRADE = -3509001, + + // Andorov spells + SPELL_AURA_OF_COMMAND = 25516, + SPELL_BASH = 25515, + SPELL_STRIKE = 22591, + + // Kaldorei spell + SPELL_CLEAVE = 26350, + SPELL_MORTAL_STRIKE = 16856, + + POINT_ID_MOVE_INTRO = 2, + POINT_ID_MOVE_ATTACK = 4, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_ANDOROV_INTRO_1, NPC_GENERAL_ANDOROV, 7000}, + {SAY_ANDOROV_INTRO_2, NPC_GENERAL_ANDOROV, 0}, + {SAY_ANDOROV_INTRO_3, NPC_GENERAL_ANDOROV, 4000}, + {SAY_ANDOROV_INTRO_4, NPC_GENERAL_ANDOROV, 6000}, + {SAY_ANDOROV_ATTACK_START, NPC_GENERAL_ANDOROV, 0}, + {0, 0, 0}, +}; + +struct npc_general_andorovAI : public ScriptedAI, private DialogueHelper +{ + npc_general_andorovAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (instance_ruins_of_ahnqiraj*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + m_uiMoveTimer = 5000; + m_uiPointId = 0; + Reset(); + } + + instance_ruins_of_ahnqiraj* m_pInstance; + + uint32 m_uiCommandAuraTimer; + uint32 m_uiBashTimer; + uint32 m_uiStrikeTimer; + uint32 m_uiMoveTimer; + + uint8 m_uiPointId; + + void Reset() override + { + m_uiCommandAuraTimer = urand(1000, 3000); + m_uiBashTimer = urand(8000, 11000); + m_uiStrikeTimer = urand(2000, 5000); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // If Rajaxx is in range attack him + if (pWho->GetEntry() == NPC_RAJAXX && m_creature->IsWithinDistInMap(pWho, 50.0f)) + AttackStart(pWho); + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustDied(Unit* pKiller) override + { + if (pKiller->GetEntry() != NPC_RAJAXX) + return; + + // Yell when killed by Rajaxx + if (m_pInstance) + { + if (Creature* pRajaxx = m_pInstance->GetSingleCreatureFromStorage(NPC_RAJAXX)) + DoScriptText(SAY_KILLS_ANDOROV, pRajaxx); + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + // Start the event when the dialogue is finished + if (iEntry == SAY_ANDOROV_ATTACK_START) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_RAJAXX, IN_PROGRESS); + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case 0: + case 1: + case 3: + ++m_uiPointId; + m_creature->GetMotionMaster()->MovePoint(m_uiPointId, aAndorovMoveLocs[m_uiPointId].m_fX, aAndorovMoveLocs[m_uiPointId].m_fY, aAndorovMoveLocs[m_uiPointId].m_fZ); + break; + case POINT_ID_MOVE_INTRO: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->SetFacingTo(aAndorovMoveLocs[3].m_fO); + ++m_uiPointId; + break; + case POINT_ID_MOVE_ATTACK: + // Start dialogue only the first time it reaches the point + if (m_uiPointId == 4) + { + StartNextDialogueText(SAY_ANDOROV_INTRO_3); + ++m_uiPointId; + } + break; + } + } + + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive()) + { + // reset to combat position + if (m_uiPointId >= 4) + m_creature->GetMotionMaster()->MovePoint(POINT_ID_MOVE_ATTACK, aAndorovMoveLocs[4].m_fX, aAndorovMoveLocs[4].m_fY, aAndorovMoveLocs[4].m_fZ); + // reset to intro position + else + m_creature->GetMotionMaster()->MovePoint(POINT_ID_MOVE_INTRO, aAndorovMoveLocs[2].m_fX, aAndorovMoveLocs[2].m_fY, aAndorovMoveLocs[2].m_fZ); + } + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + // Wrapper to start initialize Kaldorei followers + void DoInitializeFollowers() + { + if (!m_pInstance) + return; + + GuidList m_lKaldoreiGuids; + m_pInstance->GetKaldoreiGuidList(m_lKaldoreiGuids); + + for (GuidList::const_iterator itr = m_lKaldoreiGuids.begin(); itr != m_lKaldoreiGuids.end(); ++itr) + { + if (Creature* pKaldorei = m_creature->GetMap()->GetCreature(*itr)) + pKaldorei->GetMotionMaster()->MoveFollow(m_creature, pKaldorei->GetDistance(m_creature), pKaldorei->GetAngle(m_creature)); + } + } + + // Wrapper to start the event + void DoMoveToEventLocation() + { + m_creature->GetMotionMaster()->MovePoint(m_uiPointId, aAndorovMoveLocs[m_uiPointId].m_fX, aAndorovMoveLocs[m_uiPointId].m_fY, aAndorovMoveLocs[m_uiPointId].m_fZ); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + StartNextDialogueText(SAY_ANDOROV_INTRO_1); + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (m_uiMoveTimer) + { + if (m_uiMoveTimer <= uiDiff) + { + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(m_uiPointId, aAndorovMoveLocs[m_uiPointId].m_fX, aAndorovMoveLocs[m_uiPointId].m_fY, aAndorovMoveLocs[m_uiPointId].m_fZ); + + DoInitializeFollowers(); + m_uiMoveTimer = 0; + } + else + m_uiMoveTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BASH) == CAST_OK) + m_uiBashTimer = urand(12000, 15000); + } + else + m_uiBashTimer -= uiDiff; + + if (m_uiStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRIKE) == CAST_OK) + m_uiStrikeTimer = urand(4000, 6000); + } + else + m_uiStrikeTimer -= uiDiff; + + if (m_uiCommandAuraTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_AURA_OF_COMMAND) == CAST_OK) + m_uiCommandAuraTimer = urand(30000, 45000); + } + else + m_uiCommandAuraTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_general_andorov(Creature* pCreature) +{ + return new npc_general_andorovAI(pCreature); +} + +bool GossipHello_npc_general_andorov(Player* pPlayer, Creature* pCreature) +{ + if (instance_ruins_of_ahnqiraj* pInstance = (instance_ruins_of_ahnqiraj*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_RAJAXX) == IN_PROGRESS) + return true; + + if (pInstance->GetData(TYPE_RAJAXX) == NOT_STARTED || pInstance->GetData(TYPE_RAJAXX) == FAIL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_VENDOR, GOSSIP_ITEM_TRADE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_INTRO, pCreature->GetObjectGuid()); + } + + return true; +} + +bool GossipSelect_npc_general_andorov(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + if (npc_general_andorovAI* pAndorovAI = dynamic_cast(pCreature->AI())) + pAndorovAI->DoMoveToEventLocation(); + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + if (uiAction == GOSSIP_ACTION_TRADE) + pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); + + return true; +} + +struct npc_kaldorei_eliteAI : public ScriptedAI +{ + npc_kaldorei_eliteAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiCleaveTimer; + uint32 m_uiStrikeTimer; + + void Reset() override + { + m_uiCleaveTimer = urand(2000, 4000); + m_uiStrikeTimer = urand(8000, 11000); + } + + void EnterEvadeMode() override + { + if (!m_pInstance) + return; + + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + // reset only to the last position + if (m_creature->isAlive()) + { + if (Creature* pAndorov = m_pInstance->GetSingleCreatureFromStorage(NPC_GENERAL_ANDOROV)) + { + if (pAndorov->isAlive()) + m_creature->GetMotionMaster()->MoveFollow(pAndorov, m_creature->GetDistance(pAndorov), m_creature->GetAngle(pAndorov)); + } + } + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(5000, 7000); + } + else + m_uiCleaveTimer -= uiDiff; + + if (m_uiStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiStrikeTimer = urand(9000, 13000); + } + else + m_uiStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_kaldorei_elite(Creature* pCreature) +{ + return new npc_kaldorei_eliteAI(pCreature); +} + +void AddSC_boss_rajaxx() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_general_andorov"; + pNewScript->GetAI = &GetAI_npc_general_andorov; + pNewScript->pGossipHello = &GossipHello_npc_general_andorov; + pNewScript->pGossipSelect = &GossipSelect_npc_general_andorov; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_kaldorei_elite"; + pNewScript->GetAI = &GetAI_npc_kaldorei_elite; + pNewScript->RegisterSelf(); +} diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp index 728f567c4..2ef042dd0 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/instance_ruins_of_ahnqiraj.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,14 +17,16 @@ /* ScriptData SDName: Instance_Ruins_of_Ahnqiraj SD%Complete: 80 -SDComment: +SDComment: It's not clear if the Rajaxx event should reset if Andorov dies, or party wipes. SDCategory: Ruins of Ahn'Qiraj EndScriptData */ #include "precompiled.h" #include "ruins_of_ahnqiraj.h" -instance_ruins_of_ahnqiraj::instance_ruins_of_ahnqiraj(Map* pMap) : ScriptedInstance(pMap) +instance_ruins_of_ahnqiraj::instance_ruins_of_ahnqiraj(Map* pMap) : ScriptedInstance(pMap), + m_uiArmyDelayTimer(0), + m_uiCurrentArmyWave(0) { Initialize(); } @@ -34,23 +36,37 @@ void instance_ruins_of_ahnqiraj::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } -void instance_ruins_of_ahnqiraj::OnPlayerEnter(Player* pPlayer) +void instance_ruins_of_ahnqiraj::OnPlayerEnter(Player* /*pPlayer*/) { // Spawn andorov if necessary - DoSapwnAndorovIfCan(); + if (m_auiEncounter[TYPE_KURINNAXX] == DONE) + DoSapwnAndorovIfCan(); } void instance_ruins_of_ahnqiraj::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_OSSIRIAN_TRIGGER: - // Only store static spawned (if this can be checked, else use a bool) + // Only store static spawned + if (pCreature->IsTemporarySummon()) + break; case NPC_BURU: case NPC_OSSIRIAN: + case NPC_RAJAXX: case NPC_GENERAL_ANDOROV: + case NPC_COLONEL_ZERRAN: + case NPC_MAJOR_PAKKON: + case NPC_MAJOR_YEGGETH: + case NPC_CAPTAIN_XURREM: + case NPC_CAPTAIN_DRENN: + case NPC_CAPTAIN_TUUBID: + case NPC_CAPTAIN_QEEZ: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_KALDOREI_ELITE: + m_lKaldoreiGuidList.push_back(pCreature->GetObjectGuid()); + return; } } @@ -59,7 +75,6 @@ void instance_ruins_of_ahnqiraj::OnCreatureEnterCombat(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_KURINNAXX: SetData(TYPE_KURINNAXX, IN_PROGRESS); break; - case NPC_RAJAXX: SetData(TYPE_RAJAXX, IN_PROGRESS); break; case NPC_MOAM: SetData(TYPE_MOAM, IN_PROGRESS); break; case NPC_BURU: SetData(TYPE_BURU, IN_PROGRESS); break; case NPC_AYAMISS: SetData(TYPE_AYAMISS, IN_PROGRESS); break; @@ -72,11 +87,23 @@ void instance_ruins_of_ahnqiraj::OnCreatureEvade(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_KURINNAXX: SetData(TYPE_KURINNAXX, FAIL); break; - case NPC_RAJAXX: SetData(TYPE_RAJAXX, FAIL); break; case NPC_MOAM: SetData(TYPE_MOAM, FAIL); break; case NPC_BURU: SetData(TYPE_BURU, FAIL); break; case NPC_AYAMISS: SetData(TYPE_AYAMISS, FAIL); break; case NPC_OSSIRIAN: SetData(TYPE_OSSIRIAN, FAIL); break; + case NPC_RAJAXX: + // Rajaxx yells on evade + DoScriptText(SAY_DEAGGRO, pCreature); + // no break; + case NPC_COLONEL_ZERRAN: + case NPC_MAJOR_PAKKON: + case NPC_MAJOR_YEGGETH: + case NPC_CAPTAIN_XURREM: + case NPC_CAPTAIN_DRENN: + case NPC_CAPTAIN_TUUBID: + case NPC_CAPTAIN_QEEZ: + SetData(TYPE_RAJAXX, FAIL); + break; } } @@ -90,12 +117,37 @@ void instance_ruins_of_ahnqiraj::OnCreatureDeath(Creature* pCreature) case NPC_BURU: SetData(TYPE_BURU, DONE); break; case NPC_AYAMISS: SetData(TYPE_AYAMISS, DONE); break; case NPC_OSSIRIAN: SetData(TYPE_OSSIRIAN, DONE); break; + case NPC_COLONEL_ZERRAN: + case NPC_MAJOR_PAKKON: + case NPC_MAJOR_YEGGETH: + case NPC_CAPTAIN_XURREM: + case NPC_CAPTAIN_DRENN: + case NPC_CAPTAIN_TUUBID: + case NPC_CAPTAIN_QEEZ: + case NPC_QIRAJI_WARRIOR: + case NPC_SWARMGUARD_NEEDLER: + { + // If event isn't started by Andorov, return + if (GetData(TYPE_RAJAXX) != IN_PROGRESS) + return; + + // Check if the dead creature belongs to the current wave + if (m_sArmyWavesGuids[m_uiCurrentArmyWave - 1].find(pCreature->GetObjectGuid()) != m_sArmyWavesGuids[m_uiCurrentArmyWave - 1].end()) + { + m_sArmyWavesGuids[m_uiCurrentArmyWave - 1].erase(pCreature->GetObjectGuid()); + + // If all the soldiers from the current wave are dead, then send the next one + if (m_sArmyWavesGuids[m_uiCurrentArmyWave - 1].empty()) + DoSendNextArmyWave(); + } + break; + } } } void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_KURINNAXX: if (uiData == DONE) @@ -108,6 +160,18 @@ void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; case TYPE_RAJAXX: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + DoSortArmyWaves(); + if (uiData == DONE) + { + if (Creature* pAndorov = GetSingleCreatureFromStorage(NPC_GENERAL_ANDOROV)) + { + if (pAndorov->isAlive()) + pAndorov->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + } + break; case TYPE_MOAM: case TYPE_BURU: case TYPE_AYAMISS: @@ -122,7 +186,7 @@ void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] - << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + << " " << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; m_strInstData = saveStream.str(); @@ -131,9 +195,9 @@ void instance_ruins_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_ruins_of_ahnqiraj::GetData(uint32 uiType) +uint32 instance_ruins_of_ahnqiraj::GetData(uint32 uiType) const { - if (uiType < MAX_ENCOUNTER) + if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; return 0; @@ -141,10 +205,6 @@ uint32 instance_ruins_of_ahnqiraj::GetData(uint32 uiType) void instance_ruins_of_ahnqiraj::DoSapwnAndorovIfCan() { - // The npc is also a vendor so always spawn after kurinnaxx - if (m_auiEncounter[TYPE_KURINNAXX] != DONE) - return; - if (GetSingleCreatureFromStorage(NPC_GENERAL_ANDOROV)) return; @@ -171,7 +231,7 @@ void instance_ruins_of_ahnqiraj::Load(const char* chrIn) loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -180,6 +240,110 @@ void instance_ruins_of_ahnqiraj::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } +void instance_ruins_of_ahnqiraj::Update(uint32 uiDiff) +{ + if (GetData(TYPE_RAJAXX) == IN_PROGRESS) + { + if (m_uiArmyDelayTimer) + { + if (m_uiArmyDelayTimer <= uiDiff) + { + DoSendNextArmyWave(); + m_uiArmyDelayTimer = 2 * MINUTE * IN_MILLISECONDS; + } + else + m_uiArmyDelayTimer -= uiDiff; + } + } +} + +void instance_ruins_of_ahnqiraj::DoSortArmyWaves() +{ + std::list lCreatureList; + + // Sort the 7 army waves + // We need to use gridsearcher for this, because coords search is too complicated here + for (uint8 i = 0; i < MAX_ARMY_WAVES; ++i) + { + // Clear all the army waves + m_sArmyWavesGuids[i].clear(); + lCreatureList.clear(); + + if (Creature* pTemp = GetSingleCreatureFromStorage(aArmySortingParameters[i].m_uiEntry)) + { + GetCreatureListWithEntryInGrid(lCreatureList, pTemp, NPC_QIRAJI_WARRIOR, aArmySortingParameters[i].m_fSearchDist); + GetCreatureListWithEntryInGrid(lCreatureList, pTemp, NPC_SWARMGUARD_NEEDLER, aArmySortingParameters[i].m_fSearchDist); + + for (std::list::const_iterator itr = lCreatureList.begin(); itr != lCreatureList.end(); ++itr) + { + if ((*itr)->isAlive()) + m_sArmyWavesGuids[i].insert((*itr)->GetObjectGuid()); + } + + if (pTemp->isAlive()) + m_sArmyWavesGuids[i].insert(pTemp->GetObjectGuid()); + } + } + + // send the first wave + m_uiCurrentArmyWave = 0; + DoSendNextArmyWave(); +} + +void instance_ruins_of_ahnqiraj::DoSendNextArmyWave() +{ + // The next army wave is sent into battle after 2 min or after the previous wave is finished + if (GetData(TYPE_RAJAXX) != IN_PROGRESS) + return; + + // The last wave is General Rajaxx itself + if (m_uiCurrentArmyWave == MAX_ARMY_WAVES) + { + if (Creature* pRajaxx = GetSingleCreatureFromStorage(NPC_RAJAXX)) + { + DoScriptText(SAY_INTRO, pRajaxx); + pRajaxx->SetInCombatWithZone(); + } + } + else + { + // Increase the wave id if some are already dead + while (m_sArmyWavesGuids[m_uiCurrentArmyWave].empty() && m_uiCurrentArmyWave < MAX_ARMY_WAVES) + ++m_uiCurrentArmyWave; + + if (m_uiCurrentArmyWave == MAX_ARMY_WAVES) + { + script_error_log("Instance Ruins of Ahn'Qiraj: ERROR Something unexpected happened. Please report to SD2 team."); + return; + } + + float fX, fY, fZ; + for (GuidSet::const_iterator itr = m_sArmyWavesGuids[m_uiCurrentArmyWave].begin(); itr != m_sArmyWavesGuids[m_uiCurrentArmyWave].end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + { + if (!pTemp->isAlive()) + continue; + + pTemp->SetWalk(false); + pTemp->GetRandomPoint(aAndorovMoveLocs[4].m_fX, aAndorovMoveLocs[4].m_fY, aAndorovMoveLocs[4].m_fZ, 10.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + + // Yell on each wave (except the first 2) + if (aArmySortingParameters[m_uiCurrentArmyWave].m_uiYellEntry) + { + if (Creature* pRajaxx = GetSingleCreatureFromStorage(NPC_RAJAXX)) + DoScriptText(aArmySortingParameters[m_uiCurrentArmyWave].m_uiYellEntry, pRajaxx); + } + } + + // on wowwiki it states that there were 3 min between the waves, but this was reduced in later patches + m_uiArmyDelayTimer = 2 * MINUTE * IN_MILLISECONDS; + ++m_uiCurrentArmyWave; +} + InstanceData* GetInstanceData_instance_ruins_of_ahnqiraj(Map* pMap) { return new instance_ruins_of_ahnqiraj(pMap); diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp b/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp index 9cb970517..654f064dc 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp +++ b/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum NPC_ANUB_SWARM = 15538 }; -struct MANGOS_DLL_DECL mob_anubisath_guardianAI : public ScriptedAI +struct mob_anubisath_guardianAI : public ScriptedAI { mob_anubisath_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -68,13 +68,13 @@ struct MANGOS_DLL_DECL mob_anubisath_guardianAI : public ScriptedAI bool m_bIsEnraged; - void Reset() + void Reset() override { - m_uiSpell1 = urand(0,1) ? SPELL_METEOR : SPELL_PLAGUE; - m_uiSpell2 = urand(0,1) ? SPELL_SHADOW_STORM : SPELL_THUNDER_CLAP; - m_uiSpell3 = urand(0,1) ? SPELL_REFLECT_ARFR : SPELL_REFLECT_FSSH; - m_uiSpell4 = urand(0,1) ? SPELL_ENRAGE : SPELL_EXPLODE; - m_uiSpell5 = urand(0,1) ? SPELL_SUMMON_ANUB_SWARMGUARD : SPELL_SUMMON_ANUB_WARRIOR; + m_uiSpell1 = urand(0, 1) ? SPELL_METEOR : SPELL_PLAGUE; + m_uiSpell2 = urand(0, 1) ? SPELL_SHADOW_STORM : SPELL_THUNDER_CLAP; + m_uiSpell3 = urand(0, 1) ? SPELL_REFLECT_ARFR : SPELL_REFLECT_FSSH; + m_uiSpell4 = urand(0, 1) ? SPELL_ENRAGE : SPELL_EXPLODE; + m_uiSpell5 = urand(0, 1) ? SPELL_SUMMON_ANUB_SWARMGUARD : SPELL_SUMMON_ANUB_WARRIOR; m_uiSpell1Timer = 10000; m_uiSpell2Timer = 20000; @@ -83,24 +83,24 @@ struct MANGOS_DLL_DECL mob_anubisath_guardianAI : public ScriptedAI m_bIsEnraged = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { // spell reflection DoCastSpellIfCan(m_creature, m_uiSpell3); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature->getVictim()); ++m_uiSummonCount; } - void SummonedCreatureDespawn(Creature* pDespawned) + void SummonedCreatureDespawn(Creature* /*pDespawned*/) override { --m_uiSummonCount; } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& /*uiDamage*/) override { // when we reach 10% of HP explode or enrage if (!m_bIsEnraged && m_creature->GetHealthPercent() < 10.0f) @@ -116,7 +116,7 @@ struct MANGOS_DLL_DECL mob_anubisath_guardianAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h b/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h index fc7561ed7..3bd3019f8 100644 --- a/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h +++ b/scripts/kalimdor/ruins_of_ahnqiraj/ruins_of_ahnqiraj.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -25,18 +25,32 @@ enum NPC_GENERAL_ANDOROV = 15471, // The general and the kaldorei are escorted for the rajaxx encounter NPC_KALDOREI_ELITE = 15473, NPC_RAJAXX = 15341, // All of the following are used in the rajaxx encounter - // NPC_COLONEL_ZERRAN = 15385, - // NPC_MAJOR_PAKKON = 15388, - // NPC_MAJOR_YEGGETH = 15386, - // NPC_CAPTAIN_XURREM = 15390, - // NPC_CAPTAIN_DRENN = 15389, - // NPC_CAPTAIN_TUUBID = 15392, - // NPC_CAPTAIN_QEEZ = 15391, + NPC_COLONEL_ZERRAN = 15385, + NPC_MAJOR_PAKKON = 15388, + NPC_MAJOR_YEGGETH = 15386, + NPC_CAPTAIN_XURREM = 15390, + NPC_CAPTAIN_DRENN = 15389, + NPC_CAPTAIN_TUUBID = 15392, + NPC_CAPTAIN_QEEZ = 15391, + NPC_QIRAJI_WARRIOR = 15387, + NPC_SWARMGUARD_NEEDLER = 15344, + + MAX_ARMY_WAVES = 7, GO_OSSIRIAN_CRYSTAL = 180619, // Used in the ossirian encounter NPC_OSSIRIAN_TRIGGER = 15590, // Triggers ossirian weakness - SAY_OSSIRIAN_INTRO = -1509022 // Yelled after Kurinnax dies + SAY_OSSIRIAN_INTRO = -1509022, // Yelled after Kurinnax dies + + // Rajaxx yells + SAY_WAVE3 = -1509005, + SAY_WAVE4 = -1509006, + SAY_WAVE5 = -1509007, + SAY_WAVE6 = -1509008, + SAY_WAVE7 = -1509009, + SAY_INTRO = -1509010, + SAY_DEAGGRO = -1509015, // on Rajaxx evade + SAY_COMPLETE_QUEST = -1509017, // Yell when realm complete quest 8743 for world event }; struct SpawnLocation @@ -45,6 +59,7 @@ struct SpawnLocation float m_fX, m_fY, m_fZ, m_fO; }; +// Spawn coords for Andorov and his team static const SpawnLocation aAndorovSpawnLocs[MAX_HELPERS] = { {NPC_GENERAL_ANDOROV, -8660.4f, 1510.29f, 32.449f, 2.2184f}, @@ -54,33 +69,73 @@ static const SpawnLocation aAndorovSpawnLocs[MAX_HELPERS] = {NPC_KALDOREI_ELITE, -8664.45f, 1506.44f, 32.0944f, 2.33302f} }; -class MANGOS_DLL_DECL instance_ruins_of_ahnqiraj : public ScriptedInstance +// Movement locations for Andorov +static const SpawnLocation aAndorovMoveLocs[] = +{ + {0, -8701.51f, 1561.80f, 32.092f}, + {0, -8718.66f, 1577.69f, 21.612f}, + {0, -8876.97f, 1651.96f, 21.57f, 5.52f}, + {0, -8882.15f, 1602.77f, 21.386f}, + {0, -8940.45f, 1550.69f, 21.616f}, +}; + +struct SortingParameters +{ + uint32 m_uiEntry; + int32 m_uiYellEntry; + float m_fSearchDist; +}; + +static const SortingParameters aArmySortingParameters[MAX_ARMY_WAVES] = +{ + {NPC_CAPTAIN_QEEZ, 0, 20.0f}, + {NPC_CAPTAIN_TUUBID, 0, 22.0f}, + {NPC_CAPTAIN_DRENN, SAY_WAVE3, 22.0f}, + {NPC_CAPTAIN_XURREM, SAY_WAVE4, 22.0f}, + {NPC_MAJOR_YEGGETH, SAY_WAVE5, 20.0f}, + {NPC_MAJOR_PAKKON, SAY_WAVE6, 21.0f}, + {NPC_COLONEL_ZERRAN, SAY_WAVE7, 17.0f}, +}; + +class instance_ruins_of_ahnqiraj : public ScriptedInstance { public: instance_ruins_of_ahnqiraj(Map* pMap); ~instance_ruins_of_ahnqiraj() {} - void Initialize(); + void Initialize() override; - // bool IsEncounterInProgress() const; // not active in AQ20 + // bool IsEncounterInProgress() const override; // not active in AQ20 - void OnCreatureCreate(Creature* pCreature); - void OnPlayerEnter(Player* pPlayer); + void OnCreatureCreate(Creature* pCreature) override; + void OnPlayerEnter(Player* pPlayer) override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void GetKaldoreiGuidList(GuidList& lList) { lList = m_lKaldoreiGuidList; } - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void Update(uint32 uiDiff) override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: void DoSapwnAndorovIfCan(); + void DoSortArmyWaves(); + void DoSendNextArmyWave(); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + + GuidList m_lKaldoreiGuidList; + GuidSet m_sArmyWavesGuids[MAX_ARMY_WAVES]; + + uint32 m_uiArmyDelayTimer; + uint8 m_uiCurrentArmyWave; }; #endif diff --git a/scripts/kalimdor/silithus.cpp b/scripts/kalimdor/silithus.cpp index 576e6dad1..77c89b4fc 100644 --- a/scripts/kalimdor/silithus.cpp +++ b/scripts/kalimdor/silithus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,224 +17,16 @@ /* ScriptData SDName: Silithus SD%Complete: 100 -SDComment: Quest support: 7785, 8304, 8519. +SDComment: Quest support: 8519. SDCategory: Silithus EndScriptData */ /* ContentData -npc_highlord_demitrian -npcs_rutgar_and_frankal npc_anachronos_the_ancient EndContentData */ #include "precompiled.h" -/*### -## npc_highlord_demitrian -###*/ - -#define GOSSIP_ITEM_DEMITRIAN1 "What do you know of it?" -#define GOSSIP_ITEM_DEMITRIAN2 "I am listening , Demitrian." -#define GOSSIP_ITEM_DEMITRIAN3 "Continue, please." -#define GOSSIP_ITEM_DEMITRIAN4 "A battle?" -#define GOSSIP_ITEM_DEMITRIAN5 "" -#define GOSSIP_ITEM_DEMITRIAN6 "Caught unaware? How?" -#define GOSSIP_ITEM_DEMITRIAN7 "So what did Ragnaros do next?" - -enum -{ - QUEST_EXAMINE_THE_VESSEL = 7785, - ITEM_BINDINGS_WINDSEEKER_LEFT = 18563, - ITEM_BINDINGS_WINDSEEKER_RIGHT = 18564, - ITEM_VESSEL_OF_REBIRTH = 19016, - GOSSIP_TEXTID_DEMITRIAN1 = 6842, - GOSSIP_TEXTID_DEMITRIAN2 = 6843, - GOSSIP_TEXTID_DEMITRIAN3 = 6844, - GOSSIP_TEXTID_DEMITRIAN4 = 6867, - GOSSIP_TEXTID_DEMITRIAN5 = 6868, - GOSSIP_TEXTID_DEMITRIAN6 = 6869, - GOSSIP_TEXTID_DEMITRIAN7 = 6870 -}; - -bool GossipHello_npc_highlord_demitrian(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(QUEST_EXAMINE_THE_VESSEL) == QUEST_STATUS_NONE && - (pPlayer->HasItemCount(ITEM_BINDINGS_WINDSEEKER_LEFT,1,false) || pPlayer->HasItemCount(ITEM_BINDINGS_WINDSEEKER_RIGHT,1,false))) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_highlord_demitrian(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN1, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN2, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN3, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN4, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN5, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEMITRIAN7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN6, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEMITRIAN7, pCreature->GetObjectGuid()); - - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_VESSEL_OF_REBIRTH, 1)) - pPlayer->SendNewItem(pItem, 1, true, false); - - break; - } - return true; -} - -/*### -## npcs_rutgar_and_frankal -###*/ - -//gossip item text best guess -#define GOSSIP_ITEM_SEEK1 "I seek information about Natalia" - -#define GOSSIP_ITEM_RUTGAR2 "That sounds dangerous!" -#define GOSSIP_ITEM_RUTGAR3 "What did you do?" -#define GOSSIP_ITEM_RUTGAR4 "Who?" -#define GOSSIP_ITEM_RUTGAR5 "Women do that. What did she demand?" -#define GOSSIP_ITEM_RUTGAR6 "What do you mean?" -#define GOSSIP_ITEM_RUTGAR7 "What happened next?" - -#define GOSSIP_ITEM_FRANKAL11 "Yes, please continue" -#define GOSSIP_ITEM_FRANKAL12 "What language?" -#define GOSSIP_ITEM_FRANKAL13 "The Priestess attacked you?!" -#define GOSSIP_ITEM_FRANKAL14 "I should ask the monkey about this" -#define GOSSIP_ITEM_FRANKAL15 "Then what..." - -enum -{ - QUEST_DEAREST_NATALIA = 8304, - NPC_RUTGAR = 15170, - NPC_FRANKAL = 15171, - TRIGGER_RUTGAR = 15222, - TRIGGER_FRANKAL = 15221, - GOSSIP_TEXTID_RF = 7754, - GOSSIP_TEXTID_RUTGAR1 = 7755, - GOSSIP_TEXTID_RUTGAR2 = 7756, - GOSSIP_TEXTID_RUTGAR3 = 7757, - GOSSIP_TEXTID_RUTGAR4 = 7758, - GOSSIP_TEXTID_RUTGAR5 = 7759, - GOSSIP_TEXTID_RUTGAR6 = 7760, - GOSSIP_TEXTID_RUTGAR7 = 7761, - GOSSIP_TEXTID_FRANKAL1 = 7762, - GOSSIP_TEXTID_FRANKAL2 = 7763, - GOSSIP_TEXTID_FRANKAL3 = 7764, - GOSSIP_TEXTID_FRANKAL4 = 7765, - GOSSIP_TEXTID_FRANKAL5 = 7766, - GOSSIP_TEXTID_FRANKAL6 = 7767 -}; - -bool GossipHello_npcs_rutgar_and_frankal(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(QUEST_DEAREST_NATALIA) == QUEST_STATUS_INCOMPLETE && - pCreature->GetEntry() == NPC_RUTGAR && - !pPlayer->GetReqKillOrCastCurrentCount(QUEST_DEAREST_NATALIA, TRIGGER_RUTGAR)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SEEK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - if (pPlayer->GetQuestStatus(QUEST_DEAREST_NATALIA) == QUEST_STATUS_INCOMPLETE && - pCreature->GetEntry() == NPC_FRANKAL && - pPlayer->GetReqKillOrCastCurrentCount(QUEST_DEAREST_NATALIA, TRIGGER_RUTGAR)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SEEK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+9); - - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RF, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npcs_rutgar_and_frankal(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTGAR2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR1, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTGAR3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR2, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTGAR4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR3, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTGAR5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR4, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTGAR6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR5, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_RUTGAR7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR6, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_RUTGAR7, pCreature->GetObjectGuid()); - //'kill' our trigger to update quest status - pPlayer->KilledMonsterCredit(TRIGGER_RUTGAR, pCreature->GetObjectGuid()); - break; - - case GOSSIP_ACTION_INFO_DEF + 9: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FRANKAL11, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL1, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 10: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FRANKAL12, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL2, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FRANKAL13, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL3, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FRANKAL14, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL4, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FRANKAL15, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL5, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 14: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_FRANKAL6, pCreature->GetObjectGuid()); - //'kill' our trigger to update quest status - pPlayer->KilledMonsterCredit(TRIGGER_FRANKAL, pCreature->GetObjectGuid()); - break; - } - return true; -} - /*### ## npc_anachronos_the_ancient ###*/ @@ -303,7 +95,7 @@ enum SPELL_GREEN_DRAGON_TRANSFORM = 25105, SPELL_RED_DRAGON_TRANSFORM = 25106, SPELL_BLUE_DRAGON_TRANSFORM = 25107, - //SPELL_BRONZE_DRAGON_TRANSFORM = 25108, // Spell was removed - exists only before 2.0.1 + // SPELL_BRONZE_DRAGON_TRANSFORM = 25108, // Spell was removed - exists only before 2.0.1 SPELL_MERITHRA_WAKE = 25145, // should trigger 25172 on targets SPELL_ARYGOS_VENGEANCE = 25149, @@ -402,28 +194,28 @@ struct EventLocations static EventLocations aEternalBoardNPCs[MAX_DRAGONS] = { - {-8029.301f, 1534.612f, 2.609f, 3.121f, NPC_FANDRAL_STAGHELM}, - {-8034.227f, 1536.580f, 2.609f, 6.161f, NPC_ARYGOS}, - {-8031.935f, 1532.658f, 2.609f, 1.012f, NPC_CAELESTRASZ}, - {-8034.106f, 1534.224f, 2.609f, 0.290f, NPC_MERITHRA_OF_THE_DREAM}, + { -8029.301f, 1534.612f, 2.609f, 3.121f, NPC_FANDRAL_STAGHELM}, + { -8034.227f, 1536.580f, 2.609f, 6.161f, NPC_ARYGOS}, + { -8031.935f, 1532.658f, 2.609f, 1.012f, NPC_CAELESTRASZ}, + { -8034.106f, 1534.224f, 2.609f, 0.290f, NPC_MERITHRA_OF_THE_DREAM}, }; static EventLocations aEternalBoardMovement[] = { - {-8159.951f, 1525.241f, 74.994f}, // 0 Flight position for dragons - {-8106.238f, 1525.948f, 2.639f}, // 1 Anachronos gate location - {-8103.861f, 1525.923f, 2.677f}, // 2 Fandral gate location - {-8107.387f, 1523.641f, 2.609f}, // 3 Shattered scepter - {-8100.921f, 1527.740f, 2.871f}, // 4 Fandral epilogue location - {-8115.270f, 1515.926f, 3.305f}, // 5 Anachronos gather broken scepter 1 - {-8116.879f, 1530.615f, 3.762f}, // 6 Anachronos gather broken scepter 2 - {-7997.790f, 1548.664f, 3.738f}, // 7 Fandral exit location - {-8061.933f, 1496.196f, 2.556f}, // 8 Anachronos launch location - {-8008.705f, 1446.063f, 44.104f}, // 9 Anachronos flight location - {-8085.748f, 1521.484f, 2.624f} // 10 Anchor point for the army summoning + { -8159.951f, 1525.241f, 74.994f}, // 0 Flight position for dragons + { -8106.238f, 1525.948f, 2.639f}, // 1 Anachronos gate location + { -8103.861f, 1525.923f, 2.677f}, // 2 Fandral gate location + { -8107.387f, 1523.641f, 2.609f}, // 3 Shattered scepter + { -8100.921f, 1527.740f, 2.871f}, // 4 Fandral epilogue location + { -8115.270f, 1515.926f, 3.305f}, // 5 Anachronos gather broken scepter 1 + { -8116.879f, 1530.615f, 3.762f}, // 6 Anachronos gather broken scepter 2 + { -7997.790f, 1548.664f, 3.738f}, // 7 Fandral exit location + { -8061.933f, 1496.196f, 2.556f}, // 8 Anachronos launch location + { -8008.705f, 1446.063f, 44.104f}, // 9 Anachronos flight location + { -8085.748f, 1521.484f, 2.624f} // 10 Anchor point for the army summoning }; -struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private DialogueHelper +struct npc_anachronos_the_ancientAI : public ScriptedAI, private DialogueHelper { npc_anachronos_the_ancientAI(Creature* pCreature) : ScriptedAI(pCreature), DialogueHelper(aEventDialogue) @@ -442,18 +234,18 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private ObjectGuid m_playerGuid; ObjectGuid m_triggerGuid; - GUIDList m_lQirajiWarriorsList; + GuidList m_lQirajiWarriorsList; - void Reset() + void Reset() override { // We summon the rest of the dragons on timer m_uiEventTimer = 100; m_uiEventStage = 0; } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { - switch(iEntry) + switch (iEntry) { case NPC_ANACHRONOS_THE_ANCIENT: // Call the other dragons @@ -510,7 +302,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private // Move Merithra to the exit point if (Creature* pMerithra = m_creature->GetMap()->GetCreature(m_merithraGuid)) { - pMerithra->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + pMerithra->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); pMerithra->SetLevitate(true); pMerithra->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[0].m_fX, aEternalBoardMovement[0].m_fY, aEternalBoardMovement[0].m_fZ); pMerithra->ForcedDespawn(9000); @@ -528,7 +320,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private // Move Arygos to the exit point if (Creature* pArygos = m_creature->GetMap()->GetCreature(m_arygosGuid)) { - pArygos->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + pArygos->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); pArygos->SetLevitate(true); pArygos->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[0].m_fX, aEternalBoardMovement[0].m_fY, aEternalBoardMovement[0].m_fZ); pArygos->ForcedDespawn(9000); @@ -557,7 +349,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private // Send Caelestrasz on flight if (Creature* pCaelestrasz = m_creature->GetMap()->GetCreature(m_CaelestraszGuid)) { - pCaelestrasz->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + pCaelestrasz->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); pCaelestrasz->SetLevitate(true); pCaelestrasz->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aEternalBoardMovement[0].m_fX, aEternalBoardMovement[0].m_fY, aEternalBoardMovement[0].m_fZ); pCaelestrasz->ForcedDespawn(9000); @@ -638,7 +430,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private } } - Creature* GetSpeakerByEntry(uint32 uiEntry) + Creature* GetSpeakerByEntry(uint32 uiEntry) override { switch (uiEntry) { @@ -671,14 +463,14 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private { float fX, fY, fZ; // Summon kaldorei warriors - for(uint8 i = 0; i < MAX_KALDOREI; ++i) + for (uint8 i = 0; i < MAX_KALDOREI; ++i) { m_creature->GetRandomPoint(aEternalBoardMovement[10].m_fX, aEternalBoardMovement[10].m_fY, aEternalBoardMovement[10].m_fZ, 10.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_KALDOREI_INFANTRY, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); } // Summon Qiraji warriors - for(uint8 i = 0; i < MAX_QIRAJI; ++i) + for (uint8 i = 0; i < MAX_QIRAJI; ++i) { m_creature->GetRandomPoint(aEternalBoardMovement[10].m_fX, aEternalBoardMovement[10].m_fY, aEternalBoardMovement[10].m_fZ, 15.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_QIRAJI_WASP, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); @@ -693,17 +485,17 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private void DoUnsummonArmy() { - for (GUIDList::const_iterator itr = m_lQirajiWarriorsList.begin(); itr != m_lQirajiWarriorsList.end(); ++itr) + for (GuidList::const_iterator itr = m_lQirajiWarriorsList.begin(); itr != m_lQirajiWarriorsList.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) pTemp->ForcedDespawn(); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Also remove npc flags where needed - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_FANDRAL_STAGHELM: m_fandralGuid = pSummoned->GetObjectGuid(); @@ -730,12 +522,12 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private } } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; - switch(uiPointId) + switch (uiPointId) { case POINT_ID_GATE: // Cast time stop when he reaches the gate @@ -756,21 +548,21 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private break; case POINT_ID_EXIT: // Spell was removed, manually change the display - //DoCastSpellIfCan(m_creature, SPELL_BRONZE_DRAGON_TRANSFORM); + // DoCastSpellIfCan(m_creature, SPELL_BRONZE_DRAGON_TRANSFORM); m_creature->SetDisplayId(DISPLAY_ID_BRONZE_DRAGON); m_uiEventTimer = 4000; break; } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; if (pSummoned->GetEntry() == NPC_FANDRAL_STAGHELM) { - switch(uiPointId) + switch (uiPointId) { case POINT_ID_EPILOGUE: // Face Anachronos and restart the dialogue @@ -788,7 +580,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private } else if (uiPointId == POINT_ID_DRAGON_ATTACK) { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_MERITHRA_OF_THE_DREAM: StartNextDialogueText(DATA_MERITHRA_ATTACK); @@ -800,7 +592,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); @@ -808,7 +600,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private { if (m_uiEventTimer <= uiDiff) { - switch(m_uiEventStage) + switch (m_uiEventStage) { case 0: // Start the dialogue @@ -836,7 +628,7 @@ struct MANGOS_DLL_DECL npc_anachronos_the_ancientAI : public ScriptedAI, private break; case 4: // Take off and fly - m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); m_creature->SetLevitate(true); m_creature->GetMotionMaster()->MovePoint(0, aEternalBoardMovement[9].m_fX, aEternalBoardMovement[9].m_fY, aEternalBoardMovement[9].m_fZ); m_creature->ForcedDespawn(10000); @@ -862,7 +654,7 @@ bool QuestAcceptGO_crystalline_tear(Player* pPlayer, GameObject* pGo, const Ques if (pQuest->GetQuestId() == QUEST_A_PAWN_ON_THE_ETERNAL_BOARD) { // Check if event is already in progress first - if (Creature* pAnachronos = GetClosestCreatureWithEntry(pGo, NPC_ANACHRONOS_THE_ANCIENT, 90.0f)) + if (GetClosestCreatureWithEntry(pGo, NPC_ANACHRONOS_THE_ANCIENT, 90.0f)) return true; if (Creature* pAnachronos = pPlayer->SummonCreature(NPC_ANACHRONOS_THE_ANCIENT, pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), 3.75f, TEMPSUMMON_CORPSE_DESPAWN, 0)) @@ -880,18 +672,6 @@ void AddSC_silithus() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_highlord_demitrian"; - pNewScript->pGossipHello = &GossipHello_npc_highlord_demitrian; - pNewScript->pGossipSelect = &GossipSelect_npc_highlord_demitrian; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npcs_rutgar_and_frankal"; - pNewScript->pGossipHello = &GossipHello_npcs_rutgar_and_frankal; - pNewScript->pGossipSelect = &GossipSelect_npcs_rutgar_and_frankal; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_anachronos_the_ancient"; pNewScript->GetAI = &GetAI_npc_anachronos_the_ancient; diff --git a/scripts/kalimdor/stonetalon_mountains.cpp b/scripts/kalimdor/stonetalon_mountains.cpp index a5411906c..65a9bb6f1 100644 --- a/scripts/kalimdor/stonetalon_mountains.cpp +++ b/scripts/kalimdor/stonetalon_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,55 +16,14 @@ /* ScriptData SDName: Stonetalon_Mountains -SD%Complete: 95 -SDComment: Quest support: 6627 (Braug Dimspirits questions/'answers' might have more to it, need more info),6523 +SD%Complete: 100 +SDComment: Quest support: 6523. SDCategory: Stonetalon Mountains EndScriptData */ #include "precompiled.h" #include "escort_ai.h" -/*###### -## npc_braug_dimspirit -######*/ - -bool GossipHello_npc_braug_dimspirit(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(6627) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ysera", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Neltharion", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Nozdormu", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Alexstrasza", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Malygos", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(5820, pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_GOSSIP_MENU(5819, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_braug_dimspirit(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->CastSpell(pPlayer,6766,false); - - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(6627); - } - return true; -} - /*###### ## npc_kaya ######*/ @@ -82,32 +41,32 @@ enum QUEST_PROTECT_KAYA = 6523 }; -struct MANGOS_DLL_DECL npc_kayaAI : public npc_escortAI +struct npc_kayaAI : public npc_escortAI { npc_kayaAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { - //Ambush + // Ambush case 16: - //note about event here: - //apparently NPC say _after_ the ambush is over, and is most likely a bug at you-know-where. - //we simplify this, and make say when the ambush actually start. + // note about event here: + // apparently NPC say _after_ the ambush is over, and is most likely a bug at you-know-where. + // we simplify this, and make say when the ambush actually start. DoScriptText(SAY_AMBUSH, m_creature); m_creature->SummonCreature(NPC_GRIMTOTEM_RUFFIAN, -50.75f, -500.77f, -46.13f, 0.4f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); m_creature->SummonCreature(NPC_GRIMTOTEM_BRUTE, -40.05f, -510.89f, -46.05f, 1.7f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); m_creature->SummonCreature(NPC_GRIMTOTEM_SORCERER, -32.21f, -499.20f, -45.35f, 2.8f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); break; - // Award quest credit + // Award quest credit case 18: DoScriptText(SAY_END, m_creature); @@ -125,12 +84,12 @@ CreatureAI* GetAI_npc_kaya(Creature* pCreature) bool QuestAccept_npc_kaya(Player* pPlayer, Creature* pCreature, Quest const* pQuest) { - //Casting Spell and Starting the Escort quest is buggy, so this is a hack. Use the spell when it is possible. + // Casting Spell and Starting the Escort quest is buggy, so this is a hack. Use the spell when it is possible. if (pQuest->GetQuestId() == QUEST_PROTECT_KAYA) { - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); - DoScriptText(SAY_START,pCreature); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + DoScriptText(SAY_START, pCreature); if (npc_kayaAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -146,12 +105,6 @@ void AddSC_stonetalon_mountains() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_braug_dimspirit"; - pNewScript->pGossipHello = &GossipHello_npc_braug_dimspirit; - pNewScript->pGossipSelect = &GossipSelect_npc_braug_dimspirit; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_kaya"; pNewScript->GetAI = &GetAI_npc_kaya; diff --git a/scripts/kalimdor/tanaris.cpp b/scripts/kalimdor/tanaris.cpp index 943b0ab54..aee49f5d6 100644 --- a/scripts/kalimdor/tanaris.cpp +++ b/scripts/kalimdor/tanaris.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,14 +17,13 @@ /* ScriptData SDName: Tanaris SD%Complete: 80 -SDComment: Quest support: 648, 1560, 2954, 4005, 10277. Noggenfogger vendor +SDComment: Quest support: 648, 1560, 2954, 4005, 10277. SDCategory: Tanaris EndScriptData */ /* ContentData mob_aquementas npc_custodian_of_time -npc_marin_noggenfogger npc_oox17tn npc_stone_watcher_of_norgannon npc_tooga @@ -38,89 +37,96 @@ EndContentData */ ## mob_aquementas ######*/ -#define AGGRO_YELL_AQUE -1000168 +enum +{ + AGGRO_YELL_AQUE = -1000168, -#define SPELL_AQUA_JET 13586 -#define SPELL_FROST_SHOCK 15089 + SPELL_AQUA_JET = 13586, + SPELL_FROST_SHOCK = 15089, -struct MANGOS_DLL_DECL mob_aquementasAI : public ScriptedAI -{ - mob_aquementasAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + ITEM_SILVER_TOTEM = 11522, + ITEM_BOOK_AQUOR = 11169, + ITEM_SILVERY_CLAWS = 11172, + ITEM_IRONTREE_HEART = 11173, + + FACTION_FRIENDLY = 35, + FACTION_ELEMENTAL = 91, +}; - uint32 SendItem_Timer; - uint32 SwitchFaction_Timer; - bool isFriendly; +struct mob_aquementasAI : public ScriptedAI +{ + mob_aquementasAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 FrostShock_Timer; - uint32 AquaJet_Timer; + uint32 m_uiSwitchFactionTimer; + uint32 m_uiFrostShockTimer; + uint32 m_uiAquaJetTimer; - void Reset() + void Reset() override { - SendItem_Timer = 0; - SwitchFaction_Timer = 10000; - m_creature->setFaction(35); - isFriendly = true; + m_uiSwitchFactionTimer = 10000; + m_uiAquaJetTimer = 5000; + m_uiFrostShockTimer = 1000; - AquaJet_Timer = 5000; - FrostShock_Timer = 1000; + m_creature->setFaction(FACTION_FRIENDLY); // TODO: Either do this way, or might require a DB change } - void SendItem(Unit* receiver) + void SendItem(Player* pReceiver) { - if (((Player*)receiver)->HasItemCount(11169,1,false) && - ((Player*)receiver)->HasItemCount(11172,11,false) && - ((Player*)receiver)->HasItemCount(11173,1,false) && - !((Player*)receiver)->HasItemCount(11522,1,true)) + if (pReceiver->HasItemCount(ITEM_BOOK_AQUOR, 1) && + pReceiver->HasItemCount(ITEM_SILVERY_CLAWS, 11) && + pReceiver->HasItemCount(ITEM_IRONTREE_HEART, 1) && + !pReceiver->HasItemCount(ITEM_SILVER_TOTEM, 1)) { - if (Item* pItem = ((Player*)receiver)->StoreNewItemInInventorySlot(11522, 1)) - ((Player*)receiver)->SendNewItem(pItem, 1, true, false); + if (Item* pItem = pReceiver->StoreNewItemInInventorySlot(ITEM_SILVER_TOTEM, 1)) + pReceiver->SendNewItem(pItem, 1, true, false); } } - void Aggro(Unit* who) + void Aggro(Unit* pWho) override { - DoScriptText(AGGRO_YELL_AQUE, m_creature, who); + DoScriptText(AGGRO_YELL_AQUE, m_creature, pWho); + + Player* pInvokedPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (pInvokedPlayer) + SendItem(pInvokedPlayer); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (isFriendly) + if (m_uiSwitchFactionTimer) { - if (SwitchFaction_Timer < diff) + if (m_uiSwitchFactionTimer <= uiDiff) { - m_creature->setFaction(91); - isFriendly = false; - }else SwitchFaction_Timer -= diff; + m_creature->setFaction(FACTION_ELEMENTAL); + m_uiSwitchFactionTimer = 0; + } + else + m_uiSwitchFactionTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!isFriendly) + if (m_uiFrostShockTimer < uiDiff) { - if (SendItem_Timer < diff) - { - if (m_creature->getVictim()->GetTypeId() == TYPEID_PLAYER) - SendItem(m_creature->getVictim()); - SendItem_Timer = 5000; - }else SendItem_Timer -= diff; + DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK); + m_uiFrostShockTimer = 15000; } + else + m_uiFrostShockTimer -= uiDiff; - if (FrostShock_Timer < diff) + if (m_uiAquaJetTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROST_SHOCK); - FrostShock_Timer = 15000; - }else FrostShock_Timer -= diff; - - if (AquaJet_Timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_AQUA_JET); - AquaJet_Timer = 15000; - }else AquaJet_Timer -= diff; + DoCastSpellIfCan(m_creature, SPELL_AQUA_JET); + m_uiAquaJetTimer = 15000; + } + else + m_uiAquaJetTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_mob_aquementas(Creature* pCreature) { return new mob_aquementasAI(pCreature); @@ -130,33 +136,41 @@ CreatureAI* GetAI_mob_aquementas(Creature* pCreature) ## npc_custodian_of_time ######*/ -#define WHISPER_CUSTODIAN_1 -1000217 -#define WHISPER_CUSTODIAN_2 -1000218 -#define WHISPER_CUSTODIAN_3 -1000219 -#define WHISPER_CUSTODIAN_4 -1000220 -#define WHISPER_CUSTODIAN_5 -1000221 -#define WHISPER_CUSTODIAN_6 -1000222 -#define WHISPER_CUSTODIAN_7 -1000223 -#define WHISPER_CUSTODIAN_8 -1000224 -#define WHISPER_CUSTODIAN_9 -1000225 -#define WHISPER_CUSTODIAN_10 -1000226 -#define WHISPER_CUSTODIAN_11 -1000227 -#define WHISPER_CUSTODIAN_12 -1000228 -#define WHISPER_CUSTODIAN_13 -1000229 -#define WHISPER_CUSTODIAN_14 -1000230 - -struct MANGOS_DLL_DECL npc_custodian_of_timeAI : public npc_escortAI +enum +{ + WHISPER_CUSTODIAN_1 = -1000217, + WHISPER_CUSTODIAN_2 = -1000218, + WHISPER_CUSTODIAN_3 = -1000219, + WHISPER_CUSTODIAN_4 = -1000220, + WHISPER_CUSTODIAN_5 = -1000221, + WHISPER_CUSTODIAN_6 = -1000222, + WHISPER_CUSTODIAN_7 = -1000223, + WHISPER_CUSTODIAN_8 = -1000224, + WHISPER_CUSTODIAN_9 = -1000225, + WHISPER_CUSTODIAN_10 = -1000226, + WHISPER_CUSTODIAN_11 = -1000227, + WHISPER_CUSTODIAN_12 = -1000228, + WHISPER_CUSTODIAN_13 = -1000229, + WHISPER_CUSTODIAN_14 = -1000230, + + SPELL_CUSTODIAN_OF_TIME = 34877, + SPELL_QID_10277 = 34883, + + QUEST_ID_CAVERNS_OF_TIME = 10277, +}; + +struct npc_custodian_of_timeAI : public npc_escortAI { npc_custodian_of_timeAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(i) + switch (uiPointId) { case 0: DoScriptText(WHISPER_CUSTODIAN_1, m_creature, pPlayer); break; case 1: DoScriptText(WHISPER_CUSTODIAN_2, m_creature, pPlayer); break; @@ -177,31 +191,29 @@ struct MANGOS_DLL_DECL npc_custodian_of_timeAI : public npc_escortAI case 23: DoScriptText(WHISPER_CUSTODIAN_4, m_creature, pPlayer); break; case 24: DoScriptText(WHISPER_CUSTODIAN_14, m_creature, pPlayer); - DoCastSpellIfCan(pPlayer, 34883); - //below here is temporary workaround, to be removed when spell works properly - pPlayer->AreaExploredOrEventHappens(10277); + DoCastSpellIfCan(pPlayer, SPELL_QID_10277); break; } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) return; if (pWho->GetTypeId() == TYPEID_PLAYER) { - if (pWho->HasAura(34877, EFFECT_INDEX_1) && ((Player*)pWho)->GetQuestStatus(10277) == QUEST_STATUS_INCOMPLETE) + if (pWho->HasAura(SPELL_CUSTODIAN_OF_TIME) && ((Player*)pWho)->GetQuestStatus(QUEST_ID_CAVERNS_OF_TIME) == QUEST_STATUS_INCOMPLETE) { - float Radius = 10.0; + float fRadius = 10.0f; - if (m_creature->IsWithinDistInMap(pWho, Radius)) + if (m_creature->IsWithinDistInMap(pWho, fRadius)) Start(false, (Player*)pWho); } } } - void Reset() { } + void Reset() override { } }; CreatureAI* GetAI_npc_custodian_of_time(Creature* pCreature) @@ -209,31 +221,6 @@ CreatureAI* GetAI_npc_custodian_of_time(Creature* pCreature) return new npc_custodian_of_timeAI(pCreature); } -/*###### -## npc_marin_noggenfogger -######*/ - -bool GossipHello_npc_marin_noggenfogger(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pCreature->isVendor() && pPlayer->GetQuestRewardStatus(2662)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_marin_noggenfogger(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - /*###### ## npc_oox17tn ######*/ @@ -254,11 +241,11 @@ enum NPC_SHADOW_MAGE = 5617 }; -struct MANGOS_DLL_DECL npc_oox17tnAI : public npc_escortAI +struct npc_oox17tnAI : public npc_escortAI { npc_oox17tnAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 i) override { Player* pPlayer = GetPlayerForEscort(); @@ -267,14 +254,14 @@ struct MANGOS_DLL_DECL npc_oox17tnAI : public npc_escortAI switch (i) { - //1. Ambush: 3 scorpions + // 1. Ambush: 3 scorpions case 22: DoScriptText(SAY_OOX_AMBUSH, m_creature); m_creature->SummonCreature(NPC_SCORPION, -8340.70f, -4448.17f, 9.17f, 3.10f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); m_creature->SummonCreature(NPC_SCORPION, -8343.18f, -4444.35f, 9.44f, 2.35f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); m_creature->SummonCreature(NPC_SCORPION, -8348.70f, -4457.80f, 9.58f, 2.02f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); break; - //2. Ambush: 2 Rogues & 1 Shadow Mage + // 2. Ambush: 2 Rogues & 1 Shadow Mage case 28: DoScriptText(SAY_OOX_AMBUSH, m_creature); @@ -282,7 +269,7 @@ struct MANGOS_DLL_DECL npc_oox17tnAI : public npc_escortAI m_creature->SummonCreature(NPC_SHADOW_MAGE, -7486.41f, -4791.55f, 10.54f, 3.26f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000); if (Creature* pCreature = m_creature->SummonCreature(NPC_SCOFFLAW, -7488.47f, -4800.77f, 9.77f, 2.50f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000)) - DoScriptText(SAY_OOX17_AMBUSH_REPLY,pCreature); + DoScriptText(SAY_OOX17_AMBUSH_REPLY, pCreature); break; case 34: @@ -293,19 +280,19 @@ struct MANGOS_DLL_DECL npc_oox17tnAI : public npc_escortAI } } - void Reset() { } + void Reset() override { } - void Aggro(Unit* who) + void Aggro(Unit* /*who*/) override { - //For an small probability he say something when it aggros - switch(urand(0, 9)) + // For an small probability he say something when it aggros + switch (urand(0, 9)) { - case 0: DoScriptText(SAY_OOX_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_OOX_AGGRO2, m_creature); break; + case 0: DoScriptText(SAY_OOX_AGGRO1, m_creature); break; + case 1: DoScriptText(SAY_OOX_AGGRO2, m_creature); break; } } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* summoned) override { summoned->AI()->AttackStart(m_creature); } @@ -325,10 +312,10 @@ bool QuestAccept_npc_oox17tn(Player* pPlayer, Creature* pCreature, const Quest* pCreature->SetStandState(UNIT_STAND_STATE_STAND); if (pPlayer->GetTeam() == ALLIANCE) - pCreature->setFaction(FACTION_ESCORT_A_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (pPlayer->GetTeam() == HORDE) - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_oox17tnAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -360,28 +347,28 @@ bool GossipHello_npc_stone_watcher_of_norgannon(Player* pPlayer, Creature* pCrea return true; } -bool GossipSelect_npc_stone_watcher_of_norgannon(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_stone_watcher_of_norgannon(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(1675, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(1676, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); pPlayer->SEND_GOSSIP_MENU(1677, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); pPlayer->SEND_GOSSIP_MENU(1678, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NORGANNON_6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); pPlayer->SEND_GOSSIP_MENU(1679, pCreature->GetObjectGuid()); break; case GOSSIP_ACTION_INFO_DEF+5: @@ -413,9 +400,9 @@ enum POINT_ID_TO_WATER = 1 }; -const float m_afToWaterLoc[] = {-7032.664551f, -4906.199219f, -1.606446f}; +const float m_afToWaterLoc[] = { -7032.664551f, -4906.199219f, -1.606446f}; -struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI +struct npc_toogaAI : public FollowerAI { npc_toogaAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } @@ -425,7 +412,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI Unit* pTorta; - void Reset() + void Reset() override { m_uiCheckSpeechTimer = 2500; m_uiPostEventTimer = 1000; @@ -434,7 +421,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI pTorta = NULL; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); @@ -454,7 +441,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI } } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { FollowerAI::MovementInform(uiMotionType, uiPointId); @@ -465,11 +452,11 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI SetFollowComplete(); } - void UpdateFollowerAI(const uint32 uiDiff) + void UpdateFollowerAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { - //we are doing the post-event, or... + // we are doing the post-event, or... if (HasFollowState(STATE_FOLLOW_POSTEVENT)) { if (m_uiPostEventTimer < uiDiff) @@ -478,12 +465,12 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI if (!pTorta || !pTorta->isAlive()) { - //something happened, so just complete + // something happened, so just complete SetFollowComplete(); return; } - switch(m_uiPhasePostEvent) + switch (m_uiPhasePostEvent) { case 1: DoScriptText(SAY_TOOG_POST_1, m_creature); @@ -518,7 +505,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI { m_uiCheckSpeechTimer = 5000; - switch(urand(0, 50)) + switch (urand(0, 50)) { case 10: DoScriptText(SAY_TOOG_THIRST, m_creature); break; case 25: DoScriptText(SAY_TOOG_WORRIED, m_creature); break; @@ -565,12 +552,6 @@ void AddSC_tanaris() pNewScript->GetAI = &GetAI_npc_custodian_of_time; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_marin_noggenfogger"; - pNewScript->pGossipHello = &GossipHello_npc_marin_noggenfogger; - pNewScript->pGossipSelect = &GossipSelect_npc_marin_noggenfogger; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_oox17tn"; pNewScript->GetAI = &GetAI_npc_oox17tn; diff --git a/scripts/kalimdor/teldrassil.cpp b/scripts/kalimdor/teldrassil.cpp index 8d749a0ea..8b5f9dc76 100644 --- a/scripts/kalimdor/teldrassil.cpp +++ b/scripts/kalimdor/teldrassil.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,13 +41,13 @@ enum FACTION_DARNASSUS = 79 }; -struct MANGOS_DLL_DECL npc_mistAI : public FollowerAI +struct npc_mistAI : public FollowerAI { npc_mistAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void MoveInLineOfSight(Unit *pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); @@ -71,12 +71,12 @@ struct MANGOS_DLL_DECL npc_mistAI : public FollowerAI pPlayer->GroupEventHappens(QUEST_MIST, m_creature); } - //The follow is over (and for later development, run off to the woods before really end) + // The follow is over (and for later development, run off to the woods before really end) SetFollowComplete(); } - //call not needed here, no known abilities - /*void UpdateFollowerAI(const uint32 uiDiff) + // call not needed here, no known abilities + /*void UpdateFollowerAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp index 491827c2b..60048a8f9 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_bug_trio.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,7 +43,7 @@ enum NPC_YAUJ_BROOD = 15621 }; -struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI +struct boss_kriAI : public ScriptedAI { boss_kriAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -56,13 +56,13 @@ struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI uint32 m_uiCleaveTimer; uint32 m_uiToxicVolleyTimer; - void Reset() + void Reset() override { m_uiCleaveTimer = urand(4000, 8000); m_uiToxicVolleyTimer = urand(6000, 12000); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { // poison cloud on death DoCastSpellIfCan(m_creature, SPELL_SUMMON_CLOUD, CAST_TRIGGERED); @@ -78,13 +78,13 @@ struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_BUG_TRIO, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -112,7 +112,7 @@ struct MANGOS_DLL_DECL boss_kriAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI +struct boss_vemAI : public ScriptedAI { boss_vemAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -125,13 +125,13 @@ struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI uint32 m_uiChargeTimer; uint32 m_uiKnockBackTimer; - void Reset() + void Reset() override { m_uiChargeTimer = urand(15000, 27000); m_uiKnockBackTimer = urand(8000, 20000); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { // Enrage the other bugs DoCastSpellIfCan(m_creature, SPELL_VENGEANCE, CAST_TRIGGERED); @@ -147,13 +147,13 @@ struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_BUG_TRIO, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -189,7 +189,7 @@ struct MANGOS_DLL_DECL boss_vemAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL boss_yaujAI : public ScriptedAI +struct boss_yaujAI : public ScriptedAI { boss_yaujAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -202,20 +202,20 @@ struct MANGOS_DLL_DECL boss_yaujAI : public ScriptedAI uint32 m_uiHealTimer; uint32 m_uiFearTimer; - void Reset() + void Reset() override { m_uiHealTimer = urand(25000, 40000); m_uiFearTimer = urand(12000, 24000); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*Killer*/) override { // Spawn 10 yauj brood on death float fX, fY, fZ; - for(int i = 0; i < 10; ++i) + for (int i = 0; i < 10; ++i) { m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, fX, fY, fZ); - m_creature->SummonCreature(NPC_YAUJ_BROOD, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_YAUJ_BROOD, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); } if (!m_pInstance) @@ -229,13 +229,13 @@ struct MANGOS_DLL_DECL boss_yaujAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_BUG_TRIO, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp index c43285366..97a16c7b9 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_cthun.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Cthun SD%Complete: 95 -SDComment: Darkglare tracking issue +SDComment: Transform spell has some minor core issues. Eject from stomach event contains workarounds because of the missing spells. Digestive Acid should be handled in core. SDCategory: Temple of Ahn'Qiraj EndScriptData */ @@ -28,1174 +28,716 @@ enum { EMOTE_WEAKENED = -1531011, - // ****** Out of Combat ****** - // Random Wispers - No text only sound, maybe handle them in instance script! - RANDOM_SOUND_WHISPER = 8663, - // ***** Phase 1 ******** - NPC_EYE_OF_CTHUN = 15589, - MOB_CLAW_TENTACLE = 15725, - MOB_EYE_TENTACLE = 15726, - MOB_SMALL_PORTAL = 15904, - - SPELL_GREEN_BEAM = 26134, - SPELL_DARK_GLARE = 26029, - SPELL_RED_COLORATION = 22518, // Probably not the right spell but looks similar - - // Eye Tentacles Spells - SPELL_MIND_FLAY = 26143, - - // Claw Tentacles Spells - SPELL_GROUND_RUPTURE = 26139, - SPELL_HAMSTRING = 26141, + SPELL_EYE_BEAM = 26134, + // SPELL_DARK_GLARE = 26029, + SPELL_ROTATE_TRIGGER = 26137, // phase switch spell - triggers 26009 or 26136. These trigger the Dark Glare spell - 26029 + SPELL_ROTATE_360_LEFT = 26009, + SPELL_ROTATE_360_RIGHT = 26136, - // *****Phase 2****** - // Body spells + // ***** Phase 2 ****** // SPELL_CARAPACE_CTHUN = 26156, // Was removed from client dbcs SPELL_TRANSFORM = 26232, + SPELL_CTHUN_VULNERABLE = 26235, + SPELL_MOUTH_TENTACLE = 26332, // prepare target to teleport to stomach + // SPELL_DIGESTIVE_ACID_TELEPORT = 26220, // removed from DBC. stomach teleport spell + SPELL_EXIT_STOMACH_KNOCKBACK = 25383, // spell id is wrong + // SPELL_EXIT_STOMACH_JUMP = 26224, // removed from DBC. should make the player jump to the ceiling + // SPELL_EXIT_STOMACH_EFFECT = 26230, // removed from DBC. used to complete the eject effect from the stomach + // SPELL_PORT_OUT_STOMACH_EFFECT = 26648, // removed from DBC. used to kill players inside the stomach on evade + SPELL_DIGESTIVE_ACID = 26476, // damage spell - should be handled by the map + // SPELL_EXIT_STOMACH = 26221, // summons 15800 + + // ***** Summoned spells ***** + // Giant Claw tentacles + SPELL_GIANT_GROUND_RUPTURE = 26478, + // SPELL_MASSIVE_GROUND_RUPTURE = 26100, // spell not confirmed + SPELL_GROUND_TREMOR = 6524, + SPELL_HAMSTRING = 26211, + SPELL_THRASH = 3391, - // Giant Claw Tentacles - SPELL_MASSIVE_GROUND_RUPTURE = 26100, + // Npcs + // Phase 1 npcs + NPC_CLAW_TENTACLE = 15725, // summoned by missing spell 26140 + NPC_EYE_TENTACLE = 15726, // summoned by spells 26144 - 26151; script effect of 26152 - triggered every 45 secs + NPC_TENTACLE_PORTAL = 15904, // summoned by missing spell 26396 - // Also casts Hamstring - SPELL_THRASH = 3391, + // Phase 2 npcs + NPC_GIANT_CLAW_TENTACLE = 15728, // summoned by missing spell 26216 every 60 secs - also teleported by spell 26191 + NPC_GIANT_EYE_TENTACLE = 15334, // summoned by missing spell 26768 every 60 secs + NPC_FLESH_TENTACLE = 15802, // summoned by missing spell 26237 every 10 secs + NPC_GIANT_TENTACLE_PORTAL = 15910, // summoned by missing spell 26477 + NPC_EXIT_TRIGGER = 15800, - // Giant Eye Tentacles - // CHAIN CASTS "SPELL_GREEN_BEAM" + DISPLAY_ID_CTHUN_BODY = 15786, // Helper display id; This is needed in order to have the proper transform animation. ToDo: remove this when auras are fixed in core. - // Stomach Spells - SPELL_MOUTH_TENTACLE = 26332, - SPELL_EXIT_STOMACH_KNOCKBACK = 25383, - SPELL_DIGESTIVE_ACID = 26476, + AREATRIGGER_STOMACH_1 = 4033, + AREATRIGGER_STOMACH_2 = 4034, - // Mobs - MOB_BODY_OF_CTHUN = 15809, - MOB_GIANT_CLAW_TENTACLE = 15728, - MOB_GIANT_EYE_TENTACLE = 15334, - MOB_FLESH_TENTACLE = 15802, - MOB_GIANT_PORTAL = 15910, + MAX_FLESH_TENTACLES = 2, + MAX_EYE_TENTACLES = 8, }; -//Stomach Teleport positions -#define STOMACH_X -8562.0f -#define STOMACH_Y 2037.0f -#define STOMACH_Z -70.0f -#define STOMACH_O 5.05f - -//Flesh tentacle positions -#define TENTACLE_POS1_X -8571.0f -#define TENTACLE_POS1_Y 1990.0f -#define TENTACLE_POS1_Z -98.0f -#define TENTACLE_POS1_O 1.22f - -#define TENTACLE_POS2_X -8525.0f -#define TENTACLE_POS2_Y 1994.0f -#define TENTACLE_POS2_Z -98.0f -#define TENTACLE_POS2_O 2.12f - -//Kick out position -- unneeded - replace this with areatrigger handling of trigger [Trigger 4033]! -#define KICK_X -8545.0f -#define KICK_Y 1984.0f -#define KICK_Z -96.0f - -struct MANGOS_DLL_DECL flesh_tentacleAI : public ScriptedAI +static const float afCthunLocations[4][4] = { - flesh_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - SetCombatMovement(false); - Reset(); - } - - ObjectGuid m_cThunGuid; - uint32 m_uiCheckTimer; - - void SpawnedByCthun(Creature* pCThun) - { - m_cThunGuid = pCThun->GetObjectGuid(); - } - - void Reset() - { - m_uiCheckTimer = 1000; - } - - void UpdateAI(const uint32 diff); + { -8571.0f, 1990.0f, -98.0f, 1.22f}, // flesh tentacles locations + { -8525.0f, 1994.0f, -98.0f, 2.12f}, + { -8562.0f, 2037.0f, -70.0f, 5.05f}, // stomach teleport location + { -8545.6f, 1987.7f, -32.9f, 0.0f}, // stomach eject location +}; - void JustDied(Unit* killer); +enum CThunPhase +{ + PHASE_EYE_NORMAL = 0, + PHASE_EYE_DARK_GLARE = 1, + PHASE_TRANSITION = 2, + PHASE_CTHUN = 3, + PHASE_CTHUN_WEAKENED = 4, }; -struct MANGOS_DLL_DECL eye_of_cthunAI : public ScriptedAI +/*###### +## boss_eye_of_cthun +######*/ + +struct boss_eye_of_cthunAI : public Scripted_NoMovementAI { - eye_of_cthunAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_eye_of_cthunAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - SetCombatMovement(false); - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - if (!m_pInstance) - error_log("SD2: No Instance eye_of_cthunAI"); - Reset(); } ScriptedInstance* m_pInstance; - // Global variables - uint32 m_uiPhaseTimer; + CThunPhase m_Phase; - // Eye beam phase - uint32 m_uiBeamTimer; - uint32 m_uiEyeTentacleTimer; uint32 m_uiClawTentacleTimer; + uint32 m_uiEyeTentacleTimer; + uint32 m_uiBeamTimer; + uint32 m_uiDarkGlareTimer; + uint32 m_uiDarkGlareEndTimer; - // Dark Glare phase - uint32 m_uiDarkGlareTick; - uint32 m_uiDarkGlareTickTimer; - float m_fDarkGlareAngle; - bool m_bClockWise; + GuidList m_lEyeTentaclesList; - void Reset() + void Reset() override { - // Phase information - m_uiPhaseTimer = 50000; // First dark glare in 50 seconds + m_Phase = PHASE_EYE_NORMAL; - // Eye beam phase 50 seconds - m_uiBeamTimer = 3000; - m_uiEyeTentacleTimer = 45000; // Always spawns 5 seconds before Dark Beam - m_uiClawTentacleTimer = 12500; // 4 per Eye beam phase (unsure if they spawn durring Dark beam) + m_uiDarkGlareTimer = 45000; + m_uiDarkGlareEndTimer = 40000; + m_uiClawTentacleTimer = urand(10000, 15000); + m_uiBeamTimer = 0; + m_uiEyeTentacleTimer = 45000; + } - // Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks) - m_uiDarkGlareTick = 0; - m_uiDarkGlareTickTimer = 1000; - m_fDarkGlareAngle = 0; - m_bClockWise = false; + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, IN_PROGRESS); + } - // Reset flags - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + void JustDied(Unit* pKiller) override + { + // Allow the body to begin the transition + if (m_pInstance) + { + if (Creature* pCthun = m_pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) + pCthun->AI()->AttackStart(pKiller); + else + script_error_log("C'thun could not be found. Please check your database!"); + } } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override { - if (pSummoned->GetEntry() == MOB_EYE_TENTACLE) + // Despawn Eye tentacles on evade + DoDespawnEyeTentacles(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + case NPC_EYE_TENTACLE: + m_lEyeTentaclesList.push_back(pSummoned->GetObjectGuid()); + // no break; + case NPC_CLAW_TENTACLE: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + pSummoned->SummonCreature(NPC_TENTACLE_PORTAL, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; } } - void SpawnEyeTentacle(float x, float y) + void SummonedCreatureJustDied(Creature* pSummoned) override { - m_creature->SummonCreature(MOB_EYE_TENTACLE, m_creature->GetPositionX()+x ,m_creature->GetPositionY()+y, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 500); + // Despawn the tentacle portal - this applies to all the summoned tentacles + if (Creature* pPortal = GetClosestCreatureWithEntry(pSummoned, NPC_TENTACLE_PORTAL, 5.0f)) + pPortal->ForcedDespawn(); } - void Aggro(Unit* pWho) + void SummonedCreatureDespawn(Creature* pSummoned) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_EYE_NORMAL); + // Used only after evade + if (SelectHostileTarget()) + return; + + // Despawn the tentacle portal - this applies to all the summoned tentacles for evade case (which is handled by creature linking) + if (Creature* pPortal = GetClosestCreatureWithEntry(pSummoned, NPC_TENTACLE_PORTAL, 5.0f)) + pPortal->ForcedDespawn(); } - void EnterEvadeMode() + // Wrapper to kill the eye tentacles before summoning new ones + void DoDespawnEyeTentacles() { - if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_NOT_STARTED); + for (GuidList::const_iterator itr = m_lEyeTentaclesList.begin(); itr != m_lEyeTentaclesList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } - ScriptedAI::EnterEvadeMode(); + m_lEyeTentaclesList.clear(); } - void UpdateAI(const uint32 uiDiff) + // Custom threat management + bool SelectHostileTarget() { - // Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + Unit* pTarget = NULL; + Unit* pOldTarget = m_creature->getVictim(); + + if (!m_creature->getThreatManager().isThreatListEmpty()) + pTarget = m_creature->getThreatManager().getHostileTarget(); + + if (pTarget) + { + if (pOldTarget != pTarget && m_Phase == PHASE_EYE_NORMAL) + AttackStart(pTarget); + + // Set victim to old target (if not while Dark Glare) + if (pOldTarget && pOldTarget->isAlive() && m_Phase == PHASE_EYE_NORMAL) + { + m_creature->SetTargetGuid(pOldTarget->GetObjectGuid()); + m_creature->SetInFront(pOldTarget); + } - // No instance - if (!m_pInstance) + return true; + } + + // Will call EnterEvadeMode if fit + return m_creature->SelectHostileTarget(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectHostileTarget()) return; - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + switch (m_Phase) { case PHASE_EYE_NORMAL: - { - // m_uiBeamTimer + if (m_uiBeamTimer < uiDiff) { - // SPELL_GREEN_BEAM if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(pTarget, SPELL_GREEN_BEAM); - - // Correctly update our target - m_creature->SetTargetGuid(pTarget->GetObjectGuid()); + if (DoCastSpellIfCan(pTarget, SPELL_EYE_BEAM) == CAST_OK) + { + m_creature->SetTargetGuid(pTarget->GetObjectGuid()); + m_uiBeamTimer = 3000; + } } - - //Beam every 3 seconds - m_uiBeamTimer = 3000; } else m_uiBeamTimer -= uiDiff; - // m_uiClawTentacleTimer - if (m_uiClawTentacleTimer < uiDiff) + if (m_uiDarkGlareTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + // Cast the rotation spell + if (DoCastSpellIfCan(m_creature, SPELL_ROTATE_TRIGGER) == CAST_OK) { - // Spawn claw tentacle on the random target - if (Creature* pSummoned = m_creature->SummonCreature(MOB_CLAW_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 500)) - pSummoned->AI()->AttackStart(pTarget); - } - - // One claw tentacle every 12.5 seconds - m_uiClawTentacleTimer = 12500; - } - else - m_uiClawTentacleTimer -= uiDiff; - - // m_uiEyeTentacleTimer - if (m_uiEyeTentacleTimer < uiDiff) - { - //Spawn the 8 Eye Tentacles in the corret spots - SpawnEyeTentacle(0, 20); //south - SpawnEyeTentacle(10, 10); //south west - SpawnEyeTentacle(20, 0); //west - SpawnEyeTentacle(10, -10); //north west - - SpawnEyeTentacle(0, -20); //north - SpawnEyeTentacle(-10, -10); //north east - SpawnEyeTentacle(-20, 0); // east - SpawnEyeTentacle(-10, 10); // south east - - // No point actually putting a timer here since - // These shouldn't trigger agian until after phase shifts - m_uiEyeTentacleTimer = 45000; - } - else - m_uiEyeTentacleTimer -= uiDiff; - - // m_uiPhaseTimer - if (m_uiPhaseTimer < uiDiff) - { - //Switch to Dark Beam - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_EYE_DARK_GLARE); - - m_creature->InterruptNonMeleeSpells(false); + // Remove the target focus but allow the boss to face the current victim + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->SetFacingToObject(m_creature->getVictim()); - // Select random target for dark beam to start on - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - // Correctly update our target - m_creature->SetTargetGuid(pTarget->GetObjectGuid()); - - // Face our target - m_fDarkGlareAngle = m_creature->GetAngle(pTarget); - m_uiDarkGlareTickTimer = 1000; - m_uiDarkGlareTick = 0; - m_bClockWise = urand(0, 1); + // Switch to Dark Glare phase + m_uiDarkGlareTimer = 45000; + m_Phase = PHASE_EYE_DARK_GLARE; } - - // Add red coloration to C'thun - DoCastSpellIfCan(m_creature, SPELL_RED_COLORATION); - - // Freeze animation - - // Darkbeam for 35 seconds - m_uiPhaseTimer = 35000; } else - m_uiPhaseTimer -= uiDiff; + m_uiDarkGlareTimer -= uiDiff; break; - } case PHASE_EYE_DARK_GLARE: - { - // Dark Glare - if (m_uiDarkGlareTick < 35) - { - if (m_uiDarkGlareTickTimer < uiDiff) - { - // Remove any target - m_creature->SetTargetGuid(ObjectGuid()); - - // Set angle and cast - m_creature->SetOrientation(m_fDarkGlareAngle + (m_bClockWise ? 1 : -1) * ((float)m_uiDarkGlareTick*M_PI_F/35)); - - m_creature->StopMoving(); - // Actual dark glare cast, maybe something missing here? - DoCastSpellIfCan(m_creature, SPELL_DARK_GLARE); - - // Increase tick - ++m_uiDarkGlareTick; - - // 1 second per tick - m_uiDarkGlareTickTimer = 1000; - } - else - m_uiDarkGlareTickTimer -= uiDiff; - } - - // m_uiPhaseTimer - if (m_uiPhaseTimer < uiDiff) + if (m_uiDarkGlareEndTimer < uiDiff) { - // Switch to Eye Beam - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_EYE_NORMAL); - - m_uiBeamTimer = 3000; - m_uiEyeTentacleTimer = 45000; //Always spawns 5 seconds before Dark Beam - m_uiClawTentacleTimer = 12500; //4 per Eye beam phase (unsure if they spawn durring Dark beam) - - m_creature->InterruptNonMeleeSpells(false); - - // Remove Red coloration from C'thun - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); + // Remove rotation auras + m_creature->RemoveAurasDueToSpell(SPELL_ROTATE_360_LEFT); + m_creature->RemoveAurasDueToSpell(SPELL_ROTATE_360_RIGHT); - // Freeze animation - m_creature->SetUInt32Value(UNIT_FIELD_FLAGS, 0); - - // Eye Beam for 50 seconds - m_uiPhaseTimer = 50000; + // Switch to Eye Beam + m_uiDarkGlareEndTimer = 40000; + m_uiBeamTimer = 1000; + m_Phase = PHASE_EYE_NORMAL; } else - m_uiPhaseTimer -= uiDiff; + m_uiDarkGlareEndTimer -= uiDiff; break; - } - // Transition phase - case PHASE_TRANSITION: - { - // Remove any target - m_creature->SetTargetGuid(ObjectGuid()); - m_creature->SetHealth(0); - - // Do not kill yet, to be able to reset on evade - break; - } + } - // Dead phase - case PHASE_FINISH: + if (m_uiClawTentacleTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - return; + // Spawn claw tentacle on the random target on both phases + m_creature->SummonCreature(NPC_CLAW_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiClawTentacleTimer = urand(7000, 13000); } } - } - - void DamageTaken(Unit* pDealer, uint32& uiDamage) - { - // No instance - if (!m_pInstance) - return; + else + m_uiClawTentacleTimer -= uiDiff; - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + if (m_uiEyeTentacleTimer <= uiDiff) { - case PHASE_EYE_NORMAL: - case PHASE_EYE_DARK_GLARE: - { - // Only if it will kill - if (uiDamage < m_creature->GetHealth()) - return; - - // Fake death in phase 0 or 1 (green beam or dark glare phase) - m_creature->InterruptNonMeleeSpells(false); - - // Remove Red coloration from c'thun - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - - // Reset to normal emote state and prevent select and attack - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - // Remove Target field - m_creature->SetTargetGuid(ObjectGuid()); - - // Death animation/ respawning; - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_TRANSITION); - // Ensure CThun is in combat - if (Creature* pCThun = m_pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) - pCThun->AI()->AttackStart(pDealer); - - m_creature->SetHealth(0); - uiDamage = 0; + // Despawn the eye tentacles if necessary + DoDespawnEyeTentacles(); - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveAllAuras(); - - break; - } - case PHASE_FINISH: + // Spawn 8 Eye Tentacles + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_EYE_TENTACLES; ++i) { - // Allow death here - return; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 30.0f, M_PI_F / 4 * i); + m_creature->SummonCreature(NPC_EYE_TENTACLE, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); } - default: - { - // Prevent death in this phase - uiDamage = 0; - return; - } - break; + m_uiEyeTentacleTimer = 45000; } + else + m_uiEyeTentacleTimer -= uiDiff; } }; -struct MANGOS_DLL_DECL cthunAI : public ScriptedAI +/*###### +## boss_cthun +######*/ + +struct boss_cthunAI : public Scripted_NoMovementAI { - cthunAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_cthunAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - SetCombatMovement(false); - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - if (!m_pInstance) - error_log("SD2: No Instance eye_of_cthunAI"); - + // Set active in order to be used during the instance progress + m_creature->SetActiveObjectState(true); Reset(); } ScriptedInstance* m_pInstance; - // Out of combat whisper timer - uint32 m_uiWisperTimer; + CThunPhase m_Phase; // Global variables uint32 m_uiPhaseTimer; - - //------------------- - - // Body Phase - uint32 m_uiEyeTentacleTimer; uint8 m_uiFleshTentaclesKilled; + uint32 m_uiEyeTentacleTimer; uint32 m_uiGiantClawTentacleTimer; uint32 m_uiGiantEyeTentacleTimer; - uint32 m_uiStomachAcidTimer; + uint32 m_uiDigestiveAcidTimer; + + // Body Phase + uint32 m_uiMouthTentacleTimer; uint32 m_uiStomachEnterTimer; - uint32 m_uiStomachEnterVisTimer; - ObjectGuid m_stomachEnterTargetGuid; + GuidList m_lEyeTentaclesList; + GuidList m_lPlayersInStomachList; - // Stomach map, bool = true then in stomach - typedef UNORDERED_MAP StomachMap; - StomachMap m_mStomachMap; + ObjectGuid m_stomachEnterTargetGuid; - void Reset() + void Reset() override { - // One random wisper every 90 - 300 seconds - m_uiWisperTimer = 90000; - // Phase information - m_uiPhaseTimer = 10000; // Emerge in 10 seconds + m_Phase = PHASE_TRANSITION; + + m_uiPhaseTimer = 5000; + m_uiFleshTentaclesKilled = 0; + m_uiEyeTentacleTimer = 35000; + m_uiGiantClawTentacleTimer = 20000; + m_uiGiantEyeTentacleTimer = 50000; + m_uiDigestiveAcidTimer = 4000; // Body Phase - m_uiEyeTentacleTimer = 30000; - m_uiFleshTentaclesKilled = 0; - m_uiGiantClawTentacleTimer = 15000; // 15 seconds into body phase (1 min repeat) - m_uiGiantEyeTentacleTimer = 45000; // 15 seconds into body phase (1 min repeat) - m_uiStomachAcidTimer = 4000; // Every 4 seconds - m_uiStomachEnterTimer = 10000; // Every 10 seconds - m_uiStomachEnterVisTimer = 0; // Always 3.5 seconds after Stomach Enter Timer - m_stomachEnterTargetGuid.Clear(); // Target to be teleported to stomach + m_uiMouthTentacleTimer = 15000; + m_uiStomachEnterTimer = 0; - // Clear players in stomach and outside - m_mStomachMap.clear(); + // Clear players in stomach + m_lPlayersInStomachList.clear(); // Reset flags - m_creature->RemoveAurasDueToSpell(SPELL_TRANSFORM); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void JustSummoned(Creature* pSummoned) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { - if (pSummoned->GetEntry() == MOB_EYE_TENTACLE) + // Ignore damage reduction when vulnerable + if (m_Phase == PHASE_CTHUN_WEAKENED) + return; + + // Not weakened so reduce damage by 99% - workaround for missing spell 26156 + if (uiDamage / 99 > 0) + uiDamage /= 99; + else + uiDamage = 1; + + // Prevent death in non-weakened state + if (uiDamage >= m_creature->GetHealth()) + uiDamage = 0; + } + + void EnterEvadeMode() override + { + // Kill any player from the stomach on evade - this is becuase C'thun cannot be soloed. + for (GuidList::const_iterator itr = m_lPlayersInStomachList.begin(); itr != m_lPlayersInStomachList.end(); ++itr) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + // Workaround for missing spell 26648 + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(*itr)) + m_creature->DealDamage(pPlayer, pPlayer->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); } + + Scripted_NoMovementAI::EnterEvadeMode(); } - void SpawnEyeTentacle(float x, float y) + void JustReachedHome() override { - m_creature->SummonCreature(MOB_EYE_TENTACLE, m_creature->GetPositionX()+x ,m_creature->GetPositionY()+y, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 500); + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, FAIL); } - Player* SelectRandomNotStomach() + void JustDied(Unit* /*pKiller*/) override { - if (m_mStomachMap.empty()) - return NULL; + m_creature->SetActiveObjectState(false); - std::vector vTempTargets; - vTempTargets.reserve(m_mStomachMap.size()); + if (m_pInstance) + m_pInstance->SetData(TYPE_CTHUN, DONE); + } - // Get all players in map - for (StomachMap::const_iterator itr = m_mStomachMap.begin(); itr != m_mStomachMap.end(); ++itr) + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - // Check for valid player - Player* pPlayer = m_creature->GetMap()->GetPlayer(itr->first); + case NPC_EYE_TENTACLE: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); - // Only units out of stomach - if (pPlayer && itr->second == false) - vTempTargets.push_back(pPlayer); + m_lEyeTentaclesList.push_back(pSummoned->GetObjectGuid()); + pSummoned->SummonCreature(NPC_TENTACLE_PORTAL, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + case NPC_GIANT_EYE_TENTACLE: + case NPC_GIANT_CLAW_TENTACLE: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + pSummoned->SummonCreature(NPC_GIANT_TENTACLE_PORTAL, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + // Handle portal despawn on tentacle kill + case NPC_EYE_TENTACLE: + if (Creature* pPortal = GetClosestCreatureWithEntry(pSummoned, NPC_TENTACLE_PORTAL, 5.0f)) + pPortal->ForcedDespawn(); + break; + case NPC_GIANT_EYE_TENTACLE: + case NPC_GIANT_CLAW_TENTACLE: + if (Creature* pPortal = GetClosestCreatureWithEntry(pSummoned, NPC_GIANT_TENTACLE_PORTAL, 5.0f)) + pPortal->ForcedDespawn(); + break; + // Handle the stomach tentacles kill + case NPC_FLESH_TENTACLE: + ++m_uiFleshTentaclesKilled; + if (m_uiFleshTentaclesKilled == MAX_FLESH_TENTACLES) + { + if (DoCastSpellIfCan(m_creature, SPELL_CTHUN_VULNERABLE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(EMOTE_WEAKENED, m_creature); + m_uiPhaseTimer = 45000; + m_Phase = PHASE_CTHUN_WEAKENED; + } + } + break; } + } - if (vTempTargets.empty()) - return NULL; + // Wrapper to handle the Flesh Tentacles spawn + void DoSpawnFleshTentacles() + { + m_uiFleshTentaclesKilled = 0; - // Get random but only if we have more than one unit on threat list - return vTempTargets[urand(0, vTempTargets.size()- 1)]; + // Spawn 2 flesh tentacles + for (uint8 i = 0; i < MAX_FLESH_TENTACLES; ++i) + m_creature->SummonCreature(NPC_FLESH_TENTACLE, afCthunLocations[i][0], afCthunLocations[i][1], afCthunLocations[i][2], afCthunLocations[i][3], TEMPSUMMON_DEAD_DESPAWN, 0); } - void UpdateAI(const uint32 uiDiff) + // Wrapper to kill the eye tentacles before summoning new ones + void DoDespawnEyeTentacles() { - // Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + for (GuidList::const_iterator itr = m_lEyeTentaclesList.begin(); itr != m_lEyeTentaclesList.end(); ++itr) { - // No target so we'll use this section to do our random wispers instance wide - // WisperTimer - if (m_uiWisperTimer < uiDiff) - { - if (!m_creature->GetMap()->IsDungeon()) - return; + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->DealDamage(pTemp, pTemp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + + m_lEyeTentaclesList.clear(); + } + + // Wrapper to remove a stored player from the stomach + void DoRemovePlayerFromStomach(Player* pPlayer) + { + if (pPlayer) + m_lPlayersInStomachList.remove(pPlayer->GetObjectGuid()); + } + + // Custom threat management + bool SelectHostileTarget() + { + Unit* pTarget = NULL; + Unit* pOldTarget = m_creature->getVictim(); + + if (!m_creature->getThreatManager().isThreatListEmpty()) + pTarget = m_creature->getThreatManager().getHostileTarget(); - // Play random sound to the map - m_creature->GetMap()->PlayDirectSoundToMap(RANDOM_SOUND_WHISPER); + if (pTarget) + { + if (pOldTarget != pTarget) + AttackStart(pTarget); - // One random wisper every 90 - 300 seconds - m_uiWisperTimer = urand(90000, 300000); + // Set victim to old target + if (pOldTarget && pOldTarget->isAlive()) + { + m_creature->SetTargetGuid(pOldTarget->GetObjectGuid()); + m_creature->SetInFront(pOldTarget); } - else - m_uiWisperTimer -= uiDiff; - return; + return true; } - m_creature->SetTargetGuid(ObjectGuid()); + // Will call EnterEvadeMode if fit + return m_creature->SelectHostileTarget(); + } - // No instance - if (!m_pInstance) + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectHostileTarget()) return; - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) + switch (m_Phase) { - // Transition phase case PHASE_TRANSITION: - { - // PhaseTimer + if (m_uiPhaseTimer < uiDiff) { - // Switch - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_CTHUN); - - // Switch to C'thun model - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature, SPELL_TRANSFORM); - m_creature->SetHealth(m_creature->GetMaxHealth()); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - // Emerging phase - m_creature->SetInCombatWithZone(); + // Note: we need to set the display id before casting the transform spell, in order to get the proper animation + m_creature->SetDisplayId(DISPLAY_ID_CTHUN_BODY); - // Place all units in threat list on outside of stomach - m_mStomachMap.clear(); - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) + // Transform and start C'thun phase + if (DoCastSpellIfCan(m_creature, SPELL_TRANSFORM) == CAST_OK) { - // Outside stomach, only players - if ((*i)->getUnitGuid().IsPlayer()) - m_mStomachMap[(*i)->getUnitGuid()] = false; - } - - // Spawn 2 flesh tentacles - m_uiFleshTentaclesKilled = 0; - - // Spawn flesh tentacle - Creature* pSpawned = m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoSpawnFleshTentacles(); - if (!pSpawned) - ++m_uiFleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature); + m_Phase = PHASE_CTHUN; + m_uiPhaseTimer = 0; } - - // Spawn flesh tentacle - pSpawned = m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!pSpawned) - ++m_uiFleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature); - } - - m_uiPhaseTimer = 0; } else m_uiPhaseTimer -= uiDiff; break; - - } - // Body Phase case PHASE_CTHUN: - { - // Weaken - if (m_uiFleshTentaclesKilled > 1) - { - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_CTHUN_WEAKENED); - - DoScriptText(EMOTE_WEAKENED, m_creature); - m_uiPhaseTimer = 45000; - - DoCastSpellIfCan(m_creature, SPELL_RED_COLORATION, CAST_TRIGGERED); - - // Kick all players out of stomach - for (StomachMap::iterator itr = m_mStomachMap.begin(); itr != m_mStomachMap.end(); ++itr) - { - // Check for valid player - Player* pPlayer = m_creature->GetMap()->GetPlayer(itr->first); - - if (pPlayer && itr->second == true) - { - // Teleport each player out - DoTeleportPlayer(pPlayer, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+10, rand()%6); - - // Cast knockback on them - DoCastSpellIfCan(pPlayer, SPELL_EXIT_STOMACH_KNOCKBACK, CAST_TRIGGERED); - - // Remove the acid debuff - pPlayer->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); - - itr->second = false; - } - } - - return; - } - - // Stomach acid - if (m_uiStomachAcidTimer < uiDiff) - { - // Apply aura to all players in stomach - for (StomachMap::iterator itr = m_mStomachMap.begin(); itr != m_mStomachMap.end(); ++itr) - { - // Check for valid player - Player* pPlayer = m_creature->GetMap()->GetPlayer(itr->first); - - // Only apply to units in stomach - if (pPlayer && itr->second == true) - { - // Cast digestive acid on them - DoCastSpellIfCan(pPlayer, SPELL_DIGESTIVE_ACID, CAST_TRIGGERED); - - // Check if player should be kicked from stomach - if (pPlayer->IsWithinDist3d(KICK_X, KICK_Y, KICK_Z, 10.0f)) - { - // Teleport each player out - DoTeleportPlayer(pPlayer, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()+10, rand()%6); - - // Cast knockback on them - DoCastSpellIfCan(pPlayer, SPELL_EXIT_STOMACH_KNOCKBACK, CAST_TRIGGERED); - - // Remove the acid debuff - pPlayer->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); - - itr->second = false; - } - } - } - - m_uiStomachAcidTimer = 4000; - } - else - m_uiStomachAcidTimer -= uiDiff; - // Stomach Enter Timer - if (m_uiStomachEnterTimer < uiDiff) + if (m_uiMouthTentacleTimer < uiDiff) { - if (Player* pTarget = SelectRandomNotStomach()) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_LOS)) { - // Set target in stomach - m_mStomachMap[pTarget->GetObjectGuid()] = true; + // Cast the spell using the target as source pTarget->InterruptNonMeleeSpells(false); pTarget->CastSpell(pTarget, SPELL_MOUTH_TENTACLE, true, NULL, NULL, m_creature->GetObjectGuid()); m_stomachEnterTargetGuid = pTarget->GetObjectGuid(); - m_uiStomachEnterVisTimer = 3800; - } - m_uiStomachEnterTimer = 13800; + m_uiStomachEnterTimer = 3800; + m_uiMouthTentacleTimer = urand(13000, 15000); + } } else - m_uiStomachEnterTimer -= uiDiff; + m_uiMouthTentacleTimer -= uiDiff; - if (m_uiStomachEnterVisTimer && m_stomachEnterTargetGuid) + // Teleport the target to the stomach after a few seconds + if (m_uiStomachEnterTimer) { - if (m_uiStomachEnterVisTimer <= uiDiff) + if (m_uiStomachEnterTimer <= uiDiff) { // Check for valid player if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_stomachEnterTargetGuid)) - DoTeleportPlayer(pPlayer, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); - - m_stomachEnterTargetGuid.Clear(); - m_uiStomachEnterVisTimer = 0; - - // Note that actually C'Thun cannot be soloed, so kill all players, if no player left outside of stomach - bool bKillAllPlayer = true; - for (StomachMap::iterator itr = m_mStomachMap.begin(); itr != m_mStomachMap.end(); ++itr) - { - Player* pPlayer = m_creature->GetMap()->GetPlayer(itr->first); - if (itr->second == false && pPlayer) - { - bKillAllPlayer = false; - break; - } - } - if (bKillAllPlayer) { - for (StomachMap::iterator itr = m_mStomachMap.begin(); itr != m_mStomachMap.end(); ++itr) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(itr->first)) - m_creature->DealDamage(pPlayer, pPlayer->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - EnterEvadeMode(); - return; + DoTeleportPlayer(pPlayer, afCthunLocations[2][0], afCthunLocations[2][1], afCthunLocations[2][2], afCthunLocations[2][3]); + m_lPlayersInStomachList.push_back(pPlayer->GetObjectGuid()); } - } - else - m_uiStomachEnterVisTimer -= uiDiff; - } - // GientClawTentacleTimer - if (m_uiGiantClawTentacleTimer < uiDiff) - { - if (Player* pTarget = SelectRandomNotStomach()) - { - // Spawn claw tentacle on the random target - if (Creature* pSummoned = m_creature->SummonCreature(MOB_GIANT_CLAW_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 500)) - pSummoned->AI()->AttackStart(pTarget); - } - - // One giant claw tentacle every minute - m_uiGiantClawTentacleTimer = 60000; - } - else - m_uiGiantClawTentacleTimer -= uiDiff; - - // GiantEyeTentacleTimer - if (m_uiGiantEyeTentacleTimer < uiDiff) - { - if (Player* pTarget = SelectRandomNotStomach()) - { - // Spawn claw tentacle on the random target - if (Creature* pSummoned = m_creature->SummonCreature(MOB_GIANT_EYE_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 500)) - pSummoned->AI()->AttackStart(pTarget); + m_stomachEnterTargetGuid.Clear(); + m_uiStomachEnterTimer = 0; } - - // One giant eye tentacle every minute - m_uiGiantEyeTentacleTimer = 60000; - } - else - m_uiGiantEyeTentacleTimer -= uiDiff; - - // EyeTentacleTimer - if (m_uiEyeTentacleTimer < uiDiff) - { - // Spawn the 8 Eye Tentacles in the corret spots - SpawnEyeTentacle(0, 25); //south - SpawnEyeTentacle(12, 12); //south west - SpawnEyeTentacle(25, 0); //west - SpawnEyeTentacle(12, -12); //north west - - SpawnEyeTentacle(0, -25); //north - SpawnEyeTentacle(-12, -12); //north east - SpawnEyeTentacle(-25, 0); // east - SpawnEyeTentacle(-12, 12); // south east - - //These spawn at every 30 seconds - m_uiEyeTentacleTimer = 30000; + else + m_uiStomachEnterTimer -= uiDiff; } - else - m_uiEyeTentacleTimer -= uiDiff; break; - - } - // Weakened state case PHASE_CTHUN_WEAKENED: - { - // PhaseTimer + + // Handle Flesh Tentacles respawn when the vulnerability spell expires if (m_uiPhaseTimer < uiDiff) { - // Switch - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_CTHUN); - - // Remove red coloration - m_creature->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - - // Spawn 2 flesh tentacles - m_uiFleshTentaclesKilled = 0; - - // Spawn flesh tentacle - Creature* pSpawned = m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!pSpawned) - ++m_uiFleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature); - } - - pSpawned = NULL; - // Spawn flesh tentacle - pSpawned = m_creature->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); - - if (!pSpawned) - ++m_uiFleshTentaclesKilled; - else - { - if (flesh_tentacleAI* pTentacleAI = dynamic_cast(pSpawned->AI())) - pTentacleAI->SpawnedByCthun(m_creature); - } + DoSpawnFleshTentacles(); m_uiPhaseTimer = 0; + m_Phase = PHASE_CTHUN; } else m_uiPhaseTimer -= uiDiff; - } - } - } - - void JustDied(Unit* pKiller) - { - // Switch - if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_FINISH); - } - - void EnterEvadeMode() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_CTHUN_PHASE, PHASE_NOT_STARTED); - - ScriptedAI::EnterEvadeMode(); - } - - void DamageTaken(Unit* pDealer, uint32& uiDamage) - { - // No instance - if (!m_pInstance) - return; - - switch (m_pInstance->GetData(TYPE_CTHUN_PHASE)) - { - case PHASE_CTHUN: - { - // Not weakened so reduce damage by 99% - if (uiDamage / 99 > 0) uiDamage/= 99; - else - uiDamage = 1; - - // Prevent death in non-weakened state - if (uiDamage >= m_creature->GetHealth()) - uiDamage = 0; - return; - } - break; - - case PHASE_CTHUN_WEAKENED: - { - //Weakened - takes normal damage - return; - } - - default: - uiDamage = 0; break; } - } - - void FleshTentcleKilled() - { - ++m_uiFleshTentaclesKilled; - } -}; -struct MANGOS_DLL_DECL eye_tentacleAI : public ScriptedAI -{ - eye_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - SetCombatMovement(false); - Reset(); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_portalGuid = pPortal->GetObjectGuid(); - } - - uint32 m_uiMindflayTimer; - uint32 m_uiKillSelfTimer; - ObjectGuid m_portalGuid; - - void JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_portalGuid)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - - void Reset() - { - // Mind flay half a second after we spawn - m_uiMindflayTimer = 500; - - // This prevents eyes from overlapping - m_uiKillSelfTimer = 35000; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 uiDiff) - { - // Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // KillSelfTimer - if (m_uiKillSelfTimer < uiDiff) + if (m_uiGiantClawTentacleTimer < uiDiff) { - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + // Summon 1 Giant Claw Tentacle every 60 seconds + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_LOS)) + m_creature->SummonCreature(NPC_GIANT_CLAW_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); - return; + m_uiGiantClawTentacleTimer = 60000; } else - m_uiKillSelfTimer -= uiDiff; + m_uiGiantClawTentacleTimer -= uiDiff; - // MindflayTimer - if (m_uiMindflayTimer < uiDiff) + if (m_uiGiantEyeTentacleTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (target && !target->HasAura(SPELL_DIGESTIVE_ACID, EFFECT_INDEX_0)) - DoCastSpellIfCan(target, SPELL_MIND_FLAY); + // Summon 1 Giant Eye Tentacle every 60 seconds + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_LOS)) + m_creature->SummonCreature(NPC_GIANT_EYE_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); - //Mindflay every 10 seconds - m_uiMindflayTimer = 10100; + m_uiGiantEyeTentacleTimer = 60000; } else - m_uiMindflayTimer -= uiDiff; - } -}; + m_uiGiantEyeTentacleTimer -= uiDiff; -struct MANGOS_DLL_DECL claw_tentacleAI : public ScriptedAI -{ - claw_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - SetCombatMovement(false); - Reset(); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_portalGuid = pPortal->GetObjectGuid(); - } - - uint32 m_uiGroundRuptureTimer; - uint32 m_uiHamstringTimer; - uint32 m_uiEvadeTimer; - ObjectGuid m_portalGuid; - - void JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_portalGuid)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } - - void Reset() - { - // First rupture should happen half a second after we spawn - m_uiGroundRuptureTimer = 500; - m_uiHamstringTimer = 2000; - m_uiEvadeTimer = 5000; - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } - - void UpdateAI(const uint32 uiDiff) - { - // Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // EvadeTimer - if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + if (m_uiEyeTentacleTimer < uiDiff) { - if (m_uiEvadeTimer < uiDiff) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_portalGuid)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - - // Dissapear and reappear at new position - m_creature->SetVisibility(VISIBILITY_OFF); + DoDespawnEyeTentacles(); - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (!pTarget) - { - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - return; - } - - if (!pTarget->HasAura(SPELL_DIGESTIVE_ACID, EFFECT_INDEX_0)) - { - m_creature->GetMap()->CreatureRelocation(m_creature, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_SMALL_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_portalGuid = pPortal->GetObjectGuid(); - - m_uiGroundRuptureTimer = 500; - m_uiHamstringTimer = 2000; - m_uiEvadeTimer = 5000; - AttackStart(pTarget); - } - - m_creature->SetVisibility(VISIBILITY_ON); + // Spawn 8 Eye Tentacles every 30 seconds + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_EYE_TENTACLES; ++i) + { + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 30.0f, M_PI_F / 4 * i); + m_creature->SummonCreature(NPC_EYE_TENTACLE, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); } - else - m_uiEvadeTimer -= uiDiff; - } - // GroundRuptureTimer - if (m_uiGroundRuptureTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GROUND_RUPTURE); - m_uiGroundRuptureTimer = 30000; + m_uiEyeTentacleTimer = 30000; } else - m_uiGroundRuptureTimer -= uiDiff; + m_uiEyeTentacleTimer -= uiDiff; - // HamstringTimer - if (m_uiHamstringTimer < uiDiff) + // Note: this should be handled by the maps + if (m_uiDigestiveAcidTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HAMSTRING); - m_uiHamstringTimer = 5000; + // Iterate the Stomach players list and apply the Digesti acid debuff on them every 4 sec + for (GuidList::const_iterator itr = m_lPlayersInStomachList.begin(); itr != m_lPlayersInStomachList.end(); ++itr) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(*itr)) + pPlayer->CastSpell(pPlayer, SPELL_DIGESTIVE_ACID, true, NULL, NULL, m_creature->GetObjectGuid()); + } + m_uiDigestiveAcidTimer = 4000; } else - m_uiHamstringTimer -= uiDiff; - - DoMeleeAttackIfReady(); + m_uiDigestiveAcidTimer -= uiDiff; } }; -struct MANGOS_DLL_DECL giant_claw_tentacleAI : public ScriptedAI +/*###### +## npc_giant_claw_tentacle +######*/ + +struct npc_giant_claw_tentacleAI : public Scripted_NoMovementAI { - giant_claw_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_giant_claw_tentacleAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - SetCombatMovement(false); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_portalGuid = pPortal->GetObjectGuid(); } - uint32 m_uiGroundRuptureTimer; + ScriptedInstance* m_pInstance; + uint32 m_uiThrashTimer; uint32 m_uiHamstringTimer; - uint32 m_uiEvadeTimer; - ObjectGuid m_portalGuid; - - void JustDied(Unit*) - { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_portalGuid)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } + uint32 m_uiDistCheckTimer; - void Reset() + void Reset() override { - //First rupture should happen half a second after we spawn - m_uiGroundRuptureTimer = 500; - m_uiHamstringTimer = 2000; - m_uiThrashTimer = 5000; - m_uiEvadeTimer = 5000; - } + m_uiHamstringTimer = 2000; + m_uiThrashTimer = 5000; + m_uiDistCheckTimer = 5000; - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_GIANT_GROUND_RUPTURE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Check if we have a target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // EvadeTimer - if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + if (m_uiDistCheckTimer < uiDiff) { - if (m_uiEvadeTimer < uiDiff) + // If there is nobody in range, spawn a new tentacle at a new target location + if (!m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE) && m_pInstance) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_portalGuid)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - - // Dissapear and reappear at new position - m_creature->SetVisibility(VISIBILITY_OFF); - - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (!target) - { - m_creature->DealDamage(m_creature, m_creature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - return; - } - - if (!target->HasAura(SPELL_DIGESTIVE_ACID, EFFECT_INDEX_0)) + if (Creature* pCthun = m_pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) { - m_creature->GetMap()->CreatureRelocation(m_creature, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_portalGuid = pPortal->GetObjectGuid(); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + pCthun->SummonCreature(NPC_GIANT_CLAW_TENTACLE, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); - m_uiGroundRuptureTimer = 500; - m_uiHamstringTimer = 2000; - m_uiThrashTimer = 5000; - m_uiEvadeTimer = 5000; - AttackStart(target); + // Self kill when a new tentacle is spawned + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + return; + } } - - m_creature->SetVisibility(VISIBILITY_ON); - } else - m_uiEvadeTimer -= uiDiff; - } - - // GroundRuptureTimer - if (m_uiGroundRuptureTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_GROUND_RUPTURE); - m_uiGroundRuptureTimer = 30000; + m_uiDistCheckTimer = 5000; } else - m_uiGroundRuptureTimer -= uiDiff; + m_uiDistCheckTimer -= uiDiff; - // ThrashTimer if (m_uiThrashTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_THRASH); - m_uiThrashTimer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_THRASH) == CAST_OK) + m_uiThrashTimer = 10000; } else m_uiThrashTimer -= uiDiff; - // HamstringTimer if (m_uiHamstringTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HAMSTRING); - m_uiHamstringTimer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING) == CAST_OK) + m_uiHamstringTimer = 10000; } else m_uiHamstringTimer -= uiDiff; @@ -1204,177 +746,83 @@ struct MANGOS_DLL_DECL giant_claw_tentacleAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL giant_eye_tentacleAI : public ScriptedAI -{ - giant_eye_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - SetCombatMovement(false); - Reset(); - - if (Unit* pPortal = m_creature->SummonCreature(MOB_GIANT_PORTAL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_portalGuid = pPortal->GetObjectGuid(); - } - - uint32 m_uiBeamTimer; - ObjectGuid m_portalGuid; +/*###### +## at_stomach_cthun +######*/ - void JustDied(Unit*) +bool AreaTrigger_at_stomach_cthun(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_STOMACH_1) { - if (Creature* pCreature = m_creature->GetMap()->GetCreature(m_portalGuid)) - pCreature->DealDamage(pCreature, pCreature->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - } + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; - void Reset() - { - //Green Beam half a second after we spawn - m_uiBeamTimer = 500; - } + // Summon the exit trigger which should push the player outside the stomach - not used because missing eject spells + // if (!GetClosestCreatureWithEntry(pPlayer, NPC_EXIT_TRIGGER, 10.0f)) + // pPlayer->CastSpell(pPlayer, SPELL_EXIT_STOMACH, true); - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); + // Note: because of the missing spell id 26224, we will use basic jump movement + pPlayer->GetMotionMaster()->MoveJump(afCthunLocations[3][0], afCthunLocations[3][1], afCthunLocations[3][2], pPlayer->GetSpeed(MOVE_RUN) * 5, 0); } - - void UpdateAI(const uint32 uiDiff) + else if (pAt->id == AREATRIGGER_STOMACH_2) { - // Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // BeamTimer - if (m_uiBeamTimer < uiDiff) + if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target && !target->HasAura(SPELL_DIGESTIVE_ACID, EFFECT_INDEX_0)) - DoCastSpellIfCan(target,SPELL_GREEN_BEAM); - - // Beam every 2 seconds - m_uiBeamTimer = 2100; - } - else - m_uiBeamTimer -= uiDiff; - } -}; + if (Creature* pCthun = pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) + { + // Remove player from the Stomach + if (boss_cthunAI* pBossAI = dynamic_cast(pCthun->AI())) + pBossAI->DoRemovePlayerFromStomach(pPlayer); -// Flesh tentacle functions -void flesh_tentacleAI::UpdateAI(const uint32 uiDiff) -{ - // Check if we have a target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + // Teleport back to C'thun and remove the Digestive Acid + pPlayer->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + pPlayer->NearTeleportTo(pCthun->GetPositionX(), pCthun->GetPositionY(), pCthun->GetPositionZ() + 15.0f, frand(0, 2 * M_PI_F)); - if (m_cThunGuid) - { - if (m_uiCheckTimer < uiDiff) - { - Creature* pParent = m_creature->GetMap()->GetCreature(m_cThunGuid); - - if (!pParent || !pParent->isAlive() || !pParent->isInCombat()) - { - m_cThunGuid.Clear(); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); - return; + // Note: the real knockback spell id should be 26230 + pPlayer->CastSpell(pPlayer, SPELL_EXIT_STOMACH_KNOCKBACK, true, NULL, NULL, pCthun->GetObjectGuid()); } - - m_uiCheckTimer = 1000; } - else - m_uiCheckTimer -= uiDiff; - } - - DoMeleeAttackIfReady(); -} - -void flesh_tentacleAI::JustDied(Unit* killer) -{ - if (!m_cThunGuid) - { - error_log("SD2: flesh_tentacle: No m_cThunGuid variable"); - return; } - if (Creature* pCthun = m_creature->GetMap()->GetCreature(m_cThunGuid)) - { - if (cthunAI* pCthunAI = dynamic_cast(pCthun->AI())) - pCthunAI->FleshTentcleKilled(); - } - else - error_log("SD2: flesh_tentacle: No Cthun"); -} - -// GetAIs -CreatureAI* GetAI_eye_of_cthun(Creature* pCreature) -{ - return new eye_of_cthunAI(pCreature); -} - -CreatureAI* GetAI_cthun(Creature* pCreature) -{ - return new cthunAI(pCreature); -} - -CreatureAI* GetAI_eye_tentacle(Creature* pCreature) -{ - return new eye_tentacleAI(pCreature); -} - -CreatureAI* GetAI_claw_tentacle(Creature* pCreature) -{ - return new claw_tentacleAI(pCreature); + return false; } -CreatureAI* GetAI_giant_claw_tentacle(Creature* pCreature) +CreatureAI* GetAI_boss_eye_of_cthun(Creature* pCreature) { - return new giant_claw_tentacleAI(pCreature); + return new boss_eye_of_cthunAI(pCreature); } -CreatureAI* GetAI_giant_eye_tentacle(Creature* pCreature) +CreatureAI* GetAI_boss_cthun(Creature* pCreature) { - return new giant_eye_tentacleAI(pCreature); + return new boss_cthunAI(pCreature); } -CreatureAI* GetAI_flesh_tentacle(Creature* pCreature) +CreatureAI* GetAI_npc_giant_claw_tentacle(Creature* pCreature) { - return new flesh_tentacleAI(pCreature); + return new npc_giant_claw_tentacleAI(pCreature); } void AddSC_boss_cthun() { Script* pNewScript; - //Eye pNewScript = new Script; pNewScript->Name = "boss_eye_of_cthun"; - pNewScript->GetAI = &GetAI_eye_of_cthun; + pNewScript->GetAI = &GetAI_boss_eye_of_cthun; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "boss_cthun"; - pNewScript->GetAI = &GetAI_cthun; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_eye_tentacle"; - pNewScript->GetAI = &GetAI_eye_tentacle; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_claw_tentacle"; - pNewScript->GetAI = &GetAI_claw_tentacle; + pNewScript->GetAI = &GetAI_boss_cthun; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "mob_giant_claw_tentacle"; - pNewScript->GetAI = &GetAI_giant_claw_tentacle; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_giant_eye_tentacle"; - pNewScript->GetAI = &GetAI_giant_eye_tentacle; + pNewScript->GetAI = &GetAI_npc_giant_claw_tentacle; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_giant_flesh_tentacle"; - pNewScript->GetAI = &GetAI_flesh_tentacle; + pNewScript->Name = "at_stomach_cthun"; + pNewScript->pAreaTrigger = &AreaTrigger_at_stomach_cthun; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp index b5fa403bf..5b8666eea 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_fankriss.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,135 +22,145 @@ SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" -#define SOUND_SENTENCE_YOU 8588 -#define SOUND_SERVE_TO 8589 -#define SOUND_LAWS 8590 -#define SOUND_TRESPASS 8591 -#define SOUND_WILL_BE 8592 - -#define SPELL_MORTAL_WOUND 28467 -#define SPELL_ROOT 28858 +enum +{ + SOUND_SENTENCE_YOU = 8588, + SOUND_SERVE_TO = 8589, + SOUND_LAWS = 8590, + SOUND_TRESPASS = 8591, + SOUND_WILL_BE = 8592, + + SPELL_MORTAL_WOUND = 25646, + SPELL_ENTANGLE_1 = 720, + SPELL_ENTANGLE_2 = 731, + SPELL_ENTANGLE_3 = 1121, + SPELL_SUMMON_WORM_1 = 518, + SPELL_SUMMON_WORM_2 = 25831, + SPELL_SUMMON_WORM_3 = 25832, + + NPC_SPAWN_FANKRISS = 15630, + NPC_VEKNISS_HATCHLING = 15962, +}; -// Enrage for his spawns -#define SPELL_ENRAGE 28798 +static const uint32 aSummonWormSpells[3] = {SPELL_SUMMON_WORM_1, SPELL_SUMMON_WORM_2, SPELL_SUMMON_WORM_3}; +static const uint32 aEntangleSpells[3] = {SPELL_ENTANGLE_1, SPELL_ENTANGLE_2, SPELL_ENTANGLE_3}; -struct MANGOS_DLL_DECL boss_fankrissAI : public ScriptedAI +struct boss_fankrissAI : public ScriptedAI { - boss_fankrissAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_fankrissAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiMortalWoundTimer; + uint32 m_uiSummonWormTimer; + uint32 m_uiEntangleTimer; + uint32 m_uiEntangleSummonTimer; - uint32 MortalWound_Timer; - uint32 SpawnHatchlings_Timer; - uint32 SpawnSpawns_Timer; - int Rand; - int RandX; - int RandY; + ObjectGuid m_EntangleTargetGuid; - Creature* Spawn; + void Reset() override + { + m_uiMortalWoundTimer = urand(10000, 15000); + m_uiSummonWormTimer = urand(30000, 50000); + m_uiEntangleTimer = urand(25000, 40000); + m_uiEntangleSummonTimer = 0; + } - void Reset() + void Aggro(Unit* /*pWho*/) override { - MortalWound_Timer = urand(10000, 15000); - SpawnHatchlings_Timer = urand(6000, 12000); - SpawnSpawns_Timer = urand(15000, 45000); + if (m_pInstance) + m_pInstance->SetData(TYPE_FANKRISS, IN_PROGRESS); } - void SummonSpawn(Unit* pVictim) + void JustReachedHome() override { - Rand = 10 + (rand()%10); - switch(urand(0, 1)) + if (m_pInstance) + m_pInstance->SetData(TYPE_FANKRISS, FAIL); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FANKRISS, DONE); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SPAWN_FANKRISS) { - case 0: RandX = 0 - Rand; break; - case 1: RandX = 0 + Rand; break; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } - Rand = 0; - Rand = 10 + (rand()%10); - switch(urand(0, 1)) + else if (pSummoned->GetEntry() == NPC_VEKNISS_HATCHLING) { - case 0: RandY = 0 - Rand; break; - case 1: RandY = 0 + Rand; break; + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_EntangleTargetGuid)) + pSummoned->AI()->AttackStart(pTarget); } - Rand = 0; - Spawn = DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - if (Spawn && pVictim) - Spawn->AI()->AttackStart(pVictim); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //MortalWound_Timer - if (MortalWound_Timer < diff) + if (m_uiMortalWoundTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTAL_WOUND); - MortalWound_Timer = urand(10000, 20000); - }else MortalWound_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_WOUND) == CAST_OK) + m_uiMortalWoundTimer = urand(7000, 14000); + } + else + m_uiMortalWoundTimer -= uiDiff; - //Summon 1-3 Spawns of Fankriss at random time. - if (SpawnSpawns_Timer < diff) + if (m_uiSummonWormTimer < uiDiff) { - switch(urand(0, 2)) - { - case 0: - SummonSpawn(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); - break; - case 1: - SummonSpawn(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); - SummonSpawn(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); - break; - case 2: - SummonSpawn(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); - SummonSpawn(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); - SummonSpawn(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)); - break; - } - SpawnSpawns_Timer = urand(30000, 60000); + uint8 uiSpawnIndex = urand(0, 2); + if (DoCastSpellIfCan(m_creature, aSummonWormSpells[uiSpawnIndex]) == CAST_OK) + m_uiSummonWormTimer = urand(15000, 40000); } else - SpawnSpawns_Timer -= diff; + m_uiSummonWormTimer -= uiDiff; // Teleporting Random Target to one of the three tunnels and spawn 4 hatchlings near the gamer. - //We will only telport if fankriss has more than 3% of hp so teleported gamers can always loot. - if (m_creature->GetHealthPercent() > 3.0f) + if (m_uiEntangleTimer < uiDiff) { - if (SpawnHatchlings_Timer< diff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_ROOT, SELECT_FLAG_PLAYER)) + uint8 uiEntangleIndex = urand(0, 2); + if (DoCastSpellIfCan(pTarget, aEntangleSpells[uiEntangleIndex]) == CAST_OK) { - DoCastSpellIfCan(pTarget, SPELL_ROOT); - - if (m_creature->getThreatManager().getThreat(pTarget)) - m_creature->getThreatManager().modifyThreatPercent(pTarget, -100); + m_EntangleTargetGuid = pTarget->GetObjectGuid(); + m_uiEntangleSummonTimer = 1000; + m_uiEntangleTimer = urand(40000, 70000); + } + } + } + else + m_uiEntangleTimer -= uiDiff; - switch(urand(0, 2)) + // Summon 4 Hatchlings around the target + if (m_uiEntangleSummonTimer) + { + if (m_uiEntangleSummonTimer <= uiDiff) + { + if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_EntangleTargetGuid)) + { + float fX, fY, fZ; + for (uint8 i = 0; i < 4; ++i) { - case 0: - DoTeleportPlayer(pTarget, -8106.0142f, 1289.2900f, -74.419533f, 5.112f); - break; - case 1: - DoTeleportPlayer(pTarget, -7990.135354f, 1155.1907f, -78.849319f, 2.608f); - break; - case 2: - DoTeleportPlayer(pTarget, -8159.7753f, 1127.9064f, -76.868660f, 0.675f); - break; + m_creature->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 3.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_VEKNISS_HATCHLING, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 10000); } - Creature* pHatchling = NULL; - if (pHatchling = m_creature->SummonCreature(15962, pTarget->GetPositionX()-3, pTarget->GetPositionY()-3, pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - pHatchling->AI()->AttackStart(pTarget); - if (pHatchling = m_creature->SummonCreature(15962, pTarget->GetPositionX()-3, pTarget->GetPositionY()+3, pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - pHatchling->AI()->AttackStart(pTarget); - if (pHatchling = m_creature->SummonCreature(15962, pTarget->GetPositionX()-5, pTarget->GetPositionY()-5, pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - pHatchling->AI()->AttackStart(pTarget); - if (pHatchling = m_creature->SummonCreature(15962, pTarget->GetPositionX()-5, pTarget->GetPositionY()+5, pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) - pHatchling->AI()->AttackStart(pTarget); + m_uiEntangleSummonTimer = 0; } - SpawnHatchlings_Timer = urand(45000, 60000); } else - SpawnHatchlings_Timer -= diff; + m_uiEntangleSummonTimer -= uiDiff; } DoMeleeAttackIfReady(); diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp index 9ab086b12..417d0899b 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_huhuran.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,6 +22,7 @@ SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" enum { @@ -35,9 +36,15 @@ enum SPELL_ACID_SPIT = 26050 }; -struct MANGOS_DLL_DECL boss_huhuranAI : public ScriptedAI +struct boss_huhuranAI : public ScriptedAI { - boss_huhuranAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_huhuranAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; uint32 m_uiFrenzyTimer; uint32 m_uiWyvernTimer; @@ -46,7 +53,7 @@ struct MANGOS_DLL_DECL boss_huhuranAI : public ScriptedAI bool m_bIsBerserk; - void Reset() + void Reset() override { m_uiFrenzyTimer = urand(25000, 35000); m_uiWyvernTimer = urand(18000, 28000); @@ -55,7 +62,25 @@ struct MANGOS_DLL_DECL boss_huhuranAI : public ScriptedAI m_bIsBerserk = false; } - void UpdateAI(const uint32 uiDiff) + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HUHURAN, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HUHURAN, FAIL); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HUHURAN, DONE); + } + + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp index e47e2818a..cdb8987d1 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_ouro.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Ouro -SD%Complete: 50 -SDComment: script needs to be reworked +SD%Complete: 90 +SDComment: Some minor adjustments may be required SDCategory: Temple of Ahn'Qiraj EndScriptData */ @@ -26,58 +26,112 @@ EndScriptData */ enum { + // ground spells SPELL_SWEEP = 26103, SPELL_SANDBLAST = 26102, - SPELL_GROUND_RUPTURE = 26100, - SPELL_BIRTH = 26262, //The Birth Animation SPELL_BOULDER = 26616, SPELL_BERSERK = 26615, - SPELL_SUMMON_SCARABS = 26060, - SPELL_SUMMON_OURO_MOUND = 26058, - SPELL_SUMMON_OURO = 26642, + // emerge spells + SPELL_BIRTH = 26262, // The Birth Animation + SPELL_GROUND_RUPTURE = 26100, // spell not confirmed + SPELL_SUMMON_BASE = 26133, // summons gameobject 180795 - SPELL_DIRTMOUND_PASSIVE = 26092, + // submerge spells SPELL_SUBMERGE_VISUAL = 26063, + SPELL_SUMMON_OURO_MOUND = 26058, // summons 5 dirt mounds + SPELL_SUMMON_TRIGGER = 26284, - NPC_OURO_SCARAB = 15718, - NPC_OURO_SPAWNER = 15957, - NPC_OURO_TRIGGER = 15717 + // SPELL_SUMMON_OURO_TRIGG = 26642, + SPELL_SUMMON_OURO = 26061, // used by the script to summon the boss directly + SPELL_QUAKE = 26093, + + // other spells - not used + // SPELL_SUMMON_SCARABS = 26060, // triggered after 30 secs - cast by the Dirt Mounds + // SPELL_DIRTMOUND_PASSIVE = 26092, // casts 26093 every 1 sec - removed from DBC + // SPELL_SET_OURO_HEALTH = 26075, // removed from DBC + // SPELL_SAVE_OURO_HEALTH = 26076, // removed from DBC + // SPELL_TELEPORT_TRIGGER = 26285, // removed from DBC + // SPELL_SUBMERGE_TRIGGER = 26104, // removed from DBC + // SPELL_SUMMON_OURO_MOUND = 26617, // removed from DBC + // SPELL_SCARABS_PERIODIC = 26619, // cast by the Dirt Mounds in order to spawn the scarabs - removed from DBC + + // summoned npcs + NPC_OURO = 15517, + // NPC_OURO_SCARAB = 15718, // summoned by Dirt Mounds + NPC_OURO_TRIGGER = 15717, + NPC_DIRT_MOUND = 15712, // summoned also by missing spell 26617 }; -struct MANGOS_DLL_DECL boss_ouroAI : public ScriptedAI +struct boss_ouroAI : public Scripted_NoMovementAI { - boss_ouroAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_ouroAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; uint32 m_uiSweepTimer; uint32 m_uiSandBlastTimer; uint32 m_uiSubmergeTimer; - uint32 m_uiBackTimer; - uint32 m_uiChangeTargetTimer; - uint32 m_uiSpawnTimer; + uint32 m_uiSummonBaseTimer; + + uint32 m_uiSummonMoundTimer; bool m_bEnraged; bool m_bSubmerged; - void Reset() + ObjectGuid m_ouroTriggerGuid; + + void Reset() override + { + m_uiSweepTimer = urand(35000, 40000); + m_uiSandBlastTimer = urand(30000, 45000); + m_uiSubmergeTimer = 90000; + m_uiSummonBaseTimer = 2000; + + m_uiSummonMoundTimer = 10000; + + m_bEnraged = false; + m_bSubmerged = false; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_OURO, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_OURO, FAIL); + + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* /*pKiller*/) override { - m_uiSweepTimer = urand(5000, 10000); - m_uiSandBlastTimer = urand(20000, 35000); - m_uiSubmergeTimer = urand(90000, 150000); - m_uiBackTimer = urand(30000, 45000); - m_uiChangeTargetTimer = urand(5000, 8000); - m_uiSpawnTimer = urand(10000, 20000); - - m_bEnraged = false; - m_bSubmerged = false; + if (m_pInstance) + m_pInstance->SetData(TYPE_OURO, DONE); } - void Aggro(Unit* pWho) + void JustSummoned(Creature* pSummoned) override { - DoCastSpellIfCan(m_creature, SPELL_BIRTH); + switch (pSummoned->GetEntry()) + { + case NPC_OURO_TRIGGER: + m_ouroTriggerGuid = pSummoned->GetObjectGuid(); + // no break; + case NPC_DIRT_MOUND: + pSummoned->GetMotionMaster()->MoveRandomAroundPoint(pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 40.0f); + break; + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no pTarget if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -85,11 +139,24 @@ struct MANGOS_DLL_DECL boss_ouroAI : public ScriptedAI if (!m_bSubmerged) { + // Summon sandworm base + if (m_uiSummonBaseTimer) + { + if (m_uiSummonBaseTimer <= uiDiff) + { + // Note: server side spells should be cast directly + m_creature->CastSpell(m_creature, SPELL_SUMMON_BASE, true); + m_uiSummonBaseTimer = 0; + } + else + m_uiSummonBaseTimer -= uiDiff; + } + // Sweep if (m_uiSweepTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SWEEP); - m_uiSweepTimer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_SWEEP) == CAST_OK) + m_uiSweepTimer = 20000; } else m_uiSweepTimer -= uiDiff; @@ -97,67 +164,87 @@ struct MANGOS_DLL_DECL boss_ouroAI : public ScriptedAI // Sand Blast if (m_uiSandBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SANDBLAST); - m_uiSandBlastTimer = urand(20000, 35000); + if (DoCastSpellIfCan(m_creature, SPELL_SANDBLAST) == CAST_OK) + m_uiSandBlastTimer = 22000; } else m_uiSandBlastTimer -= uiDiff; if (!m_bEnraged) { + // Enrage at 20% HP if (m_creature->GetHealthPercent() < 20.0f) { - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - m_bEnraged = true; - return; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + m_bEnraged = true; + return; + } } // Submerge if (m_uiSubmergeTimer < uiDiff) { - //Cast - m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(35); - DoCastSpellIfCan(m_creature, SPELL_DIRTMOUND_PASSIVE); - - m_bSubmerged = true; - m_uiBackTimer = urand(30000, 45000); + if (DoCastSpellIfCan(m_creature, SPELL_SUBMERGE_VISUAL) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_OURO_MOUND, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_TRIGGER, CAST_TRIGGERED); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_bSubmerged = true; + m_uiSubmergeTimer = 30000; + } } else m_uiSubmergeTimer -= uiDiff; } - - DoMeleeAttackIfReady(); - } - else - { - // Change Target - if (m_uiChangeTargetTimer < uiDiff) + else { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + // Summon 1 mound every 10 secs when enraged + if (m_uiSummonMoundTimer < uiDiff) { - m_creature->MonsterMoveWithSpeed(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 28.f); + DoSpawnCreature(NPC_DIRT_MOUND, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_uiSummonMoundTimer = 10000; } - - m_uiChangeTargetTimer = urand(10000, 20000); + else + m_uiSummonMoundTimer -= uiDiff; } - else - m_uiChangeTargetTimer -= uiDiff; - // Back - if (m_uiBackTimer < uiDiff) + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + // Spam Boulder spell when enraged and not tanked + else if (m_bEnraged) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->setFaction(14); + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_BOULDER); + } + } + } + else + { + // Resume combat + if (m_uiSubmergeTimer < uiDiff) + { + // Teleport to the trigger in order to get a new location + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_ouroTriggerGuid)) + m_creature->NearTeleportTo(pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GROUND_RUPTURE); + if (DoCastSpellIfCan(m_creature, SPELL_BIRTH) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_bSubmerged = false; - m_uiSubmergeTimer = urand(60000, 120000); + m_bSubmerged = false; + m_uiSummonBaseTimer = 2000; + m_uiSubmergeTimer = 90000; + } } else - m_uiBackTimer -= uiDiff; + m_uiSubmergeTimer -= uiDiff; } } }; @@ -167,6 +254,57 @@ CreatureAI* GetAI_boss_ouro(Creature* pCreature) return new boss_ouroAI(pCreature); } +struct npc_ouro_spawnerAI : public Scripted_NoMovementAI +{ + npc_ouro_spawnerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} + + uint32 m_uiQuakeTimer; + bool m_bHasSummoned; + + void Reset() override + { + m_uiQuakeTimer = 1000; + m_bHasSummoned = false; + } + + void Aggro(Unit* /*pWho*/) override + { + if (!m_bHasSummoned) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_OURO, CAST_TRIGGERED); + m_bHasSummoned = true; + } + } + + void JustSummoned(Creature* pSummoned) override + { + // Despanw when Ouro is spawned + if (pSummoned->GetEntry() == NPC_OURO) + { + pSummoned->CastSpell(pSummoned, SPELL_BIRTH, false); + pSummoned->SetInCombatWithZone(); + m_creature->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // triggered by missing spell 26092 + if (m_uiQuakeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_QUAKE) == CAST_OK) + m_uiQuakeTimer = 1000; + } + else + m_uiQuakeTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_ouro_spawner(Creature* pCreature) +{ + return new npc_ouro_spawnerAI(pCreature); +} + void AddSC_boss_ouro() { Script* pNewScript; @@ -175,4 +313,9 @@ void AddSC_boss_ouro() pNewScript->Name = "boss_ouro"; pNewScript->GetAI = &GetAI_boss_ouro; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ouro_spawner"; + pNewScript->GetAI = &GetAI_npc_ouro_spawner; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp index f9933e1b7..2a541492b 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_sartura.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss_Sartura -SD%Complete: 85 -SDComment: Targeting currently doesn't work as expected +SD%Complete: 95 +SDComment: SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" enum { @@ -38,9 +39,15 @@ enum SPELL_KNOCKBACK = 26027, }; -struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI +struct boss_sarturaAI : public ScriptedAI { - boss_sarturaAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + boss_sarturaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; uint32 m_uiWhirlWindTimer; uint32 m_uiWhirlWindRandomTimer; @@ -50,56 +57,58 @@ struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI uint32 m_uiEnrageHardTimer; bool m_bIsEnraged; - bool m_bIsEnragedHard; - bool m_bIsWhirlWind; - bool m_bAggroReset; - void Reset() + void Reset() override { m_uiWhirlWindTimer = 30000; m_uiWhirlWindRandomTimer = urand(3000, 7000); - m_uiWhirlWindEndTimer = 15000; + m_uiWhirlWindEndTimer = 0; m_uiAggroResetTimer = urand(45000, 55000); - m_uiAggroResetEndTimer = 5000; - m_uiEnrageHardTimer = 10*60000; + m_uiAggroResetEndTimer = 0; + m_uiEnrageHardTimer = 10 * 60000; - m_bIsWhirlWind = false; - m_bAggroReset = false; m_bIsEnraged = false; - m_bIsEnragedHard = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTURA, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTURA, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTURA, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_bIsWhirlWind) + if (m_uiWhirlWindEndTimer) // Is in Whirlwind { // While whirlwind, switch to random targets often if (m_uiWhirlWindRandomTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - { - m_creature->AddThreat(pTarget); - m_creature->TauntApply(pTarget); - AttackStart(pTarget); - } + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->FixateTarget(pTarget); m_uiWhirlWindRandomTimer = urand(3000, 7000); } @@ -107,49 +116,49 @@ struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI m_uiWhirlWindRandomTimer -= uiDiff; // End Whirlwind Phase - if (m_uiWhirlWindEndTimer < uiDiff) - m_bIsWhirlWind = false; + if (m_uiWhirlWindEndTimer <= uiDiff) + { + m_creature->FixateTarget(NULL); + m_uiWhirlWindEndTimer = 0; + m_uiWhirlWindTimer = urand(25000, 40000); + } else m_uiWhirlWindEndTimer -= uiDiff; } - else // if (!m_bIsWhirlWind) + else // if (!m_uiWhirlWindEndTimer) // Is not in whirlwind { // Enter Whirlwind Phase if (m_uiWhirlWindTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) { - m_bIsWhirlWind = true; m_uiWhirlWindEndTimer = 15000; - m_uiWhirlWindTimer = urand(25000, 40000); + m_uiWhirlWindRandomTimer = 500; } } else m_uiWhirlWindTimer -= uiDiff; // Aquire a new target sometimes - if (m_uiAggroResetTimer < uiDiff) + if (!m_uiAggroResetEndTimer) // No random target picket { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + if (m_uiAggroResetTimer < uiDiff) { - m_creature->AddThreat(pTarget); - m_creature->TauntApply(pTarget); - AttackStart(pTarget); - } + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + m_creature->FixateTarget(pTarget); - m_bAggroReset = true; - m_uiAggroResetTimer = urand(2000, 5000); + m_uiAggroResetEndTimer = 5000; + } + else + m_uiAggroResetTimer -= uiDiff; } - else - m_uiAggroResetTimer -= uiDiff; - - // Remove remaining taunts, TODO - if (m_bAggroReset) + else // Reset from recent random target { - if (m_uiAggroResetEndTimer < uiDiff) + // Remove remaining taunts + if (m_uiAggroResetEndTimer <= uiDiff) { - m_bAggroReset = false; - m_uiAggroResetEndTimer = 5000; + m_creature->FixateTarget(NULL); + m_uiAggroResetEndTimer = 0; m_uiAggroResetTimer = urand(35000, 45000); } else @@ -160,29 +169,29 @@ struct MANGOS_DLL_DECL boss_sarturaAI : public ScriptedAI // If she is 20% enrage if (!m_bIsEnraged && m_creature->GetHealthPercent() <= 20.0f) { - if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE, m_bIsWhirlWind ? CAST_TRIGGERED : 0) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE, m_uiWhirlWindEndTimer ? CAST_TRIGGERED : 0) == CAST_OK) m_bIsEnraged = true; } // After 10 minutes hard enrage - if (!m_bIsEnragedHard) + if (m_uiEnrageHardTimer) { - if (m_uiEnrageHardTimer < uiDiff) + if (m_uiEnrageHardTimer <= uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_ENRAGEHARD, m_bIsWhirlWind ? CAST_TRIGGERED : 0) == CAST_OK) - m_bIsEnragedHard = true; + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGEHARD, m_uiWhirlWindEndTimer ? CAST_TRIGGERED : 0) == CAST_OK) + m_uiEnrageHardTimer = 0; } else m_uiEnrageHardTimer -= uiDiff; } // No melee damage while in whirlwind - if (!m_bIsWhirlWind) + if (!m_uiWhirlWindEndTimer) DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI +struct mob_sartura_royal_guardAI : public ScriptedAI { mob_sartura_royal_guardAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -193,38 +202,28 @@ struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI uint32 m_uiAggroResetEndTimer; uint32 m_uiKnockBackTimer; - bool m_IsWhirlWind; - bool m_bAggroReset; - - void Reset() + void Reset() override { m_uiWhirlWindTimer = 30000; m_uiWhirlWindRandomTimer = urand(3000, 7000); - m_uiWhirlWindEndTimer = 15000; + m_uiWhirlWindEndTimer = 0; m_uiAggroResetTimer = urand(45000, 55000); - m_uiAggroResetEndTimer = 5000; + m_uiAggroResetEndTimer = 0; m_uiKnockBackTimer = 10000; - - m_IsWhirlWind = false; - m_bAggroReset = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_IsWhirlWind) + if (m_uiWhirlWindEndTimer) // Is in Whirlwind { // While whirlwind, switch to random targets often if (m_uiWhirlWindRandomTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - { - m_creature->AddThreat(pTarget); - m_creature->TauntApply(pTarget); - AttackStart(pTarget); - } + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->FixateTarget(pTarget); m_uiWhirlWindRandomTimer = urand(3000, 7000); } @@ -232,49 +231,48 @@ struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI m_uiWhirlWindRandomTimer -= uiDiff; // End Whirlwind Phase - if (m_uiWhirlWindEndTimer < uiDiff) - m_IsWhirlWind = false; + if (m_uiWhirlWindEndTimer <= uiDiff) + { + m_creature->FixateTarget(NULL); + m_uiWhirlWindEndTimer = 0; + m_uiWhirlWindTimer = urand(25000, 40000); + } else m_uiWhirlWindEndTimer -= uiDiff; } - else // if (!m_IsWhirlWind) + else // if (!m_uiWhirlWindEndTimer) // Is not in Whirlwind { // Enter Whirlwind Phase if (m_uiWhirlWindTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND_ADD) == CAST_OK) { - m_IsWhirlWind = true; m_uiWhirlWindEndTimer = 8000; - m_uiWhirlWindTimer = urand(25000, 40000); + m_uiWhirlWindRandomTimer = 500; } } else m_uiWhirlWindTimer -= uiDiff; // Aquire a new target sometimes - if (m_uiAggroResetTimer < uiDiff) + if (!m_uiAggroResetEndTimer) // No random target picket { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + if (m_uiAggroResetTimer < uiDiff) { - m_creature->AddThreat(pTarget); - m_creature->TauntApply(pTarget); - AttackStart(pTarget); - } + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + m_creature->FixateTarget(pTarget); - m_bAggroReset = true; - m_uiAggroResetTimer = urand(2000, 5000); + m_uiAggroResetEndTimer = 5000; + } + else + m_uiAggroResetTimer -= uiDiff; } - else - m_uiAggroResetTimer -= uiDiff; - - // Remove remaining taunts, TODO - if (m_bAggroReset) + else // Reset from recent random target { - if (m_uiAggroResetEndTimer FixateTarget(NULL); + m_uiAggroResetEndTimer = 0; m_uiAggroResetTimer = urand(30000, 40000); } else @@ -292,7 +290,7 @@ struct MANGOS_DLL_DECL mob_sartura_royal_guardAI : public ScriptedAI } // No melee damage while in whirlwind - if (!m_IsWhirlWind) + if (!m_uiWhirlWindEndTimer) DoMeleeAttackIfReady(); } }; diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp index 924677068..10517ae16 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_skeram.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,87 +16,74 @@ /* ScriptData SDName: Boss_Skeram -SD%Complete: 75 -SDComment: Mind Control buggy. +SD%Complete: 90 +SDComment: Timers SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" #include "temple_of_ahnqiraj.h" -#include "Group.h" - -#define SAY_AGGRO1 -1531000 -#define SAY_AGGRO2 -1531001 -#define SAY_AGGRO3 -1531002 -#define SAY_SLAY1 -1531003 -#define SAY_SLAY2 -1531004 -#define SAY_SLAY3 -1531005 -#define SAY_SPLIT -1531006 -#define SAY_DEATH -1531007 - -#define SPELL_ARCANE_EXPLOSION 25679 -#define SPELL_EARTH_SHOCK 26194 -#define SPELL_TRUE_FULFILLMENT4 26526 -#define SPELL_BLINK 28391 - -class ov_mycoordinates + +enum { - public: - float x,y,z,r; - ov_mycoordinates(float cx, float cy, float cz, float cr) - { - x = cx; y = cy; z = cz; r = cr; - } + SAY_AGGRO1 = -1531000, + SAY_AGGRO2 = -1531001, + SAY_AGGRO3 = -1531002, + SAY_SLAY1 = -1531003, + SAY_SLAY2 = -1531004, + SAY_SLAY3 = -1531005, + SAY_SPLIT = -1531006, + SAY_DEATH = -1531007, + + SPELL_ARCANE_EXPLOSION = 26192, + SPELL_EARTH_SHOCK = 26194, + SPELL_TRUE_FULFILLMENT = 785, + SPELL_TELEPORT_1 = 4801, + SPELL_TELEPORT_2 = 8195, + SPELL_TELEPORT_3 = 20449, + SPELL_INITIALIZE_IMAGE = 3730, + SPELL_SUMMON_IMAGES = 747, }; -struct MANGOS_DLL_DECL boss_skeramAI : public ScriptedAI +struct boss_skeramAI : public ScriptedAI { boss_skeramAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - IsImage = false; Reset(); + + // Check this for images, because the Initialize spell hits the target only after aggro + if (m_creature->IsTemporarySummon()) + m_bIsImage = true; + else + m_bIsImage = false; } ScriptedInstance* m_pInstance; - uint32 ArcaneExplosion_Timer; - uint32 EarthShock_Timer; - uint32 FullFillment_Timer; - uint32 Blink_Timer; - uint32 Invisible_Timer; + uint32 m_uiArcaneExplosionTimer; + uint32 m_uiFullFillmentTimer; + uint32 m_uiBlinkTimer; - Creature *Image1, *Image2; + float m_fHpCheck; - bool Images75; - bool Images50; - bool Images25; - bool IsImage; - bool Invisible; + bool m_bIsImage; - void Reset() + void Reset() override { - ArcaneExplosion_Timer = urand(6000, 12000); - EarthShock_Timer = 2000; - FullFillment_Timer = 15000; - Blink_Timer = urand(8000, 20000); - Invisible_Timer = 500; - - Images75 = false; - Images50 = false; - Images25 = false; - Invisible = false; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); - - if (IsImage) - m_creature->SetDeathState(JUST_DIED); + m_uiArcaneExplosionTimer = urand(6000, 12000); + m_uiFullFillmentTimer = 15000; + m_uiBlinkTimer = urand(30000, 45000); + + m_fHpCheck = 75.0f; + + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -104,23 +91,26 @@ struct MANGOS_DLL_DECL boss_skeramAI : public ScriptedAI } } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { - if (!IsImage) + if (!m_bIsImage) { DoScriptText(SAY_DEATH, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_SKERAM, DONE); } + // Else despawn to avoid looting + else + m_creature->ForcedDespawn(1); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { - if (IsImage || Images75) + if (m_bIsImage) return; - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -131,183 +121,147 @@ struct MANGOS_DLL_DECL boss_skeramAI : public ScriptedAI m_pInstance->SetData(TYPE_SKERAM, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SKERAM, FAIL); + + if (m_bIsImage) + m_creature->ForcedDespawn(); + } + + void JustSummoned(Creature* pSummoned) override + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + DoCastSpellIfCan(pSummoned, SPELL_INITIALIZE_IMAGE, CAST_TRIGGERED); + } + + // Wrapper to handle the image version initialize + void DoInitializeImage() + { + if (!m_pInstance) + return; + + // Initialize the health of the clone + if (Creature* pProphet = m_pInstance->GetSingleCreatureFromStorage(NPC_SKERAM)) + { + float fHealthPct = pProphet->GetHealthPercent(); + float fMaxHealthPct = 0; + + // The max health depends on the split phase. It's percent * original boss health + if (fHealthPct < 25.0f) + fMaxHealthPct = 0.50f; + else if (fHealthPct < 50.0f) + fMaxHealthPct = 0.20f; + else + fMaxHealthPct = 0.10f; + + // Set the same health percent as the original boss + m_creature->SetMaxHealth(m_creature->GetMaxHealth()*fMaxHealthPct); + m_creature->SetHealthPercent(fHealthPct); + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //ArcaneExplosion_Timer - if (ArcaneExplosion_Timer < diff) + // ArcaneExplosion_Timer + if (m_uiArcaneExplosionTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - ArcaneExplosion_Timer = urand(8000, 18000); - }else ArcaneExplosion_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = urand(8000, 18000); + } + else + m_uiArcaneExplosionTimer -= uiDiff; - //If we are within range melee the target - if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + // True Fullfilment + if (m_uiFullFillmentTimer < uiDiff) { - //Make sure our attack is ready and we arn't currently casting - if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); + if (DoCastSpellIfCan(pTarget, SPELL_TRUE_FULFILLMENT) == CAST_OK) + m_uiFullFillmentTimer = urand(20000, 30000); } - }else - { - //EarthShock_Timer - if (EarthShock_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_EARTH_SHOCK); - EarthShock_Timer = 1000; - }else EarthShock_Timer -= diff; } + else + m_uiFullFillmentTimer -= uiDiff; - //Blink_Timer - if (Blink_Timer < diff) + // Blink_Timer + if (m_uiBlinkTimer < uiDiff) { - //DoCastSpellIfCan(m_creature, SPELL_BLINK); - switch(urand(0, 2)) + switch (urand(0, 2)) { - case 0: - m_creature->GetMap()->CreatureRelocation(m_creature, -8340.782227f, 2083.814453f, 125.648788f, 0.0f); - DoResetThreat(); - break; - case 1: - m_creature->GetMap()->CreatureRelocation(m_creature, -8341.546875f, 2118.504639f, 133.058151f, 0.0f); - DoResetThreat(); - break; - case 2: - m_creature->GetMap()->CreatureRelocation(m_creature, -8318.822266f, 2058.231201f, 133.058151f, 0.0f); - DoResetThreat(); - break; + case 0: DoCastSpellIfCan(m_creature, SPELL_TELEPORT_1); break; + case 1: DoCastSpellIfCan(m_creature, SPELL_TELEPORT_2); break; + case 2: DoCastSpellIfCan(m_creature, SPELL_TELEPORT_3); break; } - DoStopAttack(); - - Blink_Timer = urand(20000, 40000); - }else Blink_Timer -= diff; - - float procent = m_creature->GetHealthPercent(); - //Summoning 2 Images and teleporting to a random position on 75% health - if (!Images75 && !IsImage && procent <= 75.0f && procent > 70.0f) - DoSplit(75); - - //Summoning 2 Images and teleporting to a random position on 50% health - if (!Images50 && !IsImage && procent <= 50.0f && procent > 45.0f) - DoSplit(50); - - //Summoning 2 Images and teleporting to a random position on 25% health - if (!Images25 && !IsImage && procent <= 25.0f && procent > 20.0f) - DoSplit(25); - - //Invisible_Timer - if (Invisible) - { - if (Invisible_Timer < diff) - { - //Making Skeram visible after telporting + DoResetThreat(); + if (m_creature->GetVisibility() != VISIBILITY_ON) m_creature->SetVisibility(VISIBILITY_ON); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Invisible_Timer = 2500; - Invisible = false; - }else Invisible_Timer -= diff; + m_uiBlinkTimer = urand(10000, 30000); } + else + m_uiBlinkTimer -= uiDiff; - DoMeleeAttackIfReady(); - } - - void DoSplit(int atPercent /* 75 50 25 */) - { - DoScriptText(SAY_SPLIT, m_creature); - - ov_mycoordinates *place1 = new ov_mycoordinates(-8340.782227f, 2083.814453f, 125.648788f, 0.0f); - ov_mycoordinates *place2 = new ov_mycoordinates(-8341.546875f, 2118.504639f, 133.058151f, 0.0f); - ov_mycoordinates *place3 = new ov_mycoordinates(-8318.822266f, 2058.231201f, 133.058151f, 0.0f); - - ov_mycoordinates *bossc=place1, *i1=place2, *i2=place3; - - switch(urand(0, 2)) + // Summon images at 75%, 50% and 25% + if (!m_bIsImage && m_creature->GetHealthPercent() < m_fHpCheck) { - case 0: - bossc = place1; - i1 = place2; - i2 = place3; - break; - case 1: - bossc = place2; - i1 = place1; - i2 = place3; - break; - case 2: - bossc = place3; - i1 = place1; - i2 = place2; - break; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_IMAGES) == CAST_OK) + { + DoScriptText(SAY_SPLIT, m_creature); + m_fHpCheck -= 25.0f; + // Teleport shortly after the images are summoned and set invisible to clear the selection (Workaround alert!!!) + m_creature->SetVisibility(VISIBILITY_OFF); + m_uiBlinkTimer = 2000; + } } - m_creature->RemoveAllAuras(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_OFF); - - m_creature->GetMap()->CreatureRelocation(m_creature, bossc->x, bossc->y, bossc->z, bossc->r); - - Invisible = true; - DoResetThreat(); - DoStopAttack(); - - switch (atPercent) + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + else { - case 75: Images75 = true; break; - case 50: Images50 = true; break; - case 25: Images25 = true; break; + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_EARTH_SHOCK); + } } + } +}; - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - - Image1 = m_creature->SummonCreature(15263, i1->x, i1->y, i1->z, i1->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); - if (Image1) - { - Image1->SetMaxHealth(m_creature->GetMaxHealth() / 5); - Image1->SetHealth(m_creature->GetHealth() / 5); - - if (boss_skeramAI* pImageAI = dynamic_cast(Image1->AI())) - pImageAI->IsImage = true; - - if (target) - Image1->AI()->AttackStart(target); - } +CreatureAI* GetAI_boss_skeram(Creature* pCreature) +{ + return new boss_skeramAI(pCreature); +} - Image2 = m_creature->SummonCreature(15263,i2->x, i2->y, i2->z, i2->r, TEMPSUMMON_CORPSE_DESPAWN, 30000); - if (Image2) +bool EffectDummyCreature_prophet_skeram(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_INITIALIZE_IMAGE && uiEffIndex == EFFECT_INDEX_0) + { + // check for target == caster first + if (instance_temple_of_ahnqiraj* pInstance = (instance_temple_of_ahnqiraj*)pCreatureTarget->GetInstanceData()) { - Image2->SetMaxHealth(m_creature->GetMaxHealth() / 5); - Image2->SetHealth(m_creature->GetHealth() / 5); - - if (boss_skeramAI* pImageAI = dynamic_cast(Image2->AI())) - pImageAI->IsImage = true; - - if (target) - Image2->AI()->AttackStart(target); + if (Creature* pProphet = pInstance->GetSingleCreatureFromStorage(NPC_SKERAM)) + { + if (pProphet == pCreatureTarget) + return false; + } } - Invisible = true; - delete place1; - delete place2; - delete place3; + if (boss_skeramAI* pSkeramAI = dynamic_cast(pCreatureTarget->AI())) + pSkeramAI->DoInitializeImage(); } -}; -CreatureAI* GetAI_boss_skeram(Creature* pCreature) -{ - return new boss_skeramAI(pCreature); + return false; } void AddSC_boss_skeram() @@ -317,5 +271,6 @@ void AddSC_boss_skeram() pNewScript = new Script; pNewScript->Name = "boss_skeram"; pNewScript->GetAI = &GetAI_boss_skeram; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_prophet_skeram; pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp index f0c2a3167..777a4266c 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_twinemperors.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,621 +17,400 @@ /* ScriptData SDName: Boss_Twinemperors SD%Complete: 95 -SDComment: +SDComment: Timers SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" #include "temple_of_ahnqiraj.h" -#include "WorldPacket.h" -#include "Item.h" -#include "Spell.h" - -#define SPELL_HEAL_BROTHER 7393 -#define SPELL_TWIN_TELEPORT 800 // CTRA watches for this spell to start its teleport timer -#define SPELL_TWIN_TELEPORT_VISUAL 26638 // visual - -#define SPELL_EXPLODEBUG 804 -#define SPELL_MUTATE_BUG 802 - -#define SOUND_VN_DEATH 8660 //8660 - Death - Feel -#define SOUND_VN_AGGRO 8661 //8661 - Aggro - Let none -#define SOUND_VN_KILL 8662 //8661 - Kill - your fate - -#define SOUND_VL_AGGRO 8657 //8657 - Aggro - To Late -#define SOUND_VL_KILL 8658 //8658 - Kill - You will not -#define SOUND_VL_DEATH 8659 //8659 - Death - -#define PULL_RANGE 50 -#define ABUSE_BUG_RANGE 20 -#define SPELL_BERSERK 26662 -#define TELEPORTTIME 30000 - -#define SPELL_UPPERCUT 26007 -#define SPELL_UNBALANCING_STRIKE 26613 - -#define VEKLOR_DIST 20 // VL will not come to melee when attacking - -#define SPELL_SHADOWBOLT 26006 -#define SPELL_BLIZZARD 26607 -#define SPELL_ARCANEBURST 568 +enum +{ + // yells + SAY_VEKLOR_AGGRO_1 = -1531019, + SAY_VEKLOR_AGGRO_2 = -1531020, + SAY_VEKLOR_AGGRO_3 = -1531021, + SAY_VEKLOR_AGGRO_4 = -1531022, + SAY_VEKLOR_SLAY = -1531023, + SAY_VEKLOR_DEATH = -1531024, + SAY_VEKLOR_SPECIAL = -1531025, + + SAY_VEKNILASH_AGGRO_1 = -1531026, + SAY_VEKNILASH_AGGRO_2 = -1531027, + SAY_VEKNILASH_AGGRO_3 = -1531028, + SAY_VEKNILASH_AGGRO_4 = -1531029, + SAY_VEKNILASH_SLAY = -1531030, + SAY_VEKNILASH_DEATH = -1531031, + SAY_VEKNILASH_SPECIAL = -1531032, + + // common spells + SPELL_TWIN_TELEPORT = 799, + SPELL_TWIN_TELEPORT_STUN = 800, + SPELL_HEAL_BROTHER = 7393, + SPELL_TWIN_TELEPORT_VISUAL = 26638, + + // veklor spells + SPELL_ARCANE_BURST = 568, + SPELL_EXPLODE_BUG = 804, // targets 15316 or 15317 + SPELL_SHADOW_BOLT = 26006, + SPELL_BLIZZARD = 26607, + SPELL_FRENZY = 27897, + + // veknilash spells + SPELL_MUTATE_BUG = 802, // targets 15316 or 15317 + SPELL_UPPERCUT = 26007, + SPELL_UNBALANCING_STRIKE = 26613, + SPELL_BERSERK = 27680, +}; -struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI +struct boss_twin_emperorsAI : public ScriptedAI { - ScriptedInstance* m_pInstance; - uint32 Heal_Timer; - uint32 Teleport_Timer; - bool AfterTeleport; - uint32 AfterTeleportTimer; - bool DontYellWhenDead; - uint32 Abuse_Bug_Timer, BugsTimer; - bool tspellcasted; - uint32 EnrageTimer; - - virtual bool IAmVeklor() = 0; - virtual void Reset() = 0; - virtual void CastSpellOnBug(Creature *target) = 0; - - boss_twinemperorsAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_twin_emperorsAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_temple_of_ahnqiraj*)pCreature->GetInstanceData(); + Reset(); } - void TwinReset() - { - Heal_Timer = 0; // first heal immediately when they get close together - Teleport_Timer = TELEPORTTIME; - AfterTeleport = false; - tspellcasted = false; - AfterTeleportTimer = 0; - Abuse_Bug_Timer = urand(10000, 17000); - BugsTimer = 2000; - m_creature->clearUnitState(UNIT_STAT_STUNNED); - DontYellWhenDead = false; - EnrageTimer = 15*60000; - } + instance_temple_of_ahnqiraj* m_pInstance; + + uint32 m_uiBerserkTimer; + uint32 m_uiBugAbilityTimer; + uint32 m_uiTeleportTimer; - Creature* GetOtherBoss() + void Reset() override { - if (m_pInstance) - { - return m_pInstance->GetSingleCreatureFromStorage(IAmVeklor() ? NPC_VEKNILASH : NPC_VEKLOR); - } - else - { - return NULL; - } + m_uiTeleportTimer = 35000; + m_uiBugAbilityTimer = urand(7000, 14000); + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; } - void DamageTaken(Unit *done_by, uint32 &damage) + // Workaround for the shared health pool + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) + if (!m_pInstance) + return; + + if (Creature* pTwin = m_pInstance->GetSingleCreatureFromStorage(m_creature->GetEntry() == NPC_VEKLOR ? NPC_VEKNILASH : NPC_VEKLOR)) { - float dPercent = ((float)damage) / ((float)m_creature->GetMaxHealth()); - int odmg = (int)(dPercent * ((float)pOtherBoss->GetMaxHealth())); - int ohealth = pOtherBoss->GetHealth()-odmg; - pOtherBoss->SetHealth(ohealth > 0 ? ohealth : 0); - if (ohealth <= 0) + float fDamPercent = ((float)uiDamage) / ((float)m_creature->GetMaxHealth()); + uint32 uiTwinDamage = (uint32)(fDamPercent * ((float)pTwin->GetMaxHealth())); + uint32 uiTwinHealth = pTwin->GetHealth() - uiTwinDamage; + pTwin->SetHealth(uiTwinHealth > 0 ? uiTwinHealth : 0); + + if (!uiTwinHealth) { - pOtherBoss->SetDeathState(JUST_DIED); - pOtherBoss->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + pTwin->SetDeathState(JUST_DIED); + pTwin->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); } } } - void JustDied(Unit* Killer) + // Workaround for the shared health pool + void HealedBy(Unit* pHealer, uint32& uiHealedAmount) override { - if (Creature* pOtherBoss = GetOtherBoss()) - { - pOtherBoss->SetHealth(0); - pOtherBoss->SetDeathState(JUST_DIED); - pOtherBoss->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); + if (!m_pInstance) + return; - if (boss_twinemperorsAI* pOtherAI = dynamic_cast(pOtherBoss->AI())) - pOtherAI->DontYellWhenDead = true; + if (Creature* pTwin = m_pInstance->GetSingleCreatureFromStorage(m_creature->GetEntry() == NPC_VEKLOR ? NPC_VEKNILASH : NPC_VEKLOR)) + { + float fHealPercent = ((float)uiHealedAmount) / ((float)m_creature->GetMaxHealth()); + uint32 uiTwinHeal = (uint32)(fHealPercent * ((float)pTwin->GetMaxHealth())); + uint32 uiTwinHealth = pTwin->GetHealth() + uiTwinHeal; + pTwin->SetHealth(uiTwinHealth < pTwin->GetMaxHealth() ? uiTwinHealth : pTwin->GetMaxHealth()); } + } - if (!DontYellWhenDead) // I hope AI is not threaded - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_DEATH : SOUND_VN_DEATH); + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_TWINS, IN_PROGRESS); + } + void JustDied(Unit* /*pKiller*/) override + { if (m_pInstance) m_pInstance->SetData(TYPE_TWINS, DONE); } - void KilledUnit(Unit* victim) + void JustReachedHome() override { - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_KILL : SOUND_VN_KILL); + if (m_pInstance) + m_pInstance->SetData(TYPE_TWINS, FAIL); } - void Aggro(Unit* pWho) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) + if (pSpell->Id == SPELL_TWIN_TELEPORT) { - // TODO: we should activate the other boss location so he can start attackning even if nobody - // is near I dont know how to do that - if (!pOtherBoss->isInCombat()) - { - DoPlaySoundToSet(m_creature, IAmVeklor() ? SOUND_VL_AGGRO : SOUND_VN_AGGRO); - pOtherBoss->AI()->AttackStart(pWho); - } + DoTeleportAbility(); + DoResetThreat(); + DoCastSpellIfCan(m_creature, SPELL_TWIN_TELEPORT_STUN, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TWIN_TELEPORT_VISUAL, CAST_TRIGGERED); } - - if (m_pInstance) - m_pInstance->SetData(TYPE_TWINS, IN_PROGRESS); } - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_TWINS, DONE); - } + // Return true, if succeeded + virtual void DoTeleportAbility() {} + virtual bool DoHandleBugAbility() = 0; + virtual bool DoHandleBerserk() = 0; + + // Return true to handle shared timers and MeleeAttack + virtual bool UpdateEmperorAI(const uint32 /*uiDiff*/) { return true; } - void SpellHit(Unit *caster, const SpellEntry *entry) + void UpdateAI(const uint32 uiDiff) override { - if (caster == m_creature) + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - Creature *pOtherBoss = GetOtherBoss(); - if (entry->Id != SPELL_HEAL_BROTHER || !pOtherBoss) + // Call emperor specific virtual function + if (!UpdateEmperorAI(uiDiff)) return; - // add health so we keep same percentage for both brothers - uint32 mytotal = m_creature->GetMaxHealth(), histotal = pOtherBoss->GetMaxHealth(); - float mult = ((float)mytotal) / ((float)histotal); - if (mult < 1) - mult = 1.0f/mult; - #define HEAL_BROTHER_AMOUNT 30000.0f - uint32 largerAmount = (uint32)((HEAL_BROTHER_AMOUNT * mult) - HEAL_BROTHER_AMOUNT); - - if (mytotal > histotal) + if (m_uiTeleportTimer < uiDiff) { - uint32 h = m_creature->GetHealth()+largerAmount; - m_creature->SetHealth(std::min(mytotal, h)); + if (DoCastSpellIfCan(m_creature, SPELL_TWIN_TELEPORT) == CAST_OK) + m_uiTeleportTimer = 35000; } else + m_uiTeleportTimer -= uiDiff; + + if (m_uiBugAbilityTimer < uiDiff) { - uint32 h = pOtherBoss->GetHealth()+largerAmount; - pOtherBoss->SetHealth(std::min(histotal, h)); + if (DoHandleBugAbility()) + m_uiBugAbilityTimer = urand(10000, 17000); } - } - - void TryHealBrother(uint32 diff) - { - if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it - return; + else + m_uiBugAbilityTimer -= uiDiff; - if (Heal_Timer < diff) + if (m_uiBerserkTimer) { - Unit *pOtherBoss = GetOtherBoss(); - if (pOtherBoss && pOtherBoss->IsWithinDist(m_creature, 60.0f)) + if (m_uiBerserkTimer <= uiDiff) { - DoCastSpellIfCan(pOtherBoss, SPELL_HEAL_BROTHER); - Heal_Timer = 1000; + if (DoHandleBerserk()) + m_uiBerserkTimer = 0; } - } else Heal_Timer -= diff; + else + m_uiBerserkTimer -= uiDiff; + } } +}; - Unit *GetAnyoneCloseEnough(float dist, bool totallyRandom) - { - int cnt = 0; - std::list candidates; +struct boss_veknilashAI : public boss_twin_emperorsAI +{ + boss_veknilashAI(Creature* pCreature) : boss_twin_emperorsAI(pCreature) { Reset(); } - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) - { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); + uint32 m_uiUppercutTimer; + uint32 m_uiUnbalancingStrikeTimer; - if (m_creature->GetCombatDistance(pUnit) < dist) - { - if (!totallyRandom) - return pUnit; - candidates.push_back((*i)); - ++cnt; - } - } - if (!cnt) - return NULL; - for (int randomi = rand() % cnt; randomi > 0; randomi --) - candidates.pop_front(); - - Unit *ret = m_creature->GetMap()->GetUnit(candidates.front()->getUnitGuid()); - candidates.clear(); - return ret; - } - - Unit *PickNearestPlayer() + void Reset() override { - Unit *nearp = NULL; - float neardist = 0.0f; - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) - { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); + boss_twin_emperorsAI::Reset(); - if (!pUnit) - continue; - - float pudist = pUnit->GetDistance((const Creature *)m_creature); - if (!nearp || (neardist > pudist)) - { - nearp = pUnit; - neardist = pudist; - } - } - return nearp; + m_uiUppercutTimer = urand(14000, 29000); + m_uiUnbalancingStrikeTimer = urand(8000, 18000); } - void TeleportToMyBrother() + void MoveInLineOfSight(Unit* pWho) override { - if (!m_pInstance) - return; + if (m_pInstance && m_pInstance->GetData(TYPE_TWINS) == IN_PROGRESS && pWho->GetEntry() == NPC_VEKLOR && pWho->IsWithinDistInMap(m_creature, 60.0f)) + DoCastSpellIfCan(pWho, SPELL_HEAL_BROTHER); - Teleport_Timer = TELEPORTTIME; + ScriptedAI::MoveInLineOfSight(pWho); + } - if (IAmVeklor()) - return; // mechanics handled by veknilash so they teleport exactly at the same time and to correct coordinates + void Aggro(Unit* pWho) override + { + boss_twin_emperorsAI::Aggro(pWho); - Creature *pOtherBoss = GetOtherBoss(); - if (pOtherBoss) + switch (urand(0, 3)) { - //m_creature->MonsterYell("Teleporting ...", LANG_UNIVERSAL); - float other_x = pOtherBoss->GetPositionX(); - float other_y = pOtherBoss->GetPositionY(); - float other_z = pOtherBoss->GetPositionZ(); - float other_o = pOtherBoss->GetOrientation(); - - Map *thismap = m_creature->GetMap(); - thismap->CreatureRelocation(pOtherBoss, m_creature->GetPositionX(), - m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation()); - thismap->CreatureRelocation(m_creature, other_x, other_y, other_z, other_o); - - SetAfterTeleport(); - - if (boss_twinemperorsAI* pOtherAI = dynamic_cast(pOtherBoss->AI())) - pOtherAI->SetAfterTeleport(); + case 0: DoScriptText(SAY_VEKNILASH_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_VEKNILASH_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_VEKNILASH_AGGRO_3, m_creature); break; + case 3: DoScriptText(SAY_VEKNILASH_AGGRO_4, m_creature); break; } } - void SetAfterTeleport() + void KilledUnit(Unit* /*pVictim*/) override { - m_creature->InterruptNonMeleeSpells(false); - DoStopAttack(); - DoResetThreat(); - DoCastSpellIfCan(m_creature, SPELL_TWIN_TELEPORT_VISUAL); - m_creature->addUnitState(UNIT_STAT_STUNNED); - AfterTeleport = true; - AfterTeleportTimer = 2000; - tspellcasted = false; + DoScriptText(SAY_VEKNILASH_SLAY, m_creature); } - bool TryActivateAfterTTelep(uint32 diff) + void JustDied(Unit* pKiller) override { - if (AfterTeleport) - { - if (!tspellcasted) - { - m_creature->clearUnitState(UNIT_STAT_STUNNED); - DoCastSpellIfCan(m_creature, SPELL_TWIN_TELEPORT); - m_creature->addUnitState(UNIT_STAT_STUNNED); - } + boss_twin_emperorsAI::JustDied(pKiller); - tspellcasted = true; - - if (AfterTeleportTimer < diff) - { - AfterTeleport = false; - m_creature->clearUnitState(UNIT_STAT_STUNNED); - Unit *nearu = PickNearestPlayer(); - //DoYell(nearu->GetName(), LANG_UNIVERSAL, 0); - AttackStart(nearu); - m_creature->getThreatManager().addThreat(nearu, 10000); - return true; - } - else - { - AfterTeleportTimer -= diff; - // update important timers which would otherwise get skipped - if (EnrageTimer > diff) - EnrageTimer -= diff; - else - EnrageTimer = 0; - if (Teleport_Timer > diff) - Teleport_Timer -= diff; - else - Teleport_Timer = 0; - return false; - } - } - else - { - return true; - } + DoScriptText(SAY_VEKNILASH_DEATH, m_creature); } - void MoveInLineOfSight(Unit *who) + bool DoHandleBugAbility() { - if (!who || m_creature->getVictim()) - return; + if (DoCastSpellIfCan(m_creature, SPELL_MUTATE_BUG) == CAST_OK) + return true; - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) - { - float attackRadius = m_creature->GetAttackDistance(who); - if (attackRadius < PULL_RANGE) - attackRadius = PULL_RANGE; - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/) - { - if (who->HasStealthAura()) - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - } + return false; } - Creature *RespawnNearbyBugsAndGetOne() + bool DoHandleBerserk() { - std::list lUnitList; - GetCreatureListWithEntryInGrid(lUnitList,m_creature,15316,150.0f); - GetCreatureListWithEntryInGrid(lUnitList,m_creature,15317,150.0f); + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + return true; - if (lUnitList.empty()) - return NULL; + return false; + } - Creature *nearb = NULL; + // Only Vek'nilash handles the teleport for both of them + void DoTeleportAbility() + { + if (!m_pInstance) + return; - for(std::list::iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter) + if (Creature* pVeklor = m_pInstance->GetSingleCreatureFromStorage(NPC_VEKLOR)) { - Creature *c = (Creature *)(*iter); - if (c->isDead()) - { - c->Respawn(); - c->setFaction(7); - c->RemoveAllAuras(); - } - if (c->IsWithinDistInMap(m_creature, ABUSE_BUG_RANGE)) - { - if (!nearb || !urand(0, 3)) - nearb = c; - } + float fTargetX, fTargetY, fTargetZ, fTargetOrient; + pVeklor->GetPosition(fTargetX, fTargetY, fTargetZ); + fTargetOrient = pVeklor->GetOrientation(); + + pVeklor->NearTeleportTo(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), true); + m_creature->NearTeleportTo(fTargetX, fTargetY, fTargetZ, fTargetOrient, true); } - return nearb; } - void HandleBugs(uint32 diff) + bool UpdateEmperorAI(const uint32 uiDiff) { - if (BugsTimer < diff || Abuse_Bug_Timer < diff) + if (m_uiUnbalancingStrikeTimer < uiDiff) { - Creature *c = RespawnNearbyBugsAndGetOne(); - if (Abuse_Bug_Timer < diff) - { - if (c) - { - CastSpellOnBug(c); - Abuse_Bug_Timer = urand(10000, 17000); - } - else - { - Abuse_Bug_Timer = 1000; - } - } - else - { - Abuse_Bug_Timer -= diff; - } - BugsTimer = 2000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_UNBALANCING_STRIKE) == CAST_OK) + m_uiUnbalancingStrikeTimer = urand(8000, 20000); } else - { - BugsTimer -= diff; - Abuse_Bug_Timer -= diff; - } - } + m_uiUnbalancingStrikeTimer -= uiDiff; - void CheckEnrage(uint32 diff) - { - if (EnrageTimer < diff) + if (m_uiUppercutTimer < uiDiff) { - if (!m_creature->IsNonMeleeSpellCasted(true)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_UPPERCUT, SELECT_FLAG_IN_MELEE_RANGE)) { - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - EnrageTimer = 60*60000; - } else EnrageTimer = 0; - } else EnrageTimer-=diff; + if (DoCastSpellIfCan(pTarget, SPELL_UPPERCUT) == CAST_OK) + m_uiUppercutTimer = urand(15000, 30000); + } + } + else + m_uiUppercutTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + return true; } }; -struct MANGOS_DLL_DECL boss_veknilashAI : public boss_twinemperorsAI +struct boss_veklorAI : public boss_twin_emperorsAI { - bool IAmVeklor() {return false;} - boss_veknilashAI(Creature* pCreature) : boss_twinemperorsAI(pCreature) - { - Reset(); - } + boss_veklorAI(Creature* pCreature) : boss_twin_emperorsAI(pCreature) { Reset(); } - uint32 UpperCut_Timer; - uint32 UnbalancingStrike_Timer; - uint32 Scarabs_Timer; - int Rand; - int RandX; - int RandY; + uint32 m_uiShadowBoltTimer; + uint32 m_uiBlizzardTimer; + uint32 m_uiArcaneBurstTimer; - Creature* Summoned; - - void Reset() + void Reset() override { - TwinReset(); - UpperCut_Timer = urand(14000, 29000); - UnbalancingStrike_Timer = urand(8000, 18000); - Scarabs_Timer = urand(7000, 14000); + boss_twin_emperorsAI::Reset(); - //Added. Can be removed if its included in DB. - m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + m_uiShadowBoltTimer = 1000; + m_uiBlizzardTimer = urand(15000, 20000); + m_uiArcaneBurstTimer = 1000; } - void CastSpellOnBug(Creature *target) + void MoveInLineOfSight(Unit* pWho) override { - target->setFaction(14); + if (m_pInstance && m_pInstance->GetData(TYPE_TWINS) == IN_PROGRESS && pWho->GetEntry() == NPC_VEKNILASH && pWho->IsWithinDistInMap(m_creature, 60.0f)) + DoCastSpellIfCan(pWho, SPELL_HEAL_BROTHER); - DoCastSpellIfCan(target, SPELL_MUTATE_BUG, CAST_TRIGGERED); + ScriptedAI::MoveInLineOfSight(pWho); } - void UpdateAI(const uint32 diff) + void Aggro(Unit* pWho) override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (!TryActivateAfterTTelep(diff)) - return; + boss_twin_emperorsAI::Aggro(pWho); - //UnbalancingStrike_Timer - if (UnbalancingStrike_Timer < diff) + switch (urand(0, 3)) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_UNBALANCING_STRIKE); - UnbalancingStrike_Timer = urand(8000, 20000); - }else UnbalancingStrike_Timer -= diff; - - if (UpperCut_Timer < diff) - { - Unit* randomMelee = GetAnyoneCloseEnough(2*ATTACK_DISTANCE, true); - if (randomMelee) - DoCastSpellIfCan(randomMelee,SPELL_UPPERCUT); - UpperCut_Timer = urand(15000, 30000); - }else UpperCut_Timer -= diff; - - HandleBugs(diff); - - //Heal brother when 60yrds close - TryHealBrother(diff); - - //Teleporting to brother - if (Teleport_Timer < diff) - { - TeleportToMyBrother(); - }else Teleport_Timer -= diff; - - CheckEnrage(diff); - - DoMeleeAttackIfReady(); + case 0: DoScriptText(SAY_VEKLOR_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_VEKLOR_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_VEKLOR_AGGRO_3, m_creature); break; + case 3: DoScriptText(SAY_VEKLOR_AGGRO_4, m_creature); break; + } } -}; -struct MANGOS_DLL_DECL boss_veklorAI : public boss_twinemperorsAI -{ - bool IAmVeklor() {return true;} - boss_veklorAI(Creature* pCreature) : boss_twinemperorsAI(pCreature) + void KilledUnit(Unit* /*pVictim*/) override { - Reset(); + DoScriptText(SAY_VEKLOR_SLAY, m_creature); } - uint32 ShadowBolt_Timer; - uint32 Blizzard_Timer; - uint32 ArcaneBurst_Timer; - uint32 Scorpions_Timer; - int Rand; - int RandX; - int RandY; + void JustDied(Unit* pKiller) override + { + boss_twin_emperorsAI::JustDied(pKiller); - Creature* Summoned; + DoScriptText(SAY_VEKLOR_DEATH, m_creature); + } - void Reset() + void AttackStart(Unit* pWho) override { - TwinReset(); - ShadowBolt_Timer = 0; - Blizzard_Timer = urand(15000, 20000); - ArcaneBurst_Timer = 1000; - Scorpions_Timer = urand(7000, 14000); - - //Added. Can be removed if its included in DB. - m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 0); - m_creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 0); + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + m_creature->GetMotionMaster()->MoveChase(pWho, 20.0f); + } } - void CastSpellOnBug(Creature *target) + bool DoHandleBugAbility() { - target->setFaction(14); + if (DoCastSpellIfCan(m_creature, SPELL_EXPLODE_BUG) == CAST_OK) + return true; - DoCastSpellIfCan(target, SPELL_EXPLODEBUG, CAST_TRIGGERED); + return false; } - void UpdateAI(const uint32 diff) + bool DoHandleBerserk() { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + return true; - // reset arcane burst after teleport - we need to do this because - // when VL jumps to VN's location there will be a warrior who will get only 2s to run away - // which is almost impossible - if (AfterTeleport) - ArcaneBurst_Timer = 5000; - if (!TryActivateAfterTTelep(diff)) - return; + return false; + } - //ShadowBolt_Timer - if (ShadowBolt_Timer < diff) + bool UpdateEmperorAI(const uint32 uiDiff) + { + if (m_uiShadowBoltTimer < uiDiff) { - if (!m_creature->IsWithinDist(m_creature->getVictim(), 45.0f)) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim(), VEKLOR_DIST, 0); - else - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHADOWBOLT); - ShadowBolt_Timer = 2000; - }else ShadowBolt_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT) == CAST_OK) + m_uiShadowBoltTimer = 2000; + } + else + m_uiShadowBoltTimer -= uiDiff; - //Blizzard_Timer - if (Blizzard_Timer < diff) - { - Unit* target = NULL; - target = GetAnyoneCloseEnough(45, true); - if (target) - DoCastSpellIfCan(target,SPELL_BLIZZARD); - Blizzard_Timer = urand(15000, 30000); - }else Blizzard_Timer -= diff; - - if (ArcaneBurst_Timer < diff) + if (m_uiBlizzardTimer < uiDiff) { - Unit *mvic; - if ((mvic=GetAnyoneCloseEnough(2*ATTACK_DISTANCE, false))!=NULL) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(mvic,SPELL_ARCANEBURST); - ArcaneBurst_Timer = 5000; + if (DoCastSpellIfCan(pTarget, SPELL_BLIZZARD) == CAST_OK) + m_uiBlizzardTimer = urand(15000, 30000); } - }else ArcaneBurst_Timer -= diff; - - HandleBugs(diff); - - //Heal brother when 60yrds close - TryHealBrother(diff); - - //Teleporting to brother - if (Teleport_Timer < diff) - { - TeleportToMyBrother(); - }else Teleport_Timer -= diff; - - CheckEnrage(diff); - - //VL doesn't melee - //DoMeleeAttackIfReady(); - } - - void AttackStart(Unit* who) - { - if (!who) - return; + } + else + m_uiBlizzardTimer -= uiDiff; - // VL doesn't melee - if (m_creature->Attack(who, false)) + if (m_uiArcaneBurstTimer < uiDiff) { - m_creature->AddThreat(who); - m_creature->SetInCombatWith(who); - who->SetInCombatWith(m_creature); - - m_creature->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0); + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_BURST) == CAST_OK) + m_uiArcaneBurstTimer = 5000; } + else + m_uiArcaneBurstTimer -= uiDiff; + + return true; } }; diff --git a/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp b/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp index 70fded3c8..ed86cfd62 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/boss_viscidus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,20 +16,28 @@ /* ScriptData SDName: Boss_Viscidus -SD%Complete: 0 -SDComment: place holder +SD%Complete: 90 +SDComment: Server side spells implementation need to be checked. SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" +#include "temple_of_ahnqiraj.h" enum { + // emotes + EMOTE_SLOW = -1531041, + EMOTE_FREEZE = -1531042, + EMOTE_FROZEN = -1531043, + EMOTE_CRACK = -1531044, + EMOTE_SHATTER = -1531045, + EMOTE_EXPLODE = -1531046, + // Timer spells SPELL_POISON_SHOCK = 25993, SPELL_POISONBOLT_VOLLEY = 25991, - SPELL_TOXIN = 26575, // Triggers toxin cloud - SPELL_TOXIN_CLOUD = 25989, + SPELL_TOXIN = 26575, // Triggers toxin cloud - 25989 // Debuffs gained by the boss on frost damage SPELL_VISCIDUS_SLOWED = 26034, @@ -38,12 +46,349 @@ enum // When frost damage exceeds a certain limit, then boss explodes SPELL_REJOIN_VISCIDUS = 25896, - SPELL_VISCIDUS_EXPLODE = 25938, // Casts a lot of spells in the same time: 25865 to 25884; All spells have target coords - SPELL_VISCIDUS_SUICIDE = 26003, + SPELL_VISCIDUS_EXPLODE = 25938, + SPELL_VISCIDUS_SUICIDE = 26003, // cast when boss explodes and is below 5% Hp - should trigger 26002 + SPELL_DESPAWN_GLOBS = 26608, + + // SPELL_MEMBRANE_VISCIDUS = 25994, // damage reduction spell - removed from DBC + // SPELL_VISCIDUS_WEAKNESS = 25926, // aura which procs at damage - should trigger the slow spells - removed from DBC + // SPELL_VISCIDUS_SHRINKS = 25893, // removed from DBC + // SPELL_VISCIDUS_SHRINKS_2 = 27934, // removed from DBC + // SPELL_VISCIDUS_GROWS = 25897, // removed from DBC + // SPELL_SUMMON_GLOBS = 25885, // summons npc 15667 using spells from 25865 to 25884; All spells have target coords - removed from DBC + // SPELL_VISCIDUS_TELEPORT = 25904, // removed from DBC + // SPELL_SUMMONT_TRIGGER = 26564, // summons 15992 - removed from DBC + + NPC_GLOB_OF_VISCIDUS = 15667, + NPC_VISCIDUS_TRIGGER = 15922, // handles aura 26575 + + MAX_VISCIDUS_GLOBS = 20, // there are 20 summoned globs; each glob = 5% hp + + // hitcounts + HITCOUNT_SLOW = 100, + HITCOUNT_SLOW_MORE = 150, + HITCOUNT_FREEZE = 200, + HITCOUNT_CRACK = 50, + HITCOUNT_SHATTER = 100, + HITCOUNT_EXPLODE = 150, - NPC_GLOB_OF_VISCIDUS = 15667 + // phases + PHASE_NORMAL = 1, + PHASE_FROZEN = 2, + PHASE_EXPLODED = 3, }; +static const uint32 auiGlobSummonSpells[MAX_VISCIDUS_GLOBS] = { 25865, 25866, 25867, 25868, 25869, 25870, 25871, 25872, 25873, 25874, 25875, 25876, 25877, 25878, 25879, 25880, 25881, 25882, 25883, 25884 }; + +struct boss_viscidusAI : public ScriptedAI +{ + boss_viscidusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint8 m_uiPhase; + + uint32 m_uiHitCount; + uint32 m_uiToxinTimer; + uint32 m_uiExplodeDelayTimer; + uint32 m_uiPoisonShockTimer; + uint32 m_uiPoisonBoltVolleyTimer; + + GuidList m_lGlobesGuidList; + + void Reset() override + { + m_uiPhase = PHASE_NORMAL; + m_uiHitCount = 0; + + m_uiExplodeDelayTimer = 0; + m_uiToxinTimer = 30000; + m_uiPoisonShockTimer = urand(7000, 12000); + m_uiPoisonBoltVolleyTimer = urand(10000, 15000); + + SetCombatMovement(true); + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetObjectScale(DEFAULT_OBJECT_SCALE); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_TOXIN); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VISCIDUS, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VISCIDUS, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_DESPAWN_GLOBS, CAST_TRIGGERED); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VISCIDUS, DONE); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_GLOB_OF_VISCIDUS) + { + float fX, fY, fZ; + m_creature->GetRespawnCoord(fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_lGlobesGuidList.push_back(pSummoned->GetObjectGuid()); + } + else if (pSummoned->GetEntry() == NPC_VISCIDUS_TRIGGER) + pSummoned->CastSpell(pSummoned, SPELL_TOXIN, true); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_GLOB_OF_VISCIDUS) + { + // shrink - modify scale + m_creature->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X, float(-4), true); + m_creature->UpdateModelData(); + m_creature->SetHealth(m_creature->GetHealth() - (m_creature->GetMaxHealth() * 0.05f)); + m_lGlobesGuidList.remove(pSummoned->GetObjectGuid()); + + // suicide if required + if (m_creature->GetHealthPercent() < 5.0f) + { + m_creature->SetVisibility(VISIBILITY_ON); + + if (DoCastSpellIfCan(m_creature, SPELL_VISCIDUS_SUICIDE, CAST_TRIGGERED) == CAST_OK) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + else if (m_lGlobesGuidList.empty()) + { + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiPhase = PHASE_NORMAL; + + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + } + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (pSummoned->GetEntry() != NPC_GLOB_OF_VISCIDUS || uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + m_lGlobesGuidList.remove(pSummoned->GetObjectGuid()); + pSummoned->CastSpell(m_creature, SPELL_REJOIN_VISCIDUS, true); + pSummoned->ForcedDespawn(1000); + + if (m_lGlobesGuidList.empty()) + { + m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiPhase = PHASE_NORMAL; + + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + } + } + + void DamageTaken(Unit* pDealer, uint32& uiDamage) override + { + // apply missing aura: 50% damage reduction; + uiDamage = uiDamage * 0.5f; + + if (m_uiPhase != PHASE_FROZEN) + return; + + ++m_uiHitCount; + + // only count melee attacks + if (pDealer->hasUnitState(UNIT_STAT_MELEE_ATTACKING) && m_uiHitCount >= HITCOUNT_EXPLODE) + { + if (m_creature->GetHealthPercent() <= 5.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_VISCIDUS_SUICIDE, CAST_TRIGGERED) == CAST_OK) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + else if (DoCastSpellIfCan(m_creature, SPELL_VISCIDUS_EXPLODE, CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(EMOTE_EXPLODE, m_creature); + m_uiPhase = PHASE_EXPLODED; + m_uiHitCount = 0; + m_lGlobesGuidList.clear(); + uint32 uiGlobeCount = m_creature->GetHealthPercent() / 5.0f; + + for (uint8 i = 0; i < uiGlobeCount; ++i) + DoCastSpellIfCan(m_creature, auiGlobSummonSpells[i], CAST_TRIGGERED); + + m_creature->RemoveAurasDueToSpell(SPELL_VISCIDUS_FREEZE); + m_uiExplodeDelayTimer = 2000; + + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + } + } + else if (m_uiHitCount == HITCOUNT_SHATTER) + DoScriptText(EMOTE_SHATTER, m_creature); + else if (m_uiHitCount == HITCOUNT_CRACK) + DoScriptText(EMOTE_CRACK, m_creature); + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (m_uiPhase != PHASE_NORMAL) + return; + + // only count frost damage + if (pSpell->SchoolMask == SPELL_SCHOOL_MASK_FROST) + { + ++m_uiHitCount; + + if (m_uiHitCount >= HITCOUNT_FREEZE) + { + m_uiPhase = PHASE_FROZEN; + m_uiHitCount = 0; + + DoScriptText(EMOTE_FROZEN, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_VISCIDUS_SLOWED_MORE); + DoCastSpellIfCan(m_creature, SPELL_VISCIDUS_FREEZE, CAST_TRIGGERED); + } + else if (m_uiHitCount >= HITCOUNT_SLOW_MORE) + { + DoScriptText(EMOTE_FREEZE, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_VISCIDUS_SLOWED); + DoCastSpellIfCan(m_creature, SPELL_VISCIDUS_SLOWED_MORE, CAST_TRIGGERED); + } + else if (m_uiHitCount >= HITCOUNT_SLOW) + { + DoScriptText(EMOTE_SLOW, m_creature); + DoCastSpellIfCan(m_creature, SPELL_VISCIDUS_SLOWED, CAST_TRIGGERED); + } + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_CUSTOM_A) + { + if (m_uiPhase == PHASE_EXPLODED) + return; + + // reset phase if not already exploded + m_uiPhase = PHASE_NORMAL; + m_uiHitCount = 0; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiExplodeDelayTimer) + { + if (m_uiExplodeDelayTimer <= uiDiff) + { + // Make invisible + m_creature->SetVisibility(VISIBILITY_OFF); + + // Teleport to room center + float fX, fY, fZ, fO; + m_creature->GetRespawnCoord(fX, fY, fZ, &fO); + m_creature->NearTeleportTo(fX, fY, fZ, fO); + m_uiExplodeDelayTimer = 0; + } + else + m_uiExplodeDelayTimer -= uiDiff; + } + + if (m_uiPhase != PHASE_NORMAL) + return; + + if (m_uiPoisonShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POISON_SHOCK) == CAST_OK) + m_uiPoisonShockTimer = urand(7000, 12000); + } + else + m_uiPoisonShockTimer -= uiDiff; + + if (m_uiPoisonBoltVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POISONBOLT_VOLLEY) == CAST_OK) + m_uiPoisonBoltVolleyTimer = urand(10000, 15000); + } + else + m_uiPoisonBoltVolleyTimer -= uiDiff; + + if (m_uiToxinTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->SummonCreature(NPC_VISCIDUS_TRIGGER, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiToxinTimer = 30000; + } + else + m_uiToxinTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_viscidus(Creature* pCreature) +{ + return new boss_viscidusAI(pCreature); +} + +bool EffectAuraDummy_spell_aura_dummy_viscidus_freeze(const Aura* pAura, bool bApply) +{ + // On Aura removal inform the boss + if (pAura->GetId() == SPELL_VISCIDUS_FREEZE && pAura->GetEffIndex() == EFFECT_INDEX_1 && !bApply) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + pTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pTarget, pTarget); + } + return true; +} + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_glob_of_viscidusAI : public ScriptedAI +{ + npc_glob_of_viscidusAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + void Reset() override { } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_glob_of_viscidus(Creature* pCreature) +{ + return new npc_glob_of_viscidusAI(pCreature); +} + void AddSC_boss_viscidus() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_viscidus"; + pNewScript->GetAI = &GetAI_boss_viscidus; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_viscidus_freeze; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_glob_of_viscidus"; + pNewScript->GetAI = &GetAI_npc_glob_of_viscidus; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp b/scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp index 17e75d66e..2301d21b5 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/instance_temple_of_ahnqiraj.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,15 +17,30 @@ /* ScriptData SDName: Instance_Temple_of_Ahnqiraj SD%Complete: 80 -SDComment: +SDComment: C'thun whisperings spells NYI. SDCategory: Temple of Ahn'Qiraj EndScriptData */ #include "precompiled.h" #include "temple_of_ahnqiraj.h" +static const DialogueEntry aIntroDialogue[] = +{ + {EMOTE_EYE_INTRO, NPC_MASTERS_EYE, 7000}, + {SAY_EMPERORS_INTRO_1, NPC_VEKLOR, 6000}, + {SAY_EMPERORS_INTRO_2, NPC_VEKNILASH, 8000}, + {SAY_EMPERORS_INTRO_3, NPC_VEKLOR, 3000}, + {SAY_EMPERORS_INTRO_4, NPC_VEKNILASH, 3000}, + {SAY_EMPERORS_INTRO_5, NPC_VEKLOR, 3000}, + {SAY_EMPERORS_INTRO_6, NPC_VEKNILASH, 0}, + {0, 0, 0} +}; + instance_temple_of_ahnqiraj::instance_temple_of_ahnqiraj(Map* pMap) : ScriptedInstance(pMap), - m_uiBugTrioDeathCount(0) + m_uiBugTrioDeathCount(0), + m_uiCthunWhisperTimer(90000), + m_bIsEmperorsIntroDone(false), + m_dialogueHelper(aIntroDialogue) { Initialize(); }; @@ -33,14 +48,54 @@ instance_temple_of_ahnqiraj::instance_temple_of_ahnqiraj(Map* pMap) : ScriptedIn void instance_temple_of_ahnqiraj::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + m_dialogueHelper.InitializeDialogueHelper(this); +} + +bool instance_temple_of_ahnqiraj::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + + return false; } -void instance_temple_of_ahnqiraj::OnCreatureCreate (Creature* pCreature) +void instance_temple_of_ahnqiraj::DoHandleTempleAreaTrigger(uint32 uiTriggerId) +{ + if (uiTriggerId == AREATRIGGER_TWIN_EMPERORS && !m_bIsEmperorsIntroDone) + { + m_dialogueHelper.StartNextDialogueText(EMOTE_EYE_INTRO); + // Note: there may be more related to this; The emperors should kneel before the Eye and they stand up after it despawns + if (Creature* pEye = GetSingleCreatureFromStorage(NPC_MASTERS_EYE)) + pEye->ForcedDespawn(1000); + m_bIsEmperorsIntroDone = true; + } + else if (uiTriggerId == AREATRIGGER_SARTURA) + { + if (GetData(TYPE_SARTURA) == NOT_STARTED || GetData(TYPE_SARTURA) == FAIL) + { + if (Creature* pSartura = GetSingleCreatureFromStorage(NPC_SARTURA)) + pSartura->SetInCombatWithZone(); + } + } +} + +void instance_temple_of_ahnqiraj::OnCreatureCreate(Creature* pCreature) { switch (pCreature->GetEntry()) { + case NPC_SKERAM: + // Don't store the summoned images guid + if (GetData(TYPE_SKERAM) == IN_PROGRESS) + break; + case NPC_SARTURA: case NPC_VEKLOR: case NPC_VEKNILASH: + case NPC_MASTERS_EYE: + case NPC_OURO_SPAWNER: case NPC_CTHUN: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; @@ -61,6 +116,8 @@ void instance_temple_of_ahnqiraj::OnObjectCreate(GameObject* pGo) if (m_auiEncounter[TYPE_TWINS] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + case GO_SANDWORM_BASE: + break; default: return; @@ -69,15 +126,9 @@ void instance_temple_of_ahnqiraj::OnObjectCreate(GameObject* pGo) m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } -bool instance_temple_of_ahnqiraj::IsEncounterInProgress() const -{ - // not active in AQ40 - return false; -} - void instance_temple_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_SKERAM: m_auiEncounter[uiType] = uiData; @@ -98,6 +149,12 @@ void instance_temple_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) m_uiBugTrioDeathCount = 0; m_auiEncounter[uiType] = uiData; break; + case TYPE_SARTURA: + case TYPE_FANKRISS: + case TYPE_VISCIDUS: + case TYPE_HUHURAN: + m_auiEncounter[uiType] = uiData; + break; case TYPE_TWINS: // Either of the twins can set data, so return to avoid double changing if (m_auiEncounter[uiType] == uiData) @@ -108,7 +165,23 @@ void instance_temple_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) if (uiData == DONE) DoUseDoorOrButton(GO_TWINS_EXIT_DOOR); break; - case TYPE_CTHUN_PHASE: + case TYPE_OURO: + switch (uiData) + { + case FAIL: + // Respawn the Ouro spawner on fail + if (Creature* pSpawner = GetSingleCreatureFromStorage(NPC_OURO_SPAWNER)) + pSpawner->Respawn(); + // no break; + case DONE: + // Despawn the sandworm base on Done or Fail + if (GameObject* pBase = GetSingleGameObjectFromStorage(GO_SANDWORM_BASE)) + pBase->SetLootState(GO_JUST_DEACTIVATED); + break; + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_CTHUN: m_auiEncounter[uiType] = uiData; break; } @@ -118,7 +191,9 @@ void instance_temple_of_ahnqiraj::SetData(uint32 uiType, uint32 uiData) OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " + << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " + << m_auiEncounter[8]; m_strInstData = saveStream.str(); @@ -138,9 +213,11 @@ void instance_temple_of_ahnqiraj::Load(const char* chrIn) OUT_LOAD_INST_DATA(chrIn); std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -149,7 +226,7 @@ void instance_temple_of_ahnqiraj::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_temple_of_ahnqiraj::GetData(uint32 uiType) +uint32 instance_temple_of_ahnqiraj::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -157,11 +234,58 @@ uint32 instance_temple_of_ahnqiraj::GetData(uint32 uiType) return 0; } +void instance_temple_of_ahnqiraj::Update(uint32 uiDiff) +{ + m_dialogueHelper.DialogueUpdate(uiDiff); + + if (GetData(TYPE_CTHUN) == IN_PROGRESS || GetData(TYPE_CTHUN) == DONE) + return; + + if (m_uiCthunWhisperTimer < uiDiff) + { + if (Player* pPlayer = GetPlayerInMap()) + { + if (Creature* pCthun = GetSingleCreatureFromStorage(NPC_CTHUN)) + { + // ToDo: also cast the C'thun Whispering charm spell - requires additional research + switch (urand(0, 7)) + { + case 0: DoScriptText(SAY_CTHUN_WHISPER_1, pCthun, pPlayer); break; + case 1: DoScriptText(SAY_CTHUN_WHISPER_2, pCthun, pPlayer); break; + case 2: DoScriptText(SAY_CTHUN_WHISPER_3, pCthun, pPlayer); break; + case 3: DoScriptText(SAY_CTHUN_WHISPER_4, pCthun, pPlayer); break; + case 4: DoScriptText(SAY_CTHUN_WHISPER_5, pCthun, pPlayer); break; + case 5: DoScriptText(SAY_CTHUN_WHISPER_6, pCthun, pPlayer); break; + case 6: DoScriptText(SAY_CTHUN_WHISPER_7, pCthun, pPlayer); break; + case 7: DoScriptText(SAY_CTHUN_WHISPER_8, pCthun, pPlayer); break; + } + } + } + m_uiCthunWhisperTimer = urand(1.5 * MINUTE * IN_MILLISECONDS, 5 * MINUTE * IN_MILLISECONDS); + } + else + m_uiCthunWhisperTimer -= uiDiff; +} + InstanceData* GetInstanceData_instance_temple_of_ahnqiraj(Map* pMap) { return new instance_temple_of_ahnqiraj(pMap); } +bool AreaTrigger_at_temple_ahnqiraj(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_TWIN_EMPERORS || pAt->id == AREATRIGGER_SARTURA) + { + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; + + if (instance_temple_of_ahnqiraj* pInstance = (instance_temple_of_ahnqiraj*)pPlayer->GetInstanceData()) + pInstance->DoHandleTempleAreaTrigger(pAt->id); + } + + return false; +} + void AddSC_instance_temple_of_ahnqiraj() { Script* pNewScript; @@ -170,4 +294,9 @@ void AddSC_instance_temple_of_ahnqiraj() pNewScript->Name = "instance_temple_of_ahnqiraj"; pNewScript->GetInstanceData = &GetInstanceData_instance_temple_of_ahnqiraj; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_temple_ahnqiraj"; + pNewScript->pAreaTrigger = &AreaTrigger_at_temple_ahnqiraj; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp b/scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp index db5b570ee..2f3578a7b 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp +++ b/scripts/kalimdor/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -42,7 +42,7 @@ enum MAX_BUDDY = 4 }; -struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI +struct npc_anubisath_sentinelAI : public ScriptedAI { npc_anubisath_sentinelAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -53,17 +53,27 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI uint32 m_uiMyAbility; bool m_bEnraged; - GUIDList m_lAssistList; + GuidList m_lAssistList; - void Reset() + void Reset() override { m_uiMyAbility = 0; m_bEnraged = false; } - void JustReachedHome() + void GetAIInformation(ChatHandler& reader) override { - for(GUIDList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) + if (m_lAssistList.empty()) + reader.PSendSysMessage("Anubisath Sentinel - group not assigned, will be assigned OnAggro"); + if (m_lAssistList.size() == MAX_BUDDY) + reader.PSendSysMessage("Anubisath Sentinel - proper group found"); + else + reader.PSendSysMessage("Anubisath Sentinel - not correct number of mobs for group found. Number found %u, should be %u", m_lAssistList.size(), MAX_BUDDY); + } + + void JustReachedHome() override + { + for (GuidList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) { if (*itr == m_creature->GetObjectGuid()) continue; @@ -76,13 +86,13 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { SetAbility(); InitSentinelsNear(pWho); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoTransferAbility(); } @@ -90,7 +100,7 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI // this way will make it quite possible that sentinels get the same buff as others, need to fix that, it should be one unique each void SetAbility() { - switch(urand(0, 8)) + switch (urand(0, 8)) { case 0: m_uiMyAbility = SPELL_MENDING; break; case 1: m_uiMyAbility = SPELL_PERIODIC_KNOCK_AWAY; break; @@ -108,7 +118,7 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI void DoTransferAbility() { - for(GUIDList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) + for (GuidList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) { if (Creature* pBuddy = m_creature->GetMap()->GetCreature(*itr)) { @@ -128,7 +138,7 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI { if (!m_lAssistList.empty()) { - for(GUIDList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) + for (GuidList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) { if (*itr == m_creature->GetObjectGuid()) continue; @@ -146,10 +156,7 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI std::list lAssistList; GetCreatureListWithEntryInGrid(lAssistList, m_creature, m_creature->GetEntry(), 80.0f); - if (lAssistList.empty()) - return; - - for(std::list::iterator iter = lAssistList.begin(); iter != lAssistList.end(); ++iter) + for (std::list::iterator iter = lAssistList.begin(); iter != lAssistList.end(); ++iter) { m_lAssistList.push_back((*iter)->GetObjectGuid()); @@ -160,10 +167,10 @@ struct MANGOS_DLL_DECL npc_anubisath_sentinelAI : public ScriptedAI } if (m_lAssistList.size() != MAX_BUDDY) - error_log("SD2: npc_anubisath_sentinel found too few/too many buddies, expected %u.", MAX_BUDDY); + script_error_log("npc_anubisath_sentinel for %s found too few/too many buddies, expected %u.", m_creature->GetGuidStr().c_str(), MAX_BUDDY); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 /*uiDiff*/) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h b/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h index 8a83155ee..090041f7a 100644 --- a/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h +++ b/scripts/kalimdor/temple_of_ahnqiraj/temple_of_ahnqiraj.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,62 +7,99 @@ enum { - MAX_ENCOUNTER = 4, + MAX_ENCOUNTER = 9, TYPE_SKERAM = 0, TYPE_BUG_TRIO = 1, - TYPE_TWINS = 2, - TYPE_CTHUN_PHASE = 3, - - // NPC_SKERAM = 15263, - //NPC_KRI = 15511, - //NPC_VEM = 15544, - //NPC_YAUJ = 15543, + TYPE_SARTURA = 2, + TYPE_FANKRISS = 3, + TYPE_VISCIDUS = 4, + TYPE_HUHURAN = 5, + TYPE_TWINS = 6, + TYPE_OURO = 7, + TYPE_CTHUN = 8, + + NPC_SKERAM = 15263, + // NPC_KRI = 15511, + // NPC_VEM = 15544, + // NPC_YAUJ = 15543, + NPC_SARTURA = 15516, NPC_VEKLOR = 15276, NPC_VEKNILASH = 15275, + NPC_MASTERS_EYE = 15963, + NPC_OURO_SPAWNER = 15957, + // NPC_EYE_OF_CTHUN = 15589, NPC_CTHUN = 15727, GO_SKERAM_GATE = 180636, GO_TWINS_ENTER_DOOR = 180634, GO_TWINS_EXIT_DOOR = 180635, + GO_SANDWORM_BASE = 180795, + + EMOTE_EYE_INTRO = -1531012, + SAY_EMPERORS_INTRO_1 = -1531013, + SAY_EMPERORS_INTRO_2 = -1531014, + SAY_EMPERORS_INTRO_3 = -1531015, + SAY_EMPERORS_INTRO_4 = -1531016, + SAY_EMPERORS_INTRO_5 = -1531017, + SAY_EMPERORS_INTRO_6 = -1531018, + + // Whispered on players around the map + SAY_CTHUN_WHISPER_1 = -1531033, + SAY_CTHUN_WHISPER_2 = -1531034, + SAY_CTHUN_WHISPER_3 = -1531035, + SAY_CTHUN_WHISPER_4 = -1531036, + SAY_CTHUN_WHISPER_5 = -1531037, + SAY_CTHUN_WHISPER_6 = -1531038, + SAY_CTHUN_WHISPER_7 = -1531039, + SAY_CTHUN_WHISPER_8 = -1531040, + + AREATRIGGER_TWIN_EMPERORS = 4047, + AREATRIGGER_SARTURA = 4052, SPELL_SUMMON_PLAYER = 20477, -}; -enum CThunPhase -{ - PHASE_NOT_STARTED = 0, - PHASE_EYE_NORMAL = 1, - PHASE_EYE_DARK_GLARE = 2, - PHASE_TRANSITION = 3, - PHASE_CTHUN = 4, - PHASE_CTHUN_WEAKENED = 5, - PHASE_FINISH = 6, + // Cast periodically on players around the instance + SPELL_WHISPERINGS_CTHUN_1 = 26195, + SPELL_WHISPERINGS_CTHUN_2 = 26197, + SPELL_WHISPERINGS_CTHUN_3 = 26198, + SPELL_WHISPERINGS_CTHUN_4 = 26258, + SPELL_WHISPERINGS_CTHUN_5 = 26259, }; -class MANGOS_DLL_DECL instance_temple_of_ahnqiraj : public ScriptedInstance +class instance_temple_of_ahnqiraj : public ScriptedInstance { public: instance_temple_of_ahnqiraj(Map* pMap); + ~instance_temple_of_ahnqiraj() {} + + void Initialize() override; - void Initialize(); + bool IsEncounterInProgress() const override; - bool IsEncounterInProgress() const; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void DoHandleTempleAreaTrigger(uint32 uiTriggerId); - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; uint8 m_uiBugTrioDeathCount; + uint32 m_uiCthunWhisperTimer; + + bool m_bIsEmperorsIntroDone; + + DialogueHelper m_dialogueHelper; }; #endif diff --git a/scripts/kalimdor/the_barrens.cpp b/scripts/kalimdor/the_barrens.cpp index 06b2ea169..9376e3755 100644 --- a/scripts/kalimdor/the_barrens.cpp +++ b/scripts/kalimdor/the_barrens.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,14 +17,13 @@ /* ScriptData SDName: The_Barrens SD%Complete: 90 -SDComment: Quest support: 863, 898, 1719, 2458, 4921, 6981 +SDComment: Quest support: 863, 898, 1719, 2458, 4921. SDCategory: Barrens EndScriptData */ /* ContentData npc_beaten_corpse npc_gilthares -npc_sputtervalve npc_taskmaster_fizzule npc_twiggy_flathead at_twiggy_flathead @@ -46,16 +45,16 @@ enum bool GossipHello_npc_beaten_corpse(Player* pPlayer, Creature* pCreature) { if (pPlayer->GetQuestStatus(QUEST_LOST_IN_BATTLE) == QUEST_STATUS_INCOMPLETE || - pPlayer->GetQuestStatus(QUEST_LOST_IN_BATTLE) == QUEST_STATUS_COMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,"Examine corpse in detail...",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF+1); + pPlayer->GetQuestStatus(QUEST_LOST_IN_BATTLE) == QUEST_STATUS_COMPLETE) + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Examine corpse in detail...", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(3557, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_beaten_corpse(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_beaten_corpse(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF +1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { pPlayer->SEND_GOSSIP_MENU(3558, pCreature->GetObjectGuid()); pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); @@ -85,20 +84,20 @@ enum AREA_MERCHANT_COAST = 391 }; -struct MANGOS_DLL_DECL npc_giltharesAI : public npc_escortAI +struct npc_giltharesAI : public npc_escortAI { npc_giltharesAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(uiPointId) + switch (uiPointId) { case 16: DoScriptText(SAY_GIL_AT_LAST, m_creature, pPlayer); @@ -122,17 +121,17 @@ struct MANGOS_DLL_DECL npc_giltharesAI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { - //not always use + // not always use if (urand(0, 3)) return; - //only aggro text if not player and only in this area + // only aggro text if not player and only in this area if (pWho->GetTypeId() != TYPEID_PLAYER && m_creature->GetAreaId() == AREA_MERCHANT_COAST) { - //appears to be pretty much random (possible only if escorter not in combat with pWho yet?) - switch(urand(0, 3)) + // appears to be pretty much random (possible only if escorter not in combat with pWho yet?) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_GIL_AGGRO_1, m_creature, pWho); break; case 1: DoScriptText(SAY_GIL_AGGRO_2, m_creature, pWho); break; @@ -152,7 +151,7 @@ bool QuestAccept_npc_gilthares(Player* pPlayer, Creature* pCreature, const Quest { if (pQuest->GetQuestId() == QUEST_FREE_FROM_HOLD) { - pCreature->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); pCreature->SetStandState(UNIT_STAND_STATE_STAND); DoScriptText(SAY_GIL_START, pCreature, pPlayer); @@ -163,32 +162,6 @@ bool QuestAccept_npc_gilthares(Player* pPlayer, Creature* pCreature, const Quest return true; } -/*###### -## npc_sputtervalve -######*/ - -bool GossipHello_npc_sputtervalve(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(6981) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,"Can you tell me about this shard?",GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_sputtervalve(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF) - { - pPlayer->SEND_GOSSIP_MENU(2013, pCreature->GetObjectGuid()); - pPlayer->AreaExploredOrEventHappens(6981); - } - return true; -} - /*###### ## npc_taskmaster_fizzule ######*/ @@ -200,59 +173,59 @@ enum SPELL_FOLLY = 10137, }; -struct MANGOS_DLL_DECL npc_taskmaster_fizzuleAI : public ScriptedAI +struct npc_taskmaster_fizzuleAI : public ScriptedAI { - npc_taskmaster_fizzuleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - factionNorm = pCreature->getFaction(); - Reset(); - } + npc_taskmaster_fizzuleAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 factionNorm; - bool IsFriend; - uint32 Reset_Timer; - uint8 FlareCount; + uint32 m_uiResetTimer; + uint8 m_uiFlareCount; - void Reset() + void Reset() override { - IsFriend = false; - Reset_Timer = 120000; - FlareCount = 0; - m_creature->setFaction(factionNorm); + m_uiResetTimer = 0; + m_uiFlareCount = 0; } - void DoFriend() + void EnterEvadeMode() override { - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); + if (m_uiResetTimer) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); - m_creature->StopMoving(); - m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetLootRecipient(NULL); - m_creature->setFaction(FACTION_FRIENDLY_F); - m_creature->HandleEmote(EMOTE_ONESHOT_SALUTE); + m_creature->SetFactionTemporary(FACTION_FRIENDLY_F, TEMPFACTION_RESTORE_REACH_HOME); + m_creature->HandleEmote(EMOTE_ONESHOT_SALUTE); + } + else + ScriptedAI::EnterEvadeMode(); } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (spell->Id == SPELL_FLARE || spell->Id == SPELL_FOLLY) + if (pCaster->GetTypeId() == TYPEID_PLAYER && (pSpell->Id == SPELL_FLARE || pSpell->Id == SPELL_FOLLY)) { - ++FlareCount; + ++m_uiFlareCount; - if (FlareCount >= 2) - IsFriend = true; + if (m_uiFlareCount >= 2 && m_creature->getFaction() != FACTION_FRIENDLY_F) + m_uiResetTimer = 120000; } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (IsFriend) + if (m_uiResetTimer) { - if (Reset_Timer < diff) + if (m_uiResetTimer <= uiDiff) { + m_uiResetTimer = 0; EnterEvadeMode(); - } else Reset_Timer -= diff; + } + else + m_uiResetTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -261,17 +234,12 @@ struct MANGOS_DLL_DECL npc_taskmaster_fizzuleAI : public ScriptedAI DoMeleeAttackIfReady(); } - void ReceiveEmote(Player* pPlayer, uint32 emote) + void ReceiveEmote(Player* /*pPlayer*/, uint32 uiTextEmote) override { - if (emote == TEXTEMOTE_SALUTE) + if (uiTextEmote == TEXTEMOTE_SALUTE) { - if (FlareCount >= 2) - { - if (m_creature->getFaction() == FACTION_FRIENDLY_F) - return; - - DoFriend(); - } + if (m_uiFlareCount >= 2 && m_creature->getFaction() != FACTION_FRIENDLY_F) + EnterEvadeMode(); } } }; @@ -285,65 +253,74 @@ CreatureAI* GetAI_npc_taskmaster_fizzule(Creature* pCreature) ## npc_twiggy_flathead #####*/ -#define SAY_BIG_WILL_READY -1000123 -#define SAY_TWIGGY_BEGIN -1000124 -#define SAY_TWIGGY_FRAY -1000125 -#define SAY_TWIGGY_DOWN -1000126 -#define SAY_TWIGGY_OVER -1000127 +enum +{ + SAY_BIG_WILL_READY = -1000123, + SAY_TWIGGY_BEGIN = -1000124, + SAY_TWIGGY_FRAY = -1000125, + SAY_TWIGGY_DOWN = -1000126, + SAY_TWIGGY_OVER = -1000127, + + NPC_TWIGGY = 6248, + NPC_BIG_WILL = 6238, + NPC_AFFRAY_CHALLENGER = 6240, -#define NPC_TWIGGY 6248 -#define NPC_BIG_WILL 6238 -#define NPC_AFFRAY_CHALLENGER 6240 -#define QUEST_AFFRAY 1719 + QUEST_AFFRAY = 1719, -float AffrayChallengerLoc[6][4]= + FACTION_FRIENDLY = 35, + FACTION_HOSTILE_WILL = 32, + FACTION_HOSTILE_CHALLENGER = 14, + + MAX_CHALLENGERS = 6, +}; + +static const float aAffrayChallengerLoc[8][4] = { - {-1683.0f, -4326.0f, 2.79f, 0.00f}, - {-1682.0f, -4329.0f, 2.79f, 0.00f}, - {-1683.0f, -4330.0f, 2.79f, 0.00f}, - {-1680.0f, -4334.0f, 2.79f, 1.49f}, - {-1674.0f, -4326.0f, 2.79f, 3.49f}, - {-1677.0f, -4334.0f, 2.79f, 1.66f} + { -1683.0f, -4326.0f, 2.79f, 0.00f}, + { -1682.0f, -4329.0f, 2.79f, 0.00f}, + { -1683.0f, -4330.0f, 2.79f, 0.00f}, + { -1680.0f, -4334.0f, 2.79f, 1.49f}, + { -1674.0f, -4326.0f, 2.79f, 3.49f}, + { -1677.0f, -4334.0f, 2.79f, 1.66f}, + { -1713.79f, -4342.09f, 6.05f, 6.15f}, // Big Will spawn loc + { -1682.31f, -4329.68f, 2.78f, 0.0f}, // Big Will move loc }; -struct MANGOS_DLL_DECL npc_twiggy_flatheadAI : public ScriptedAI +struct npc_twiggy_flatheadAI : public ScriptedAI { - npc_twiggy_flatheadAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_twiggy_flatheadAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool EventInProgress; + bool m_bIsEventInProgress; - uint32 Event_Timer; - uint32 Step; - uint32 Challenger_Count; - uint32 ChallengerDeath_Timer; + uint32 m_uiEventTimer; + uint32 m_uiChallengerCount; + uint8 m_uiStep; ObjectGuid m_playerGuid; ObjectGuid m_bigWillGuid; - ObjectGuid m_aAffrayChallengerGuids[6]; + GuidVector m_vAffrayChallengerGuidsVector; - void Reset() + void Reset() override { - EventInProgress = false; + m_bIsEventInProgress = false; - Event_Timer = 2000; - Step = 0; - Challenger_Count = 0; - ChallengerDeath_Timer = 0; + m_uiEventTimer = 1000; + m_uiChallengerCount = 0; + m_uiStep = 0; m_playerGuid.Clear(); m_bigWillGuid.Clear(); - - for(uint8 i = 0; i < 6; ++i) - m_aAffrayChallengerGuids[i].Clear(); + m_vAffrayChallengerGuidsVector.clear(); } bool CanStartEvent(Player* pPlayer) { - if (!EventInProgress) + if (!m_bIsEventInProgress) { - EventInProgress = true; - m_playerGuid = pPlayer->GetObjectGuid(); DoScriptText(SAY_TWIGGY_BEGIN, m_creature, pPlayer); + m_playerGuid = pPlayer->GetObjectGuid(); + m_bIsEventInProgress = true; + return true; } @@ -353,110 +330,113 @@ struct MANGOS_DLL_DECL npc_twiggy_flatheadAI : public ScriptedAI void SetChallengers() { - for(uint8 i = 0; i < 6; ++i) - { - Creature* pCreature = m_creature->SummonCreature(NPC_AFFRAY_CHALLENGER, AffrayChallengerLoc[i][0], AffrayChallengerLoc[i][1], AffrayChallengerLoc[i][2], AffrayChallengerLoc[i][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - if (!pCreature) - { - debug_log("SD2: npc_twiggy_flathead event cannot summon challenger as expected."); - continue; - } + m_vAffrayChallengerGuidsVector.reserve(MAX_CHALLENGERS); - pCreature->setFaction(35); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pCreature->HandleEmote(EMOTE_ONESHOT_ROAR); - m_aAffrayChallengerGuids[i] = pCreature->GetObjectGuid(); - } + for (uint8 i = 0; i < MAX_CHALLENGERS; ++i) + m_creature->SummonCreature(NPC_AFFRAY_CHALLENGER, aAffrayChallengerLoc[i][0], aAffrayChallengerLoc[i][1], aAffrayChallengerLoc[i][2], aAffrayChallengerLoc[i][3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600000); } - void SetChallengerReady(Unit *pUnit) + void SetChallengerReady(Creature* pChallenger) { - pUnit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pUnit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pUnit->HandleEmote(EMOTE_ONESHOT_ROAR); - pUnit->setFaction(14); + pChallenger->setFaction(FACTION_HOSTILE_CHALLENGER); + pChallenger->HandleEmote(EMOTE_ONESHOT_ROAR); + ++m_uiChallengerCount; + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pChallenger->AI()->AttackStart(pPlayer); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_BIG_WILL) + { + m_bigWillGuid = pSummoned->GetObjectGuid(); + pSummoned->setFaction(FACTION_FRIENDLY); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, aAffrayChallengerLoc[7][0], aAffrayChallengerLoc[7][1], aAffrayChallengerLoc[7][2]); + } + else + { + pSummoned->setFaction(FACTION_FRIENDLY); + pSummoned->HandleEmote(EMOTE_ONESHOT_ROAR); + m_vAffrayChallengerGuidsVector.push_back(pSummoned->GetObjectGuid()); + } } - void UpdateAI(const uint32 diff) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) override { - if (!EventInProgress) + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId || pSummoned->GetEntry() != NPC_BIG_WILL) return; - if (ChallengerDeath_Timer) + pSummoned->setFaction(FACTION_HOSTILE_WILL); + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { - if (ChallengerDeath_Timer <= diff) - { - for(uint8 i = 0; i < 6; ++i) - { - Creature *challenger = m_creature->GetMap()->GetCreature(m_aAffrayChallengerGuids[i]); - if (challenger && !challenger->isAlive() && challenger->isDead()) - { - DoScriptText(SAY_TWIGGY_DOWN, m_creature); - challenger->RemoveCorpse(); - m_aAffrayChallengerGuids[i].Clear(); - continue; - } - } - ChallengerDeath_Timer = 2500; - } else ChallengerDeath_Timer -= diff; + DoScriptText(SAY_BIG_WILL_READY, pSummoned, pPlayer); + pSummoned->SetFacingToObject(pPlayer); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_BIG_WILL) + { + DoScriptText(SAY_TWIGGY_OVER, m_creature); + EnterEvadeMode(); } + else + { + DoScriptText(SAY_TWIGGY_DOWN, m_creature); + m_uiEventTimer = 15000; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_bIsEventInProgress) + return; - if (Event_Timer < diff) + if (m_uiEventTimer < uiDiff) { Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); - if (!pPlayer || pPlayer->isDead()) - Reset(); + if (!pPlayer || !pPlayer->isAlive()) + EnterEvadeMode(); - switch(Step) + switch (m_uiStep) { case 0: SetChallengers(); - ChallengerDeath_Timer = 2500; - Event_Timer = 5000; - ++Step; + m_uiEventTimer = 5000; + ++m_uiStep; break; case 1: DoScriptText(SAY_TWIGGY_FRAY, m_creature); - if (Creature *challenger = m_creature->GetMap()->GetCreature(m_aAffrayChallengerGuids[Challenger_Count])) - SetChallengerReady(challenger); - else Reset(); - ++Challenger_Count; - Event_Timer = 25000; - if (Challenger_Count == 6) - ++Step; - break; - case 2: - if (Unit *temp = m_creature->SummonCreature(NPC_BIG_WILL, -1713.79f, -4342.09f, 6.05f, 6.15f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,300000)) + if (Creature* pChallenger = m_creature->GetMap()->GetCreature(m_vAffrayChallengerGuidsVector[m_uiChallengerCount])) + SetChallengerReady(pChallenger); + else + EnterEvadeMode(); + + if (m_uiChallengerCount == MAX_CHALLENGERS) { - m_bigWillGuid = temp->GetObjectGuid(); - temp->setFaction(35); - temp->GetMotionMaster()->MovePoint(0, -1682.31f, -4329.68f, 2.78f); + ++m_uiStep; + m_uiEventTimer = 5000; } - Event_Timer = 15000; - ++Step; + else + m_uiEventTimer = 25000; break; - case 3: - if (Creature *will = m_creature->GetMap()->GetCreature(m_bigWillGuid)) - { - will->setFaction(32); - DoScriptText(SAY_BIG_WILL_READY, will, pPlayer); - } - Event_Timer = 5000; - ++Step; + case 2: + m_creature->SummonCreature(NPC_BIG_WILL, aAffrayChallengerLoc[6][0], aAffrayChallengerLoc[6][1], aAffrayChallengerLoc[6][2], aAffrayChallengerLoc[6][3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 300000); + m_uiEventTimer = 15000; + ++m_uiStep; break; - case 4: - Creature *will = m_creature->GetMap()->GetCreature(m_bigWillGuid); - if (will && will->isDead()) - { - DoScriptText(SAY_TWIGGY_OVER, m_creature); - Reset(); - } else if (!will) - Reset(); - Event_Timer = 5000; + default: + m_uiEventTimer = 5000; break; } - } else Event_Timer -= diff; + } + else + m_uiEventTimer -= uiDiff; } }; @@ -465,19 +445,18 @@ CreatureAI* GetAI_npc_twiggy_flathead(Creature* pCreature) return new npc_twiggy_flatheadAI(pCreature); } -bool AreaTrigger_at_twiggy_flathead(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_twiggy_flathead(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { - if (!pPlayer->isDead() && pPlayer->GetQuestStatus(QUEST_AFFRAY) == QUEST_STATUS_INCOMPLETE) + if (pPlayer->isAlive() && !pPlayer->isGameMaster() && pPlayer->GetQuestStatus(QUEST_AFFRAY) == QUEST_STATUS_INCOMPLETE) { Creature* pCreature = GetClosestCreatureWithEntry(pPlayer, NPC_TWIGGY, 30.0f); - if (!pCreature) return true; if (npc_twiggy_flatheadAI* pTwiggyAI = dynamic_cast(pCreature->AI())) { if (pTwiggyAI->CanStartEvent(pPlayer)) - return false; //ok to let mangos process further + return false; // ok to let mangos process further } return true; @@ -506,7 +485,7 @@ enum NPC_MERCENARY = 3282 }; -struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI +struct npc_wizzlecranks_shredderAI : public npc_escortAI { npc_wizzlecranks_shredderAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -520,7 +499,7 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI uint32 m_uiPostEventTimer; uint32 m_uiPostEventCount; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -533,9 +512,9 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: if (Player* pPlayer = GetPlayerForEscort()) @@ -545,10 +524,10 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI SetRun(false); break; case 17: - if (Creature* pTemp = m_creature->SummonCreature(NPC_MERCENARY, 1128.489f, -3037.611f, 92.701f, 1.472f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (Creature* pTemp = m_creature->SummonCreature(NPC_MERCENARY, 1128.489f, -3037.611f, 92.701f, 1.472f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) { DoScriptText(SAY_MERCENARY, pTemp); - m_creature->SummonCreature(NPC_MERCENARY, 1160.172f, -2980.168f, 97.313f, 3.690f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + m_creature->SummonCreature(NPC_MERCENARY, 1160.172f, -2980.168f, 97.313f, 3.690f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000); } break; case 24: @@ -557,9 +536,9 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI } } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 9: if (Player* pPlayer = GetPlayerForEscort()) @@ -573,7 +552,7 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_PILOT_WIZZ) m_creature->SetStandState(UNIT_STAND_STATE_DEAD); @@ -582,7 +561,7 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -590,7 +569,7 @@ struct MANGOS_DLL_DECL npc_wizzlecranks_shredderAI : public npc_escortAI { if (m_uiPostEventTimer < uiDiff) { - switch(m_uiPostEventCount) + switch (m_uiPostEventCount) { case 0: DoScriptText(SAY_PROGRESS_2, m_creature); @@ -629,7 +608,7 @@ bool QuestAccept_npc_wizzlecranks_shredder(Player* pPlayer, Creature* pCreature, if (pQuest->GetQuestId() == QUEST_ESCAPE) { DoScriptText(SAY_START, pCreature); - pCreature->setFaction(FACTION_RATCHET); + pCreature->SetFactionTemporary(FACTION_RATCHET, TEMPFACTION_RESTORE_RESPAWN); if (npc_wizzlecranks_shredderAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(true, pPlayer, pQuest); @@ -658,12 +637,6 @@ void AddSC_the_barrens() pNewScript->pQuestAcceptNPC = &QuestAccept_npc_gilthares; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_sputtervalve"; - pNewScript->pGossipHello = &GossipHello_npc_sputtervalve; - pNewScript->pGossipSelect = &GossipSelect_npc_sputtervalve; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_taskmaster_fizzule"; pNewScript->GetAI = &GetAI_npc_taskmaster_fizzule; diff --git a/scripts/kalimdor/thousand_needles.cpp b/scripts/kalimdor/thousand_needles.cpp index 087fdd162..be8b2167a 100644 --- a/scripts/kalimdor/thousand_needles.cpp +++ b/scripts/kalimdor/thousand_needles.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,17 +44,17 @@ enum NPC_GALAK_ASS = 10720 }; -const float m_afGalakLoc[] = {-4867.387695f, -1357.353760f, -48.226f}; +const float m_afGalakLoc[] = { -4867.387695f, -1357.353760f, -48.226f}; -struct MANGOS_DLL_DECL npc_kanatiAI : public npc_escortAI +struct npc_kanatiAI : public npc_escortAI { npc_kanatiAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: DoScriptText(SAY_KAN_START, m_creature); @@ -69,13 +69,13 @@ struct MANGOS_DLL_DECL npc_kanatiAI : public npc_escortAI void DoSpawnGalak() { - for(int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) m_creature->SummonCreature(NPC_GALAK_ASS, - m_afGalakLoc[0], m_afGalakLoc[1], m_afGalakLoc[2], 0.0f, - TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_afGalakLoc[0], m_afGalakLoc[1], m_afGalakLoc[2], 0.0f, + TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } @@ -116,25 +116,25 @@ enum ID_AMBUSH_3 = 4 }; -float m_afBanditLoc[6][6]= +float m_afBanditLoc[6][6] = { - {-4905.479492f, -2062.732666f, 84.352f}, - {-4915.201172f, -2073.528320f, 84.733f}, - {-4878.883301f, -1986.947876f, 91.966f}, - {-4877.503906f, -1966.113403f, 91.859f}, - {-4767.985352f, -1873.169189f, 90.192f}, - {-4788.861328f, -1888.007813f, 89.888f} + { -4905.479492f, -2062.732666f, 84.352f}, + { -4915.201172f, -2073.528320f, 84.733f}, + { -4878.883301f, -1986.947876f, 91.966f}, + { -4877.503906f, -1966.113403f, 91.859f}, + { -4767.985352f, -1873.169189f, 90.192f}, + { -4788.861328f, -1888.007813f, 89.888f} }; -struct MANGOS_DLL_DECL npc_lakota_windsongAI : public npc_escortAI +struct npc_lakota_windsongAI : public npc_escortAI { npc_lakota_windsongAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 8: DoScriptText(SAY_LAKO_LOOK_OUT, m_creature); @@ -157,10 +157,10 @@ struct MANGOS_DLL_DECL npc_lakota_windsongAI : public npc_escortAI void DoSpawnBandits(int uiAmbushId) { - for(int i = 0; i < 2; ++i) + for (int i = 0; i < 2; ++i) m_creature->SummonCreature(NPC_GRIM_BANDIT, - m_afBanditLoc[i+uiAmbushId][0], m_afBanditLoc[i+uiAmbushId][1], m_afBanditLoc[i+uiAmbushId][2], 0.0f, - TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + m_afBanditLoc[i + uiAmbushId][0], m_afBanditLoc[i + uiAmbushId][1], m_afBanditLoc[i + uiAmbushId][2], 0.0f, + TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); } }; @@ -174,7 +174,7 @@ bool QuestAccept_npc_lakota_windsong(Player* pPlayer, Creature* pCreature, const if (pQuest->GetQuestId() == QUEST_FREE_AT_LAST) { DoScriptText(SAY_LAKO_START, pCreature, pPlayer); - pCreature->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_lakota_windsongAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -196,22 +196,22 @@ enum NPC_WYVERN = 4107 }; -float m_afWyvernLoc[3][3]= +float m_afWyvernLoc[3][3] = { - {-4990.606f, -906.057f, -5.343f}, - {-4970.241f, -927.378f, -4.951f}, - {-4985.364f, -952.528f, -5.199f} + { -4990.606f, -906.057f, -5.343f}, + { -4970.241f, -927.378f, -4.951f}, + { -4985.364f, -952.528f, -5.199f} }; -struct MANGOS_DLL_DECL npc_paoka_swiftmountainAI : public npc_escortAI +struct npc_paoka_swiftmountainAI : public npc_escortAI { npc_paoka_swiftmountainAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 15: DoScriptText(SAY_WYVERN, m_creature); @@ -229,10 +229,10 @@ struct MANGOS_DLL_DECL npc_paoka_swiftmountainAI : public npc_escortAI void DoSpawnWyvern() { - for(int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) m_creature->SummonCreature(NPC_WYVERN, - m_afWyvernLoc[i][0], m_afWyvernLoc[i][1], m_afWyvernLoc[i][2], 0.0f, - TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + m_afWyvernLoc[i][0], m_afWyvernLoc[i][1], m_afWyvernLoc[i][2], 0.0f, + TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); } }; @@ -246,7 +246,7 @@ bool QuestAccept_npc_paoka_swiftmountain(Player* pPlayer, Creature* pCreature, c if (pQuest->GetQuestId() == QUEST_HOMEWARD) { DoScriptText(SAY_START, pCreature, pPlayer); - pCreature->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_paoka_swiftmountainAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -268,37 +268,32 @@ enum #define GOSSIP_ITEM_QUEST "Please tell me the Phrase.." -struct MANGOS_DLL_DECL npc_plucky_johnsonAI : public ScriptedAI +struct npc_plucky_johnsonAI : public ScriptedAI { npc_plucky_johnsonAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiNormFaction = pCreature->getFaction(); Reset(); } - uint32 m_uiNormFaction; uint32 m_uiResetTimer; - void Reset() + void Reset() override { m_uiResetTimer = 120000; - if (m_creature->getFaction() != m_uiNormFaction) - m_creature->setFaction(m_uiNormFaction); - if (m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP)) m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); m_creature->CastSpell(m_creature, SPELL_PLUCKY_CHICKEN, false); } - void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) + void ReceiveEmote(Player* pPlayer, uint32 uiTextEmote) override { if (pPlayer->GetQuestStatus(QUEST_SCOOP) == QUEST_STATUS_INCOMPLETE) { if (uiTextEmote == TEXTEMOTE_BECKON) { - m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_COMBAT_STOP); m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); m_creature->CastSpell(m_creature, SPELL_PLUCKY_HUMAN, false); } @@ -310,7 +305,7 @@ struct MANGOS_DLL_DECL npc_plucky_johnsonAI : public ScriptedAI return; else { - m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_COMBAT_STOP); m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); m_creature->CastSpell(m_creature, SPELL_PLUCKY_HUMAN, false); m_creature->HandleEmote(EMOTE_ONESHOT_WAVE); @@ -318,7 +313,7 @@ struct MANGOS_DLL_DECL npc_plucky_johnsonAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP)) { @@ -356,7 +351,7 @@ bool GossipHello_npc_plucky_johnson(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_plucky_johnson(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_plucky_johnson(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF) { diff --git a/scripts/kalimdor/thunder_bluff.cpp b/scripts/kalimdor/thunder_bluff.cpp index d23346963..53022a4a6 100644 --- a/scripts/kalimdor/thunder_bluff.cpp +++ b/scripts/kalimdor/thunder_bluff.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,119 +16,17 @@ /* ScriptData SDName: Thunder_Bluff -SD%Complete: 100 -SDComment: Quest support: 925 +SD%Complete: 0 +SDComment: SDCategory: Thunder Bluff EndScriptData */ #include "precompiled.h" /*##### -# npc_cairne_bloodhoof +# ######*/ -#define SPELL_BERSERKER_CHARGE 16636 -#define SPELL_CLEAVE 16044 -#define SPELL_MORTAL_STRIKE 16856 -#define SPELL_THUNDERCLAP 23931 -#define SPELL_UPPERCUT 22916 - -//TODO: verify abilities/timers -struct MANGOS_DLL_DECL npc_cairne_bloodhoofAI : public ScriptedAI -{ - npc_cairne_bloodhoofAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - uint32 BerserkerCharge_Timer; - uint32 Cleave_Timer; - uint32 MortalStrike_Timer; - uint32 Thunderclap_Timer; - uint32 Uppercut_Timer; - - void Reset() - { - BerserkerCharge_Timer = 30000; - Cleave_Timer = 5000; - MortalStrike_Timer = 10000; - Thunderclap_Timer = 15000; - Uppercut_Timer = 10000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (BerserkerCharge_Timer < diff) - { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - DoCastSpellIfCan(target,SPELL_BERSERKER_CHARGE); - BerserkerCharge_Timer = 25000; - }else BerserkerCharge_Timer -= diff; - - if (Uppercut_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_UPPERCUT); - Uppercut_Timer = 20000; - }else Uppercut_Timer -= diff; - - if (Thunderclap_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_THUNDERCLAP); - Thunderclap_Timer = 15000; - }else Thunderclap_Timer -= diff; - - if (MortalStrike_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MORTAL_STRIKE); - MortalStrike_Timer = 15000; - }else MortalStrike_Timer -= diff; - - if (Cleave_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_CLEAVE); - Cleave_Timer = 7000; - }else Cleave_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_npc_cairne_bloodhoof(Creature* pCreature) -{ - return new npc_cairne_bloodhoofAI(pCreature); -} - -bool GossipHello_npc_cairne_bloodhoof(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(925) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I know this is rather silly but a young ward who is a bit shy would like your hoofprint.", GOSSIP_SENDER_MAIN, GOSSIP_SENDER_INFO); - - pPlayer->SEND_GOSSIP_MENU(7013, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_cairne_bloodhoof(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_SENDER_INFO) - { - pPlayer->CastSpell(pPlayer, 23123, false); - pPlayer->SEND_GOSSIP_MENU(7014, pCreature->GetObjectGuid()); - } - return true; -} - void AddSC_thunder_bluff() { - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "npc_cairne_bloodhoof"; - pNewScript->GetAI = &GetAI_npc_cairne_bloodhoof; - pNewScript->pGossipHello = &GossipHello_npc_cairne_bloodhoof; - pNewScript->pGossipSelect = &GossipSelect_npc_cairne_bloodhoof; - pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/ungoro_crater.cpp b/scripts/kalimdor/ungoro_crater.cpp index aeefe27d7..724e4a5ee 100644 --- a/scripts/kalimdor/ungoro_crater.cpp +++ b/scripts/kalimdor/ungoro_crater.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,6 +22,7 @@ SDCategory: Un'Goro Crater EndScriptData */ /* ContentData +npc_ame01 npc_ringo EndContentData */ @@ -45,15 +46,15 @@ enum QUEST_CHASING_AME = 4245 }; -struct MANGOS_DLL_DECL npc_ame01AI : public npc_escortAI +struct npc_ame01AI : public npc_escortAI { npc_ame01AI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: DoScriptText(SAY_AME_START, m_creature); @@ -69,7 +70,7 @@ struct MANGOS_DLL_DECL npc_ame01AI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->GetTypeId() == TYPEID_PLAYER) return; @@ -79,11 +80,11 @@ struct MANGOS_DLL_DECL npc_ame01AI : public npc_escortAI if (pPlayer->getVictim() && pPlayer->getVictim() == pWho) return; - switch(urand(0, 2)) + switch (urand(0, 2)) { - case 0: DoScriptText(SAY_AME_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_AME_AGGRO2, m_creature); break; - case 2: DoScriptText(SAY_AME_AGGRO3, m_creature); break; + case 0: DoScriptText(SAY_AME_AGGRO1, m_creature, pWho); break; + case 1: DoScriptText(SAY_AME_AGGRO2, m_creature, pWho); break; + case 2: DoScriptText(SAY_AME_AGGRO3, m_creature, pWho); break; } } } @@ -98,9 +99,9 @@ bool QuestAccept_npc_ame01(Player* pPlayer, Creature* pCreature, const Quest* pQ pCreature->SetStandState(UNIT_STAND_STATE_STAND); if (pPlayer->GetTeam() == ALLIANCE) - pCreature->setFaction(FACTION_ESCORT_A_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); else if (pPlayer->GetTeam() == HORDE) - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); pAmeAI->Start(false, pPlayer, pQuest); } @@ -146,7 +147,7 @@ enum NPC_SPRAGGLE = 9997 }; -struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI +struct npc_ringoAI : public FollowerAI { npc_ringoAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } @@ -156,7 +157,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI Unit* pSpraggle; - void Reset() + void Reset() override { m_uiFaintTimer = urand(30000, 60000); m_uiEndEventProgress = 0; @@ -164,7 +165,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI pSpraggle = NULL; } - void MoveInLineOfSight(Unit *pWho) + void MoveInLineOfSight(Unit* pWho) override { FollowerAI::MoveInLineOfSight(pWho); @@ -184,7 +185,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (HasFollowState(STATE_FOLLOW_INPROGRESS | STATE_FOLLOW_PAUSED) && pSpell->Id == SPELL_REVIVE_RINGO) ClearFaint(); @@ -196,7 +197,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI { SetFollowPaused(true); - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_FAINT_1, m_creature); break; case 1: DoScriptText(SAY_FAINT_2, m_creature); break; @@ -205,7 +206,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI } } - //what does actually happen here? Emote? Aura? + // what does actually happen here? Emote? Aura? m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); } @@ -216,7 +217,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI if (HasFollowState(STATE_FOLLOW_POSTEVENT)) return; - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_WAKE_1, m_creature); break; case 1: DoScriptText(SAY_WAKE_2, m_creature); break; @@ -227,7 +228,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI SetFollowPaused(false); } - void UpdateFollowerAI(const uint32 uiDiff) + void UpdateFollowerAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -241,7 +242,7 @@ struct MANGOS_DLL_DECL npc_ringoAI : public FollowerAI return; } - switch(m_uiEndEventProgress) + switch (m_uiEndEventProgress) { case 1: DoScriptText(SAY_RIN_END_1, m_creature); diff --git a/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp b/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp index 60a8c8389..c890e2e8b 100644 --- a/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp +++ b/scripts/kalimdor/wailing_caverns/instance_wailing_caverns.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ void instance_wailing_caverns::OnPlayerEnter(Player* pPlayer) { // Respawn the Mysterious chest if one of the players who enter the instance has the quest in his log if (pPlayer->GetQuestStatus(QUEST_FORTUNE_AWAITS) == QUEST_STATUS_COMPLETE && - !pPlayer->GetQuestRewardStatus(QUEST_FORTUNE_AWAITS)) + !pPlayer->GetQuestRewardStatus(QUEST_FORTUNE_AWAITS)) DoRespawnGameObject(GO_MYSTERIOUS_CHEST, HOUR); } @@ -61,7 +61,7 @@ void instance_wailing_caverns::OnObjectCreate(GameObject* pGo) void instance_wailing_caverns::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ANACONDRA: m_auiEncounter[0] = uiData; @@ -103,7 +103,7 @@ void instance_wailing_caverns::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; m_strInstData = saveStream.str(); SaveToDB(); @@ -123,9 +123,9 @@ void instance_wailing_caverns::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] - >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; + >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -134,17 +134,11 @@ void instance_wailing_caverns::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_wailing_caverns::GetData(uint32 uiType) +uint32 instance_wailing_caverns::GetData(uint32 uiType) const { - switch (uiType) - { - case TYPE_ANACONDRA: return m_auiEncounter[0]; break; - case TYPE_COBRAHN: return m_auiEncounter[1]; break; - case TYPE_PYTHAS: return m_auiEncounter[2]; break; - case TYPE_SERPENTIS: return m_auiEncounter[3]; break; - case TYPE_DISCIPLE: return m_auiEncounter[4]; break; - case TYPE_MUTANUS: return m_auiEncounter[5]; break; - } + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + return 0; } diff --git a/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp b/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp index a75952e0d..a6fb9a17c 100644 --- a/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp +++ b/scripts/kalimdor/wailing_caverns/wailing_caverns.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -49,6 +49,7 @@ enum EMOTE_VISION = -1043011, GOSSIP_ITEM_BEGIN = -3043000, + TEXT_ID_BEGIN = 699, TEXT_ID_DISCIPLE = 698, SPELL_MARK = 5232, // Buff before the fight. To be removed after 4.0.3 @@ -75,7 +76,7 @@ static const float aSummonPositions[5][2] = {47.0f, 0.5901f} // Mutanus }; -struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI +struct npc_disciple_of_naralexAI : public npc_escortAI { npc_disciple_of_naralexAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -95,7 +96,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI uint32 m_uiPoint; uint8 m_uiSubeventPhase; - void Reset() + void Reset() override { m_uiSleepTimer = 5000; m_uiPotionTimer = 5000; @@ -114,7 +115,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI } } - void JustRespawned() + void JustRespawned() override { npc_escortAI::JustRespawned(); @@ -123,7 +124,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI m_pInstance->SetData(TYPE_DISCIPLE, FAIL); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (!m_bIsFirstHit) { @@ -141,7 +142,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI } // Overwrite the evade function, to change the combat stop function (keep casting some spells) - void EnterEvadeMode() + void EnterEvadeMode() override { // Do not stop casting at these points if (m_uiPoint == 15 || m_uiPoint == 32) @@ -158,7 +159,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI npc_escortAI::EnterEvadeMode(); } - void JustStartedEscort() + void JustStartedEscort() override { DoScriptText(SAY_PREPARE, m_creature); @@ -166,7 +167,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI m_pInstance->SetData(TYPE_DISCIPLE, IN_PROGRESS); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { @@ -199,7 +200,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Attack the disciple pSummoned->AI()->AttackStart(m_creature); @@ -207,7 +208,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI ++m_uiSummonedAlive; } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override { if (m_uiSummonedAlive == 0) return; // Actually if this happens, something went wrong before @@ -225,10 +226,10 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI float fX, fY, fZ; m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, fDistance, fAngle); - m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); + m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_uiEventTimer) { @@ -236,7 +237,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI { switch (m_uiPoint) { - // Corner stop -> raptors + // Corner stop -> raptors case 7: switch (m_uiSubeventPhase) { @@ -255,7 +256,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI break; } break; - // Circle stop -> vipers + // Circle stop -> vipers case 15: switch (m_uiSubeventPhase) { @@ -272,7 +273,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI case 2: // Summon vipers at the first circle for (uint8 i = 0; i < 3; ++i) - DoSpawnMob(NPC_DEVIATE_VIPER, aSummonPositions[2][0], aSummonPositions[2][1] + 2*M_PI_F/3 * i); + DoSpawnMob(NPC_DEVIATE_VIPER, aSummonPositions[2][0], aSummonPositions[2][1] + 2 * M_PI_F / 3 * i); m_uiEventTimer = 0; ++m_uiSubeventPhase; break; @@ -289,7 +290,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI break; } break; - // Chamber stop -> ritual and final boss + // Chamber stop -> ritual and final boss case 32: switch (m_uiSubeventPhase) { @@ -314,21 +315,21 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI case 3: // First set of mobs for (uint8 i = 0; i < 3; ++i) - DoSpawnMob(NPC_DEVIATE_MOCCASIN, aSummonPositions[3][0], aSummonPositions[3][1] + M_PI_F /3 * i); + DoSpawnMob(NPC_DEVIATE_MOCCASIN, aSummonPositions[3][0], aSummonPositions[3][1] + M_PI_F / 3 * i); m_uiEventTimer = 20000; ++m_uiSubeventPhase; break; case 4: // Second set of mobs for (uint8 i = 0; i < 7; ++i) - DoSpawnMob(NPC_NIGHTMARE_ECTOPLASM, aSummonPositions[3][0], aSummonPositions[3][1] + M_PI_F /7 * i); + DoSpawnMob(NPC_NIGHTMARE_ECTOPLASM, aSummonPositions[3][0], aSummonPositions[3][1] + M_PI_F / 7 * i); m_uiEventTimer = 0; ++m_uiSubeventPhase; break; case 5: // Advance only when all mobs are dead if (Creature* pNaralex = m_pInstance->GetSingleCreatureFromStorage(NPC_NARALEX)) - DoScriptText(EMOTE_BREAK_THROUGH, pNaralex); + DoScriptText(EMOTE_BREAK_THROUGH, pNaralex); ++m_uiSubeventPhase; m_uiEventTimer = 10000; break; @@ -387,7 +388,7 @@ struct MANGOS_DLL_DECL npc_disciple_of_naralexAI : public npc_escortAI { // ToDo: Make Naralex fly // sort of a hack, compare to boss_onyxia - pNaralex->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + pNaralex->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); // Set to flying pNaralex->SetLevitate(true); @@ -453,27 +454,27 @@ bool GossipHello_npc_disciple_of_naralex(Player* pPlayer, Creature* pCreature) if (m_pInstance && m_pInstance->GetData(TYPE_DISCIPLE) == SPECIAL) { pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(TEXT_ID_DISCIPLE, pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_BEGIN, pCreature->GetObjectGuid()); } else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_DISCIPLE, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_disciple_of_naralex(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_disciple_of_naralex(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { ScriptedInstance* m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); if (!m_pInstance) return false; - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { if (npc_disciple_of_naralexAI* pEscortAI = dynamic_cast(pCreature->AI())) { pEscortAI->Start(false, pPlayer); // Note: after 4.0.3 set him run = true - pCreature->setFaction(FACTION_ESCORT_N_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); } pPlayer->CLOSE_GOSSIP_MENU(); } diff --git a/scripts/kalimdor/wailing_caverns/wailing_caverns.h b/scripts/kalimdor/wailing_caverns/wailing_caverns.h index 7291ddf09..a4f052bd1 100644 --- a/scripts/kalimdor/wailing_caverns/wailing_caverns.h +++ b/scripts/kalimdor/wailing_caverns/wailing_caverns.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -26,23 +26,23 @@ enum QUEST_FORTUNE_AWAITS = 7944, }; -class MANGOS_DLL_DECL instance_wailing_caverns : public ScriptedInstance +class instance_wailing_caverns : public ScriptedInstance { public: instance_wailing_caverns(Map* pMap); ~instance_wailing_caverns() {} - void Initialize(); + void Initialize() override; - void OnPlayerEnter(Player* pPlayer); - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/kalimdor/winterspring.cpp b/scripts/kalimdor/winterspring.cpp index 37c18b0f2..10f93dc3f 100644 --- a/scripts/kalimdor/winterspring.cpp +++ b/scripts/kalimdor/winterspring.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,12 +17,11 @@ /* ScriptData SDName: Winterspring SD%Complete: 90 -SDComment: Quest support: 4901, 5126 (Loraxs' tale missing proper gossip items text). +SDComment: Quest support: 4901. SDCategory: Winterspring EndScriptData */ /* ContentData -npc_lorax npc_ranshalla EndContentData */ @@ -30,55 +29,6 @@ EndContentData */ #include "escort_ai.h" /*###### -## npc_lorax -######*/ - -bool GossipHello_npc_lorax(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(5126) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Talk to me", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_lorax(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What do you do here?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(3759, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I can help you", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(3760, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What deal?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(3761, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Then what happened?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(3762, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "He is not safe, i'll make sure of that.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(3763, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(5126); - break; - } - return true; -} - -/*#### # npc_ranshalla ####*/ @@ -138,6 +88,7 @@ enum GO_ELUNE_FIRE = 177417, GO_ELUNE_GEM = 177414, // is respawned in script GO_ELUNE_LIGHT = 177415, // are respawned in script + GO_ELUNE_AURA = 177416, // is respawned in script QUEST_GUARDIANS_ALTAR = 4901, }; @@ -146,32 +97,32 @@ static const DialogueEntry aIntroDialogue[] = { {SAY_REACH_ALTAR_1, NPC_RANSHALLA, 2000}, {SAY_REACH_ALTAR_2, NPC_RANSHALLA, 3000}, - {NPC_RANSHALLA, 0, 0}, // start the altar channeling + {NPC_RANSHALLA, 0, 0}, // start the altar channeling {SAY_PRIESTESS_ALTAR_3, NPC_PRIESTESS_DATA_2, 1000}, {SAY_PRIESTESS_ALTAR_4, NPC_PRIESTESS_DATA_1, 4000}, {SAY_RANSHALLA_ALTAR_5, NPC_RANSHALLA, 4000}, - {SAY_RANSHALLA_ALTAR_6, NPC_RANSHALLA, 4000}, // start the escort here + {SAY_RANSHALLA_ALTAR_6, NPC_RANSHALLA, 4000}, // start the escort here {SAY_PRIESTESS_ALTAR_7, NPC_PRIESTESS_DATA_2, 4000}, - {SAY_PRIESTESS_ALTAR_8, NPC_PRIESTESS_DATA_2, 5000}, // show the gem + {SAY_PRIESTESS_ALTAR_8, NPC_PRIESTESS_DATA_2, 5000}, // show the gem {GO_ELUNE_GEM, 0, 5000}, - {SAY_PRIESTESS_ALTAR_9, NPC_PRIESTESS_DATA_1, 4000}, // move priestess 1 near m_creature + {SAY_PRIESTESS_ALTAR_9, NPC_PRIESTESS_DATA_1, 4000}, // move priestess 1 near m_creature {NPC_PRIESTESS_DATA_1, 0, 3000}, {SAY_PRIESTESS_ALTAR_10, NPC_PRIESTESS_DATA_1, 5000}, {SAY_PRIESTESS_ALTAR_11, NPC_PRIESTESS_DATA_1, 4000}, {SAY_PRIESTESS_ALTAR_12, NPC_PRIESTESS_DATA_1, 5000}, - {SAY_PRIESTESS_ALTAR_13, NPC_PRIESTESS_DATA_1, 8000}, // summon voice and guard of elune + {SAY_PRIESTESS_ALTAR_13, NPC_PRIESTESS_DATA_1, 8000}, // summon voice and guard of elune {NPC_VOICE_ELUNE, 0, 12000}, - {SAY_VOICE_ALTAR_15, NPC_VOICE_ELUNE, 5000}, // move priestess 2 near m_creature + {SAY_VOICE_ALTAR_15, NPC_VOICE_ELUNE, 5000}, // move priestess 2 near m_creature {NPC_PRIESTESS_DATA_2, 0, 3000}, {SAY_PRIESTESS_ALTAR_16, NPC_PRIESTESS_DATA_2, 4000}, {SAY_PRIESTESS_ALTAR_17, NPC_PRIESTESS_DATA_2, 6000}, {SAY_PRIESTESS_ALTAR_18, NPC_PRIESTESS_DATA_1, 5000}, - {SAY_PRIESTESS_ALTAR_19, NPC_PRIESTESS_DATA_1, 3000}, // move the owlbeast + {SAY_PRIESTESS_ALTAR_19, NPC_PRIESTESS_DATA_1, 3000}, // move the owlbeast {NPC_GUARDIAN_ELUNE, 0, 2000}, - {SAY_PRIESTESS_ALTAR_20, NPC_PRIESTESS_DATA_1, 4000}, // move the first priestess up - {SAY_PRIESTESS_ALTAR_21, NPC_PRIESTESS_DATA_2, 10000}, // move second priestess up - {DATA_MOVE_PRIESTESS, 0, 6000}, // despawn the gem - {DATA_EVENT_END, 0, 2000}, // turn towards the player + {SAY_PRIESTESS_ALTAR_20, NPC_PRIESTESS_DATA_1, 4000}, // move the first priestess up + {SAY_PRIESTESS_ALTAR_21, NPC_PRIESTESS_DATA_2, 10000}, // move second priestess up + {DATA_MOVE_PRIESTESS, 0, 6000}, // despawn the gem + {DATA_EVENT_END, 0, 2000}, // turn towards the player {SAY_QUEST_END_2, NPC_RANSHALLA, 0}, {0, 0, 0}, }; @@ -193,7 +144,7 @@ static EventLocations aWingThicketLocations[] = {5514.40f, -4921.16f, 845.49f} // 7 left priestess second move loc }; -struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHelper +struct npc_ranshallaAI : public npc_escortAI, private DialogueHelper { npc_ranshallaAI(Creature* pCreature) : npc_escortAI(pCreature), DialogueHelper(aIntroDialogue) @@ -209,7 +160,7 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe ObjectGuid m_voiceEluneGuid; ObjectGuid m_altarGuid; - void Reset() + void Reset() override { m_uiDelayTimer = 0; } @@ -221,7 +172,7 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe DoScriptText(SAY_RANSHALLA_ALTAR_1, m_creature); else { - switch(urand(0, 1)) + switch (urand(0, 1)) { case 0: DoScriptText(SAY_AFTER_TORCH_1, m_creature); break; case 1: DoScriptText(SAY_AFTER_TORCH_2, m_creature); break; @@ -251,7 +202,7 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe } // Yell and set escort to pause - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_REACH_TORCH_1, m_creature); break; case 1: DoScriptText(SAY_REACH_TORCH_2, m_creature); break; @@ -279,7 +230,7 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_PRIESTESS_ELUNE || uiPointId != 1) return; @@ -288,9 +239,9 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe StartNextDialogueText(SAY_PRIESTESS_ALTAR_3); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 3: DoScriptText(SAY_ENTER_OWL_THICKET, m_creature); @@ -307,23 +258,23 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe SetEscortPaused(true); break; case 41: + { + // Search for all nearest lights and respawn them + std::list m_lEluneLights; + GetGameObjectListWithEntryInGrid(m_lEluneLights, m_creature, GO_ELUNE_LIGHT, 20.0f); + for (std::list::const_iterator itr = m_lEluneLights.begin(); itr != m_lEluneLights.end(); ++itr) { - // Search for all nearest lights and respawn them - std::list m_lEluneLights; - GetGameObjectListWithEntryInGrid(m_lEluneLights, m_creature, GO_ELUNE_LIGHT, 20.0f); - for (std::list::const_iterator itr = m_lEluneLights.begin(); itr != m_lEluneLights.end(); ++itr) - { - if ((*itr)->isSpawned()) - continue; - - (*itr)->SetRespawnTime(115); - (*itr)->Refresh(); - } - - if (GameObject* pAltar = m_creature->GetMap()->GetGameObject(m_altarGuid)) - m_creature->SetFacingToObject(pAltar); - break; + if ((*itr)->isSpawned()) + continue; + + (*itr)->SetRespawnTime(115); + (*itr)->Refresh(); } + + if (GameObject* pAltar = m_creature->GetMap()->GetGameObject(m_altarGuid)) + m_creature->SetFacingToObject(pAltar); + break; + } case 42: // Summon the 2 priestess SetEscortPaused(true); @@ -339,9 +290,9 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe } } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { - switch(iEntry) + switch (iEntry) { case NPC_RANSHALLA: // Start the altar channeling @@ -351,7 +302,7 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe SetEscortPaused(false); break; case SAY_PRIESTESS_ALTAR_8: - // make the gem respawn + // make the gem and its aura respawn if (GameObject* pGem = GetClosestGameObjectWithEntry(m_creature, GO_ELUNE_GEM, 10.0f)) { if (pGem->isSpawned()) @@ -360,6 +311,14 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe pGem->SetRespawnTime(90); pGem->Refresh(); } + if (GameObject* pAura = GetClosestGameObjectWithEntry(m_creature, GO_ELUNE_AURA, 10.0f)) + { + if (pAura->isSpawned()) + break; + + pAura->SetRespawnTime(90); + pAura->Refresh(); + } break; case SAY_PRIESTESS_ALTAR_9: // move near the escort npc @@ -431,7 +390,7 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe } } - Creature* GetSpeakerByEntry(uint32 uiEntry) + Creature* GetSpeakerByEntry(uint32 uiEntry) override { switch (uiEntry) { @@ -443,10 +402,9 @@ struct MANGOS_DLL_DECL npc_ranshallaAI : public npc_escortAI, private DialogueHe default: return NULL; } - } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); @@ -479,7 +437,7 @@ bool QuestAccept_npc_ranshalla(Player* pPlayer, Creature* pCreature, const Quest if (pQuest->GetQuestId() == QUEST_GUARDIANS_ALTAR) { DoScriptText(SAY_QUEST_START, pCreature); - pCreature->setFaction(FACTION_ESCORT_A_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_ranshallaAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest, true); @@ -490,7 +448,7 @@ bool QuestAccept_npc_ranshalla(Player* pPlayer, Creature* pCreature, const Quest return false; } -bool GOUse_go_elune_fire(Player* pPlayer, GameObject* pGo) +bool GOUse_go_elune_fire(Player* /*pPlayer*/, GameObject* pGo) { // Check if we are using the torches or the altar bool bIsAltar = false; @@ -511,12 +469,6 @@ void AddSC_winterspring() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_lorax"; - pNewScript->pGossipHello = &GossipHello_npc_lorax; - pNewScript->pGossipSelect = &GossipSelect_npc_lorax; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_ranshalla"; pNewScript->GetAI = &GetAI_npc_ranshalla; diff --git a/scripts/kalimdor/zulfarrak/boss_zumrah.cpp b/scripts/kalimdor/zulfarrak/boss_zumrah.cpp index 57de52393..eedb03f37 100644 --- a/scripts/kalimdor/zulfarrak/boss_zumrah.cpp +++ b/scripts/kalimdor/zulfarrak/boss_zumrah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,210 @@ /* ScriptData SDName: boss_zumrah -SD%Complete: 0 -SDComment: Placeholder - Needs SD2 support for summoning zombies from graves +SD%Complete: 100 +SDComment: SDCategory: Zul'Farrak EndScriptData */ #include "precompiled.h" +#include "zulfarrak.h" + +enum +{ + SAY_INTRO = -1209000, + SAY_AGGRO = -1209001, + SAY_KILL = -1209002, + SAY_SUMMON = -1209003, + + SPELL_SHADOW_BOLT = 12739, + SPELL_SHADOW_BOLT_VOLLEY = 15245, + SPELL_WARD_OF_ZUMRAH = 11086, + SPELL_HEALING_WAVE = 12491, + SPELL_SUMMON_ZOMBIES = 10247, // spell should be triggered by missing trap 128972 + + // NPC_WARD_OF_ZUMRAH = 7785, + // NPC_SKELETON_OF_ZUMRAH = 7786, + NPC_ZULFARRAK_ZOMBIE = 7286, // spawned by the graves + NPC_ZULFARRAK_DEAD_HERO = 7276, // spawned by the graves + + FACTION_HOSTILE = 14, +}; + +struct boss_zumrahAI : public ScriptedAI +{ + boss_zumrahAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_zulfarrak*) pCreature->GetInstanceData(); + m_bHasTurnedHostile = false; + Reset(); + } + + instance_zulfarrak* m_pInstance; + + uint32 m_uiShadowBoltTimer; + uint32 m_uiShadowBoltVolleyTimer; + uint32 m_uiWardOfZumrahTimer; + uint32 m_uHealingWaveTimer; + uint32 m_uiSpawnZombieTimer; + + bool m_bHasTurnedHostile; + + void Reset() override + { + m_uiShadowBoltTimer = 1000; + m_uiShadowBoltVolleyTimer = urand(6000, 30000); + m_uiWardOfZumrahTimer = urand(7000, 20000); + m_uHealingWaveTimer = urand(10000, 15000); + m_uiSpawnZombieTimer = 1000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(SAY_KILL, m_creature); + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 10.0f); + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasTurnedHostile && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 9.0f) && m_creature->IsWithinLOSInMap(pWho)) + { + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_NONE); + DoScriptText(SAY_INTRO, m_creature); + m_bHasTurnedHostile = true; + AttackStart(pWho); + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ZULFARRAK_ZOMBIE || pSummoned->GetEntry() == NPC_ZULFARRAK_DEAD_HERO) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + + GameObject* SelectNearbyShallowGrave() + { + if (!m_pInstance) + return NULL; + + // Get the list of usable graves (not used already by players) + GuidList lTempList; + std::list lGravesInRange; + + m_pInstance->GetShallowGravesGuidList(lTempList); + for (GuidList::const_iterator itr = lTempList.begin(); itr != lTempList.end(); ++itr) + { + GameObject* pGo = m_creature->GetMap()->GetGameObject(*itr); + // Go spawned and no looting in process + if (pGo && pGo->isSpawned() && pGo->getLootState() == GO_READY) + lGravesInRange.push_back(pGo); + } + + if (lGravesInRange.empty()) + return NULL; + + // Sort the graves + lGravesInRange.sort(ObjectDistanceOrder(m_creature)); + + return *lGravesInRange.begin(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSpawnZombieTimer) + { + if (m_uiSpawnZombieTimer <= uiDiff) + { + // Use a nearby grave to spawn zombies + if (GameObject* pGrave = SelectNearbyShallowGrave()) + { + m_creature->CastSpell(pGrave->GetPositionX(), pGrave->GetPositionY(), pGrave->GetPositionZ(), SPELL_SUMMON_ZOMBIES, true, NULL, NULL, pGrave->GetObjectGuid()); + pGrave->SetLootState(GO_JUST_DEACTIVATED); + + if (roll_chance_i(30)) + DoScriptText(SAY_SUMMON, m_creature); + + m_uiSpawnZombieTimer = 20000; + } + else // No Grave usable any more + m_uiSpawnZombieTimer = 0; + } + else + m_uiSpawnZombieTimer -= uiDiff; + } + + if (m_uiShadowBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_BOLT) == CAST_OK) + m_uiShadowBoltTimer = urand(3500, 5000); + } + } + else + m_uiShadowBoltTimer -= uiDiff; + + if (m_uiShadowBoltVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_BOLT_VOLLEY) == CAST_OK) + m_uiShadowBoltVolleyTimer = urand(10000, 18000); + } + else + m_uiShadowBoltVolleyTimer -= uiDiff; + + if (m_uiWardOfZumrahTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WARD_OF_ZUMRAH) == CAST_OK) + m_uiWardOfZumrahTimer = urand(15000, 32000); + } + else + m_uiWardOfZumrahTimer -= uiDiff; + + if (m_uHealingWaveTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(40.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HEALING_WAVE) == CAST_OK) + m_uHealingWaveTimer = urand(15000, 23000); + } + } + else + m_uHealingWaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_zumrah(Creature* pCreature) +{ + return new boss_zumrahAI(pCreature); +} void AddSC_boss_zumrah() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_zumrah"; + pNewScript->GetAI = &GetAI_boss_zumrah; + pNewScript->RegisterSelf(); } diff --git a/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp b/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp index c6f5f0b7a..be5e4bf4f 100644 --- a/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp +++ b/scripts/kalimdor/zulfarrak/instance_zulfarrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: instance_zulfarrak -SD%Complete: 50% +SD%Complete: 80% SDComment: SDCategory: Zul'Farrak EndScriptData */ @@ -24,12 +24,13 @@ EndScriptData */ #include "precompiled.h" #include "zulfarrak.h" -instance_zulfarrak::instance_zulfarrak(Map* pMap) : ScriptedInstance(pMap) +instance_zulfarrak::instance_zulfarrak(Map* pMap) : ScriptedInstance(pMap), + m_uiPyramidEventTimer(0) { Initialize(); } - void instance_zulfarrak::Initialize() +void instance_zulfarrak::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } @@ -39,24 +40,58 @@ void instance_zulfarrak::OnCreatureCreate(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_ANTUSUL: - m_mNpcEntryGuidStore[NPC_ANTUSUL] = pCreature->GetObjectGuid(); + case NPC_SERGEANT_BLY: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_SANDFURY_SLAVE: + case NPC_SANDFURY_DRUDGE: + case NPC_SANDFURY_CRETIN: + case NPC_SANDFURY_ACOLYTE: + case NPC_SANDFURY_ZEALOT: + m_lPyramidTrollsGuidList.push_back(pCreature->GetObjectGuid()); + break; + } +} + +void instance_zulfarrak::OnObjectCreate(GameObject* pGo) +{ + if (pGo->GetEntry() == GO_SHALLOW_GRAVE) + m_lShallowGravesGuidList.push_back(pGo->GetObjectGuid()); + else if (pGo->GetEntry() == GO_END_DOOR) + { + if (GetData(TYPE_PYRAMID_EVENT) == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); } } void instance_zulfarrak::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_VELRATHA: case TYPE_GAHZRILLA: case TYPE_ANTUSUL: case TYPE_THEKA: case TYPE_ZUMRAH: + case TYPE_CHIEF_SANDSCALP: + m_auiEncounter[uiType] = uiData; + break; case TYPE_NEKRUM: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE && GetData(TYPE_SEZZZIZ) == DONE) + SetData(TYPE_PYRAMID_EVENT, DONE); + break; case TYPE_SEZZZIZ: - case TYPE_CHIEF_SANDSCALP: m_auiEncounter[uiType] = uiData; + if (uiData == DONE && GetData(TYPE_NEKRUM) == DONE) + SetData(TYPE_PYRAMID_EVENT, DONE); + break; + case TYPE_PYRAMID_EVENT: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + m_uiPyramidEventTimer = 20000; + else if (uiData == DONE) + m_uiPyramidEventTimer = 0; break; default: return; @@ -68,7 +103,8 @@ void instance_zulfarrak::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] - << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6] << " " << m_auiEncounter[7]; + << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6] << " " << m_auiEncounter[7] + << " " << m_auiEncounter[8]; m_strInstData = saveStream.str(); @@ -89,9 +125,10 @@ void instance_zulfarrak::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -100,7 +137,7 @@ void instance_zulfarrak::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_zulfarrak::GetData(uint32 uiType) +uint32 instance_zulfarrak::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -153,6 +190,57 @@ void instance_zulfarrak::OnCreatureDeath(Creature* pCreature) } } +void instance_zulfarrak::Update(uint32 uiDiff) +{ + if (m_uiPyramidEventTimer) + { + if (m_uiPyramidEventTimer <= uiDiff) + { + if (m_lPyramidTrollsGuidList.empty()) + { + m_uiPyramidEventTimer = urand(3000, 10000); + return; + } + + GuidList::iterator iter = m_lPyramidTrollsGuidList.begin(); + advance(iter, urand(0, m_lPyramidTrollsGuidList.size() - 1)); + + // Remove the selected troll + ObjectGuid selectedGuid = *iter; + m_lPyramidTrollsGuidList.erase(iter); + + // Move the selected troll to the top of the pyramid. Note: the algorythm may be more complicated than this, but for the moment this will do. + if (Creature* pTroll = instance->GetCreature(selectedGuid)) + { + // Pick another one if already in combat or already killed + if (pTroll->getVictim() || !pTroll->isAlive()) + { + m_uiPyramidEventTimer = urand(0, 2) ? urand(3000, 10000) : 1000; + return; + } + + float fX, fY, fZ; + if (Creature* pBly = GetSingleCreatureFromStorage(NPC_SERGEANT_BLY)) + { + // ToDo: research if there is anything special if these guys die + if (!pBly->isAlive()) + { + m_uiPyramidEventTimer = 0; + return; + } + + pBly->GetRandomPoint(pBly->GetPositionX(), pBly->GetPositionY(), pBly->GetPositionZ(), 4.0f, fX, fY, fZ); + pTroll->SetWalk(false); + pTroll->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + m_uiPyramidEventTimer = urand(0, 2) ? urand(3000, 10000) : 1000; + } + else + m_uiPyramidEventTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_zulfarrak(Map* pMap) { return new instance_zulfarrak(pMap); diff --git a/scripts/kalimdor/zulfarrak/zulfarrak.cpp b/scripts/kalimdor/zulfarrak/zulfarrak.cpp index 8df718594..f0270deba 100644 --- a/scripts/kalimdor/zulfarrak/zulfarrak.cpp +++ b/scripts/kalimdor/zulfarrak/zulfarrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,226 +16,68 @@ /* ScriptData SDName: Zulfarrak -SD%Complete: 50 -SDComment: Consider it temporary, no instance script made for this instance yet. +SD%Complete: 100 +SDComment: SDCategory: Zul'Farrak EndScriptData */ /* ContentData -npc_sergeant_bly -npc_weegli_blastfuse +event_go_zulfarrak_gong +event_spell_unlocking +at_zulfarrak EndContentData */ #include "precompiled.h" #include "zulfarrak.h" /*###### -## npc_sergeant_bly +## event_go_zulfarrak_gong ######*/ -enum +bool ProcessEventId_event_go_zulfarrak_gong(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) { - FACTION_HOSTILE = 14, - FACTION_FRIENDLY = 35, - - SPELL_SHIELD_BASH = 11972, - SPELL_REVENGE = 12170 -}; -#define GOSSIP_BLY "That's it! I'm tired of helping you out. It's time we settled things on the battlefield!" - -//find Bly's gossip menus - -struct MANGOS_DLL_DECL npc_sergeant_blyAI : public ScriptedAI -{ - npc_sergeant_blyAI(Creature* pCreature) : ScriptedAI(pCreature) - { - //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - //ScriptedInstance* m_pInstance; - - uint32 m_uiShieldBashTimer; - uint32 m_uiRevengeTimer; //this is wrong, spell should never be used unless m_creature->getVictim() dodge, parry or block attack. Mangos support required. - - void Reset() - { - m_uiShieldBashTimer = 5000; - m_uiRevengeTimer = 8000; - - m_creature->setFaction(FACTION_FRIENDLY); - - /*if (m_pInstance) - m_pInstance->SetData(0, NOT_STARTED);*/ - } - - void Aggro(Unit* pWho) - { - /*if (m_pInstance) - m_pInstance->SetData(0, IN_PROGRESS);*/ - } - - void JustDied(Unit* pVictim) - { - /*if (m_pInstance) - m_pInstance->SetData(0, DONE);*/ - } - - void UpdateAI(const uint32 uiDiff) + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiShieldBashTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHIELD_BASH); - m_uiShieldBashTimer = 15000; - } - else - m_uiShieldBashTimer -= uiDiff; - - if (m_uiRevengeTimer < uiDiff) + if (instance_zulfarrak* pInstance = (instance_zulfarrak*)((Player*)pSource)->GetInstanceData()) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_REVENGE); - m_uiRevengeTimer = 10000; + if (pInstance->GetData(TYPE_GAHZRILLA) == NOT_STARTED || pInstance->GetData(TYPE_GAHZRILLA) == FAIL) + { + pInstance->SetData(TYPE_GAHZRILLA, IN_PROGRESS); + return false; // Summon Gahz'rilla by Database Script + } + else + return true; // Prevent DB script summoning Gahz'rilla } - else - m_uiRevengeTimer -= uiDiff; - - DoMeleeAttackIfReady(); } -}; - -CreatureAI* GetAI_npc_sergeant_bly(Creature* pCreature) -{ - return new npc_sergeant_blyAI(pCreature); -} - -bool GossipHello_npc_sergeant_bly(Player* pPlayer, Creature* pCreature) -{ - /*if (m_pInstance->GetData(0) == DONE) - {*/ - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_BLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(1517, pCreature->GetObjectGuid()); - /*} - else if (m_pInstance->GetData(0) == IN_PROGRESS) - pPlayer->SEND_GOSSIP_MENU(1516, pCreature->GetObjectGuid()); - else - pPlayer->SEND_GOSSIP_MENU(1515, pCreature->GetObjectGuid());*/ - - return true; -} - -bool GossipSelect_npc_sergeant_bly(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pCreature->setFaction(FACTION_HOSTILE); - pCreature->AI()->AttackStart(pPlayer); - } - return true; + return false; } /*###### -## npc_weegli_blastfuse +## event_spell_unlocking ######*/ -enum -{ - SPELL_BOMB = 8858, - SPELL_GOBLIN_LAND_MINE = 21688, - SPELL_SHOOT = 6660, - SPELL_WEEGLIS_BARREL = 10772 -}; - -#define GOSSIP_WEEGLI "[PH] Please blow up the door." - -struct MANGOS_DLL_DECL npc_weegli_blastfuseAI : public ScriptedAI -{ - npc_weegli_blastfuseAI(Creature* pCreature) : ScriptedAI(pCreature) - { - //m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - //ScriptedInstance* m_pInstance; - - void Reset() - { - /*if (m_pInstance) - m_pInstance->SetData(0, NOT_STARTED);*/ - } - - void Aggro(Unit* pWho) - { - /*if (m_pInstance) - m_pInstance->SetData(0, IN_PROGRESS);*/ - } - - void JustDied(Unit* pVictim) - { - /*if (m_pInstance) - m_pInstance->SetData(0, DONE);*/ - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_npc_weegli_blastfuse(Creature* pCreature) -{ - return new npc_weegli_blastfuseAI(pCreature); -} - -bool GossipHello_npc_weegli_blastfuse(Player* pPlayer, Creature* pCreature) -{ - //event not implemented yet, this is only placeholder for future developement - /*if (m_pInstance->GetData(0) == DONE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_WEEGLI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(1514, pCreature->GetObjectGuid());//if event can proceed to end - } - else if (m_pInstance->GetData(0) == IN_PROGRESS) - pPlayer->SEND_GOSSIP_MENU(1513, pCreature->GetObjectGuid());//if event are in progress - else*/ - pPlayer->SEND_GOSSIP_MENU(1511, pCreature->GetObjectGuid()); //if event not started - return true; -} - -bool GossipSelect_npc_weegli_blastfuse(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - //here we make him run to door, set the charge and run away off to nowhere - } - return true; -} - -bool ProcessEventId_event_go_zulfarrak_gong(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_spell_unlocking(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) { if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { if (instance_zulfarrak* pInstance = (instance_zulfarrak*)((Player*)pSource)->GetInstanceData()) { - if (pInstance->GetData(TYPE_GAHZRILLA) == NOT_STARTED || pInstance->GetData(TYPE_GAHZRILLA) == FAIL) + if (pInstance->GetData(TYPE_PYRAMID_EVENT) == NOT_STARTED) { - pInstance->SetData(TYPE_GAHZRILLA, IN_PROGRESS); - return false; // Summon Gahz'rilla by Database Script + pInstance->SetData(TYPE_PYRAMID_EVENT, IN_PROGRESS); + return false; // Summon pyramid trolls by Database Script } else - return true; // Prevent DB script summoning Gahz'rilla + return true; } } return false; } +/*###### +## at_zulfarrak +######*/ + bool AreaTrigger_at_zulfarrak(Player* pPlayer, AreaTriggerEntry const* pAt) { if (pAt->id == AREATRIGGER_ANTUSUL) @@ -266,22 +108,13 @@ void AddSC_zulfarrak() Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "npc_sergeant_bly"; - pNewScript->GetAI = &GetAI_npc_sergeant_bly; - pNewScript->pGossipHello = &GossipHello_npc_sergeant_bly; - pNewScript->pGossipSelect = &GossipSelect_npc_sergeant_bly; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_weegli_blastfuse"; - pNewScript->GetAI = &GetAI_npc_weegli_blastfuse; - pNewScript->pGossipHello = &GossipHello_npc_weegli_blastfuse; - pNewScript->pGossipSelect = &GossipSelect_npc_weegli_blastfuse; + pNewScript->Name = "event_go_zulfarrak_gong"; + pNewScript->pProcessEventId = &ProcessEventId_event_go_zulfarrak_gong; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "event_go_zulfarrak_gong"; - pNewScript->pProcessEventId = &ProcessEventId_event_go_zulfarrak_gong; + pNewScript->Name = "event_spell_unlocking"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_unlocking; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/kalimdor/zulfarrak/zulfarrak.h b/scripts/kalimdor/zulfarrak/zulfarrak.h index 16c3454b5..e017ed147 100644 --- a/scripts/kalimdor/zulfarrak/zulfarrak.h +++ b/scripts/kalimdor/zulfarrak/zulfarrak.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,7 +7,7 @@ enum { - MAX_ENCOUNTER = 8, + MAX_ENCOUNTER = 9, TYPE_VELRATHA = 0, TYPE_GAHZRILLA = 1, @@ -17,6 +17,7 @@ enum TYPE_NEKRUM = 5, TYPE_SEZZZIZ = 6, TYPE_CHIEF_SANDSCALP = 7, + TYPE_PYRAMID_EVENT = 8, NPC_VELRATHA = 7795, NPC_GAHZRILLA = 7273, @@ -27,32 +28,55 @@ enum NPC_SEZZZIZ = 7275, NPC_CHIEF_SANDSCALP = 7267, + NPC_SERGEANT_BLY = 7604, + NPC_SANDFURY_SLAVE = 7787, + NPC_SANDFURY_DRUDGE = 7788, + NPC_SANDFURY_CRETIN = 7789, + NPC_SANDFURY_ACOLYTE = 8876, + NPC_SANDFURY_ZEALOT = 8877, + + GO_SHALLOW_GRAVE = 128403, + GO_END_DOOR = 146084, + + // EVENT_ID_GONG_ZULFARRAK = 2488, // go 141832 + // EVENT_ID_UNLOCKING = 2609, // spell 10738 + AREATRIGGER_ANTUSUL = 1447, }; -class MANGOS_DLL_DECL instance_zulfarrak : public ScriptedInstance +class instance_zulfarrak : public ScriptedInstance { public: instance_zulfarrak(Map* pMap); ~instance_zulfarrak() {} - void Initialize(); + void Initialize() override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void GetShallowGravesGuidList(GuidList& lList) { lList = m_lShallowGravesGuidList; } - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + + GuidList m_lShallowGravesGuidList; + GuidList m_lPyramidTrollsGuidList; + + uint32 m_uiPyramidEventTimer; }; #endif diff --git a/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h b/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h index 5d950144d..2cb563e5b 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h +++ b/scripts/northrend/azjol-nerub/ahnkahet/ahnkahet.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -14,6 +14,7 @@ enum { MAX_ENCOUNTER = 5, + MAX_INITIATES = 15, TYPE_NADOX = 0, TYPE_TALDARAM = 1, @@ -21,52 +22,98 @@ enum TYPE_VOLAZJ = 3, TYPE_AMANITAR = 4, + DATA_INSANITY_PLAYER = 1, + GO_DOOR_TALDARAM = 192236, GO_ANCIENT_DEVICE_L = 193093, GO_ANCIENT_DEVICE_R = 193094, GO_VORTEX = 193564, NPC_ELDER_NADOX = 29309, + NPC_TALDARAM = 29308, + NPC_JEDOGA_SHADOWSEEKER = 29310, NPC_AHNKAHAR_GUARDIAN_EGG = 30173, NPC_AHNKAHAR_SWARM_EGG = 30172, - //NPC_JEDOGA_SHADOWSEEKER = 29310, + NPC_JEDOGA_CONTROLLER = 30181, + NPC_TWILIGHT_INITIATE = 30114, + + NPC_HERALD_VOLAZJ = 29311, + NPC_TWISTED_VISAGE_1 = 30621, + NPC_TWISTED_VISAGE_2 = 30622, + NPC_TWISTED_VISAGE_3 = 30623, + NPC_TWISTED_VISAGE_4 = 30624, + NPC_TWISTED_VISAGE_5 = 30625, + + SPELL_TWISTED_VISAGE_DEATH = 57555, + SPELL_INSANITY_SWITCH = 57538, + SPELL_INSANITY_CLEAR = 57558, + + SPELL_INSANITY_PHASE_16 = 57508, + SPELL_INSANITY_PHASE_32 = 57509, + SPELL_INSANITY_PHASE_64 = 57510, + SPELL_INSANITY_PHASE_128 = 57511, + SPELL_INSANITY_PHASE_256 = 57512, ACHIEV_START_VOLAZJ_ID = 20382, ACHIEV_CRIT_RESPECT_ELDERS = 7317, // Nadox, achiev 2038 + ACHIEV_CRIT_VOLUNTEER_WORK = 7359, // Jedoga, achiev 2056 }; -class MANGOS_DLL_DECL instance_ahnkahet : public ScriptedInstance +static const float aTaldaramLandingLoc[4] = {528.734f, -845.998f, 11.54f, 0.68f}; +static const float aJedogaLandingLoc[4] = {375.4977f, -707.3635f, -16.094f, 5.42f}; + +class instance_ahnkahet : public ScriptedInstance { public: instance_ahnkahet(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData64(uint32 uiType, uint64 uiGuid) override; ObjectGuid SelectRandomGuardianEggGuid(); ObjectGuid SelectRandomSwarmerEggGuid(); + ObjectGuid SelectJedogaSacrificeControllerGuid() { return m_jedogaSacrificeController; } - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + void GetJedogaControllersList(GuidList& lList) { lList = m_lJedogaControllersGuidList; } + void GetJedogaEventControllersList(GuidList& lList) {lList = m_lJedogaEventControllersGuidList; } - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: + void HandleInsanityClear(); + void HandleInsanitySwitch(Player* pPlayer); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; bool m_bRespectElders; + bool m_bVolunteerWork; uint8 m_uiDevicesActivated; + uint8 m_uiInitiatesKilled; + uint8 m_uiTwistedVisageCount; + + ObjectGuid m_jedogaSacrificeController; - GUIDList m_GuardianEggList; - GUIDList m_SwarmerEggList; + GuidList m_GuardianEggList; + GuidList m_SwarmerEggList; + GuidList m_lJedogaControllersGuidList; + GuidList m_lJedogaEventControllersGuidList; + GuidList m_lInsanityPlayersGuidList; }; #endif diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_amanitar.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_amanitar.cpp new file mode 100644 index 000000000..427b8f232 --- /dev/null +++ b/scripts/northrend/azjol-nerub/ahnkahet/boss_amanitar.cpp @@ -0,0 +1,227 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: Boss_Amanitar +SD%Complete: 80 +SDComment: Mushrooms summoning may need improvements; +SDCategory: Ahn'kahet +EndScriptData */ + +#include "precompiled.h" +#include "ahnkahet.h" + +enum +{ + SPELL_BASH = 57094, + SPELL_VENOM_BOLT_VOLLEY = 57088, + SPELL_ENTANGLING_ROOTS = 57095, + SPELL_MINI = 57055, + SPELL_REMOVE_MUSHROOM_POWER = 57283, // purpose unk - this spell may remove the Mini aura from all players + + // Mushroom entries + NPC_HEALTHY_MUSHROOM = 30391, + NPC_POISONOUS_MUSHROOM = 30435, + + // Mushroom spells + SPELL_POISON_CLOUD = 57061, + SPELL_POTENT_FUNGUS = 56648, + SPELL_POISON_MUSHROOM_VISUAL = 56741, + SPELL_POWER_MUSHROOM_VISUAL = 56740, + SPELL_MUSHROOM_FORM = 31690, +}; + +static const float aMushroomPos[3] = {362.8f, -869.16f, -75.03f}; + +/*###### +## boss_amanitar +######*/ + +struct boss_amanitarAI : public ScriptedAI +{ + boss_amanitarAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiBashTimer; + uint32 m_uiVenomBoltTimer; + uint32 m_uiRootsTimer; + uint32 m_uiMiniTimer; + uint32 m_uiMushroomTimer; + + void Reset() override + { + m_uiBashTimer = urand(7000, 10000); + m_uiVenomBoltTimer = urand(10000, 15000); + m_uiRootsTimer = 20000; + m_uiMiniTimer = urand(20000, 25000); + m_uiMushroomTimer = urand(10000, 20000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoSummonMushrooms(true); + + if (m_pInstance) + m_pInstance->SetData(TYPE_AMANITAR, IN_PROGRESS); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_AMANITAR, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_AMANITAR, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_POISONOUS_MUSHROOM) + pSummoned->CastSpell(pSummoned, SPELL_POISON_MUSHROOM_VISUAL, true); + else if (pSummoned->GetEntry() == NPC_HEALTHY_MUSHROOM) + pSummoned->CastSpell(pSummoned, SPELL_POWER_MUSHROOM_VISUAL, true); + + // ToDo: research if the mushrooms should have a grow effect! + pSummoned->CastSpell(pSummoned, SPELL_MUSHROOM_FORM, true); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_POISONOUS_MUSHROOM) + pSummoned->CastSpell(pSummoned, SPELL_POISON_CLOUD, true); + else if (pSummoned->GetEntry() == NPC_HEALTHY_MUSHROOM) + pSummoned->CastSpell(pSummoned, SPELL_POTENT_FUNGUS, true); + } + + void DoSummonMushrooms(bool bIsFirstSummon) + { + // This implementation may not be 100% accurate; + // On aggro boss summons about 20 mushrooms; On timer it summons about 5 mushrooms per turn + // There is a 33% chance that the mushroom will be healthy + // The summon position is based on the center of the area coords + + float fX, fY, fZ; + uint32 uiMaxMushrooms = bIsFirstSummon ? 20 : 5; + + for (uint8 i = 0; i < uiMaxMushrooms; ++i) + { + uint32 uiMushroomEntry = roll_chance_i(33) ? NPC_HEALTHY_MUSHROOM : NPC_POISONOUS_MUSHROOM; + m_creature->GetRandomPoint(aMushroomPos[0], aMushroomPos[1], aMushroomPos[2], 30.0f, fX, fY, fZ); + m_creature->SummonCreature(uiMushroomEntry, fX, fY, fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BASH) == CAST_OK) + m_uiBashTimer = urand(8000, 13000); + } + else + m_uiBashTimer -= uiDiff; + + if (m_uiVenomBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VENOM_BOLT_VOLLEY) == CAST_OK) + m_uiVenomBoltTimer = urand(15000, 20000); + } + else + m_uiVenomBoltTimer -= uiDiff; + + if (m_uiRootsTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ENTANGLING_ROOTS) == CAST_OK) + m_uiRootsTimer = urand(20000, 25000); + } + } + else + m_uiRootsTimer -= uiDiff; + + if (m_uiMiniTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MINI) == CAST_OK) + m_uiMiniTimer = 30000; + } + else + m_uiMiniTimer -= uiDiff; + + if (m_uiMushroomTimer < uiDiff) + { + DoSummonMushrooms(false); + m_uiMushroomTimer = urand(10000, 20000); + } + else + m_uiMushroomTimer -= uiDiff; + + // ToDo: Research if he requires out of combat area evade check + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_amanitar(Creature* pCreature) +{ + return new boss_amanitarAI(pCreature); +} + +/*###### +## npc_amanitar_mushroom +######*/ + +struct npc_amanitar_mushroomAI : public Scripted_NoMovementAI +{ + npc_amanitar_mushroomAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_amanitar_mushroom(Creature* pCreature) +{ + return new npc_amanitar_mushroomAI(pCreature); +} + +void AddSC_boss_amanitar() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_amanitar"; + pNewScript->GetAI = &GetAI_boss_amanitar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_amanitar_mushroom"; + pNewScript->GetAI = &GetAI_npc_amanitar_mushroom; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_jedoga.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_jedoga.cpp index b4326918d..5eeb62f4e 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/boss_jedoga.cpp +++ b/scripts/northrend/azjol-nerub/ahnkahet/boss_jedoga.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Jedoga -SD%Complete: 40 -SDComment: +SD%Complete: 90 +SDComment: The movement points for the volunteers are not 100% blizzlike. On retail they use hardcoded points SDCategory: Ahn'kahet EndScriptData */ @@ -46,74 +46,105 @@ enum SAY_VOLUNTEER_CHOOSEN = -1619031, // I have been choosen! SAY_VOLUNTEER_SACRIFICED = -1619032, // I give myself to the master! + SPELL_BEAM_VISUAL = 56312, + SPELL_SPHERE_VISUAL = 56075, // already included in creature_template_addon + SPELL_LIGHTNING_VISUAL = 56327, + SPELL_CYCLONE_STRIKE = 56855, SPELL_CYCLONE_STRIKE_H = 60030, SPELL_LIGHTNING_BOLT = 56891, SPELL_LIGHTNING_BOLT_H = 60032, SPELL_THUNDERSHOCK = 56926, SPELL_THUNDERSHOCK_H = 60029, - SPELL_GIFT_OF_THE_HERALD = 56219, + SPELL_HOVER_FALL = 56100, SPELL_SACRIFICE_VISUAL = 56133, SPELL_SACRIFICE_BEAM = 56150, + SPELL_VOLUNTEER_SPHERE = 56102, + SPELL_PILLAR_LIGHTNING = 56868, + + NPC_TWILIGHT_VOLUNTEER = 30385, - NPC_JEDOGA_CONTROLLER = 30181, - NPC_TWILIGHT_INITIATE = 30114, - NPC_TWILIGHT_VOLUNTEER = 30385 + MAX_VOLUNTEERS_PER_SIDE = 13, + + POINT_ID_PREPARE = 1, + POINT_ID_SACRIFICE = 2, + POINT_ID_LEVITATE = 3, + POINT_ID_COMBAT = 4, +}; + +static const float aVolunteerPosition[2][3] = +{ + {456.09f, -724.34f, -31.58f}, + {410.11f, -785.46f, -31.58f}, }; /*###### ## boss_jedoga ######*/ -struct MANGOS_DLL_DECL boss_jedogaAI : public ScriptedAI +struct boss_jedogaAI : public ScriptedAI { boss_jedogaAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_ahnkahet*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bHasDoneIntro = false; Reset(); } - ScriptedInstance* m_pInstance; + instance_ahnkahet* m_pInstance; bool m_bIsRegularMode; + uint32 m_uiVisualTimer; uint32 m_uiThundershockTimer; uint32 m_uiCycloneStrikeTimer; uint32 m_uiLightningBoltTimer; uint8 m_uiSacrificeCount; bool m_bSacrifice; + bool m_bIsSacrificing; + bool m_bHasDoneIntro; + + GuidList m_lVolunteerGuidList; - void Reset() + void Reset() override { m_uiThundershockTimer = 40000; m_uiCycloneStrikeTimer = 15000; m_uiLightningBoltTimer = 7000; + m_uiVisualTimer = 5000; m_bSacrifice = false; + m_bIsSacrificing = false; + + m_lVolunteerGuidList.clear(); + + SetCombatMovement(true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - Creature* SelectRandomCreatureOfEntryInRange(uint32 uiEntry, float fRange) + ObjectGuid SelectRandomVolunteer() { - std::list lCreatureList; - GetCreatureListWithEntryInGrid(lCreatureList, m_creature, uiEntry, fRange); + if (m_lVolunteerGuidList.empty()) + return ObjectGuid(); - if (lCreatureList.empty()) - return NULL; - - std::list::iterator iter = lCreatureList.begin(); - advance(iter, urand(0, lCreatureList.size()-1)); + GuidList::iterator iter = m_lVolunteerGuidList.begin(); + advance(iter, urand(0, m_lVolunteerGuidList.size() - 1)); return *iter; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + DoCallVolunteers(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_JEDOGA, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -121,20 +152,218 @@ struct MANGOS_DLL_DECL boss_jedogaAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_JEDOGA, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_JEDOGA, FAIL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasDoneIntro && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 110.0f) && m_creature->IsWithinLOSInMap(pWho)) + { + switch (urand(0, 4)) + { + case 0: DoScriptText(SAY_PREACHING1, m_creature); break; + case 1: DoScriptText(SAY_PREACHING2, m_creature); break; + case 2: DoScriptText(SAY_PREACHING3, m_creature); break; + case 3: DoScriptText(SAY_PREACHING4, m_creature); break; + case 4: DoScriptText(SAY_PREACHING5, m_creature); break; + } + m_bHasDoneIntro = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + // Helper function which summons all the Volunteers + void DoCallVolunteers() + { + // The volunteers should be summoned on the bottom of each stair in 2 lines - 7 in the front line and 6 in the back line + // However, because this would involve too many hardcoded coordinates we'll summon this on random point near the stairs + + float fX, fY, fZ; + for (uint8 j = 0; j < 2; ++j) + { + for (uint8 i = 0; i < MAX_VOLUNTEERS_PER_SIDE; ++i) + { + // In order to get a good movement position we need to handle the coordinates calculation here, inside the iteration. + m_creature->GetRandomPoint(aVolunteerPosition[j][0], aVolunteerPosition[j][1], aVolunteerPosition[j][2], 10.0f, fX, fY, fZ); + if (Creature* pVolunteer = m_creature->SummonCreature(NPC_TWILIGHT_VOLUNTEER, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + // Adjust coordinates based on the wave number and side + float fDist = i < 7 ? 20.0f : 30.0f; + float fAngle = 0; + if (!j) + fAngle = i < 7 ? (i - 2) * (3 * M_PI_F / 35) : (i - 6) * (M_PI_F / 16); + else + fAngle = i < 7 ? (i - 10) * (3 * M_PI_F / 35) : 3 * M_PI_F / 2 - (i - 6) * (M_PI_F / 16); + + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, fDist, fAngle); + pVolunteer->GetMotionMaster()->MovePoint(POINT_ID_PREPARE, fX, fY, fZ); + } + } + } + + // Summon one more Volunteer for the center position + m_creature->GetRandomPoint(aVolunteerPosition[0][0], aVolunteerPosition[0][1], aVolunteerPosition[0][2], 10.0f, fX, fY, fZ); + if (Creature* pVolunteer = m_creature->SummonCreature(NPC_TWILIGHT_VOLUNTEER, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 20.0f, 7 * M_PI_F / 4); + pVolunteer->GetMotionMaster()->MovePoint(POINT_ID_PREPARE, fX, fY, fZ); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_TWILIGHT_VOLUNTEER) + { + pSummoned->SetWalk(false); + pSummoned->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_6); + m_lVolunteerGuidList.push_back(pSummoned->GetObjectGuid()); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_TWILIGHT_VOLUNTEER) + { + m_lVolunteerGuidList.remove(pSummoned->GetObjectGuid()); + + if (m_pInstance) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(m_pInstance->SelectJedogaSacrificeControllerGuid())) + pTemp->RemoveAurasDueToSpell(SPELL_SACRIFICE_VISUAL); + } + + m_creature->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, aJedogaLandingLoc[0], aJedogaLandingLoc[1], aJedogaLandingLoc[2]); + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_TWILIGHT_VOLUNTEER) + return; + + if (uiPointId == POINT_ID_PREPARE) + { + pSummoned->CastSpell(pSummoned, SPELL_VOLUNTEER_SPHERE, true); + pSummoned->SetFacingToObject(m_creature); + pSummoned->SetStandState(UNIT_STAND_STATE_KNEEL); + } + else if (uiPointId == POINT_ID_SACRIFICE) + { + DoCastSpellIfCan(pSummoned, SPELL_SACRIFICE_BEAM); + DoScriptText(urand(0, 1) ? SAY_SACRIFICE1 : SAY_SACRIFICE2, m_creature); + } } - void UpdateAI(const uint32 uiDiff) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + // Prepare for combat + case POINT_ID_PREPARE: + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAurasDueToSpell(SPELL_LIGHTNING_VISUAL); + m_creature->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL); + m_creature->SetLevitate(false); + break; + + // Prepare for sacrifice lift off + case POINT_ID_SACRIFICE: + DoCastSpellIfCan(m_creature, SPELL_HOVER_FALL); + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_LEVITATE, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 10.0f); + break; + + // Call a volunteer to sacrifice + case POINT_ID_LEVITATE: + if (Creature* pVolunteer = m_creature->GetMap()->GetCreature(SelectRandomVolunteer())) + { + DoScriptText(urand(0, 1) ? SAY_CALL_SACRIFICE1 : SAY_CALL_SACRIFICE2, m_creature); + DoScriptText(SAY_VOLUNTEER_CHOOSEN, pVolunteer); + + pVolunteer->RemoveAurasDueToSpell(SPELL_VOLUNTEER_SPHERE); + pVolunteer->SetStandState(UNIT_STAND_STATE_STAND); + pVolunteer->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pVolunteer->CastSpell(pVolunteer, SPELL_PILLAR_LIGHTNING, false); + pVolunteer->SetWalk(true); + pVolunteer->GetMotionMaster()->MovePoint(POINT_ID_SACRIFICE, aJedogaLandingLoc[0], aJedogaLandingLoc[1], aJedogaLandingLoc[2]); + } + + // Set visual aura + if (m_pInstance) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(m_pInstance->SelectJedogaSacrificeControllerGuid())) + pTemp->CastSpell(pTemp, SPELL_SACRIFICE_VISUAL, false); + } + break; + + // Resume combat + case POINT_ID_COMBAT: + m_creature->RemoveAurasDueToSpell(SPELL_HOVER_FALL); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_bIsSacrificing = false; + SetCombatMovement(true); + m_creature->SetLevitate(false); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiVisualTimer) + { + if (m_uiVisualTimer <= uiDiff) + { + GuidList lControllersList; + if (m_pInstance) + m_pInstance->GetJedogaEventControllersList(lControllersList); + + for (GuidList::const_iterator itr = lControllersList.begin(); itr != lControllersList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->CastSpell(m_creature, SPELL_BEAM_VISUAL, false); + } + + if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_VISUAL) == CAST_OK) + m_uiVisualTimer = 0; + } + else + m_uiVisualTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Don't use abilities while sacrificing + if (m_bIsSacrificing) + return; + + // Note: this was changed in 3.3.2 and now it does this only once if (m_creature->GetHealthPercent() < 50.0f && !m_bSacrifice) { - // start sacrifice here + SetCombatMovement(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_SACRIFICE, aJedogaLandingLoc[0], aJedogaLandingLoc[1], aJedogaLandingLoc[2]); m_bSacrifice = true; + m_bIsSacrificing = true; } if (m_uiThundershockTimer < uiDiff) @@ -174,6 +403,58 @@ CreatureAI* GetAI_boss_jedoga(Creature* pCreature) return new boss_jedogaAI(pCreature); } +/*###### +## npc_twilight_volunteer +######*/ + +struct npc_twilight_volunteerAI : public Scripted_NoMovementAI +{ + npc_twilight_volunteerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() override { } + + void JustDied(Unit* pKiller) override + { + // If it's not killed by Jedoga then set the achiev to fail + if (pKiller->GetEntry() == NPC_JEDOGA_SHADOWSEEKER) + return; + + if (m_pInstance) + m_pInstance->SetData(TYPE_JEDOGA, SPECIAL); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_twilight_volunteer(Creature* pCreature) +{ + return new npc_twilight_volunteerAI(pCreature); +} + +bool EffectAuraDummy_spell_aura_dummy_sacrifice_beam(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_SACRIFICE_BEAM && pAura->GetEffIndex() == EFFECT_INDEX_0 && !bApply) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + if (ScriptedInstance* pInstance = (ScriptedInstance*)pTarget->GetInstanceData()) + { + if (Creature* pJedoga = pInstance->GetSingleCreatureFromStorage(NPC_JEDOGA_SHADOWSEEKER)) + pJedoga->DealDamage(pTarget, pTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + } + return true; +} + void AddSC_boss_jedoga() { Script* pNewScript; @@ -182,4 +463,10 @@ void AddSC_boss_jedoga() pNewScript->Name = "boss_jedoga"; pNewScript->GetAI = &GetAI_boss_jedoga; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_twilight_volunteer"; + pNewScript->GetAI = &GetAI_npc_twilight_volunteer; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_sacrifice_beam; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_nadox.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_nadox.cpp index 9609528c8..d0d6b5d8e 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/boss_nadox.cpp +++ b/scripts/northrend/azjol-nerub/ahnkahet/boss_nadox.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -53,7 +53,7 @@ enum /*###### ## mob_ahnkahat_egg ######*/ -struct MANGOS_DLL_DECL mob_ahnkahar_eggAI : public ScriptedAI +struct mob_ahnkahar_eggAI : public ScriptedAI { mob_ahnkahar_eggAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -63,11 +63,11 @@ struct MANGOS_DLL_DECL mob_ahnkahar_eggAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() {} - void MoveInLineOfSight(Unit* pWho) {} - void AttackStart(Unit* pWho) {} + void Reset() override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void AttackStart(Unit* /*pWho*/) override {} - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_AHNKAHAR_GUARDIAN) { @@ -87,7 +87,7 @@ struct MANGOS_DLL_DECL mob_ahnkahar_eggAI : public ScriptedAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { // If the Guardian is killed set the achiev criteria to false if (pSummoned->GetEntry() == NPC_AHNKAHAR_GUARDIAN) @@ -107,7 +107,7 @@ CreatureAI* GetAI_mob_ahnkahar_egg(Creature* pCreature) ## boss_nadox ######*/ -struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI +struct boss_nadoxAI : public ScriptedAI { boss_nadoxAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -125,7 +125,7 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI uint32 m_uiBroodRageTimer; uint32 m_uiSummonTimer; - void Reset() + void Reset() override { m_bBerserk = false; m_bGuardianSummoned = false; @@ -134,7 +134,7 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI m_uiBroodRageTimer = 20000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -142,15 +142,15 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI m_pInstance->SetData(TYPE_NADOX, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NADOX, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -158,7 +158,7 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -166,7 +166,7 @@ struct MANGOS_DLL_DECL boss_nadoxAI : public ScriptedAI m_pInstance->SetData(TYPE_NADOX, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp index 49bb951b5..a1fda47c8 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp +++ b/scripts/northrend/azjol-nerub/ahnkahet/boss_taldaram.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Taldaram -SD%Complete: 20% -SDComment: +SD%Complete: 90% +SDComment: Timers; SDCategory: Ahn'kahet EndScriptData */ @@ -34,37 +34,79 @@ enum SAY_SLAY_1 = -1619013, SAY_SLAY_2 = -1619014, SAY_SLAY_3 = -1619015, - SAY_DEATH = -1619016 + SAY_DEATH = -1619016, + + SPELL_BEAM_VISUAL = 60342, // Visual spell, used before Taltaram is lowered to the ground + SPELL_CONJURE_FLAME_SPHERE = 55931, + SPELL_FLAME_SPHERE_SUMMON_1 = 55895, // summons 30106 + SPELL_FLAME_SPHERE_SUMMON_2 = 59511, // summons 31686 + SPELL_FLAME_SPHERE_SUMMON_3 = 59512, // summons 31687 + SPELL_BLOODTHIRST = 55968, + SPELL_VANISH = 55964, + SPELL_EMBRACE_OF_THE_VAMPYR = 55959, + SPELL_EMBRACE_OF_THE_VAMPYR_H = 59513, + + // Spells used by the Flame Sphere + SPELL_FLAME_SPHERE_PERIODIC = 55926, + SPELL_FLAME_SPHERE_PERIODIC_H = 59508, + SPELL_FLAME_SPHERE_SPAWN_EFFECT = 55891, + SPELL_FLAME_SPHERE_VISUAL = 55928, + SPELL_FLAME_SPHERE_DEATH_EFFECT = 55947, }; /*###### ## boss_taldaram ######*/ -struct MANGOS_DLL_DECL boss_taldaramAI : public ScriptedAI +struct boss_taldaramAI : public ScriptedAI { boss_taldaramAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_ahnkahet*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + // Don't set the visual timers if the devices are already activated (reload case) + m_uiVisualTimer = m_pInstance->GetData(TYPE_TALDARAM) == SPECIAL ? 0 : 1000; Reset(); } - ScriptedInstance* m_pInstance; + instance_ahnkahet* m_pInstance; bool m_bIsRegularMode; - void Reset() + bool m_bIsFirstAggro; + uint32 m_uiVisualTimer; + uint32 m_uiBloodthirstTimer; + uint32 m_uiFlameOrbTimer; + uint32 m_uiVanishTimer; + uint32 m_uiEmbraceTimer; + + GuidList m_lFlameOrbsGuidList; + + void Reset() override { + // Timers seem to be very random... + m_uiBloodthirstTimer = urand(20000, 25000); + m_uiFlameOrbTimer = urand(15000, 20000); + m_uiVanishTimer = 0; + m_uiEmbraceTimer = 0; + m_bIsFirstAggro = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { + // Aggro is called after the boss vanish expires. There is no need to call this multiple times + if (m_bIsFirstAggro) + return; + DoScriptText(SAY_AGGRO, m_creature); + m_bIsFirstAggro = true; + + if (m_pInstance) + m_pInstance->SetData(TYPE_TALDARAM, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -72,7 +114,7 @@ struct MANGOS_DLL_DECL boss_taldaramAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -80,11 +122,167 @@ struct MANGOS_DLL_DECL boss_taldaramAI : public ScriptedAI m_pInstance->SetData(TYPE_TALDARAM, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_TALDARAM, FAIL); + } + + void EnterEvadeMode() override + { + // Don't allow him to evade during vanish + if (m_uiEmbraceTimer) + return; + + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + // should evade on the ground + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(1, aTaldaramLandingLoc[0], aTaldaramLandingLoc[1], aTaldaramLandingLoc[2]); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + // Adjust orientation + if (uiPointId) + { + m_creature->SetLevitate(false); + m_creature->SetFacingTo(aTaldaramLandingLoc[3]); + } + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->CastSpell(pSummoned, SPELL_FLAME_SPHERE_SPAWN_EFFECT, true); + pSummoned->CastSpell(pSummoned, SPELL_FLAME_SPHERE_VISUAL, true); + + m_lFlameOrbsGuidList.push_back(pSummoned->GetObjectGuid()); + } + + void SummonedCreatureDespawn(Creature* pSummoned) override + { + pSummoned->CastSpell(pSummoned, SPELL_FLAME_SPHERE_DEATH_EFFECT, true); + } + + // Wrapper which sends each sphere in a different direction + void DoSetSpheresInMotion() + { + float fX, fY; + uint8 uiIndex = m_bIsRegularMode ? urand(0, 2) : 0; + for (GuidList::const_iterator itr = m_lFlameOrbsGuidList.begin(); itr != m_lFlameOrbsGuidList.end(); ++itr) + { + if (Creature* pOrb = m_creature->GetMap()->GetCreature(*itr)) + { + pOrb->CastSpell(pOrb, m_bIsRegularMode ? SPELL_FLAME_SPHERE_PERIODIC : SPELL_FLAME_SPHERE_PERIODIC_H, true); + + pOrb->GetNearPoint2D(fX, fY, 70.0f, (2 * M_PI_F / 3)*uiIndex); + pOrb->GetMotionMaster()->MovePoint(0, fX, fY, pOrb->GetPositionZ()); + } + ++uiIndex; + } + } + + void UpdateAI(const uint32 uiDiff) override { + if (m_uiVisualTimer) + { + if (m_uiVisualTimer <= uiDiff) + { + GuidList lControllersList; + if (m_pInstance) + m_pInstance->GetJedogaControllersList(lControllersList); + + for (GuidList::const_iterator itr = lControllersList.begin(); itr != lControllersList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->CastSpell(m_creature, SPELL_BEAM_VISUAL, false); + } + m_uiVisualTimer = 0; + } + else + m_uiVisualTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Cast Embrace of the Vampyr after Vanish expires - note: because of the invisibility effect, the timers won't decrease during vanish + if (m_uiEmbraceTimer) + { + if (m_uiEmbraceTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_EMBRACE_OF_THE_VAMPYR : SPELL_EMBRACE_OF_THE_VAMPYR_H) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_FEED_1 : SAY_FEED_2, m_creature); + m_uiEmbraceTimer = 0; + } + } + } + else + m_uiEmbraceTimer -= uiDiff; + + // do not use other abilities during vanish + return; + } + + if (m_uiVanishTimer) + { + if (m_uiVanishTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VANISH) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_VANISH_1 : SAY_VANISH_2, m_creature); + m_uiVanishTimer = 0; + m_uiEmbraceTimer = 2000; + } + } + else + m_uiVanishTimer -= uiDiff; + } + + if (m_uiBloodthirstTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLOODTHIRST) == CAST_OK) + m_uiBloodthirstTimer = urand(20000, 25000); + } + else + m_uiBloodthirstTimer -= uiDiff; + + if (m_uiFlameOrbTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CONJURE_FLAME_SPHERE) == CAST_OK) + { + m_lFlameOrbsGuidList.clear(); + + // Flame speres are summoned above the boss + m_creature->CastSpell(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 5.0f, SPELL_FLAME_SPHERE_SUMMON_1, true); + + // 2 more spheres on heroic + if (!m_bIsRegularMode) + { + m_creature->CastSpell(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 5.0f, SPELL_FLAME_SPHERE_SUMMON_2, true); + m_creature->CastSpell(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 5.0f, SPELL_FLAME_SPHERE_SUMMON_3, true); + } + + m_uiFlameOrbTimer = urand(50000, 60000); + m_uiVanishTimer = 12000; + } + } + else + m_uiFlameOrbTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -94,19 +292,37 @@ CreatureAI* GetAI_boss_taldaram(Creature* pCreature) return new boss_taldaramAI(pCreature); } +bool EffectDummyCreature_spell_conjure_flame_orbs(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_CONJURE_FLAME_SPHERE && uiEffIndex == EFFECT_INDEX_0) + { + if (boss_taldaramAI* pBossAI = dynamic_cast(pCreatureTarget->AI())) + pBossAI->DoSetSpheresInMotion(); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + /*###### ## go_nerubian_device ######*/ -bool GOUse_go_nerubian_device(Player* pPlayer, GameObject* pGo) +bool GOUse_go_nerubian_device(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); if (!pInstance) return false; + // Don't allow players to use the devices if encounter is already finished or in progress (reload case) + if (pInstance->GetData(TYPE_TALDARAM) == SPECIAL || pInstance->GetData(TYPE_TALDARAM) == DONE) + return false; + pInstance->SetData(TYPE_TALDARAM, SPECIAL); - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); return false; } @@ -117,6 +333,7 @@ void AddSC_boss_taldaram() pNewScript = new Script; pNewScript->Name = "boss_taldaram"; pNewScript->GetAI = &GetAI_boss_taldaram; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_conjure_flame_orbs; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp b/scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp index 7d382617e..c825b7446 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp +++ b/scripts/northrend/azjol-nerub/ahnkahet/boss_volazj.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,6 +22,8 @@ SDCategory: Ahn'kahet EndScriptData */ #include "precompiled.h" +#include "ahnkahet.h" +#include "TemporarySummon.h" enum { @@ -40,28 +42,39 @@ enum SPELL_SHIVER = 57949, SPELL_SHIVER_H = 59978, + SPELL_WHISPER_AGGRO = 60291, + SPELL_WHISPER_INSANITY = 60292, + SPELL_WHISPER_SLAY_1 = 60293, + SPELL_WHISPER_SLAY_2 = 60294, + SPELL_WHISPER_SLAY_3 = 60295, + SPELL_WHISPER_DEATH_1 = 60296, + SPELL_WHISPER_DEATH_2 = 60297, + SPELL_INSANITY = 57496, // start insanity phasing - SPELL_INSANITY_CLEAR = 57558, // clear all insanity phasing - SPELL_WHISPER_INSANITY = 60292, // whisper insanity to players - - /* Some notes about the Insanity spell */ - /* - Related spells: - 57561 - visual effect - 57538 - switch insanity phase when a visage is killed - 57507 to 57512 - phasing spells for players - 59982 - summon twisted visage - script effect - 57500 to 57504 - summon twisted visage in each phase - 57506, 57507 - clone spells for the twisted visages - 57551, 57555 - visuals for twisted visages - */ + SPELL_INSANITY_VISUAL = 57561, + + SPELL_TWISTED_VISAGE_SPAWN = 57506, + SPELL_TWISTED_VISAGE_SPAWN_H = 59982, + SPELL_TWISTED_VISAGE_EFFECT = 57507, + SPELL_TWISTED_VISAGE_PASSIVE = 57551, + + SPELL_SUMMON_VISAGE_1 = 57500, + SPELL_SUMMON_VISAGE_2 = 57501, + SPELL_SUMMON_VISAGE_3 = 57502, + SPELL_SUMMON_VISAGE_4 = 57503, + SPELL_SUMMON_VISAGE_5 = 57504, + + MAX_INSANITY_SPELLS = 5, }; +static const uint32 aInsanityPhaseSpells[MAX_INSANITY_SPELLS] = {SPELL_INSANITY_PHASE_16, SPELL_INSANITY_PHASE_32, SPELL_INSANITY_PHASE_64, SPELL_INSANITY_PHASE_128, SPELL_INSANITY_PHASE_256}; +static const uint32 aSpawnVisageSpells[MAX_INSANITY_SPELLS] = {SPELL_SUMMON_VISAGE_1, SPELL_SUMMON_VISAGE_2, SPELL_SUMMON_VISAGE_3, SPELL_SUMMON_VISAGE_4, SPELL_SUMMON_VISAGE_5}; + /*###### ## boss_volazj ######*/ -struct MANGOS_DLL_DECL boss_volazjAI : public ScriptedAI +struct boss_volazjAI : public ScriptedAI { boss_volazjAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -78,50 +91,168 @@ struct MANGOS_DLL_DECL boss_volazjAI : public ScriptedAI uint32 m_uiShadowBoltTimer; uint32 m_uiShiverTimer; - void Reset() + uint8 m_uiInsanityIndex; + bool m_bIsInsanityInProgress; + + void Reset() override { - m_uiCombatPhase = 1; - m_uiMindFlayTimer = 10000; - m_uiShadowBoltTimer = 5000; - m_uiShiverTimer = 18000; + m_uiCombatPhase = 1; + m_uiMindFlayTimer = 10000; + m_uiShadowBoltTimer = 5000; + m_uiShiverTimer = 18000; + + m_uiInsanityIndex = 0; + m_bIsInsanityInProgress = false; + + SetCombatMovement(true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_AGGRO); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_VOLAZJ, IN_PROGRESS); + + // Start achievement only on first aggro + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_VOLAZJ_ID); + } + } + + void KilledUnit(Unit* /*pVictim*/) override + { + switch (urand(0, 2)) + { + case 0: + DoScriptText(SAY_SLAY_1, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_SLAY_1); + break; + case 1: + DoScriptText(SAY_SLAY_2, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_SLAY_2); + break; + case 2: + DoScriptText(SAY_SLAY_3, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_SLAY_3); + break; + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (urand(0, 1)) + { + DoScriptText(SAY_DEATH_1, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_DEATH_1, CAST_TRIGGERED); + } + else + { + DoScriptText(SAY_DEATH_2, m_creature); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_DEATH_2, CAST_TRIGGERED); + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLAZJ, DONE); + } + + void EnterEvadeMode() override + { + if (m_pInstance && m_pInstance->GetData(TYPE_VOLAZJ) == SPECIAL) + return; + + ScriptedAI::EnterEvadeMode(); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLAZJ, FAIL); } - void KilledUnit(Unit* pVictim) + void JustSummoned(Creature* pSummoned) override { - switch(urand(0, 2)) + pSummoned->CastSpell(pSummoned, SPELL_TWISTED_VISAGE_PASSIVE, true); + + if (pSummoned->IsTemporarySummon()) { - case 0: DoScriptText(SAY_SLAY_1, m_creature); break; - case 1: DoScriptText(SAY_SLAY_2, m_creature); break; - case 2: DoScriptText(SAY_SLAY_3, m_creature); break; + TemporarySummon* pTemporary = (TemporarySummon*)pSummoned; + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + { + pPlayer->CastSpell(pSummoned, SPELL_TWISTED_VISAGE_EFFECT, true); + pSummoned->CastSpell(pPlayer, m_bIsRegularMode ? SPELL_TWISTED_VISAGE_SPAWN : SPELL_TWISTED_VISAGE_SPAWN_H, true); + + pSummoned->AI()->AttackStart(pPlayer); + } } } - void JustDied(Unit* pKiller) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - DoScriptText(urand(0, 1) ? SAY_DEATH_1 : SAY_DEATH_2, m_creature); + if (pSpell->Id == SPELL_INSANITY && pTarget->GetTypeId() == TYPEID_PLAYER) + { + // Apply this only for the first target hit + if (!m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + { + DoCastSpellIfCan(m_creature, SPELL_INSANITY_VISUAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_WHISPER_INSANITY, CAST_TRIGGERED); + + DoScriptText(SAY_INSANITY, m_creature); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetCombatMovement(false); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VOLAZJ, SPECIAL); + + m_bIsInsanityInProgress = true; + } + + // Store the players in the instance, in order to better handle phasing + if (m_pInstance) + m_pInstance->SetData64(DATA_INSANITY_PLAYER, pTarget->GetObjectGuid()); + + // Phase and summon a Visage for each player + pTarget->CastSpell(pTarget, aInsanityPhaseSpells[m_uiInsanityIndex], true, 0, 0, m_creature->GetObjectGuid()); + pTarget->CastSpell(pTarget, aSpawnVisageSpells[m_uiInsanityIndex], true, 0, 0, m_creature->GetObjectGuid()); + ++m_uiInsanityIndex; + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - /* Note: Insanity is not yet implemented - this is just a placeholder - if (m_creature->GetHealthPercent() < 100 - m_uiCombatPhase*33) + // Check for Insanity + if (m_bIsInsanityInProgress) + { + if (!m_creature->HasAura(SPELL_INSANITY_VISUAL)) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetCombatMovement(true); + m_bIsInsanityInProgress = false; + } + + // No other actions during insanity + return; + } + + if (m_creature->GetHealthPercent() < 100.0f - (float)m_uiCombatPhase * 33.4f) { if (DoCastSpellIfCan(m_creature, SPELL_INSANITY) == CAST_OK) + { + m_uiInsanityIndex = 0; ++m_uiCombatPhase; + } } - */ if (m_uiMindFlayTimer < uiDiff) { - if (DoCastSpellIfCan (m_creature->getVictim(), m_bIsRegularMode ? SPELL_MIND_FLAY : SPELL_MIND_FLAY_H) == CAST_OK) + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MIND_FLAY : SPELL_MIND_FLAY_H) == CAST_OK) m_uiMindFlayTimer = urand(10000, 20000); } else diff --git a/scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp b/scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp index d900f497a..b7a3368fa 100644 --- a/scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp +++ b/scripts/northrend/azjol-nerub/ahnkahet/instance_ahnkahet.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,17 +16,21 @@ /* ScriptData SDName: instance_ahnkahet -SD%Complete: 0 +SD%Complete: 75 SDComment: SDCategory: Ahn'kahet EndScriptData */ #include "precompiled.h" #include "ahnkahet.h" +#include "TemporarySummon.h" instance_ahnkahet::instance_ahnkahet(Map* pMap) : ScriptedInstance(pMap), m_bRespectElders(false), - m_uiDevicesActivated(0) + m_bVolunteerWork(false), + m_uiDevicesActivated(0), + m_uiInitiatesKilled(0), + m_uiTwistedVisageCount(0) { Initialize(); } @@ -38,9 +42,12 @@ void instance_ahnkahet::Initialize() void instance_ahnkahet::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ELDER_NADOX: + case NPC_TALDARAM: + case NPC_JEDOGA_SHADOWSEEKER: + case NPC_HERALD_VOLAZJ: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; case NPC_AHNKAHAR_GUARDIAN_EGG: @@ -49,30 +56,46 @@ void instance_ahnkahet::OnCreatureCreate(Creature* pCreature) case NPC_AHNKAHAR_SWARM_EGG: m_SwarmerEggList.push_back(pCreature->GetObjectGuid()); break; + case NPC_JEDOGA_CONTROLLER: + // Sort the controllers based on their purpose + if (pCreature->GetPositionZ() > 30.0f) + // Used for Taldaram visual + m_lJedogaControllersGuidList.push_back(pCreature->GetObjectGuid()); + else if (pCreature->GetPositionZ() > 20.0f) + // Used for Jedoga visual + m_lJedogaEventControllersGuidList.push_back(pCreature->GetObjectGuid()); + else if (pCreature->GetPositionZ() < -16.0f) + // Used for Jedoga sacrifice + m_jedogaSacrificeController = pCreature->GetObjectGuid(); + break; + case NPC_TWISTED_VISAGE_1: + case NPC_TWISTED_VISAGE_2: + case NPC_TWISTED_VISAGE_3: + case NPC_TWISTED_VISAGE_4: + case NPC_TWISTED_VISAGE_5: + ++m_uiTwistedVisageCount; + break; } } void instance_ahnkahet::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_DOOR_TALDARAM: if (m_auiEncounter[TYPE_TALDARAM] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_VORTEX: - if (m_auiEncounter[TYPE_TALDARAM] != NOT_STARTED) + if (m_auiEncounter[TYPE_TALDARAM] == SPECIAL) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_ANCIENT_DEVICE_L: - if (m_auiEncounter[TYPE_TALDARAM] == NOT_STARTED) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); - return; case GO_ANCIENT_DEVICE_R: - if (m_auiEncounter[TYPE_TALDARAM] == NOT_STARTED) + if (m_auiEncounter[TYPE_NADOX] == DONE) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); - return; + break; default: return; @@ -84,55 +107,82 @@ void instance_ahnkahet::SetData(uint32 uiType, uint32 uiData) { debug_log("SD2: Instance Ahn'Kahet: SetData received for type %u with data %u", uiType, uiData); - switch(uiType) + switch (uiType) { case TYPE_NADOX: m_auiEncounter[uiType] = uiData; if (uiData == IN_PROGRESS) m_bRespectElders = true; - if (uiData == SPECIAL) + else if (uiData == SPECIAL) m_bRespectElders = false; + else if (uiData == DONE) + { + DoToggleGameObjectFlags(GO_ANCIENT_DEVICE_L, GO_FLAG_NO_INTERACT, false); + DoToggleGameObjectFlags(GO_ANCIENT_DEVICE_R, GO_FLAG_NO_INTERACT, false); + } break; case TYPE_TALDARAM: if (uiData == SPECIAL) { - if (m_uiDevicesActivated < 2) - ++m_uiDevicesActivated; + ++m_uiDevicesActivated; if (m_uiDevicesActivated == 2) { m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_VORTEX); + + // Lower Taldaram + if (Creature* pTaldaram = GetSingleCreatureFromStorage(NPC_TALDARAM)) + pTaldaram->GetMotionMaster()->MovePoint(1, aTaldaramLandingLoc[0], aTaldaramLandingLoc[1], aTaldaramLandingLoc[2]); + + // Interrupt the channeling + for (GuidList::const_iterator itr = m_lJedogaControllersGuidList.begin(); itr != m_lJedogaControllersGuidList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->InterruptNonMeleeSpells(false); + } } } - if (uiData == DONE) + else if (uiData == DONE) { m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_DOOR_TALDARAM); } break; case TYPE_JEDOGA: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + m_bVolunteerWork = true; + else if (uiData == SPECIAL) + m_bVolunteerWork = false; + else if (uiData == FAIL) + m_uiInitiatesKilled = 0; + break; case TYPE_AMANITAR: m_auiEncounter[uiType] = uiData; break; case TYPE_VOLAZJ: m_auiEncounter[uiType] = uiData; if (uiData == IN_PROGRESS) - DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_VOLAZJ_ID); + { + m_uiTwistedVisageCount = 0; + m_lInsanityPlayersGuidList.clear(); + } break; default: - error_log("SD2: Instance Ahn'Kahet: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Ahn'Kahet: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); break; } - if (uiData == DONE) + // For some encounters Special data needs to be saved + if (uiData == DONE || (uiData == SPECIAL && uiType == TYPE_TALDARAM)) { OUT_SAVE_INST_DATA; std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3] - << " " << m_auiEncounter[4]; + << " " << m_auiEncounter[4]; m_strInstData = saveStream.str(); @@ -141,13 +191,120 @@ void instance_ahnkahet::SetData(uint32 uiType, uint32 uiData) } } +void instance_ahnkahet::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_TWILIGHT_INITIATE: + ++m_uiInitiatesKilled; + + // If all initiates are killed, then land Jedoga and stop the channeling + if (m_uiInitiatesKilled == MAX_INITIATES) + { + if (Creature* pJedoga = GetSingleCreatureFromStorage(NPC_JEDOGA_SHADOWSEEKER)) + pJedoga->GetMotionMaster()->MovePoint(1, aJedogaLandingLoc[0], aJedogaLandingLoc[1], aJedogaLandingLoc[2]); + + for (GuidList::const_iterator itr = m_lJedogaEventControllersGuidList.begin(); itr != m_lJedogaEventControllersGuidList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->InterruptNonMeleeSpells(false); + } + } + + break; + case NPC_TWISTED_VISAGE_1: + case NPC_TWISTED_VISAGE_2: + case NPC_TWISTED_VISAGE_3: + case NPC_TWISTED_VISAGE_4: + case NPC_TWISTED_VISAGE_5: + pCreature->CastSpell(pCreature, SPELL_TWISTED_VISAGE_DEATH, true); + + --m_uiTwistedVisageCount; + + // When all Twisted Visages were killed or despawned switch back to combat phase + if (!m_uiTwistedVisageCount) + { + // Clear Insanity + if (Creature* pVolazj = GetSingleCreatureFromStorage(NPC_HERALD_VOLAZJ)) + { + pVolazj->CastSpell(pVolazj, SPELL_INSANITY_CLEAR, true); + pVolazj->RemoveAllAuras(); + } + + // Clear insanity manually for now, because the spell won't hit phased players + HandleInsanityClear(); + + SetData(TYPE_VOLAZJ, IN_PROGRESS); + } + else + { + // Switch Insanity + if (Creature* pVolazj = GetSingleCreatureFromStorage(NPC_HERALD_VOLAZJ)) + pVolazj->CastSpell(pVolazj, SPELL_INSANITY_SWITCH, true); + + // Handle insanity switch manually, because the boss can't hit phased players + if (pCreature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)pCreature; + + // Switch insanity phase for the master player + if (Player* pPlayer = instance->GetPlayer(pTemporary->GetSummonerGuid())) + HandleInsanitySwitch(pPlayer); + } + } + break; + } +} + +void instance_ahnkahet::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_TWISTED_VISAGE_1: + case NPC_TWISTED_VISAGE_2: + case NPC_TWISTED_VISAGE_3: + case NPC_TWISTED_VISAGE_4: + case NPC_TWISTED_VISAGE_5: + --m_uiTwistedVisageCount; + + // When all Twisted Visages were killed or despawned switch back to combat phase + if (!m_uiTwistedVisageCount) + { + // Clear Insanity + if (Creature* pVolazj = GetSingleCreatureFromStorage(NPC_HERALD_VOLAZJ)) + { + pVolazj->CastSpell(pVolazj, SPELL_INSANITY_CLEAR, true); + pVolazj->RemoveAllAuras(); + } + + // Clear insanity manually for now, because the spell won't hit phased players + HandleInsanityClear(); + + SetData(TYPE_VOLAZJ, IN_PROGRESS); + } + + pCreature->ForcedDespawn(); + break; + } +} + +void instance_ahnkahet::SetData64(uint32 uiData, uint64 uiGuid) +{ + // Store all the players hit by the insanity spell in order to use them for the phasing switch / clear + if (uiData == DATA_INSANITY_PLAYER) + { + if (Player* pPlayer = instance->GetPlayer(ObjectGuid(uiGuid))) + m_lInsanityPlayersGuidList.push_back(pPlayer->GetObjectGuid()); + } +} + ObjectGuid instance_ahnkahet::SelectRandomGuardianEggGuid() { if (m_GuardianEggList.empty()) return ObjectGuid(); - std::list::iterator iter = m_GuardianEggList.begin(); - advance(iter, urand(0, m_GuardianEggList.size()-1)); + GuidList::iterator iter = m_GuardianEggList.begin(); + advance(iter, urand(0, m_GuardianEggList.size() - 1)); return *iter; } @@ -157,18 +314,73 @@ ObjectGuid instance_ahnkahet::SelectRandomSwarmerEggGuid() if (m_SwarmerEggList.empty()) return ObjectGuid(); - std::list::iterator iter = m_SwarmerEggList.begin(); - advance(iter, urand(0, m_SwarmerEggList.size()-1)); + GuidList::iterator iter = m_SwarmerEggList.begin(); + advance(iter, urand(0, m_SwarmerEggList.size() - 1)); return *iter; } -bool instance_ahnkahet::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +void instance_ahnkahet::HandleInsanityClear() +{ + for (GuidList::const_iterator itr = m_lInsanityPlayersGuidList.begin(); itr != m_lInsanityPlayersGuidList.end(); ++itr) + { + if (Player* pPlayer = instance->GetPlayer(*itr)) + pPlayer->RemoveSpellsCausingAura(SPELL_AURA_PHASE); + } +} + +void instance_ahnkahet::HandleInsanitySwitch(Player* pPhasedPlayer) +{ + // Get the phase aura id + std::list lAuraList = pPhasedPlayer->GetAurasByType(SPELL_AURA_PHASE); + if (lAuraList.empty()) + return; + + uint32 uiPhaseAura = (*lAuraList.begin())->GetId(); + + std::list lSamePhasePlayers; + std::vector vOtherPhasePlayers; + + // Sort the insanity players, into those which have same phase and others + for (GuidList::const_iterator itr = m_lInsanityPlayersGuidList.begin(); itr != m_lInsanityPlayersGuidList.end(); ++itr) + { + if (Player* pTemp = instance->GetPlayer(*itr)) + { + if (pTemp->HasAura(uiPhaseAura)) + lSamePhasePlayers.push_back(pTemp); + // Check only for alive players + else if (pTemp->isAlive()) + vOtherPhasePlayers.push_back(pTemp); + } + } + + // This shouldn't happen + if (vOtherPhasePlayers.empty()) + return; + + // Get the phase aura of the new selected player + Player* pNewPlayer = vOtherPhasePlayers[urand(0, vOtherPhasePlayers.size() - 1)]; + + // Get the phase aura id + std::list lNewAuraList = pNewPlayer->GetAurasByType(SPELL_AURA_PHASE); + if (lNewAuraList.empty()) + return; + + uint32 uiNewPhaseAura = (*lNewAuraList.begin())->GetId(); + + // Move the same phase players to the new phase + for (std::list::const_iterator itr = lSamePhasePlayers.begin(); itr != lSamePhasePlayers.end(); ++itr) + (*itr)->CastSpell((*itr), uiNewPhaseAura, true); +} + +bool instance_ahnkahet::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { case ACHIEV_CRIT_RESPECT_ELDERS: return m_bRespectElders; + case ACHIEV_CRIT_VOLUNTEER_WORK: + return m_bVolunteerWork; default: return false; @@ -188,7 +400,7 @@ void instance_ahnkahet::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -197,7 +409,7 @@ void instance_ahnkahet::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_ahnkahet::GetData(uint32 uiType) +uint32 instance_ahnkahet::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; diff --git a/scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h b/scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h index f9e1f6559..96d10e26f 100644 --- a/scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h +++ b/scripts/northrend/azjol-nerub/azjol-nerub/azjol-nerub.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -14,6 +14,7 @@ enum TYPE_ANUBARAK = 2, NPC_KRIKTHIR = 28684, + NPC_HADRONOX = 28921, NPC_ANUBARAK = 29120, SAY_SEND_GROUP_1 = -1601004, @@ -23,51 +24,63 @@ enum NPC_GASHRA = 28730, NPC_NARJIL = 28729, NPC_SILTHIK = 28731, + NPC_ANUBAR_CRUSHER = 28922, NPC_WORLD_TRIGGER = 22515, + NPC_WORLD_TRIGGER_LARGE = 23472, GO_DOOR_KRIKTHIR = 192395, GO_DOOR_ANUBARAK_1 = 192396, GO_DOOR_ANUBARAK_2 = 192397, GO_DOOR_ANUBARAK_3 = 192398, + SAY_CRUSHER_AGGRO = -1601025, + SAY_CRUSHER_SPECIAL = -1601026, + ACHIEV_START_ANUB_ID = 20381, ACHIEV_CRITERIA_WATCH_DIE = 4240, // Krikthir, achiev 1296 + ACHIEV_CRITERIA_DENIED = 4244, // Hadronox, achiev 1297 }; static const uint32 aWatchers[] = {NPC_GASHRA, NPC_NARJIL, NPC_SILTHIK}; // Used to sort the summont triggers -static const int aSortDistance[4] = {-90, 10, 20, 30}; +static const int aSortDistance[4] = { -90, 10, 20, 30}; -class MANGOS_DLL_DECL instance_azjol_nerub : public ScriptedInstance +class instance_azjol_nerub : public ScriptedInstance { public: instance_azjol_nerub(Map* pMap); - void Initialize(); + void Initialize() override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; ObjectGuid GetRandomAssassinTrigger(); ObjectGuid GetGuardianTrigger() { return m_guardianSummonTarget; } ObjectGuid GetDarterTrigger() { return m_darterSummonTarget; } ObjectGuid GetAnubTrigger() { return m_anubSummonTarget; } - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void GetHadronoxTriggerList(GuidList& lList) { lList = m_lSpiderTriggersGuids; } + void ResetHadronoxTriggers(); + + void SetHadronoxDeniedAchievCriteria(bool bIsMet) { m_bHadronoxDenied = bIsMet; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; private: void DoSendWatcherOrKrikthir(); @@ -77,14 +90,22 @@ class MANGOS_DLL_DECL instance_azjol_nerub : public ScriptedInstance std::string m_strInstData; ObjectGuid m_playerGuid; + + // Hadronox triggers + GuidList m_lSpiderTriggersGuids; + + // Anub triggers ObjectGuid m_darterSummonTarget; ObjectGuid m_guardianSummonTarget; ObjectGuid m_anubSummonTarget; - GUIDVector m_vAssassinSummonTargetsVect; - GUIDList m_lTriggerGuids; + GuidVector m_vAssassinSummonTargetsVect; + GuidList m_lTriggerGuids; uint32 m_uiWatcherTimer; + uint32 m_uiGauntletEndTimer; bool m_bWatchHimDie; + bool m_bHadronoxDenied; + bool m_bGauntletStarted; }; #endif diff --git a/scripts/northrend/azjol-nerub/azjol-nerub/boss_anubarak.cpp b/scripts/northrend/azjol-nerub/azjol-nerub/boss_anubarak.cpp index 36c715923..44d0daa64 100644 --- a/scripts/northrend/azjol-nerub/azjol-nerub/boss_anubarak.cpp +++ b/scripts/northrend/azjol-nerub/azjol-nerub/boss_anubarak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -55,6 +55,11 @@ enum SPELL_SUMMON_VENOMANCER = 53615, // summons 29217 SPELL_SUMMON_DARTER = 53599, // summons 29213 + // impale spells + SPELL_IMPALE_VISUAL = 53455, + SPELL_IMPALE = 53454, + SPELL_IMPALE_H = 59446, + NPC_ANUBAR_DARTER = 29213, NPC_ANUBAR_ASSASSIN = 29214, NPC_ANUBAR_GUARDIAN = 29216, @@ -66,12 +71,11 @@ enum }; - /*###### ## boss_anubarak ######*/ -struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI +struct boss_anubarakAI : public ScriptedAI { boss_anubarakAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -96,7 +100,7 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI bool m_bIsFirstWave; bool m_bDoneIntro; - void Reset() + void Reset() override { m_uiPhase = PHASE_GROUND; m_uiSubmergePhase = 1; @@ -106,10 +110,10 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI m_uiPoundTimer = 15000; m_uiDarterTimer = 5000; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -117,9 +121,9 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI m_pInstance->SetData(TYPE_ANUBARAK, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -127,7 +131,7 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -135,13 +139,13 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI m_pInstance->SetData(TYPE_ANUBARAK, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ANUBARAK, NOT_STARTED); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bDoneIntro && m_creature->IsWithinDistInMap(pWho, 60.0f)) { @@ -152,7 +156,7 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (!m_pInstance) return; @@ -177,13 +181,14 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI } break; case NPC_IMPALE_TARGET: - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + pSummoned->CastSpell(pSummoned, SPELL_IMPALE_VISUAL, true); + break; + default: break; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -223,12 +228,12 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI else m_uiPoundTimer -= uiDiff; - if (m_creature->GetHealthPercent() < 100 - 25*m_uiSubmergePhase) + if (m_creature->GetHealthPercent() < 100 - 25 * m_uiSubmergePhase) { DoCastSpellIfCan(m_creature, SPELL_IMPALE_AURA, CAST_TRIGGERED); DoCastSpellIfCan(m_creature, SPELL_SUBMERGE, CAST_TRIGGERED); DoScriptText(urand(0, 1) ? SAY_SUBMERGE_1 : SAY_SUBMERGE_2, m_creature); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); m_uiPhase = PHASE_SUBMERGED; m_bIsFirstWave = true; m_uiSummonTimer = 5000; @@ -300,7 +305,7 @@ struct MANGOS_DLL_DECL boss_anubarakAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_EMERGE, CAST_INTERRUPT_PREVIOUS); m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); m_creature->RemoveAurasDueToSpell(SPELL_IMPALE_AURA); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); m_uiPhase = PHASE_GROUND; } else @@ -316,6 +321,61 @@ CreatureAI* GetAI_boss_anubarak(Creature* pCreature) return new boss_anubarakAI(pCreature); } +/*###### +## npc_impale_target +######*/ + +struct npc_impale_targetAI : public Scripted_NoMovementAI +{ + npc_impale_targetAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiImpaleTimer; + + void Reset() override + { + m_uiImpaleTimer = 3000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiImpaleTimer) + { + if (m_uiImpaleTimer <= uiDiff) + { + if (!m_pInstance) + return; + + m_creature->RemoveAurasDueToSpell(SPELL_IMPALE_VISUAL); + + // The impale is cast by Anub on the impale target + if (Creature* pAnub = m_pInstance->GetSingleCreatureFromStorage(NPC_ANUBARAK)) + pAnub->CastSpell(m_creature, m_bIsRegularMode ? SPELL_IMPALE : SPELL_IMPALE_H, true); + + m_creature->ForcedDespawn(3000); + m_uiImpaleTimer = 0; + } + else + m_uiImpaleTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_impale_target(Creature* pCreature) +{ + return new npc_impale_targetAI(pCreature); +} + void AddSC_boss_anubarak() { Script* pNewScript; @@ -324,4 +384,9 @@ void AddSC_boss_anubarak() pNewScript->Name = "boss_anubarak"; pNewScript->GetAI = &GetAI_boss_anubarak; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_impale_target"; + pNewScript->GetAI = &GetAI_npc_impale_target; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/azjol-nerub/azjol-nerub/boss_hadronox.cpp b/scripts/northrend/azjol-nerub/azjol-nerub/boss_hadronox.cpp index a6c84e805..fa3d6f54a 100644 --- a/scripts/northrend/azjol-nerub/azjol-nerub/boss_hadronox.cpp +++ b/scripts/northrend/azjol-nerub/azjol-nerub/boss_hadronox.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Hadronox -SD%Complete: 50% -SDComment: Only basic abilities. Gauntlet event NYI +SD%Complete: 90% +SDComment: Some details and timers can be improved. SDCategory: Azjol'Nerub EndScriptData */ @@ -26,6 +26,9 @@ EndScriptData */ enum { + EMOTE_MOVE_TUNNEL = -1601013, + + SPELL_TAUNT = 53799, SPELL_PIERCE_ARMOR = 53418, SPELL_ACID_CLOUD = 53400, SPELL_ACID_CLOUD_H = 59419, @@ -34,68 +37,203 @@ enum SPELL_WEB_GRAB = 57731, SPELL_WEB_GRAB_H = 59421, - // Gauntlet end spells - send events 19101 and 19102 - //SPELL_WEB_FRONT_DOORS = 53177, - //SPELL_WEB_SIDE_DOORS = 53185, - - // Gauntlet summoned npcs - //NPC_ANUBAR_CHAMPION_1 = 29062, - //NPC_ANUBAR_CRYPT_FIEND_1 = 29063, - //NPC_ANUBAR_NECROMANCER_1 = 29064, - //NPC_ANUBAR_CHAMPION_2 = 29096, - //NPC_ANUBAR_CRYPT_FIEND_2 = 29097, - //NPC_ANUBAR_NECROMANCER_2 = 29098, + // Gauntlet spells + SPELL_SUMMON_CHAMPION = 53035, + SPELL_SUMMON_NECROMANCER = 53036, + SPELL_SUMMON_CRYPT_FIEND = 53037, + SPELL_WEB_FRONT_DOORS = 53177, // sends event 19101 + SPELL_WEB_SIDE_DOORS = 53185, // sends event 19102 - it seems that this isn't actually used here + + MAX_SPIDERS = 9, }; - /* ##### Gauntlet description ##### - * This is the timed gauntlet - waves of non-elite spiders will spawn from the 3 doors located a little above the main room - * They will make their way down to fight Hadronox but she will head to the main room, fighting the spiders - * When Hadronox enters the main room, she will web the doors, and no more spiders will spawn. - */ +static const uint32 aSpiderEntries[MAX_SPIDERS] = {28924, 28925, 29051, 29062, 29063, 29064, 29096, 29097, 29098}; + +/* ##### Gauntlet description ##### + * This is the timed gauntlet - waves of non-elite spiders will spawn from the 3 doors located a little above the main room + * They will make their way down to fight Hadronox but she will head to the main room, fighting the spiders + * When Hadronox enters the main room, she will web the doors, and no more spiders will spawn. + */ /*###### ## boss_hadronox ######*/ -struct MANGOS_DLL_DECL boss_hadronoxAI : public ScriptedAI +struct boss_hadronoxAI : public ScriptedAI { boss_hadronoxAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_azjol_nerub*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_uiGauntletStartTimer = 1000; Reset(); } instance_azjol_nerub* m_pInstance; bool m_bIsRegularMode; + uint32 m_uiGauntletStartTimer; + uint32 m_uiAcidTimer; uint32 m_uiLeechTimer; uint32 m_uiPierceTimer; uint32 m_uiGrabTimer; + uint32 m_uiTauntTimer; - void Reset() + void Reset() override { m_uiAcidTimer = urand(10000, 14000); m_uiLeechTimer = urand(3000, 9000); m_uiPierceTimer = urand(1000, 3000); m_uiGrabTimer = urand(15000, 19000); + m_uiTauntTimer = urand(2000, 5000); } - void KilledUnit(Unit* pVictim) + void Aggro(Unit* pWho) override + { + if (pWho->GetTypeId() == TYPEID_PLAYER && m_pInstance) + m_pInstance->SetData(TYPE_HADRONOX, IN_PROGRESS); + } + + void AttackStart(Unit* pWho) override + { + // No more attacks during the movement upstairs + if ((m_pInstance && m_pInstance->GetData(TYPE_HADRONOX) == SPECIAL) && pWho->GetTypeId() != TYPEID_PLAYER) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // Force the spiders to attack him + if (pWho->GetTypeId() == TYPEID_UNIT && m_creature->IsWithinDistInMap(pWho, 2 * ATTACK_DISTANCE) && !pWho->getVictim()) + { + for (uint8 i = 0; i < MAX_SPIDERS; ++i) + { + if (pWho->GetEntry() == aSpiderEntries[i]) + ((Creature*)pWho)->AI()->AttackStart(m_creature); + } + } + + // No more attacks during the movement upstairs + if ((m_pInstance && m_pInstance->GetData(TYPE_HADRONOX) == SPECIAL) && pWho->GetTypeId() != TYPEID_PLAYER) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* /*pVictim*/) override { m_creature->SetHealth(m_creature->GetHealth() + (m_creature->GetMaxHealth() * 0.1)); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HADRONOX, DONE); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + Reset(); + + if (!m_creature->isAlive() || !m_pInstance) + return; + + // Moving upstairs, don't disturb + if (m_pInstance->GetData(TYPE_HADRONOX) == SPECIAL) + { + m_creature->GetMotionMaster()->MoveWaypoint(); + DoScriptText(EMOTE_MOVE_TUNNEL, m_creature); + } + // Stay upstairs if evade from players + else if (m_pInstance->GetData(TYPE_HADRONOX) == IN_PROGRESS) + m_creature->GetMotionMaster()->MovePoint(1, 530.42f, 560.003f, 733.0308f); + else + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { + // Mark as failed if evaded while upstairs + if (uiMoveType == POINT_MOTION_TYPE && uiPointId) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HADRONOX, FAIL); + } + // Web the doors when upstairs + else if (uiMoveType == WAYPOINT_MOTION_TYPE && uiPointId == 10) + { + if (DoCastSpellIfCan(m_creature, SPELL_WEB_FRONT_DOORS, CAST_TRIGGERED) == CAST_OK) + { + // These should be handled by the scripted event + if (m_pInstance) + { + m_pInstance->SetData(TYPE_HADRONOX, IN_PROGRESS); + m_pInstance->ResetHadronoxTriggers(); + m_pInstance->SetHadronoxDeniedAchievCriteria(false); + } + + // No more movement + m_creature->GetMotionMaster()->MoveIdle(); + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + // Allow the spawns to make a few steps so we can use move maps + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MoveWaypoint(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiGauntletStartTimer) + { + if (m_uiGauntletStartTimer <= uiDiff) + { + if (!m_pInstance) + { + script_error_log("Instance Azjol-Nerub: ERROR Failed to load instance data for this instace."); + return; + } + + GuidList m_lTriggersGuids; + m_pInstance->GetHadronoxTriggerList(m_lTriggersGuids); + + // Need to force the triggers to cast this with Hadronox Guid so we can control the summons better + for (GuidList::const_iterator itr = m_lTriggersGuids.begin(); itr != m_lTriggersGuids.end(); ++itr) + { + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(*itr)) + { + pTrigger->CastSpell(pTrigger, SPELL_SUMMON_CHAMPION, true, NULL, NULL, m_creature->GetObjectGuid()); + pTrigger->CastSpell(pTrigger, SPELL_SUMMON_NECROMANCER, true, NULL, NULL, m_creature->GetObjectGuid()); + pTrigger->CastSpell(pTrigger, SPELL_SUMMON_CRYPT_FIEND, true, NULL, NULL, m_creature->GetObjectGuid()); + } + } + + m_uiGauntletStartTimer = 0; + } + else + m_uiGauntletStartTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiPierceTimer < uiDiff) { - if(DoCastSpellIfCan(m_creature->getVictim(), SPELL_PIERCE_ARMOR) == CAST_OK) - m_uiPierceTimer = 8000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PIERCE_ARMOR) == CAST_OK) + m_uiPierceTimer = urand(8000, 15000); } else m_uiPierceTimer -= uiDiff; @@ -130,6 +268,17 @@ struct MANGOS_DLL_DECL boss_hadronoxAI : public ScriptedAI else m_uiGrabTimer -= uiDiff; + if (m_uiTauntTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_TAUNT) == CAST_OK) + m_uiTauntTimer = urand(7000, 14000); + } + } + else + m_uiTauntTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; diff --git a/scripts/northrend/azjol-nerub/azjol-nerub/boss_krikthir.cpp b/scripts/northrend/azjol-nerub/azjol-nerub/boss_krikthir.cpp index ede114568..f931fee5c 100644 --- a/scripts/northrend/azjol-nerub/azjol-nerub/boss_krikthir.cpp +++ b/scripts/northrend/azjol-nerub/azjol-nerub/boss_krikthir.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -53,7 +53,7 @@ enum ## boss_krikthir ######*/ -struct MANGOS_DLL_DECL boss_krikthirAI : public ScriptedAI +struct boss_krikthirAI : public ScriptedAI { boss_krikthirAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -72,7 +72,7 @@ struct MANGOS_DLL_DECL boss_krikthirAI : public ScriptedAI uint32 m_uiCurseTimer; uint32 m_uiMindFlayTimer; - void Reset() + void Reset() override { m_uiSwarmTimer = 15000; m_uiCurseTimer = 20000; @@ -82,14 +82,14 @@ struct MANGOS_DLL_DECL boss_krikthirAI : public ScriptedAI m_bFrenzy = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -97,11 +97,11 @@ struct MANGOS_DLL_DECL boss_krikthirAI : public ScriptedAI } } - void MoveInLineOfSight (Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bIntroSpeech && m_creature->IsWithinDistInMap(pWho, DEFAULT_VISIBILITY_INSTANCE)) + if (!m_bIntroSpeech && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, DEFAULT_VISIBILITY_INSTANCE) && m_creature->IsWithinLOSInMap(pWho)) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_PREFIGHT_1, m_creature); break; case 1: DoScriptText(SAY_PREFIGHT_2, m_creature); break; @@ -111,7 +111,7 @@ struct MANGOS_DLL_DECL boss_krikthirAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -119,48 +119,50 @@ struct MANGOS_DLL_DECL boss_krikthirAI : public ScriptedAI m_pInstance->SetData(TYPE_KRIKTHIR, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { uint32 uiEntry = pSummoned->GetEntry(); if (uiEntry == NPC_SKITTERING_SWARMER || uiEntry == NPC_SKITTERING_INFECTOR) pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!m_bFrenzy && m_creature->GetHealthPercent() <= 10.0f) { - DoCastSpellIfCan(m_creature, SPELL_FRENZY); - DoScriptText(EMOTE_BOSS_GENERIC_FRENZY, m_creature); - m_bFrenzy = true; + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(EMOTE_BOSS_GENERIC_FRENZY, m_creature); + m_bFrenzy = true; + } } if (m_uiCurseTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_CURSE_OF_FATIGUE : SPELL_CURSE_OF_FATIGUE_H); - m_uiCurseTimer = 20000; - + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_CURSE_OF_FATIGUE : SPELL_CURSE_OF_FATIGUE_H) == CAST_OK) + m_uiCurseTimer = 20000; } else m_uiCurseTimer -= uiDiff; if (m_uiMindFlayTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MINDFLAY : SPELL_MINDFLAY_H); - m_uiMindFlayTimer = 8000; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_MINDFLAY : SPELL_MINDFLAY_H) == CAST_OK) + m_uiMindFlayTimer = 8000; } else m_uiMindFlayTimer -= uiDiff; if (m_uiSwarmTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_SWARM_1 : SAY_SWARM_2, m_creature); - DoCastSpellIfCan(m_creature, SPELL_SWARM); - m_uiSwarmTimer = 15000; - + if (DoCastSpellIfCan(m_creature, SPELL_SWARM) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SWARM_1 : SAY_SWARM_2, m_creature); + m_uiSwarmTimer = 15000; + } } else m_uiSwarmTimer -= uiDiff; diff --git a/scripts/northrend/azjol-nerub/azjol-nerub/instance_azjol-nerub.cpp b/scripts/northrend/azjol-nerub/azjol-nerub/instance_azjol-nerub.cpp index bdc655fa3..4a6f7be9e 100644 --- a/scripts/northrend/azjol-nerub/azjol-nerub/instance_azjol-nerub.cpp +++ b/scripts/northrend/azjol-nerub/azjol-nerub/instance_azjol-nerub.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,8 +25,11 @@ EndScriptData */ #include "azjol-nerub.h" instance_azjol_nerub::instance_azjol_nerub(Map* pMap) : ScriptedInstance(pMap), + m_uiWatcherTimer(0), + m_uiGauntletEndTimer(0), m_bWatchHimDie(true), - m_uiWatcherTimer(0) + m_bHadronoxDenied(true), + m_bGauntletStarted(false) { Initialize(); } @@ -38,7 +41,7 @@ void instance_azjol_nerub::Initialize() void instance_azjol_nerub::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_DOOR_KRIKTHIR: if (m_auiEncounter[TYPE_KRIKTHIR] == DONE) @@ -57,18 +60,22 @@ void instance_azjol_nerub::OnObjectCreate(GameObject* pGo) void instance_azjol_nerub::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_KRIKTHIR: case NPC_GASHRA: case NPC_NARJIL: case NPC_SILTHIK: + case NPC_HADRONOX: case NPC_ANUBARAK: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; case NPC_WORLD_TRIGGER: m_lTriggerGuids.push_back(pCreature->GetObjectGuid()); break; + case NPC_WORLD_TRIGGER_LARGE: + m_lSpiderTriggersGuids.push_back(pCreature->GetObjectGuid()); + break; } } @@ -95,6 +102,32 @@ void instance_azjol_nerub::OnCreatureEnterCombat(Creature* pCreature) if (!m_playerGuid && pCreature->getVictim()) m_playerGuid = pCreature->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()->GetObjectGuid(); } + else if (uiEntry == NPC_ANUBAR_CRUSHER) + { + // Only for the first try + if (m_bGauntletStarted) + return; + + DoScriptText(SAY_CRUSHER_AGGRO, pCreature); + + // Spawn 2 more crushers - note these are not the exact spawn coords, but we need to use this workaround for better movement + if (Creature* pCrusher = pCreature->SummonCreature(NPC_ANUBAR_CRUSHER, 485.25f, 611.46f, 771.42f, 4.74f, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pCrusher->SetWalk(false); + pCrusher->GetMotionMaster()->MovePoint(0, 517.51f, 561.439f, 734.0306f); + pCrusher->HandleEmote(EMOTE_STATE_READYUNARMED); + } + if (Creature* pCrusher = pCreature->SummonCreature(NPC_ANUBAR_CRUSHER, 575.21f, 611.47f, 771.46f, 3.59f, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pCrusher->SetWalk(false); + pCrusher->GetMotionMaster()->MovePoint(0, 543.414f, 551.728f, 732.0522f); + pCrusher->HandleEmote(EMOTE_STATE_READYUNARMED); + } + + // Spawn 2 more crushers and start the countdown + m_uiGauntletEndTimer = 2 * MINUTE * IN_MILLISECONDS; + m_bGauntletStarted = true; + } } void instance_azjol_nerub::OnCreatureEvade(Creature* pCreature) @@ -116,6 +149,28 @@ void instance_azjol_nerub::Update(uint32 uiDiff) else m_uiWatcherTimer -= uiDiff; } + + if (m_uiGauntletEndTimer) + { + if (m_uiGauntletEndTimer <= uiDiff) + { + if (GetData(TYPE_HADRONOX) == IN_PROGRESS) + { + m_uiGauntletEndTimer = 0; + return; + } + + SetData(TYPE_HADRONOX, SPECIAL); + + // Allow him to evade - this will start the waypoint movement + if (Creature* pHadronox = GetSingleCreatureFromStorage(NPC_HADRONOX)) + pHadronox->AI()->EnterEvadeMode(); + + m_uiGauntletEndTimer = 0; + } + else + m_uiGauntletEndTimer -= uiDiff; + } } void instance_azjol_nerub::DoSendWatcherOrKrikthir() @@ -142,7 +197,7 @@ void instance_azjol_nerub::DoSendWatcherOrKrikthir() if (pAttacker) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SEND_GROUP_1, pKrikthir); break; case 1: DoScriptText(SAY_SEND_GROUP_2, pKrikthir); break; @@ -166,7 +221,7 @@ void instance_azjol_nerub::DoSortWorldTriggers() float fZ = pAnub->GetPositionZ(); float fTriggZ = 0; - for (GUIDList::const_iterator itr = m_lTriggerGuids.begin(); itr != m_lTriggerGuids.end(); ++itr) + for (GuidList::const_iterator itr = m_lTriggerGuids.begin(); itr != m_lTriggerGuids.end(); ++itr) { if (Creature* pTrigg = instance->GetCreature(*itr)) { @@ -197,14 +252,24 @@ ObjectGuid instance_azjol_nerub::GetRandomAssassinTrigger() { // Get a random summon target if (m_vAssassinSummonTargetsVect.size() > 0) - return m_vAssassinSummonTargetsVect[urand(0, m_vAssassinSummonTargetsVect.size() -1)]; + return m_vAssassinSummonTargetsVect[urand(0, m_vAssassinSummonTargetsVect.size() - 1)]; else return ObjectGuid(); } +void instance_azjol_nerub::ResetHadronoxTriggers() +{ + // Drop the summon auras from the triggers + for (GuidList::const_iterator itr = m_lSpiderTriggersGuids.begin(); itr != m_lSpiderTriggersGuids.end(); ++itr) + { + if (Creature* pTrigger = instance->GetCreature(*itr)) + pTrigger->RemoveAllAurasOnEvade(); + } +} + void instance_azjol_nerub::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_KRIKTHIR: m_auiEncounter[uiType] = uiData; @@ -213,6 +278,8 @@ void instance_azjol_nerub::SetData(uint32 uiType, uint32 uiData) break; case TYPE_HADRONOX: m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + ResetHadronoxTriggers(); break; case TYPE_ANUBARAK: m_auiEncounter[uiType] = uiData; @@ -241,12 +308,26 @@ void instance_azjol_nerub::SetData(uint32 uiType, uint32 uiData) } } -bool instance_azjol_nerub::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +uint32 instance_azjol_nerub::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +bool instance_azjol_nerub::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1*/ /* = 0*/) const { - if (uiCriteriaId == ACHIEV_CRITERIA_WATCH_DIE) - return m_bWatchHimDie; + switch (uiCriteriaId) + { + case ACHIEV_CRITERIA_WATCH_DIE: + return m_bWatchHimDie; + case ACHIEV_CRITERIA_DENIED: + return m_bHadronoxDenied; - return false; + default: + return false; + } } void instance_azjol_nerub::Load(const char* chrIn) @@ -262,7 +343,7 @@ void instance_azjol_nerub::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/northrend/borean_tundra.cpp b/scripts/northrend/borean_tundra.cpp index f47c41dbe..f133c80ce 100644 --- a/scripts/northrend/borean_tundra.cpp +++ b/scripts/northrend/borean_tundra.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,19 +17,25 @@ /* ScriptData SDName: Borean_Tundra SD%Complete: 100 -SDComment: Quest support: 11865, 11728, 11897, 11570 +SDComment: Quest support: 11570, 11590, 11673, 11728, 11865, 11889, 11897, 11919, 11940. SDCategory: Borean Tundra EndScriptData */ /* ContentData npc_nesingwary_trapper -go_caribou_trap npc_sinkhole_kill_credit npc_lurgglbr +npc_beryl_sorcerer +npc_captured_beryl_sorcerer +npc_nexus_drake_hatchling +npc_scourged_flamespitter +npc_bonker_togglevolt EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "TemporarySummon.h" +#include "follower_ai.h" /*###### ## npc_nesingwary_trapper @@ -46,7 +52,7 @@ enum SAY_PHRASE_4 = -1000602 }; -struct MANGOS_DLL_DECL npc_nesingwary_trapperAI : public ScriptedAI +struct npc_nesingwary_trapperAI : public ScriptedAI { npc_nesingwary_trapperAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -55,7 +61,7 @@ struct MANGOS_DLL_DECL npc_nesingwary_trapperAI : public ScriptedAI ObjectGuid m_playerGuid; ObjectGuid m_trapGuid; - void Reset() + void Reset() override { m_uiPhase = 0; m_uiPhaseTimer = 0; @@ -63,67 +69,96 @@ struct MANGOS_DLL_DECL npc_nesingwary_trapperAI : public ScriptedAI m_trapGuid.Clear(); } - void StartAction(Player* pPlayer, GameObject* pTrap) + void MoveInLineOfSight(Unit* pWho) override { - m_uiPhase = 1; - m_uiPhaseTimer = 3000; - m_playerGuid = pPlayer->GetObjectGuid(); - m_trapGuid = pTrap->GetObjectGuid(); + if (!m_uiPhase && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 20.0f)) + { + m_uiPhase = 1; + m_uiPhaseTimer = 1000; + m_playerGuid = pWho->GetObjectGuid(); + + if (m_creature->IsTemporarySummon()) + { + // Get the summoner trap + if (GameObject* pTrap = m_creature->GetMap()->GetGameObject(((TemporarySummon*)m_creature)->GetSummonerGuid())) + m_trapGuid = pTrap->GetObjectGuid(); + } + } - switch (urand(0, 3)) + ScriptedAI::MoveInLineOfSight(pWho); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (GameObject* pTrap = m_creature->GetMap()->GetGameObject(m_trapGuid)) { - case 0: DoScriptText(SAY_PHRASE_1, m_creature); break; - case 1: DoScriptText(SAY_PHRASE_2, m_creature); break; - case 2: DoScriptText(SAY_PHRASE_3, m_creature); break; - case 3: DoScriptText(SAY_PHRASE_4, m_creature); break; + // respawn the Quality Fur + if (GameObject* pGoFur = GetClosestGameObjectWithEntry(pTrap, GO_QUALITY_FUR, INTERACTION_DISTANCE)) + { + if (!pGoFur->isSpawned()) + { + pGoFur->SetRespawnTime(10); + pGoFur->Refresh(); + } + } } + + m_uiPhaseTimer = 2000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_creature->getVictim() && m_uiPhase) + if (!m_creature->getVictim() && m_uiPhaseTimer) { if (m_uiPhaseTimer <= uiDiff) { - switch(m_uiPhase) + switch (m_uiPhase) { case 1: if (GameObject* pTrap = m_creature->GetMap()->GetGameObject(m_trapGuid)) { - if (pTrap->isSpawned()) - m_creature->GetMotionMaster()->MovePoint(0, pTrap->GetPositionX(), pTrap->GetPositionY(), pTrap->GetPositionZ()); + float fX, fY, fZ; + pTrap->GetContactPoint(m_creature, fX, fY, fZ); + + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } + m_uiPhaseTimer = 0; break; case 2: + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_PHRASE_1, m_creature); break; + case 1: DoScriptText(SAY_PHRASE_2, m_creature); break; + case 2: DoScriptText(SAY_PHRASE_3, m_creature); break; + case 3: DoScriptText(SAY_PHRASE_4, m_creature); break; + } + m_creature->HandleEmote(EMOTE_ONESHOT_LOOT); + m_uiPhaseTimer = 3000; + break; + case 3: if (GameObject* pTrap = m_creature->GetMap()->GetGameObject(m_trapGuid)) { - if (pTrap->isSpawned()) - { - pTrap->Use(m_creature); + pTrap->Use(m_creature); - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) - { - if (pPlayer->isAlive()) - pPlayer->KilledMonsterCredit(m_creature->GetEntry()); - } + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + { + if (pPlayer->isAlive()) + pPlayer->KilledMonsterCredit(m_creature->GetEntry()); } } + m_uiPhaseTimer = 0; break; } - - m_uiPhase = 0; + ++m_uiPhase; } else m_uiPhaseTimer -= uiDiff; } } - - void MovementInform(uint32 uiType, uint32 uiPointId) - { - m_creature->HandleEmote(EMOTE_ONESHOT_LOOT); - m_uiPhaseTimer = 2000; - m_uiPhase = 2; - } }; CreatureAI* GetAI_npc_nesingwary_trapper(Creature* pCreature) @@ -147,20 +182,20 @@ enum POINT_DEST = 1 }; -struct MANGOS_DLL_DECL npc_oil_stained_wolfAI : public ScriptedAI +struct npc_oil_stained_wolfAI : public ScriptedAI { npc_oil_stained_wolfAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } bool m_bCanCrapInPublic; uint32 m_uiPooTimer; - void Reset() + void Reset() override { m_bCanCrapInPublic = false; m_uiPooTimer = 0; } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; @@ -172,7 +207,7 @@ struct MANGOS_DLL_DECL npc_oil_stained_wolfAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -209,7 +244,7 @@ CreatureAI* GetAI_npc_oil_stained_wolf(Creature* pCreature) return new npc_oil_stained_wolfAI(pCreature); } -bool EffectDummyCreature_npc_oil_stained_wolf(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_oil_stained_wolf(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiSpellId == SPELL_THROW_WOLF_BAIT) { @@ -244,7 +279,7 @@ bool EffectAuraDummy_npc_oil_stained_wolf(const Aura* pAura, bool bApply) else { Creature* pCreature = (Creature*)pAura->GetTarget(); - pCreature->setFaction(pCreature->GetCreatureInfo()->faction_A); + pCreature->setFaction(pCreature->GetCreatureInfo()->FactionAlliance); } return true; @@ -253,34 +288,6 @@ bool EffectAuraDummy_npc_oil_stained_wolf(const Aura* pAura, bool bApply) return false; } -/*###### -## go_caribou_trap -######*/ - -bool GOUse_go_caribou_trap(Player* pPlayer, GameObject* pGo) -{ - float fX, fY, fZ; - pGo->GetClosePoint(fX, fY, fZ, pGo->GetObjectBoundingRadius(), 2*INTERACTION_DISTANCE, frand(0, M_PI_F*2)); - - if (Creature* pCreature = pGo->SummonCreature(NPC_NESINGWARY_TRAPPER, fX, fY, fZ, pGo->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 10000)) - { - if (npc_nesingwary_trapperAI* pTrapperAI = dynamic_cast(pCreature->AI())) - pTrapperAI->StartAction(pPlayer, pGo); - - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); - - if (GameObject* pGoFur = GetClosestGameObjectWithEntry(pGo, GO_QUALITY_FUR, INTERACTION_DISTANCE)) - { - if (!pGoFur->isSpawned()) - { - pGoFur->SetRespawnTime(10); - pGoFur->Refresh(); - } - } - } - - return true; -} /*##### # npc_sinkhole_kill_credit #####*/ @@ -293,7 +300,7 @@ enum SPELL_CANNON_FIRE = 42445, }; -struct MANGOS_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI +struct npc_sinkhole_kill_creditAI : public ScriptedAI { npc_sinkhole_kill_creditAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -302,7 +309,7 @@ struct MANGOS_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI uint32 m_uiCartTimer; uint32 m_uiCartPhase; - void Reset() + void Reset() override { m_cartGuid.Clear(); m_wormGuid.Clear(); @@ -310,12 +317,12 @@ struct MANGOS_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI m_uiCartPhase = 0; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { m_wormGuid = pSummoned->GetObjectGuid(); } - void JustSummoned(GameObject* pGo) + void JustSummoned(GameObject* pGo) override { // Go is not really needed, but ok to use as a check point so only one "event" can be processed at a time if (m_cartGuid) @@ -325,13 +332,13 @@ struct MANGOS_DLL_DECL npc_sinkhole_kill_creditAI : public ScriptedAI m_cartGuid = pGo->GetObjectGuid(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_cartGuid) { if (m_uiCartTimer <= uiDiff) { - switch(m_uiCartPhase) + switch (m_uiCartPhase) { case 0: DoCastSpellIfCan(m_creature, SPELL_SUMMON_EXPLOSIVES_CART_FIRE); @@ -391,7 +398,7 @@ enum SAY_END_2 = -1000578 }; -struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI +struct npc_lurgglbrAI : public npc_escortAI { npc_lurgglbrAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -403,7 +410,7 @@ struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI uint32 m_uiSayTimer; uint8 m_uiSpeech; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -412,7 +419,7 @@ struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI } } - void JustStartedEscort() + void JustStartedEscort() override { if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_CAGE, INTERACTION_DISTANCE)) { @@ -421,9 +428,9 @@ struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI } } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 1: if (Player* pPlayer = GetPlayerForEscort()) @@ -435,9 +442,9 @@ struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: if (Player* pPlayer = GetPlayerForEscort()) @@ -456,7 +463,7 @@ struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -474,7 +481,7 @@ struct MANGOS_DLL_DECL npc_lurgglbrAI : public npc_escortAI m_creature->SetFacingToObject(pPlayer); - switch(m_uiSpeech) + switch (m_uiSpeech) { case 0: DoScriptText(SAY_END_2, m_creature, pPlayer); @@ -505,7 +512,7 @@ bool QuestAccept_npc_lurgglbr(Player* pPlayer, Creature* pCreature, const Quest* { if (npc_lurgglbrAI* pEscortAI = dynamic_cast(pCreature->AI())) { - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); pEscortAI->Start(false, pPlayer, pQuest); } } @@ -517,6 +524,525 @@ CreatureAI* GetAI_npc_lurgglbr(Creature* pCreature) return new npc_lurgglbrAI(pCreature); } +/*##### +# npc_beryl_sorcerer +#####*/ + +enum +{ + SPELL_ARCANE_CHAINS = 45611, + SPELL_ARCANE_CHAINS_CHANNEL = 45630, + SPELL_SUMMON_CHAINS_CHARACTER = 45625, // triggers 45626 + // SPELL_ENSLAVED_ARCANE_CHAINS = 45632, // chain visual - purpose unk, probably used on quest end + + NPC_BERYL_SORCERER = 25316, + NPC_CAPTURED_BERYL_SORCERER = 25474, +}; + +bool EffectAuraDummy_npc_beryl_sorcerer(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_ARCANE_CHAINS) + { + if (pAura->GetEffIndex() != EFFECT_INDEX_0 || !bApply) + return false; + + Creature* pCreature = (Creature*)pAura->GetTarget(); + Unit* pCaster = pAura->GetCaster(); + if (!pCreature || !pCaster || pCaster->GetTypeId() != TYPEID_PLAYER || pCreature->GetEntry() != NPC_BERYL_SORCERER) + return false; + + // only for wounded creatures + if (pCreature->GetHealthPercent() > 30.0f) + return false; + + // spawn the captured sorcerer, apply dummy aura on the summoned and despawn + pCaster->CastSpell(pCreature, SPELL_SUMMON_CHAINS_CHARACTER, true); + pCaster->CastSpell(pCaster, SPELL_ARCANE_CHAINS_CHANNEL, true); + pCreature->ForcedDespawn(); + return true; + } + + return false; +} + +/*##### +# npc_captured_beryl_sorcerer +#####*/ + +bool EffectAuraDummy_npc_captured_beryl_sorcerer(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_ARCANE_CHAINS_CHANNEL) + { + if (pAura->GetEffIndex() != EFFECT_INDEX_0 || !bApply) + return false; + + Creature* pCreature = (Creature*)pAura->GetTarget(); + Unit* pCaster = pAura->GetCaster(); + if (!pCreature || !pCaster || pCaster->GetTypeId() != TYPEID_PLAYER || pCreature->GetEntry() != NPC_CAPTURED_BERYL_SORCERER) + return false; + + // follow the caster + ((Player*)pCaster)->KilledMonsterCredit(NPC_CAPTURED_BERYL_SORCERER); + pCreature->GetMotionMaster()->MoveFollow(pCaster, pCreature->GetDistance(pCaster), M_PI_F - pCreature->GetAngle(pCaster)); + return true; + } + + return false; +} + +/*###### +## npc_nexus_drake_hatchling +######*/ + +enum +{ + // combat spells + SPELL_INTANGIBLE_PRESENCE = 36513, + SPELL_NETHERBREATH = 36631, + + // quest start spells + SPELL_DRAKE_HARPOON = 46607, // initial spell + SPELL_RED_DRAGONBLOOD = 46620, // applied by aura 46607 + SPELL_CAPTURE_TRIGGER = 46673, // notify the drake that it was captured; triggered by aura 46620 expire + SPELL_SUBDUED = 46675, // visual spell; triggered by spell 46673 + SPELL_DRAKE_HATCHLING_SUBDUED = 46691, // inform player that drake has been captured; triggered by spell 46673 + SPELL_DRAKE_VOMIT_PERIODIC = 46678, // visual spell; triggered by spell 46673 + + // quest completion spells + SPELL_DRAKE_TURN_IN = 46696, // notify the drake that quest is finised + SPELL_STRIP_AURAS = 46693, // remove all quest auras + SPELL_DRAKE_COMPLETION_PING = 46702, + SPELL_RAELORASZ_FIREBALL = 46704, + SPELL_COMPLETE_IMMOLATION = 46703, + + NPC_RAELORASZ = 26117, // quest giver / taker + NPC_NEXUS_DRAKE_HATCHLING = 26127, + NPC_COLDARRA_DRAKE_HUNT_INVISMAN = 26175, // quest credit + + QUEST_DRAKE_HUNT = 11919, + QUEST_DRAKE_HUNT_DAILY = 11940, + + FACTION_FRIENDLY = 35, +}; + +struct npc_nexus_drake_hatchlingAI : public FollowerAI +{ + npc_nexus_drake_hatchlingAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); } + + uint32 m_uiNetherbreathTimer; + uint32 m_uiPresenceTimer; + uint32 m_uiSubduedTimer; + + void Reset() override + { + m_uiNetherbreathTimer = urand(2000, 4000); + m_uiPresenceTimer = urand(15000, 17000); + m_uiSubduedTimer = 0; + } + + void EnterEvadeMode() override + { + // force check for evading when the faction is changed + if (m_uiSubduedTimer) + return; + + FollowerAI::EnterEvadeMode(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + FollowerAI::MoveInLineOfSight(pWho); + + if (!m_creature->HasAura(SPELL_SUBDUED) || m_creature->getVictim()) + return; + + if (pWho->GetEntry() == NPC_COLDARRA_DRAKE_HUNT_INVISMAN && m_creature->IsWithinDistInMap(pWho, 20.0f)) + { + Player* pPlayer = GetLeaderForFollower(); + if (!pPlayer || !pPlayer->HasAura(SPELL_DRAKE_HATCHLING_SUBDUED)) + return; + + pWho->CastSpell(pPlayer, SPELL_STRIP_AURAS, true); + + // give kill credit, mark the follow as completed and start the final event + pPlayer->KilledMonsterCredit(NPC_COLDARRA_DRAKE_HUNT_INVISMAN); + pPlayer->CastSpell(m_creature, SPELL_DRAKE_TURN_IN, true); + SetFollowComplete(true); + } + } + + void JustRespawned() override + { + // reset stand state if required + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + FollowerAI::JustRespawned(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // start following + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + StartFollow((Player*)pInvoker); + m_uiSubduedTimer = 3 * MINUTE * IN_MILLISECONDS; + } + // timeout; quest failed + else if (eventType == AI_EVENT_CUSTOM_A) + { + // check if the quest isn't already completed + if (!HasFollowState(STATE_FOLLOW_COMPLETE)) + { + // force reset + JustRespawned(); + ScriptedAI::EnterEvadeMode(); + } + } + } + + void UpdateFollowerAI(const uint32 uiDiff) + { + if (m_uiSubduedTimer) + { + if (m_uiSubduedTimer <= uiDiff) + m_uiSubduedTimer = 0; + else + m_uiSubduedTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiNetherbreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NETHERBREATH) == CAST_OK) + m_uiNetherbreathTimer = urand(17000, 20000); + } + else + m_uiNetherbreathTimer -= uiDiff; + + if (m_uiPresenceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INTANGIBLE_PRESENCE) == CAST_OK) + m_uiPresenceTimer = urand(18000, 20000); + } + else + m_uiPresenceTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_nexus_drake_hatchling(Creature* pCreature) +{ + return new npc_nexus_drake_hatchlingAI(pCreature); +} + +bool EffectAuraDummy_npc_nexus_drake_hatchling(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_DRAKE_HARPOON) + { + if (pAura->GetEffIndex() != EFFECT_INDEX_0 || !bApply) + return false; + + Creature* pCreature = (Creature*)pAura->GetTarget(); + Unit* pCaster = pAura->GetCaster(); + if (!pCreature || !pCaster || pCaster->GetTypeId() != TYPEID_PLAYER || pCreature->GetEntry() != NPC_NEXUS_DRAKE_HATCHLING) + return false; + + // check if drake is already doing the quest + if (pCreature->HasAura(SPELL_RED_DRAGONBLOOD) || pCreature->HasAura(SPELL_SUBDUED)) + return false; + + pCaster->CastSpell(pCreature, SPELL_RED_DRAGONBLOOD, true); + return true; + } + else if (pAura->GetId() == SPELL_RED_DRAGONBLOOD && pAura->GetEffIndex() == EFFECT_INDEX_0) + { + Creature* pCreature = (Creature*)pAura->GetTarget(); + Unit* pCaster = pAura->GetCaster(); + if (!pCreature || !pCaster || pCaster->GetTypeId() != TYPEID_PLAYER || pCreature->GetEntry() != NPC_NEXUS_DRAKE_HATCHLING) + return false; + + // start attacking on apply and capture on aura expire + if (bApply) + pCreature->AI()->AttackStart(pCaster); + else + pCaster->CastSpell(pCreature, SPELL_CAPTURE_TRIGGER, true); + + return true; + } + else if (pAura->GetId() == SPELL_SUBDUED && pAura->GetEffIndex() == EFFECT_INDEX_0 && !bApply) + { + Creature* pCreature = (Creature*)pAura->GetTarget(); + if (!pCreature || pCreature->GetEntry() != NPC_NEXUS_DRAKE_HATCHLING) + return false; + + // aura expired - evade + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCreature, pCreature); + return true; + } + + return false; +} + +bool EffectDummyCreature_npc_nexus_drake_hatchling(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_CAPTURE_TRIGGER && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_NEXUS_DRAKE_HATCHLING) + { + if (pCaster->GetTypeId() != TYPEID_PLAYER) + return true; + + if (pCaster->HasAura(SPELL_DRAKE_HATCHLING_SUBDUED) || pCreatureTarget->HasAura(SPELL_SUBDUED)) + return true; + + Player* pPlayer = (Player*)pCaster; + if (!pPlayer) + return true; + + // check the quest + if (pPlayer->GetQuestStatus(QUEST_DRAKE_HUNT) != QUEST_STATUS_INCOMPLETE && pPlayer->GetQuestStatus(QUEST_DRAKE_HUNT_DAILY) != QUEST_STATUS_INCOMPLETE) + return true; + + // evade and set friendly and start following + pCreatureTarget->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); + pCreatureTarget->DeleteThreatList(); + pCreatureTarget->CombatStop(true); + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_START_EVENT, pCaster, pCreatureTarget); + + // cast visual spells + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_DRAKE_VOMIT_PERIODIC, true); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_SUBDUED, true); + pCreatureTarget->CastSpell(pCaster, SPELL_DRAKE_HATCHLING_SUBDUED, true); + + return true; + } + else if (uiSpellId == SPELL_DRAKE_TURN_IN && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_NEXUS_DRAKE_HATCHLING) + { + if (Creature* pRaelorasz = GetClosestCreatureWithEntry(pCreatureTarget, NPC_RAELORASZ, 30.0f)) + { + // Inform Raelorasz and move in front of him + pCreatureTarget->CastSpell(pRaelorasz, SPELL_DRAKE_COMPLETION_PING, true); + + float fX, fY, fZ; + pRaelorasz->GetContactPoint(pCreatureTarget, fX, fY, fZ, CONTACT_DISTANCE); + pCreatureTarget->GetMotionMaster()->Clear(true, true); + pCreatureTarget->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + return true; + } + } + else if (uiSpellId == SPELL_RAELORASZ_FIREBALL && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_NEXUS_DRAKE_HATCHLING) + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_COMPLETE_IMMOLATION, true); + pCreatureTarget->SetStandState(UNIT_STAND_STATE_DEAD); + pCreatureTarget->ForcedDespawn(10000); + + return true; + } + + return false; +} + +/*##### +# npc_scourged_flamespitter +#####*/ + +enum +{ + SPELL_REINFORCED_NET = 46361, + SPELL_NET = 47021, + + SPELL_INCINERATE_COSMETIC = 45863, + SPELL_INCINERATE = 32707, + + NPC_FLAMESPITTER = 25582, +}; + +struct npc_scourged_flamespitterAI : public ScriptedAI +{ + npc_scourged_flamespitterAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiIncinerateTimer; + uint32 m_uiNetExpireTimer; + + void Reset() override + { + m_uiIncinerateTimer = urand(1000, 2000); + m_uiNetExpireTimer = 0; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 10.0f); + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (DoCastSpellIfCan(m_creature, SPELL_NET) == CAST_OK) + m_uiNetExpireTimer = 20000; + } + + void UpdateAI(const uint32 uiDiff) + { + if (m_uiNetExpireTimer) + { + if (m_uiNetExpireTimer <= uiDiff) + { + // evade when the net root has expired + if (!m_creature->getVictim()) + EnterEvadeMode(); + + m_uiNetExpireTimer = 0; + } + else + m_uiNetExpireTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + // incinerate visual on OOC timer, unless creature is rooted + if (!m_uiNetExpireTimer) + { + if (m_uiIncinerateTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INCINERATE_COSMETIC) == CAST_OK) + m_uiIncinerateTimer = urand(3000, 5000); + } + else + m_uiIncinerateTimer -= uiDiff; + } + + return; + } + + if (m_uiIncinerateTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INCINERATE) == CAST_OK) + m_uiIncinerateTimer = urand(3000, 5000); + } + else + m_uiIncinerateTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_scourged_flamespitter(Creature* pCreature) +{ + return new npc_scourged_flamespitterAI(pCreature); +} + +bool EffectAuraDummy_npc_scourged_flamespitter(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_REINFORCED_NET && pAura->GetEffIndex() == EFFECT_INDEX_0 && bApply) + { + Creature* pCreature = (Creature*)pAura->GetTarget(); + Unit* pCaster = pAura->GetCaster(); + if (!pCreature || !pCaster || pCaster->GetTypeId() != TYPEID_PLAYER || pCreature->GetEntry() != NPC_FLAMESPITTER) + return false; + + // move the flamespitter to the ground level + pCreature->GetMotionMaster()->Clear(); + pCreature->SetWalk(false); + + float fGroundZ = pCreature->GetMap()->GetHeight(pCreature->GetPhaseMask(), pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ()); + pCreature->GetMotionMaster()->MovePoint(1, pCreature->GetPositionX(), pCreature->GetPositionY(), fGroundZ); + return true; + } + + return false; +} + +/*##### +## npc_bonker_togglevolt +#####*/ + +enum +{ + SAY_BONKER_START = -1001013, + SAY_BONKER_GO = -1001014, + SAY_BONKER_AGGRO = -1001015, + SAY_BONKER_LEFT = -1001016, + SAY_BONKER_COMPLETE = -1001017, + + QUEST_ID_GET_ME_OUTA_HERE = 11673, +}; + +struct npc_bonker_togglevoltAI : public npc_escortAI +{ + npc_bonker_togglevoltAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + void Reset() override { } + + void Aggro(Unit* /*pWho*/) override + { + if (urand(0, 1)) + DoScriptText(SAY_BONKER_AGGRO, m_creature); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + DoScriptText(SAY_BONKER_START, m_creature); + break; + case 1: + DoScriptText(SAY_BONKER_GO, m_creature); + // WORKAROUND ALERT - temp ignore pathfinding until we pass the pool + // creature cannont find a proper swimming path in this area, so ignore pathfinding for the moment + m_creature->addUnitState(UNIT_STAT_IGNORE_PATHFINDING); + break; + case 3: + DoScriptText(SAY_BONKER_LEFT, m_creature); + // WORKAROUND END - resume pathfinding + m_creature->clearUnitState(UNIT_STAT_IGNORE_PATHFINDING); + break; + case 32: + if (Player* pPlayer = GetPlayerForEscort()) + { + pPlayer->GroupEventHappens(QUEST_ID_GET_ME_OUTA_HERE, m_creature); + DoScriptText(SAY_BONKER_COMPLETE, m_creature, pPlayer); + } + break; + } + } +}; + +CreatureAI* GetAI_npc_bonker_togglevolt(Creature* pCreature) +{ + return new npc_bonker_togglevoltAI(pCreature); +} + +bool QuestAccept_npc_bonker_togglevolt(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_GET_ME_OUTA_HERE) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + void AddSC_borean_tundra() { Script* pNewScript; @@ -533,11 +1059,6 @@ void AddSC_borean_tundra() pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_oil_stained_wolf; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "go_caribou_trap"; - pNewScript->pGOUse = &GOUse_go_caribou_trap; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_sinkhole_kill_credit"; pNewScript->GetAI = &GetAI_npc_sinkhole_kill_credit; @@ -548,4 +1069,33 @@ void AddSC_borean_tundra() pNewScript->GetAI = &GetAI_npc_lurgglbr; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_lurgglbr; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_beryl_sorcerer"; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_beryl_sorcerer; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_captured_beryl_sorcerer"; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_captured_beryl_sorcerer; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_nexus_drake_hatchling"; + pNewScript->GetAI = &GetAI_npc_nexus_drake_hatchling; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_nexus_drake_hatchling; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_nexus_drake_hatchling; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scourged_flamespitter"; + pNewScript->GetAI = &GetAI_npc_scourged_flamespitter; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_scourged_flamespitter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_bonker_togglevolt"; + pNewScript->GetAI = &GetAI_npc_bonker_togglevolt; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_bonker_togglevolt; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp new file mode 100644 index 000000000..5b14e9d2d --- /dev/null +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_argent_challenge.cpp @@ -0,0 +1,356 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: argent_challenge +SD%Complete: 90 +SDComment: Achievement NYI. +SDCategory: Crusader Coliseum, Trial of the Champion +EndScriptData */ + +#include "precompiled.h" +#include "trial_of_the_champion.h" + +enum +{ + FACTION_CHAMPION_FRIENDLY = 35, +}; + +/*###### +## argent_companion_common +######*/ + +struct argent_champion_commonAI : public ScriptedAI +{ + argent_champion_commonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bDefeated = false; + Reset(); + } + + instance_trial_of_the_champion* m_pInstance; + bool m_bIsRegularMode; + + bool m_bDefeated; + + void Reset() override { } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ARGENT_CHAMPION, IN_PROGRESS); + } + + void JustReachedHome() override + { + if (m_pInstance && m_pInstance->GetData(TYPE_ARGENT_CHAMPION) != DONE) + m_pInstance->SetData(TYPE_ARGENT_CHAMPION, FAIL); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_bDefeated) + return; + + if (m_pInstance) + m_pInstance->SetData(TYPE_ARGENT_CHAMPION, DONE); + + // Handle event completion + DoHandleEventEnd(); + + m_creature->SetFactionTemporary(FACTION_CHAMPION_FRIENDLY, TEMPFACTION_NONE); + EnterEvadeMode(); + + m_bDefeated = true; + } + } + + // Function that handles personalized event completion + virtual void DoHandleEventEnd() {} +}; + +enum +{ + SAY_EADRIC_AGGRO = -1650052, + SAY_EADRIC_HAMMER = -1650053, + SAY_EADRIC_KILL_1 = -1650054, + SAY_EADRIC_KILL_2 = -1650055, + SAY_EADRIC_DEFEAT = -1650056, + EMOTE_EADRIC_RADIANCE = -1650057, + EMOTE_EADRIC_HAMMER = -1650058, + + SPELL_KILL_CREDIT_EADRIC = 68575, + SPELL_EADRIC_ACHIEVEMENT = 68197, // required for achiev 3803 + + SPELL_HAMMER_OF_JUSTICE = 66863, + SPELL_HAMMER_OF_RIGHTEOUS = 66867, + SPELL_RADIANCE = 66935, + SPELL_VENGEANCE = 66865, +}; + +/*###### +## boss_eadric +######*/ + +struct boss_eadricAI : public argent_champion_commonAI +{ + boss_eadricAI(Creature* pCreature) : argent_champion_commonAI(pCreature) { Reset(); } + + uint32 m_uiHammerTimer; + uint32 m_uiRadianceTimer; + + void Reset() override + { + argent_champion_commonAI::Reset(); + + m_uiHammerTimer = urand(30000, 35000); + m_uiRadianceTimer = urand(10000, 15000); + } + + void Aggro(Unit* pWho) override + { + DoScriptText(SAY_EADRIC_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_VENGEANCE, CAST_TRIGGERED); + + argent_champion_commonAI::Aggro(pWho); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_EADRIC_KILL_1 : SAY_EADRIC_KILL_2, m_creature); + } + + void DoHandleEventEnd() + { + DoScriptText(SAY_EADRIC_DEFEAT, m_creature); + + // ToDo: implement the mechanics for this achiev + //DoCastSpellIfCan(m_creature, SPELL_EADRIC_ACHIEVEMENT, CAST_TRIGGERED); + m_creature->CastSpell(m_creature, SPELL_KILL_CREDIT_EADRIC, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiHammerTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HAMMER_OF_RIGHTEOUS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_HAMMER_OF_JUSTICE, CAST_TRIGGERED); + + DoScriptText(EMOTE_EADRIC_HAMMER, m_creature, pTarget); + m_uiHammerTimer = 35000; + } + } + } + else + m_uiHammerTimer -= uiDiff; + + if (m_uiRadianceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RADIANCE) == CAST_OK) + { + DoScriptText(EMOTE_EADRIC_RADIANCE, m_creature); + m_uiRadianceTimer = urand(30000, 35000); + } + } + else + m_uiRadianceTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_eadric(Creature* pCreature) +{ + return new boss_eadricAI(pCreature); +} + +enum +{ + SAY_PALETRESS_AGGRO = -1650059, + SAY_PALETRESS_MEMORY = -1650060, + SAY_PALETRESS_MEMORY_DIES = -1650061, + SAY_PALETRESS_KILL_1 = -1650062, + SAY_PALETRESS_KILL_2 = -1650063, + SAY_PALETRESS_DEFEAT = -1650064, + + SPELL_KILL_CREDIT_PALETRESS = 68574, + SPELL_CONFESSOR_ACHIEVEMENT = 68206, // required for achiev 3802 + + SPELL_CONFESS = 66547, + SPELL_CONFESS_AURA = 66680, + SPELL_SUMMON_MEMORY = 66545, + SPELL_REFLECTIVE_SHIELD = 66515, + + SPELL_HOLY_FIRE = 66538, + SPELL_HOLY_NOVA = 66546, + SPELL_HOLY_SMITE = 66536, + SPELL_RENEW = 66537, + + SPELL_MEMORY_SPAWN_EFFECT = 66675, + SPELL_SHADOWFORM = 41408, +}; + +/*###### +## boss_paletress +######*/ + +struct boss_paletressAI : public argent_champion_commonAI +{ + boss_paletressAI(Creature* pCreature) : argent_champion_commonAI(pCreature) { Reset(); } + + uint32 m_uiHolySmiteTimer; + uint32 m_uiHolyFireTimer; + uint32 m_uiHolyNovaTimer; + uint32 m_uiRenewTimer; + + bool m_bSummonedMemory; + + void Reset() override + { + argent_champion_commonAI::Reset(); + + m_uiHolySmiteTimer = 0; + m_uiHolyFireTimer = urand(7000, 12000); + m_uiHolyNovaTimer = urand(20000, 25000); + m_uiRenewTimer = urand(5000, 9000); + + m_bSummonedMemory = false; + } + + void Aggro(Unit* pWho) override + { + DoScriptText(SAY_PALETRESS_AGGRO, m_creature); + + argent_champion_commonAI::Aggro(pWho); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_PALETRESS_KILL_1 : SAY_PALETRESS_KILL_2, m_creature); + } + + void DoHandleEventEnd() + { + DoScriptText(SAY_PALETRESS_DEFEAT, m_creature); + + m_creature->CastSpell(m_creature, SPELL_KILL_CREDIT_PALETRESS, true); + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->CastSpell(pSummoned, SPELL_SHADOWFORM, true); + pSummoned->CastSpell(pSummoned, SPELL_MEMORY_SPAWN_EFFECT, true); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + DoScriptText(SAY_PALETRESS_MEMORY_DIES, m_creature); + pSummoned->CastSpell(pSummoned, SPELL_CONFESSOR_ACHIEVEMENT, true); + m_creature->RemoveAurasDueToSpell(SPELL_REFLECTIVE_SHIELD); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bSummonedMemory && m_creature->GetHealthPercent() <= 25.0f) + { + DoScriptText(SAY_PALETRESS_MEMORY, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_CONFESS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CONFESS_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MEMORY, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_REFLECTIVE_SHIELD, CAST_TRIGGERED); + m_bSummonedMemory = true; + } + + if (m_uiHolySmiteTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HOLY_SMITE)) + m_uiHolySmiteTimer = urand(1000, 2000); + } + } + else + m_uiHolySmiteTimer -= uiDiff; + + if (m_uiHolyFireTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HOLY_FIRE)) + m_uiHolyFireTimer = 25000; + } + } + else + m_uiHolyFireTimer -= uiDiff; + + if (m_uiHolyNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HOLY_NOVA)) + m_uiHolyNovaTimer = urand(30000, 40000); + } + else + m_uiHolyNovaTimer -= uiDiff; + + if (m_uiRenewTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(60.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_RENEW) == CAST_OK) + m_uiRenewTimer = 20000; + } + } + else + m_uiRenewTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_paletress(Creature* pCreature) +{ + return new boss_paletressAI(pCreature); +} + +void AddSC_boss_argent_challenge() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_eadric"; + pNewScript->GetAI = &GetAI_boss_eadric; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_paletress"; + pNewScript->GetAI = &GetAI_boss_paletress; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp new file mode 100644 index 000000000..d961266f7 --- /dev/null +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_black_knight.cpp @@ -0,0 +1,477 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: boss_black_knight +SD%Complete: 100 +SDComment: +SDCategory: Crusader Coliseum, Trial of the Champion +EndScriptData */ + +#include "precompiled.h" +#include "trial_of_the_champion.h" + +enum +{ + SAY_PHASE_2 = -1650066, + SAY_PHASE_3 = -1650067, + SAY_KILL_1 = -1650068, + SAY_KILL_2 = -1650069, + SAY_DEATH = -1650070, + + // generic spells + SPELL_KILL_CREDIT = 68663, + SPELL_FEIGN_DEATH = 67691, // triggers 67693 + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_FULL_HEAL = 17683, + SPELL_BLACK_KNIGHT_RES = 67693, + SPELL_RAISE_DEAD_ARELAS = 67705, + SPELL_RAISE_DEAD_JAEREN = 67715, + + // phase 1 + SPELL_DEATHS_RESPITE = 67745, + SPELL_ICY_TOUCH = 67718, + SPELL_OBLITERATE = 67725, + SPELL_PLAGUE_STRIKE = 67724, + + // phase 2 + SPELL_ARMY_OF_THE_DEAD = 67761, + SPELL_DESECRATION = 67778, + SPELL_GHOUL_EXPLODE = 67751, // triggers 67729 + + // phase 3 + SPELL_DEATHS_BITE = 67808, + SPELL_MARKED_FOR_DEATH = 67823, + + // ghoul spells + SPELL_CLAW = 67774, + SPELL_EXPLODE = 67729, + SPELL_LEAP = 67749, + + // risen zombies + NPC_RISEN_JAEREN = 35545, + NPC_RISEN_ARELAS = 35564, + NPC_RISEN_CHAMPION = 35590, + + // transform models + MODEL_ID_SKELETON = 29846, + MODEL_ID_GHOST = 21300, + + // equipment id + EQUIP_ID_SWORD = 40343, + + // phases + PHASE_DEATH_KNIGHT = 1, + PHASE_SKELETON = 2, + PHASE_GHOST = 3, + PHASE_TRANSITION = 4, +}; + +/*###### +## boss_black_knight +######*/ + +struct boss_black_knightAI : public ScriptedAI +{ + boss_black_knightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_champion* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiNextPhase; + + uint32 m_uiDeathsRespiteTimer; + uint32 m_uiIcyTouchTimer; + uint32 m_uiObliterateTimer; + uint32 m_uiPlagueStrikeTimer; + + uint32 m_uiDesecrationTimer; + uint32 m_uiGhoulExplodeTimer; + + uint32 m_uiDeathsBiteTimer; + uint32 m_uiMarkedDeathTimer; + + ObjectGuid m_ghoulGuid; + + void Reset() override + { + m_uiPhase = PHASE_DEATH_KNIGHT; + + m_uiDeathsRespiteTimer = 10000; + m_uiIcyTouchTimer = urand(5000, 10000); + m_uiObliterateTimer = urand(10000, 15000); + m_uiPlagueStrikeTimer = 5000; + + m_uiDesecrationTimer = 6000; + m_uiGhoulExplodeTimer = 10000; + + m_uiMarkedDeathTimer = 0; + m_uiDeathsBiteTimer = 7000; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetDisplayId(m_creature->GetNativeDisplayId()); + SetEquipmentSlots(true); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + DoCastSpellIfCan(m_creature, m_pInstance->GetPlayerTeam() == ALLIANCE ? SPELL_RAISE_DEAD_ARELAS : SPELL_RAISE_DEAD_JAEREN); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BLACK_KNIGHT, FAIL); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BLACK_KNIGHT, DONE); + + DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_KILL_CREDIT, CAST_TRIGGERED); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // no aggro during the intro + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustSummoned(Creature* pSummoned) override + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + + if (pSummoned->GetEntry() == NPC_RISEN_JAEREN || pSummoned->GetEntry() == NPC_RISEN_ARELAS) + m_ghoulGuid = pSummoned->GetObjectGuid(); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (m_uiPhase == PHASE_GHOST) + return; + + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_uiPhase == PHASE_TRANSITION) + return; + + // start transition phase + if (m_uiPhase == PHASE_DEATH_KNIGHT) + { + m_uiNextPhase = PHASE_SKELETON; + + // ghould explodes at the end of the round + if (Creature* pGhoul = m_creature->GetMap()->GetCreature(m_ghoulGuid)) + { + pGhoul->InterruptNonMeleeSpells(true); + pGhoul->CastSpell(pGhoul, SPELL_EXPLODE, false); + } + } + else if (m_uiPhase == PHASE_SKELETON) + m_uiNextPhase = PHASE_GHOST; + + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(0); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CLEAR_ALL_DEBUFFS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FULL_HEAL, CAST_TRIGGERED); + m_uiPhase = PHASE_TRANSITION; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // finish transition + if (eventType == AI_EVENT_CUSTOM_A) + { + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + DoResetThreat(); + + m_uiPhase = m_uiNextPhase; + + if (m_uiPhase == PHASE_SKELETON) + { + DoScriptText(SAY_PHASE_2, m_creature); + m_creature->SetDisplayId(MODEL_ID_SKELETON); + + DoCastSpellIfCan(m_creature, SPELL_ARMY_OF_THE_DEAD); + } + else if (m_uiPhase == PHASE_GHOST) + { + DoScriptText(SAY_PHASE_3, m_creature); + m_creature->SetDisplayId(MODEL_ID_GHOST); + + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_DEATH_KNIGHT: + + if (m_uiDeathsRespiteTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEATHS_RESPITE) == CAST_OK) + m_uiDeathsRespiteTimer = 20000; + } + } + else + m_uiDeathsRespiteTimer -= uiDiff; + + if (m_uiIcyTouchTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_ICY_TOUCH, SELECT_FLAG_IN_MELEE_RANGE | SELECT_FLAG_IN_LOS)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ICY_TOUCH) == CAST_OK) + m_uiIcyTouchTimer = urand(10000, 15000); + } + } + else + m_uiIcyTouchTimer -= uiDiff; + + if (m_uiObliterateTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_OBLITERATE) == CAST_OK) + m_uiObliterateTimer = urand(18000, 25000); + } + else + m_uiObliterateTimer -= uiDiff; + + if (m_uiPlagueStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PLAGUE_STRIKE) == CAST_OK) + m_uiPlagueStrikeTimer = 10000; + } + else + m_uiPlagueStrikeTimer -= uiDiff; + + break; + case PHASE_SKELETON: + + if (m_uiDesecrationTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DESECRATION) == CAST_OK) + m_uiDesecrationTimer = 6000; + } + else + m_uiDesecrationTimer -= uiDiff; + + if (m_uiGhoulExplodeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GHOUL_EXPLODE) == CAST_OK) + m_uiGhoulExplodeTimer = 12000; + } + else + m_uiGhoulExplodeTimer -= uiDiff; + + break; + case PHASE_GHOST: + + if (m_uiDeathsBiteTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEATHS_BITE) == CAST_OK) + m_uiDeathsBiteTimer = 2000; + } + else + m_uiDeathsBiteTimer -= uiDiff; + + if (m_uiMarkedDeathTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MARKED_FOR_DEATH) == CAST_OK) + m_uiMarkedDeathTimer = urand(10000, 15000); + } + } + else + m_uiMarkedDeathTimer -= uiDiff; + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_black_knight(Creature* pCreature) +{ + return new boss_black_knightAI(pCreature); +} + +bool EffectDummyCreature_black_knight_res(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_BLACK_KNIGHT_RES && uiEffIndex == EFFECT_INDEX_0) + { + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + return true; + } + + return false; +} + +/*###### +## npc_black_knight_ghoul +######*/ + +struct npc_black_knight_ghoulAI : public ScriptedAI +{ + npc_black_knight_ghoulAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_champion* m_pInstance; + + uint32 m_uiClawTimer; + + bool m_bExploded; + + void Reset() override + { + m_uiClawTimer = urand(3000, 6000); + + m_bExploded = false; + } + + void Aggro(Unit* pWho) override + { + if (m_creature->GetEntry() == NPC_RISEN_ARELAS || m_creature->GetEntry() == NPC_RISEN_JAEREN) + DoCastSpellIfCan(pWho, SPELL_LEAP); + } + + void SpellHitTarget(Unit* pUnit, const SpellEntry* pSpellEntry) override + { + if (pUnit->GetTypeId() != TYPEID_PLAYER) + return; + + // set achiev failed + if (pSpellEntry->Id == SPELL_EXPLODE && m_pInstance) + m_pInstance->SetHadWorseAchievFailed(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // explode on low health + if (!m_bExploded && m_creature->GetHealthPercent() < 15.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLODE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + m_bExploded = true; + } + + if (m_uiClawTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLAW) == CAST_OK) + m_uiClawTimer = urand(7000, 14000); + } + else + m_uiClawTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_black_knight_ghoul(Creature* pCreature) +{ + return new npc_black_knight_ghoulAI(pCreature); +} + +/*###### +## npc_black_knight_gryphon +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_black_knight_gryphonAI : public ScriptedAI +{ + npc_black_knight_gryphonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_black_knight_gryphon(Creature* pCreature) +{ + return new npc_black_knight_gryphonAI(pCreature); +} + +void AddSC_boss_black_knight() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_black_knight"; + pNewScript->GetAI = &GetAI_boss_black_knight; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_black_knight_res; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_black_knight_ghoul"; + pNewScript->GetAI = &GetAI_npc_black_knight_ghoul; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_black_knight_gryphon"; + pNewScript->GetAI = &GetAI_npc_black_knight_gryphon; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp index bd491f587..390d7f662 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/boss_grand_champions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,14 +16,1023 @@ /* ScriptData SDName: grand_champions -SD%Complete: 0 -SDComment: +SD%Complete: 90 +SDComment: Encounter might require additional improvements. SDCategory: Crusader Coliseum, Trial of the Champion EndScriptData */ #include "precompiled.h" #include "trial_of_the_champion.h" +#include "TransportSystem.h" + +enum +{ + // common spells + SPELL_DEFEND_DUMMY = 64101, // triggers 62719, 64192 + + SPELL_SHIELD_BREAKER = 68504, + SPELL_CHARGE = 68301, // triggers 68307 + SPELL_CHARGE_VEHICLE = 68307, + SPELL_FULL_HEAL = 43979, + SPELL_RIDE_ARGENT_VEHICLE = 69692, +}; + +/*###### +## trial_companion_common +######*/ + +struct trial_companion_commonAI : public ScriptedAI +{ + trial_companion_commonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_trial_of_the_champion* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiShieldBreakerTimer; + uint32 m_uiChargeTimer; + uint32 m_uiDefeatedTimer; + uint32 m_uiResetThreatTimer; + + bool m_bDefeated; + + ObjectGuid m_newMountGuid; + + void Reset() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + else + DoCastSpellIfCan(m_creature, SPELL_DEFEND_DUMMY, CAST_TRIGGERED); + } + + m_uiShieldBreakerTimer = urand(3000, 5000); + m_uiChargeTimer = urand(1000, 3000); + m_uiDefeatedTimer = 0; + m_uiResetThreatTimer = urand(5000, 15000); + + m_bDefeated = false; + + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void Aggro(Unit* pWho) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, IN_PROGRESS); + + m_pInstance->DoSetChamptionsInCombat(pWho); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, FAIL); + } + } + + void AttackStart(Unit* pWho) override + { + ScriptedAI::AttackStart(pWho); + + // Set Mount control + if (m_creature->GetTransportInfo() && m_creature->GetTransportInfo()->IsOnVehicle()) + { + if (Creature* pMount = (Creature*)m_creature->GetTransportInfo()->GetTransport()) + pMount->AI()->AttackStart(pWho); + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + // no aggro during the intro + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_bDefeated) + return; + + if (!m_pInstance) + return; + + // second part of the champions challenge + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_creature->SetHealth(1); + + // no movement + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + + // check if the other champions are wounded and set instance data + if (m_pInstance->IsArenaChallengeComplete(TYPE_GRAND_CHAMPIONS)) + m_pInstance->SetData(TYPE_GRAND_CHAMPIONS, DONE); + } + // first part of the champions challenge (arena encounter) + else + { + // unmount + if (Creature* pMount = (Creature*)m_creature->GetTransportInfo()->GetTransport()) + { + pMount->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + pMount->ForcedDespawn(); + } + + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + m_creature->SetHealth(1); + + // no movement + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + + m_uiDefeatedTimer = 15000; + } + + m_bDefeated = true; + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !m_pInstance) + return; + + switch (uiPointId) + { + case POINT_ID_MOUNT: + { + // mount the closest vehicle and start attacking + uint32 uiMountEntry = m_pInstance->GetMountEntryForChampion(); + + // search for the vehicle again, just in case the previous one was taken + Creature* pMount = m_creature->GetMap()->GetCreature(m_newMountGuid); + if (pMount->HasAura(SPELL_RIDE_ARGENT_VEHICLE)) + pMount = GetClosestCreatureWithEntry(m_creature, uiMountEntry, 60.0f); + + // if we don't have any mount send an error + if (!pMount) + { + script_error_log("Instance Trial of the Champion: ERROR Failed to get a mount replacement for champion %u.", m_creature->GetEntry()); + return; + } + + DoCastSpellIfCan(pMount, SPELL_RIDE_ARGENT_VEHICLE, CAST_TRIGGERED); + + if (m_creature->getVictim()) + pMount->AI()->AttackStart(m_creature->getVictim()); + + m_bDefeated = false; + break; + } + case POINT_ID_EXIT: + // mark the first part as complete if required + if (m_pInstance->GetData(TYPE_GRAND_CHAMPIONS) != DONE) + m_pInstance->SetData(TYPE_ARENA_CHALLENGE, DONE); + + m_creature->ForcedDespawn(); + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_ID_HOME || !m_pInstance) + return; + + if (Creature* pCenterTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER)) + { + pSummoned->SetRespawnCoord(pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), pSummoned->GetAngle(pCenterTrigger)); + pSummoned->SetFacingToObject(pCenterTrigger); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_B) + { + m_uiShieldBreakerTimer = urand(1000, 2000); + m_uiChargeTimer = urand(2000, 4000); + } + } + + // function that will make the champion to use the nearby available mount + void DoUseNearbyMountIfCan() + { + if (!m_pInstance) + return; + + // set instance data as special if first part is completed + if (m_pInstance->IsArenaChallengeComplete(TYPE_ARENA_CHALLENGE)) + m_pInstance->SetData(TYPE_ARENA_CHALLENGE, SPECIAL); + else + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + float fX, fY, fZ; + uint32 uiMountEntry = m_pInstance->GetMountEntryForChampion(); + + if (Creature* pMount = GetClosestCreatureWithEntry(m_creature, uiMountEntry, 60.0f)) + { + pMount->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_MOUNT, fX, fY, fZ); + + m_newMountGuid = pMount->GetObjectGuid(); + } + } + } + + // Return true to handle shared timers and MeleeAttack + virtual bool UpdateChampionAI(const uint32 /*uiDiff*/) { return true; } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // timer for other champions check + if (m_uiDefeatedTimer) + { + if (m_uiDefeatedTimer <= uiDiff) + { + DoUseNearbyMountIfCan(); + m_uiDefeatedTimer = 0; + } + else + m_uiDefeatedTimer -= uiDiff; + } + + // no combat after defeated + if (m_bDefeated) + return; + + if (!m_pInstance) + return; + + // arena battle - on vehicles + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == IN_PROGRESS) + { + if (m_uiShieldBreakerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHIELD_BREAKER) == CAST_OK) + m_uiShieldBreakerTimer = urand(2000, 4000); + } + else + m_uiShieldBreakerTimer -= uiDiff; + + if (m_uiChargeTimer) + { + if (m_uiChargeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHARGE) == CAST_OK) + { + if (m_creature->GetTransportInfo() && m_creature->GetTransportInfo()->IsOnVehicle()) + { + if (Creature* pMount = (Creature*)m_creature->GetTransportInfo()->GetTransport()) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature->getVictim(), pMount); + } + m_uiChargeTimer = 0; + } + } + else + m_uiChargeTimer -= uiDiff; + } + } + // arena challenge complete - start normal battle + else if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + { + // Call specific virtual function + if (!UpdateChampionAI(uiDiff)) + return; + + // Change target + if (m_uiResetThreatTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + DoResetThreat(); + AttackStart(pTarget); + m_uiResetThreatTimer = urand(5000, 15000); + } + } + else + m_uiResetThreatTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + } +}; + +enum +{ + // warrior spells + SPELL_INTERCEPT = 67540, + SPELL_BLADESTORM = 67541, + SPELL_MORTAL_STRIKE = 67542, + SPELL_ROLLING_THROW = 67546, +}; + +/*###### +## boss_champion_warrior +######*/ + +struct boss_champion_warriorAI : public trial_companion_commonAI +{ + boss_champion_warriorAI(Creature* pCreature) : trial_companion_commonAI(pCreature) { Reset(); } + + uint32 m_uiStrikeTimer; + uint32 m_uiBladeStormTimer; + uint32 m_uiInterceptTimer; + uint32 m_uiThrowTimer; + + void Reset() override + { + m_uiInterceptTimer = 0; + m_uiStrikeTimer = urand(5000, 8000); + m_uiBladeStormTimer = urand(10000, 20000); + m_uiThrowTimer = 30000; + + trial_companion_commonAI::Reset(); + } + + bool UpdateChampionAI(const uint32 uiDiff) + { + if (m_uiInterceptTimer < uiDiff) + { + if (!m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_INTERCEPT, SELECT_FLAG_NOT_IN_MELEE_RANGE | SELECT_FLAG_IN_LOS)) + { + if (DoCastSpellIfCan(pTarget, SPELL_INTERCEPT) == CAST_OK) + m_uiInterceptTimer = 10000; + } + } + else + m_uiInterceptTimer = 2000; + } + else + m_uiInterceptTimer -= uiDiff; + + if (m_uiBladeStormTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLADESTORM) == CAST_OK) + m_uiBladeStormTimer = urand(15000, 20000); + } + else + m_uiBladeStormTimer -= uiDiff; + + if (m_uiThrowTimer < uiDiff) + { + m_creature->getVictim()->CastSpell(m_creature->getVictim(), SPELL_ROLLING_THROW, true); + m_uiThrowTimer = urand(20000, 30000); + } + else + m_uiThrowTimer -= uiDiff; + + if (m_uiStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiStrikeTimer = urand(8000, 12000); + } + else + m_uiStrikeTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_champion_warrior(Creature* pCreature) +{ + return new boss_champion_warriorAI(pCreature); +} + +enum +{ + // mage spells + SPELL_FIREBALL = 66042, + SPELL_POLYMORPH = 66043, + SPELL_BLAST_WAVE = 66044, + SPELL_HASTE = 66045, +}; + +/*###### +## boss_champion_mage +######*/ + +struct boss_champion_mageAI : public trial_companion_commonAI +{ + boss_champion_mageAI(Creature* pCreature) : trial_companion_commonAI(pCreature) { Reset(); } + + uint32 m_uiFireballTimer; + uint32 m_uiBlastWaveTimer; + uint32 m_uiHasteTimer; + uint32 m_uiPolymorphTimer; + + void Reset() override + { + m_uiFireballTimer = 0; + m_uiBlastWaveTimer = urand(10000, 20000); + m_uiHasteTimer = 10000; + m_uiPolymorphTimer = urand(5000, 10000); + + trial_companion_commonAI::Reset(); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } + } + else + trial_companion_commonAI::AttackStart(pWho); + } + + bool UpdateChampionAI(const uint32 uiDiff) + { + if (m_uiFireballTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL) == CAST_OK) + m_uiFireballTimer = urand(2000, 4000); + } + else + m_uiFireballTimer -= uiDiff; + + if (m_uiBlastWaveTimer < uiDiff) + { + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_BLAST_WAVE, SELECT_FLAG_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE) == CAST_OK) + m_uiBlastWaveTimer = urand(10000, 20000); + } + else + m_uiBlastWaveTimer = 5000; + } + else + m_uiBlastWaveTimer -= uiDiff; + + if (m_uiHasteTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HASTE) == CAST_OK) + m_uiHasteTimer = 20000; + } + else + m_uiHasteTimer -= uiDiff; + + if (m_uiPolymorphTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_POLYMORPH) == CAST_OK) + m_uiPolymorphTimer = urand(5000, 10000); + } + } + else + m_uiPolymorphTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_champion_mage(Creature* pCreature) +{ + return new boss_champion_mageAI(pCreature); +} + +enum +{ + // shaman spells + SPELL_HEALING_WAVE = 67528, + SPELL_CHAIN_LIGHTNING = 67529, + SPELL_EARTH_SHIELD = 67530, + SPELL_HEX_OF_MENDING = 67534, +}; + +/*###### +## boss_champion_shaman +######*/ + +struct boss_champion_shamanAI : public trial_companion_commonAI +{ + boss_champion_shamanAI(Creature* pCreature) : trial_companion_commonAI(pCreature) { Reset(); } + + uint32 m_uiHealingWaveTimer; + uint32 m_uiLightningTimer; + uint32 m_uiEarthShieldTimer; + uint32 m_uiHexTimer; + + void Reset() override + { + m_uiLightningTimer = 1000; + m_uiHealingWaveTimer = 13000; + m_uiHexTimer = 10000; + m_uiEarthShieldTimer = 0; + + trial_companion_commonAI::Reset(); + } + + bool UpdateChampionAI(const uint32 uiDiff) + { + if (m_uiLightningTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiLightningTimer = urand(1000, 3000); + } + else + m_uiLightningTimer -= uiDiff; + + if (m_uiHealingWaveTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(40.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HEALING_WAVE) == CAST_OK) + m_uiHealingWaveTimer = urand(8000, 13000); + } + } + else + m_uiHealingWaveTimer -= uiDiff; + + if (m_uiEarthShieldTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EARTH_SHIELD, CAST_AURA_NOT_PRESENT) == CAST_OK) + m_uiEarthShieldTimer = 30000; + else + m_uiEarthShieldTimer = 5000; + } + else + m_uiEarthShieldTimer -= uiDiff; + + if (m_uiHexTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEX_OF_MENDING) == CAST_OK) + m_uiHexTimer = urand(17000, 25000); + } + else + m_uiHexTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_champion_shaman(Creature* pCreature) +{ + return new boss_champion_shamanAI(pCreature); +} + +enum +{ + // hunter spells + SPELL_DISENGAGE = 68340, // trigger 68340 + SPELL_LIGHTNING_ARROWS = 66083, + SPELL_LIGHTNING_ARROWS_PROC = 66085, + SPELL_MULTI_SHOT = 66081, + SPELL_SHOOT = 65868, +}; + +/*###### +## boss_champion_hunter +######*/ + +struct boss_champion_hunterAI : public trial_companion_commonAI +{ + boss_champion_hunterAI(Creature* pCreature) : trial_companion_commonAI(pCreature) { Reset(); } + + uint32 m_uiDisengageTimer; + uint32 m_uiArrowsTimer; + uint32 m_uiArrowsProcTimer; + uint32 m_uiMultiShotTimer; + uint32 m_uiShootTimer; + + void Reset() override + { + m_uiShootTimer = 1000; + m_uiArrowsTimer = urand(10000, 15000); + m_uiArrowsProcTimer = 0; + m_uiMultiShotTimer = urand(6000, 12000); + m_uiDisengageTimer = 5000; + + trial_companion_commonAI::Reset(); + } + + void AttackStart(Unit* pWho) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_ARENA_CHALLENGE) == DONE) + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } + } + else + trial_companion_commonAI::AttackStart(pWho); + } + + bool UpdateChampionAI(const uint32 uiDiff) + { + if (m_uiShootTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOOT) == CAST_OK) + m_uiShootTimer = urand(1000, 3000); + } + else + m_uiShootTimer -= uiDiff; + + if (m_uiMultiShotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MULTI_SHOT) == CAST_OK) + m_uiMultiShotTimer = urand(5000, 10000); + } + else + m_uiMultiShotTimer -= uiDiff; + + if (m_uiDisengageTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_DISENGAGE, SELECT_FLAG_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DISENGAGE) == CAST_OK) + m_uiDisengageTimer = urand(13000, 18000); + } + else + m_uiDisengageTimer = 5000; + } + else + m_uiDisengageTimer -= uiDiff; + + if (m_uiArrowsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_ARROWS) == CAST_OK) + { + m_uiArrowsTimer = urand(23000, 27000); + m_uiArrowsProcTimer = 3000; + } + } + else + m_uiArrowsTimer -= uiDiff; + + if (m_uiArrowsProcTimer) + { + if (m_uiArrowsProcTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_ARROWS_PROC) == CAST_OK) + m_uiArrowsProcTimer = 0; + } + else + m_uiArrowsProcTimer -= uiDiff; + } + + return true; + } +}; + +CreatureAI* GetAI_boss_champion_hunter(Creature* pCreature) +{ + return new boss_champion_hunterAI(pCreature); +} + +enum +{ + // rogue spells + SPELL_POISON_BOTTLE = 67701, + SPELL_FAN_OF_KNIVES = 67706, + SPELL_EVISCERATE = 67709, + SPELL_DEADLY_POISON = 67710, +}; + +/*###### +## boss_champion_rogue +######*/ + +struct boss_champion_rogueAI : public trial_companion_commonAI +{ + boss_champion_rogueAI(Creature* pCreature) : trial_companion_commonAI(pCreature) { Reset(); } + + uint32 m_uiPoisonBottleTimer; + uint32 m_uiFanKnivesTimer; + uint32 m_uiEviscerateTimer; + uint32 m_uiDeadlyPoisonTimer; + + void Reset() override + { + m_uiDeadlyPoisonTimer = 12000; + m_uiEviscerateTimer = 7000; + m_uiFanKnivesTimer = 10000; + m_uiPoisonBottleTimer = 5000; + + trial_companion_commonAI::Reset(); + } + + bool UpdateCompanionAI(const uint32 uiDiff) + { + if (m_uiPoisonBottleTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POISON_BOTTLE) == CAST_OK) + m_uiPoisonBottleTimer = urand(15000, 20000); + } + else + m_uiPoisonBottleTimer -= uiDiff; + + if (m_uiDeadlyPoisonTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEADLY_POISON) == CAST_OK) + m_uiDeadlyPoisonTimer = urand(9000, 15000); + } + else + m_uiDeadlyPoisonTimer -= uiDiff; + + if (m_uiEviscerateTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_EVISCERATE) == CAST_OK) + m_uiEviscerateTimer = 8000; + } + else + m_uiEviscerateTimer -= uiDiff; + + if (m_uiFanKnivesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FAN_OF_KNIVES) == CAST_OK) + m_uiFanKnivesTimer = urand(10000, 15000); + } + else + m_uiFanKnivesTimer -= uiDiff; + + return true; + } +}; + +CreatureAI* GetAI_boss_champion_rogue(Creature* pCreature) +{ + return new boss_champion_rogueAI(pCreature); +} + +/*###### +## npc_trial_grand_champion +######*/ + +enum +{ + SPELL_CHAMPION_CHARGE = 63010, + SPELL_CHAMPION_DEFEND = 64100, +}; + +struct npc_trial_grand_championAI : public ScriptedAI +{ + npc_trial_grand_championAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_champion* m_pInstance; + + uint32 m_uiChargeTimer; + uint32 m_uiBlockTimer; + uint32 m_uiChargeResetTimer; + + void Reset() override + { + m_uiChargeTimer = 1000; + m_uiBlockTimer = 0; + m_uiChargeResetTimer = 0; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, frand(10.0f, 20.0f)); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBlockTimer < uiDiff) + { + if (!m_creature->HasAura(SPELL_CHAMPION_DEFEND)) + { + if (DoCastSpellIfCan(m_creature, SPELL_CHAMPION_DEFEND) == CAST_OK) + m_uiBlockTimer = 7000; + } + else + m_uiBlockTimer = 2000; + } + else + m_uiBlockTimer -= uiDiff; + + if (m_uiChargeTimer) + { + if (m_uiChargeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAMPION_CHARGE) == CAST_OK) + { + DoStartMovement(m_creature->getVictim()); + m_uiChargeResetTimer = urand(5000, 10000); + m_uiChargeTimer = 0; + } + } + else + m_uiChargeTimer -= uiDiff; + } + + if (m_uiChargeResetTimer) + { + if (m_uiChargeResetTimer <= uiDiff) + { + DoStartMovement(m_creature->getVictim(), frand(10.0f, 20.0f)); + m_uiChargeResetTimer = 0; + m_uiChargeTimer = urand(2000, 4000); + } + else + m_uiChargeResetTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_trial_grand_champion(Creature* pCreature) +{ + return new npc_trial_grand_championAI(pCreature); +} + +/*###### +## npc_champion_mount +######*/ + +struct npc_champion_mountAI : public ScriptedAI +{ + npc_champion_mountAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_champion* m_pInstance; + + uint32 m_uiChargeResetTimer; + + ObjectGuid m_ownerGuid; + + void Reset() override + { + m_uiChargeResetTimer = 0; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, frand(10.0f, 20.0f)); + } + } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !m_pInstance) + return; + + switch (uiPointId) + { + case POINT_ID_CENTER: + m_pInstance->MoveChampionToHome(m_creature); + break; + case POINT_ID_HOME: + if (Creature* pCenterTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER)) + { + m_creature->SetRespawnCoord(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetAngle(pCenterTrigger)); + m_creature->SetFacingToObject(pCenterTrigger); + } + m_pInstance->InformChampionReachHome(); + break; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A) + { + DoCastSpellIfCan(pInvoker, SPELL_CHARGE_VEHICLE, CAST_TRIGGERED, pSender->GetObjectGuid()); + DoStartMovement(pInvoker); + m_ownerGuid = pSender->GetObjectGuid(); + m_uiChargeResetTimer = urand(5000, 10000); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiChargeResetTimer) + { + if (m_uiChargeResetTimer <= uiDiff) + { + if (Creature* pOwner = m_creature->GetMap()->GetCreature(m_ownerGuid)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pOwner); + + DoStartMovement(m_creature->getVictim(), frand(10.0f, 20.0f)); + m_uiChargeResetTimer = 0; + } + else + m_uiChargeResetTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_champion_mount(Creature* pCreature) +{ + return new npc_champion_mountAI(pCreature); +} void AddSC_boss_grand_champions() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_champion_warrior"; + pNewScript->GetAI = &GetAI_boss_champion_warrior; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_champion_mage"; + pNewScript->GetAI = &GetAI_boss_champion_mage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_champion_shaman"; + pNewScript->GetAI = &GetAI_boss_champion_shaman; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_champion_hunter"; + pNewScript->GetAI = &GetAI_boss_champion_hunter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_champion_rogue"; + pNewScript->GetAI = &GetAI_boss_champion_rogue; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_trial_grand_champion"; + pNewScript->GetAI = &GetAI_npc_trial_grand_champion; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_champion_mount"; + pNewScript->GetAI = &GetAI_npc_champion_mount; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp index 3f03695c5..9d5cceca3 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/instance_trial_of_the_champion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: instance_trial_of_the_champion -SD%Complete: 0 -SDComment: +SD%Complete: 90 +SDComment: Fireworks and various other fine details are not yet implemented. SDCategory: Crusader Coliseum, Trial of the Champion EndScriptData */ @@ -30,6 +30,1167 @@ EndScriptData */ 2 - Black Knight */ +enum +{ + // grand champions + SAY_HERALD_HORDE_CHALLENGE = -1650000, + SAY_HERALD_ALLIANCE_CHALLENGE = -1650006, + + SAY_TIRION_CHALLENGE_WELCOME = -1650012, + SAY_TIRION_FIRST_CHALLENGE = -1650013, + SAY_THRALL_ALLIANCE_CHALLENGE = -1650014, + SAY_GARROSH_ALLIANCE_CHALLENGE = -1650015, + SAY_VARIAN_HORDE_CHALLENGE = -1650016, + SAY_TIRION_CHALLENGE_BEGIN = -1650017, + + // argent champion + SAY_TIRION_ARGENT_CHAMPION = -1650028, + SAY_TIRION_ARGENT_CHAMPION_BEGIN = -1650029, + SAY_HERALD_EADRIC = -1650030, + SAY_HERALD_PALETRESS = -1650031, + EMOTE_HORDE_ARGENT_CHAMPION = -1650032, + EMOTE_ALLIANCE_ARGENT_CHAMPION = -1650033, + SAY_EADRIC_INTRO = -1650034, + SAY_PALETRESS_INTRO_1 = -1650035, + SAY_PALETRESS_INTRO_2 = -1650036, + + // black knight + SAY_TIRION_ARGENT_CHAMPION_COMPLETE = -1650037, + SAY_HERALD_BLACK_KNIGHT_SPAWN = -1650038, + SAY_BLACK_KNIGHT_INTRO_1 = -1650039, + SAY_TIRION_BLACK_KNIGHT_INTRO_2 = -1650040, + SAY_BLACK_KNIGHT_INTRO_3 = -1650041, + SAY_BLACK_KNIGHT_INTRO_4 = -1650042, + + // black knight aggro + SAY_BLACK_KNIGHT_AGGRO = -1650065, + SAY_GARROSH_BLACK_KNIGHT = -1650047, + SAY_VARIAN_BLACK_KNIGHT = -1650050, + + // event complete + SAY_TIRION_EPILOG_1 = -1650043, + SAY_TIRION_EPILOG_2 = -1650044, + SAY_VARIAN_ALLIANCE_EPILOG_3 = -1650045, + SAY_THRALL_HORDE_EPILOG_3 = -1650046, + + // other texts + SAY_THRALL_OTHER_2 = -1650048, + SAY_GARROSH_OTHER_3 = -1650049, + SAY_VARIAN_OTHER_5 = -1650051, + + // sounds + SOUND_ID_CHALLENGE = 15852, + + // spells + SPELL_ARGENT_GET_PLAYER_COUNT = 66986, + SPELL_ARGENT_SUMMON_CHAMPION_1 = 66654, + SPELL_ARGENT_SUMMON_CHAMPION_2 = 66671, + SPELL_ARGENT_SUMMON_CHAMPION_3 = 66673, + SPELL_ARGENT_SUMMON_BOSS_4 = 67396, + SPELL_CHAMPION_KILL_CREDIT = 68572, // achiev check spell + + SPELL_HERALD_FACE_DARK_KNIGHT = 67482, + SPELL_DEATHS_RESPITE = 66798, // triggers 66797 + SPELL_ARGENT_HERALD_FEIGN_DEATH = 66804, + + // Arena event spells - not used for the moment + // SPELL_SPECTATOR_FORCE_CHANT = 66354, + // SPELL_SPECTATOR_FX_CHANT = 66677, + // SPELL_ARGENT_SUMMON_CHAMPION_WAVE = 67295, // cast by center npc 35016; play sound 8574 + // SPELL_SPECTATOR_BUNNY_AURA = 66812, // play sound 15882 + SPELL_SPECTATOR_FORCE_CHEER = 66384, + SPELL_SPECTATOR_FORCE_CHEER_2 = 66385, + + FACTION_CHAMPION_HOSTILE = 16, +}; + +static const DialogueEntryTwoSide aTocDialogues[] = +{ + // Grand Champions intro + {TYPE_ARENA_CHALLENGE, 0, 0, 0, 1000}, + {SAY_HERALD_HORDE_CHALLENGE, NPC_ARELAS_BRIGHTSTAR, SAY_HERALD_ALLIANCE_CHALLENGE, NPC_JAEREN_SUNSWORN, 5000}, + {SAY_TIRION_CHALLENGE_WELCOME, NPC_TIRION_FORDRING, 0, 0, 6000}, + {SAY_TIRION_FIRST_CHALLENGE, NPC_TIRION_FORDRING, 0, 0, 3000}, + {NPC_TIRION_FORDRING, 0, 0, 0, 0}, + // Grand Champions complete + {NPC_ARELAS_BRIGHTSTAR, 0, 0, 0, 7000}, + {SAY_TIRION_ARGENT_CHAMPION, NPC_TIRION_FORDRING, 0, 0, 0}, + // Argent challenge intro + {NPC_ARGENT_MONK, 0, 0, 0, 5000}, + {SOUND_ID_CHALLENGE, 0, 0, 0, 5000}, + {TYPE_ARGENT_CHAMPION, 0, 0, 0, 6000}, + {NPC_JAEREN_SUNSWORN, 0, 0, 0, 4000}, + {NPC_EADRIC, 0, 0, 0, 6000}, + {NPC_PALETRESS, 0, 0, 0, 17000}, + {SAY_TIRION_ARGENT_CHAMPION_BEGIN, NPC_TIRION_FORDRING, 0, 0, 0}, + // Argetn challenge complete + {POINT_ID_MOUNT, 0, 0, 0, 5000}, + {POINT_ID_EXIT, 0, 0, 0, 0}, + // Black knight intro + {TYPE_BLACK_KNIGHT, 0, 0, 0, 4000}, + {SAY_TIRION_ARGENT_CHAMPION_COMPLETE, NPC_TIRION_FORDRING, 0, 0, 4000}, + {SAY_HERALD_BLACK_KNIGHT_SPAWN, NPC_ARELAS_BRIGHTSTAR, SAY_HERALD_BLACK_KNIGHT_SPAWN, NPC_JAEREN_SUNSWORN, 21000}, + {NPC_BLACK_KNIGHT, 0, 0, 0, 1000}, + {SAY_BLACK_KNIGHT_INTRO_1, NPC_BLACK_KNIGHT, 0, 0, 4000}, + {SPELL_DEATHS_RESPITE, 0, 0, 0, 3000}, + {SAY_TIRION_BLACK_KNIGHT_INTRO_2, NPC_TIRION_FORDRING, 0, 0, 1000}, + {NPC_BLACK_KNIGHT_GRYPHON, 0, 0, 0, 2000}, + {SAY_BLACK_KNIGHT_INTRO_3, NPC_BLACK_KNIGHT, 0, 0, 15000}, + {SAY_BLACK_KNIGHT_INTRO_4, NPC_BLACK_KNIGHT, 0, 0, 4000}, + {SPELL_ARGENT_HERALD_FEIGN_DEATH, 0, 0, 0, 0}, + // Black knight epilog + {SPELL_SPECTATOR_FORCE_CHEER, 0, 0, 0, 5000}, + {SAY_TIRION_EPILOG_1, NPC_TIRION_FORDRING, 0, 0, 7000}, + {SAY_TIRION_EPILOG_2, NPC_TIRION_FORDRING, 0, 0, 6000}, + {SAY_VARIAN_ALLIANCE_EPILOG_3, NPC_VARIAN_WRYNN, SAY_THRALL_HORDE_EPILOG_3, NPC_THRALL, 0}, + // Black knight aggro + {SAY_BLACK_KNIGHT_AGGRO, NPC_BLACK_KNIGHT, 0, 0, 5000}, + {SAY_VARIAN_BLACK_KNIGHT, NPC_VARIAN_WRYNN, SAY_GARROSH_BLACK_KNIGHT, NPC_GARROSH, 0}, + {0, 0, 0, 0, 0} +}; + +instance_trial_of_the_champion::instance_trial_of_the_champion(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aTocDialogues), + m_uiTeam(TEAM_NONE), + m_uiHeraldEntry(0), + m_uiGrandChampionEntry(0), + m_uiIntroTimer(0), + m_uiIntroStage(0), + m_uiArenaStage(0), + m_uiGateResetTimer(0), + m_uiChampionsCount(0), + m_uiChampionsTimer(0), + m_bSkipIntro(false), + m_bHadWorseAchiev(false) +{ + Initialize(); +} + +void instance_trial_of_the_champion::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + InitializeDialogueHelper(this); + + m_vAllianceTriggersGuids.resize(MAX_CHAMPIONS_AVAILABLE); + m_vHordeTriggersGuids.resize(MAX_CHAMPIONS_AVAILABLE); +} + +void instance_trial_of_the_champion::OnPlayerEnter(Player* pPlayer) +{ + if (!m_uiTeam) + { + m_uiTeam = pPlayer->GetTeam(); + SetDialogueSide(m_uiTeam == ALLIANCE); + + m_uiHeraldEntry = m_uiTeam == ALLIANCE ? NPC_ARELAS_BRIGHTSTAR : NPC_JAEREN_SUNSWORN; + + // set a random grand champion + m_uiGrandChampionEntry = urand(0, 1) ? NPC_EADRIC : NPC_PALETRESS; + + if (m_vChampionsIndex.empty()) + { + m_vChampionsIndex.resize(MAX_CHAMPIONS_AVAILABLE); + + // fill vector array with indexes from creature array + for (uint8 i = 0; i < MAX_CHAMPIONS_AVAILABLE; ++i) + m_vChampionsIndex[i] = i; + + // set a random champion list + std::random_shuffle(m_vChampionsIndex.begin(), m_vChampionsIndex.end()); + } + } + + DoSummonHeraldIfNeeded(pPlayer); +} + +void instance_trial_of_the_champion::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_JAEREN_SUNSWORN: + case NPC_ARELAS_BRIGHTSTAR: + case NPC_TIRION_FORDRING: + case NPC_VARIAN_WRYNN: + case NPC_THRALL: + case NPC_GARROSH: + case NPC_ALLIANCE_WARRIOR: + case NPC_ALLIANCE_MAGE: + case NPC_ALLIANCE_SHAMAN: + case NPC_ALLIANCE_HUNTER: + case NPC_ALLIANCE_ROGUE: + case NPC_HORDE_WARRIOR: + case NPC_HORDE_MAGE: + case NPC_HORDE_SHAMAN: + case NPC_HORDE_HUNTER: + case NPC_HORDE_ROGUE: + case NPC_EADRIC: + case NPC_PALETRESS: + case NPC_WORLD_TRIGGER: + case NPC_SPECTATOR_HUMAN: + case NPC_SPECTATOR_ORC: + case NPC_SPECTATOR_TROLL: + case NPC_SPECTATOR_TAUREN: + case NPC_SPECTATOR_BLOOD_ELF: + case NPC_SPECTATOR_UNDEAD: + case NPC_SPECTATOR_DWARF: + case NPC_SPECTATOR_DRAENEI: + case NPC_SPECTATOR_NIGHT_ELF: + case NPC_SPECTATOR_GNOME: + case NPC_SPECTATOR_HORDE: + case NPC_SPECTATOR_ALLIANCE: + case NPC_BLACK_KNIGHT: + case NPC_BLACK_KNIGHT_GRYPHON: + break; + case NPC_SPECTATOR_GENERIC: + // alliance side + if (pCreature->GetPositionX() > 775.0f) + { + // night elf + if (pCreature->GetPositionY() > 650.0f) + m_vAllianceTriggersGuids[3] = pCreature->GetObjectGuid(); + // gnome + else if (pCreature->GetPositionY() > 630.0f) + m_vAllianceTriggersGuids[1] = pCreature->GetObjectGuid(); + // human + else if (pCreature->GetPositionY() > 615.0f) + m_vAllianceTriggersGuids[0] = pCreature->GetObjectGuid(); + // dwarf + else if (pCreature->GetPositionY() > 595.0f) + m_vAllianceTriggersGuids[4] = pCreature->GetObjectGuid(); + // draenei + else if (pCreature->GetPositionY() > 580.0f) + m_vAllianceTriggersGuids[2] = pCreature->GetObjectGuid(); + } + // horde side + else if (pCreature->GetPositionX() < 715.0f) + { + // undead + if (pCreature->GetPositionY() > 650.0f) + m_vHordeTriggersGuids[4] = pCreature->GetObjectGuid(); + // blood elf + else if (pCreature->GetPositionY() > 630.0f) + m_vHordeTriggersGuids[1] = pCreature->GetObjectGuid(); + // orc + else if (pCreature->GetPositionY() > 615.0f) + m_vHordeTriggersGuids[0] = pCreature->GetObjectGuid(); + // troll + else if (pCreature->GetPositionY() > 595.0f) + m_vHordeTriggersGuids[3] = pCreature->GetObjectGuid(); + // tauren + else if (pCreature->GetPositionY() > 580.0f) + m_vHordeTriggersGuids[2] = pCreature->GetObjectGuid(); + } + return; + case NPC_WARHORSE_ALLIANCE: + case NPC_WARHORSE_HORDE: + case NPC_BATTLEWORG_ALLIANCE: + case NPC_BATTLEWORG_HORDE: + m_lArenaMountsGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_ARGENT_LIGHTWIELDER: + case NPC_ARGENT_MONK: + case NPC_ARGENT_PRIESTESS: + m_lArgentTrashGuids.push_back(pCreature->GetObjectGuid()); + return; + default: + return; + } + + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); +} + +void instance_trial_of_the_champion::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_MAIN_GATE: + case GO_NORTH_GATE: + case GO_CHAMPIONS_LOOT: + case GO_CHAMPIONS_LOOT_H: + case GO_EADRIC_LOOT: + case GO_EADRIC_LOOT_H: + case GO_PALETRESS_LOOT: + case GO_PALETRESS_LOOT_H: + break; + default: + return; + } + + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_trial_of_the_champion::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_GRAND_CHAMPIONS: + // no double count + if (m_auiEncounter[uiType] == uiData) + return; + + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_NORTH_GATE); + if (uiData == DONE) + { + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CHAMPIONS_LOOT : GO_CHAMPIONS_LOOT_H, 30 * MINUTE); + + // start delayed dialogue + StartNextDialogueText(NPC_ARELAS_BRIGHTSTAR); + + // move the herald back to center + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + pHerald->GetMotionMaster()->Clear(); + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[2][0], aHeraldPositions[2][1], aHeraldPositions[2][2]); + pHerald->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + DoSendChampionsToExit(); + } + break; + case TYPE_ARGENT_CHAMPION: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_NORTH_GATE); + if (uiData == DONE) + { + if (m_uiGrandChampionEntry == NPC_EADRIC) + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_EADRIC_LOOT : GO_EADRIC_LOOT_H, 30 * MINUTE); + else if (m_uiGrandChampionEntry == NPC_PALETRESS) + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_PALETRESS_LOOT : GO_PALETRESS_LOOT_H, 30 * MINUTE); + + // start event epilog + StartNextDialogueText(POINT_ID_MOUNT); + + // move the herald back to center + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + pHerald->GetMotionMaster()->Clear(); + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[2][0], aHeraldPositions[2][1], aHeraldPositions[2][2]); + pHerald->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + } + break; + case TYPE_BLACK_KNIGHT: + DoUseDoorOrButton(GO_NORTH_GATE); + if (uiData == DONE) + StartNextDialogueText(SPELL_SPECTATOR_FORCE_CHEER); + else if (uiData == IN_PROGRESS) + m_bHadWorseAchiev = true; + m_auiEncounter[uiType] = uiData; + break; + case TYPE_ARENA_CHALLENGE: + m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + { + // start arena challenge + m_uiArenaStage = 0; + DoSendNextArenaWave(); + } + else if (uiData == DONE) + { + // count the champions that reach the exit + ++m_uiChampionsCount; + + if (m_uiChampionsCount == MAX_CHAMPIONS_ARENA) + { + // start grand champions challenge (without mount) + m_uiChampionsCount = 0; + m_uiChampionsTimer = 5000; + + // despawn vehicle mounts + for (GuidList::const_iterator itr = m_lArenaMountsGuids.begin(); itr != m_lArenaMountsGuids.end(); ++itr) + { + if (Creature* pMount = instance->GetCreature(*itr)) + pMount->ForcedDespawn(); + } + m_lArenaMountsGuids.clear(); + } + } + else if (uiData == FAIL) + { + DoCleanupArenaOnWipe(); + SetData(TYPE_ARENA_CHALLENGE, NOT_STARTED); + } + else if (uiData == SPECIAL) + DoSendChampionsToExit(); + return; + default: + script_error_log("Instance Trial of The Champion: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_trial_of_the_champion::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_trial_of_the_champion::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +bool instance_trial_of_the_champion::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_HAD_WORSE: + return m_bHadWorseAchiev; + //case ACHIEV_CRIT_FACEROLLER: + // return m_bFacerollerAchiev; + + default: + return false; + } +} + +void instance_trial_of_the_champion::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_ALLIANCE_WARRIOR_CHAMPION: + case NPC_ALLIANCE_MAGE_CHAMPION: + case NPC_ALLIANCE_SHAMAN_CHAMPION: + case NPC_ALLIANCE_HUNTER_CHAMPION: + case NPC_ALLIANCE_ROGUE_CHAMPION: + case NPC_HORDE_WARRIOR_CHAMPION: + case NPC_HORDE_MAGE_CHAMPION: + case NPC_HORDE_SHAMAN_CHAMPION: + case NPC_HORDE_HUNTER_CHAMPION: + case NPC_HORDE_ROGUE_CHAMPION: + // handle champion trash mob kill + if (m_sArenaHelpersGuids[m_uiArenaStage].find(pCreature->GetObjectGuid()) != m_sArenaHelpersGuids[m_uiArenaStage].end()) + { + m_sArenaHelpersGuids[m_uiArenaStage].erase(pCreature->GetObjectGuid()); + + // send next arena wave if cleared + if (m_sArenaHelpersGuids[m_uiArenaStage].empty()) + { + ++m_uiArenaStage; + DoSendNextArenaWave(); + } + } + break; + case NPC_ARGENT_LIGHTWIELDER: + case NPC_ARGENT_MONK: + case NPC_ARGENT_PRIESTESS: + m_lArgentTrashGuids.remove(pCreature->GetObjectGuid()); + + // when trash is cleaned, make the champion hostile + if (m_lArgentTrashGuids.empty()) + { + if (Creature* pChampion = GetSingleCreatureFromStorage(m_uiGrandChampionEntry)) + { + pChampion->SetFactionTemporary(FACTION_CHAMPION_HOSTILE, TEMPFACTION_NONE); + pChampion->GetMotionMaster()->MovePoint(POINT_ID_CENTER, 746.630f, 636.570f, 411.572f); + pChampion->SetRespawnCoord(746.630f, 636.570f, 411.572f, pChampion->GetOrientation()); + } + } + break; + } +} + +void instance_trial_of_the_champion::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_ALLIANCE_WARRIOR_CHAMPION: + case NPC_ALLIANCE_MAGE_CHAMPION: + case NPC_ALLIANCE_SHAMAN_CHAMPION: + case NPC_ALLIANCE_HUNTER_CHAMPION: + case NPC_ALLIANCE_ROGUE_CHAMPION: + case NPC_HORDE_WARRIOR_CHAMPION: + case NPC_HORDE_MAGE_CHAMPION: + case NPC_HORDE_SHAMAN_CHAMPION: + case NPC_HORDE_HUNTER_CHAMPION: + case NPC_HORDE_ROGUE_CHAMPION: + case NPC_ALLIANCE_WARRIOR: + case NPC_ALLIANCE_MAGE: + case NPC_ALLIANCE_SHAMAN: + case NPC_ALLIANCE_HUNTER: + case NPC_ALLIANCE_ROGUE: + case NPC_HORDE_WARRIOR: + case NPC_HORDE_MAGE: + case NPC_HORDE_SHAMAN: + case NPC_HORDE_HUNTER: + case NPC_HORDE_ROGUE: + if (GetData(TYPE_ARENA_CHALLENGE) == IN_PROGRESS) + SetData(TYPE_ARENA_CHALLENGE, FAIL); + break; + } +} + +void instance_trial_of_the_champion::OnCreatureDespawn(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_WARHORSE_ALLIANCE: + case NPC_WARHORSE_HORDE: + case NPC_BATTLEWORG_ALLIANCE: + case NPC_BATTLEWORG_HORDE: + { + if (GetData(TYPE_ARENA_CHALLENGE) == DONE) + return; + + // respawn the vehicle mount + float fX, fY, fZ, fO; + pCreature->GetRespawnCoord(fX, fY, fZ, &fO); + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->SummonCreature(pCreature->GetEntry(), fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0); + break; + } + } +} + +void instance_trial_of_the_champion::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_BLACK_KNIGHT) + { + SetData(TYPE_BLACK_KNIGHT, IN_PROGRESS); + StartNextDialogueText(SAY_BLACK_KNIGHT_AGGRO); + } +} + +// Function that returns the arena challenge status +bool instance_trial_of_the_champion::IsArenaChallengeComplete(uint32 uiType) +{ + // check stand state of each champion based on the type of the encounter + uint8 uiStandState = 0; + + if (uiType == TYPE_ARENA_CHALLENGE) + { + // if this was already marked as complete return true + if (GetData(TYPE_ARENA_CHALLENGE) == SPECIAL || GetData(TYPE_ARENA_CHALLENGE) == DONE) + return true; + + uiStandState = UNIT_STAND_STATE_DEAD; + } + else if (uiType == TYPE_GRAND_CHAMPIONS) + uiStandState = UNIT_STAND_STATE_KNEEL; + + // check if all champions are defeated + for (uint8 i = 0; i < MAX_CHAMPIONS_ARENA; ++i) + { + if (Creature* pChampion = instance->GetCreature(m_ArenaChampionsGuids[i])) + { + if (pChampion->getStandState() != uiStandState) + return false; + } + } + + return true; +} + +// Function that summons herald and vehicle mounts if required +void instance_trial_of_the_champion::DoSummonHeraldIfNeeded(Unit* pSummoner) +{ + if (!pSummoner) + return; + + if (GetSingleCreatureFromStorage(m_uiHeraldEntry, true)) + return; + + pSummoner->SummonCreature(m_uiHeraldEntry, aHeraldPositions[0][0], aHeraldPositions[0][1], aHeraldPositions[0][2], aHeraldPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0); + + // summon champion mounts if required + if (GetData(TYPE_GRAND_CHAMPIONS) != DONE) + { + for (uint8 i = 0; i < MAX_CHAMPIONS_MOUNTS; ++i) + pSummoner->SummonCreature(m_uiTeam == ALLIANCE ? aTrialChampionsMounts[i].uiEntryAlliance : aTrialChampionsMounts[i].uiEntryHorde, aTrialChampionsMounts[i].fX, aTrialChampionsMounts[i].fY, aTrialChampionsMounts[i].fZ, aTrialChampionsMounts[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0); + } +} + +// Function that sends the champions and trash mobs into to fight in the arena +void instance_trial_of_the_champion::DoSendNextArenaWave() +{ + // center trigger for reference + Creature* pCenterTrigger = GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER); + if (!pCenterTrigger) + return; + + float fX, fY, fZ; + + // trash waves cleaned - send the summoned champions to the center + if (m_uiArenaStage == MAX_CHAMPIONS_ARENA) + { + for (uint8 i = 0; i < MAX_CHAMPIONS_ARENA; ++i) + { + // move mounts to center + if (Creature* pMount = instance->GetCreature(m_ArenaMountsGuids[i])) + { + pMount->SetWalk(false); + pCenterTrigger->GetContactPoint(pMount, fX, fY, fZ, 2 * INTERACTION_DISTANCE); + pMount->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, fX, fY, fZ); + } + + // set champions to attack + if (Creature* pChampion = instance->GetCreature(m_ArenaChampionsGuids[i])) + pChampion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + } + // send trash waves of champions in the arena + else + { + for (GuidSet::const_iterator itr = m_sArenaHelpersGuids[m_uiArenaStage].begin(); itr != m_sArenaHelpersGuids[m_uiArenaStage].end(); ++itr) + { + if (Creature* pHelper = instance->GetCreature(*itr)) + { + pHelper->SetWalk(false); + pCenterTrigger->GetContactPoint(pHelper, fX, fY, fZ, 2 * INTERACTION_DISTANCE); + pHelper->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, fX, fY, fZ); + pHelper->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + } + } + } +} + +// Function that cleans the arena on wipe +void instance_trial_of_the_champion::DoCleanupArenaOnWipe() +{ + // cleanup arena encounter + for (uint8 i = 0; i < MAX_CHAMPIONS_ARENA; ++i) + { + if (Creature* pMount = instance->GetCreature(m_ArenaMountsGuids[i])) + pMount->ForcedDespawn(); + + if (Creature* pChampion = instance->GetCreature(m_ArenaChampionsGuids[i])) + pChampion->ForcedDespawn(); + + for (GuidSet::const_iterator itr = m_sArenaHelpersGuids[i].begin(); itr != m_sArenaHelpersGuids[i].end(); ++itr) + { + if (Creature* pHelper = instance->GetCreature(*itr)) + pHelper->ForcedDespawn(); + } + + m_sArenaHelpersGuids[i].clear(); + } + + // reset herald + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + pHerald->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pHerald->GetMotionMaster()->MoveTargetedHome(); + } +} + +// Function that prepares the Grand Champions encounter (long and short intro) +void instance_trial_of_the_champion::DoPrepareChampions(bool bSkipIntro) +{ + m_bSkipIntro = bSkipIntro; + + // long intro + if (!bSkipIntro) + StartNextDialogueText(TYPE_ARENA_CHALLENGE); + // short intro + else + { + StartNextDialogueText(SAY_TIRION_CHALLENGE_WELCOME); + + // move the herald to the gate + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[1][0], aHeraldPositions[1][1], aHeraldPositions[1][2]); + } +} + +// Function that sends the champion to intro home location +void instance_trial_of_the_champion::MoveChampionToHome(Creature* pChampion) +{ + uint8 uiIndex = m_vChampionsIndex[m_uiIntroStage - 1]; + + // get the corresponding trigger + Creature* pTrigger = instance->GetCreature(m_uiTeam == ALLIANCE ? m_vHordeTriggersGuids[uiIndex] : m_vAllianceTriggersGuids[uiIndex]); + if (!pTrigger) + return; + + // move to the right position + pChampion->SetWalk(true); + pChampion->GetMotionMaster()->MovePoint(POINT_ID_HOME, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ()); + + if (m_uiIntroStage == MAX_CHAMPIONS_ARENA) + { + // move the herald to the gate + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[1][0], aHeraldPositions[1][1], aHeraldPositions[1][2]); + } +} + +// Function that handles instance behavior when champion reaches intro home position +// This sets the trash mobs to the right points and sends the next champion for intro +void instance_trial_of_the_champion::InformChampionReachHome() +{ + uint8 uiIndex = m_vChampionsIndex[m_uiIntroStage - 1]; + + // get the corresponding trigger + Creature* pTrigger = instance->GetCreature(m_uiTeam == ALLIANCE ? m_vHordeTriggersGuids[uiIndex] : m_vAllianceTriggersGuids[uiIndex]); + if (!pTrigger) + return; + + // center trigger for reference + Creature* pCenterTrigger = GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER); + if (!pCenterTrigger) + return; + + float fX, fY, fZ; + uint8 j = 0; + + // move helpers to the right point + for (GuidSet::const_iterator itr = m_sArenaHelpersGuids[m_uiIntroStage - 1].begin(); itr != m_sArenaHelpersGuids[m_uiIntroStage - 1].end(); ++itr) + { + if (Creature* pHelper = instance->GetCreature(*itr)) + { + pTrigger->GetNearPoint(pTrigger, fX, fY, fZ, 0, 5.0f, pTrigger->GetAngle(pCenterTrigger) - (M_PI_F * 0.25f) + j * (M_PI_F * 0.25f)); + pHelper->GetMotionMaster()->Clear(); + pHelper->GetMotionMaster()->MovePoint(POINT_ID_HOME, fX, fY, fZ); + ++j; + } + } + + // set timer + if (m_uiIntroStage == MAX_CHAMPIONS_ARENA) + m_uiIntroTimer = 5000; + else + m_uiIntroTimer = 2000; +} + +// Function that will send all the champions to the get for exit +void instance_trial_of_the_champion::DoSendChampionsToExit() +{ + // move the champions to the gate + for (uint8 i = 0; i < MAX_CHAMPIONS_ARENA; ++i) + { + if (Creature* pChampion = instance->GetCreature(m_ArenaChampionsGuids[i])) + { + // kill credit spell on completion + if (GetData(TYPE_GRAND_CHAMPIONS) == DONE) + pChampion->CastSpell(pChampion, SPELL_CHAMPION_KILL_CREDIT, true); + + pChampion->SetWalk(true); + pChampion->SetStandState(UNIT_STAND_STATE_STAND); + pChampion->GetMotionMaster()->MovePoint(POINT_ID_EXIT, aChampsPositions[0][0], aChampsPositions[0][1], aChampsPositions[0][2]); + } + } +} + +// Function that will set all the champions in combat with the target +void instance_trial_of_the_champion::DoSetChamptionsInCombat(Unit* pTarget) +{ + for (uint8 i = 0; i < MAX_CHAMPIONS_ARENA; ++i) + { + if (Creature* pChampion = instance->GetCreature(m_ArenaChampionsGuids[i])) + pChampion->AI()->AttackStart(pTarget); + } +} + +void instance_trial_of_the_champion::JustDidDialogueStep(int32 iEntry) +{ + switch (iEntry) + { + // start arena long intro + case TYPE_ARENA_CHALLENGE: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + if (Creature* pTrigger = GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER)) + pHerald->GetMotionMaster()->MovePoint(0, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ()); + + pHerald->CastSpell(pHerald, SPELL_ARGENT_GET_PLAYER_COUNT, true); + pHerald->PlayDirectSound(SOUND_ID_CHALLENGE); + } + break; + case SAY_HERALD_ALLIANCE_CHALLENGE: + case SAY_HERALD_HORDE_CHALLENGE: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_FORDRING)) + pHerald->SetFacingToObject(pTirion); + + // ToDo: play intro music + } + break; + // complete intro - start arena event + case NPC_TIRION_FORDRING: + m_uiIntroStage = 0; + m_uiIntroTimer = 1000; + break; + + // start argent challenge + case NPC_ARGENT_MONK: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[0][0], aHeraldPositions[0][1], aHeraldPositions[0][2]); + break; + case SOUND_ID_CHALLENGE: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->PlayDirectSound(SOUND_ID_CHALLENGE); + break; + case TYPE_ARGENT_CHAMPION: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_FORDRING)) + pHerald->SetFacingToObject(pTirion); + + pHerald->CastSpell(pHerald, SPELL_ARGENT_SUMMON_BOSS_4, true); + DoScriptText(m_uiGrandChampionEntry == NPC_EADRIC ? SAY_HERALD_EADRIC : SAY_HERALD_PALETRESS, pHerald); + + DoUseDoorOrButton(GO_MAIN_GATE); + m_uiGateResetTimer = 10000; // ToDo: set this as door reset timer when fixed in core + + // summon the selected champion + if (Creature* pChampion = pHerald->SummonCreature(m_uiGrandChampionEntry, aArgentChallengeHelpers[9].fX, aArgentChallengeHelpers[9].fY, aArgentChallengeHelpers[9].fZ, aArgentChallengeHelpers[9].fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pChampion->CastSpell(pChampion, SPELL_SPECTATOR_FORCE_CHEER, true); + pChampion->CastSpell(pChampion, SPELL_SPECTATOR_FORCE_CHEER_2, true); + + if (Creature* pSpectator = GetSingleCreatureFromStorage(NPC_SPECTATOR_HORDE)) + DoScriptText(EMOTE_HORDE_ARGENT_CHAMPION, pSpectator, pChampion); + if (Creature* pSpectator = GetSingleCreatureFromStorage(NPC_SPECTATOR_ALLIANCE)) + DoScriptText(EMOTE_ALLIANCE_ARGENT_CHAMPION, pSpectator, pChampion); + } + + for (uint8 i = 0; i < MAX_ARGENT_TRASH; ++i) + { + if (Creature* pHelper = pHerald->SummonCreature(aArgentChallengeHelpers[i].uiEntry, aArgentChallengeHelpers[i].fX, aArgentChallengeHelpers[i].fY, aArgentChallengeHelpers[i].fZ, aArgentChallengeHelpers[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pHelper->GetMotionMaster()->MovePoint(POINT_ID_CENTER, aArgentChallengeHelpers[i].fTargetX, aArgentChallengeHelpers[i].fTargetY, aArgentChallengeHelpers[i].fTargetZ, false); + pHelper->SetRespawnCoord(aArgentChallengeHelpers[i].fTargetX, aArgentChallengeHelpers[i].fTargetY, aArgentChallengeHelpers[i].fTargetZ, pHelper->GetOrientation()); + } + } + } + break; + case NPC_JAEREN_SUNSWORN: + if (Creature* pChampion = GetSingleCreatureFromStorage(m_uiGrandChampionEntry)) + { + pChampion->GetMotionMaster()->MovePoint(POINT_ID_CENTER, aArgentChallengeHelpers[9].fTargetX, aArgentChallengeHelpers[9].fTargetY, aArgentChallengeHelpers[9].fTargetZ, false); + pChampion->SetRespawnCoord(aArgentChallengeHelpers[9].fTargetX, aArgentChallengeHelpers[9].fTargetY, aArgentChallengeHelpers[9].fTargetZ, pChampion->GetOrientation()); + } + break; + case NPC_EADRIC: + if (Creature* pChampion = GetSingleCreatureFromStorage(m_uiGrandChampionEntry)) + DoScriptText(m_uiGrandChampionEntry == NPC_EADRIC ? SAY_EADRIC_INTRO : SAY_PALETRESS_INTRO_1, pChampion); + + // move the herald to the gate + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[1][0], aHeraldPositions[1][1], aHeraldPositions[1][2]); + break; + case NPC_PALETRESS: + if (m_uiGrandChampionEntry == NPC_PALETRESS) + { + if (Creature* pChampion = GetSingleCreatureFromStorage(m_uiGrandChampionEntry)) + DoScriptText(SAY_PALETRESS_INTRO_2, pChampion); + } + break; + case SAY_TIRION_ARGENT_CHAMPION_BEGIN: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_FORDRING)) + pHerald->SetFacingToObject(pTirion); + } + break; + // argent challenge completed + case POINT_ID_EXIT: + if (Creature* pChampion = GetSingleCreatureFromStorage(m_uiGrandChampionEntry)) + { + pChampion->GetMotionMaster()->MovePoint(0, aArgentChallengeHelpers[9].fTargetX, aArgentChallengeHelpers[9].fTargetY, aArgentChallengeHelpers[9].fTargetZ); + pChampion->ForcedDespawn(8000); + } + break; + + // start black knight intro + case TYPE_BLACK_KNIGHT: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->GetMotionMaster()->MovePoint(0, aHeraldPositions[3][0], aHeraldPositions[3][1], aHeraldPositions[3][2]); + break; + case SAY_TIRION_ARGENT_CHAMPION_COMPLETE: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + if (Creature* pKnight = pHerald->SummonCreature(NPC_BLACK_KNIGHT, aKnightPositions[0][0], aKnightPositions[0][1], aKnightPositions[0][2], aKnightPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + if (Creature* pGryphon = pHerald->SummonCreature(NPC_BLACK_KNIGHT_GRYPHON, aKnightPositions[1][0], aKnightPositions[1][1], aKnightPositions[1][2], aKnightPositions[1][3], TEMPSUMMON_TIMED_DESPAWN, 75000)) + { + pKnight->CastSpell(pGryphon, SPELL_RIDE_VEHICLE_HARDCODED, true); + pGryphon->SetWalk(false); + pGryphon->SetLevitate(true); + } + } + + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_FORDRING)) + pHerald->SetFacingToObject(pTirion); + } + break; + case SAY_HERALD_BLACK_KNIGHT_SPAWN: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->CastSpell(pHerald, SPELL_HERALD_FACE_DARK_KNIGHT, false); + if (Creature* pGryphon = GetSingleCreatureFromStorage(NPC_BLACK_KNIGHT_GRYPHON)) + pGryphon->GetMotionMaster()->MoveWaypoint(); + break; + case NPC_BLACK_KNIGHT: + if (Creature* pGryphon = GetSingleCreatureFromStorage(NPC_BLACK_KNIGHT_GRYPHON)) + pGryphon->RemoveAurasDueToSpell(SPELL_RIDE_VEHICLE_HARDCODED); + break; + case SAY_BLACK_KNIGHT_INTRO_1: + if (Creature* pKnight = GetSingleCreatureFromStorage(NPC_BLACK_KNIGHT)) + { + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + pHerald->SetFacingToObject(pKnight); + pKnight->SetFacingToObject(pHerald); + } + } + break; + case SPELL_DEATHS_RESPITE: + if (Creature* pKnight = GetSingleCreatureFromStorage(NPC_BLACK_KNIGHT)) + pKnight->CastSpell(pKnight, SPELL_DEATHS_RESPITE, false); + break; + case NPC_BLACK_KNIGHT_GRYPHON: + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + pHerald->CastSpell(pHerald, SPELL_ARGENT_HERALD_FEIGN_DEATH, true); + break; + case SAY_BLACK_KNIGHT_INTRO_3: + if (Creature* pKnight = GetSingleCreatureFromStorage(NPC_BLACK_KNIGHT)) + { + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_FORDRING)) + pKnight->SetFacingToObject(pTirion); + } + break; + case SPELL_ARGENT_HERALD_FEIGN_DEATH: + if (Creature* pKnight = GetSingleCreatureFromStorage(NPC_BLACK_KNIGHT)) + { + pKnight->SetRespawnCoord(aKnightPositions[2][0], aKnightPositions[2][1], aKnightPositions[2][2], aKnightPositions[2][3]); + pKnight->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + break; + } +} + +void instance_trial_of_the_champion::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (m_uiIntroTimer) + { + if (m_uiIntroTimer <= uiDiff) + { + switch (m_uiIntroStage) + { + // spawn champions + case 0: + case 1: + case 2: + { + uint8 uiIndex = m_vChampionsIndex[m_uiIntroStage]; + + // summoner (herald) + Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry); + if (!pHerald) + return; + + // center trigger for reference + Creature* pCenterTrigger = GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER); + if (!pCenterTrigger) + return; + + // short intro + if (m_bSkipIntro) + { + // get the summoning trigger + Creature* pTrigger = instance->GetCreature(m_uiTeam == ALLIANCE ? m_vHordeTriggersGuids[uiIndex] : m_vAllianceTriggersGuids[uiIndex]); + if (!pTrigger) + return; + + // summon grand champion, mount and emote + if (Creature* pChampion = pHerald->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiEntry : aAllianceChampions[uiIndex].uiEntry, + pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), pTrigger->GetAngle(pCenterTrigger), TEMPSUMMON_DEAD_DESPAWN, 0)) + { + // handle emote + if (Creature* pStalker = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiCrowdStalker : aAllianceChampions[uiIndex].uiCrowdStalker)) + DoScriptText(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].iEmoteEntry : aAllianceChampions[uiIndex].iEmoteEntry, pStalker, pChampion); + + // summon champion mount + if (Creature* pMount = pChampion->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiMount : aAllianceChampions[uiIndex].uiMount, + pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), pTrigger->GetAngle(pCenterTrigger), TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pChampion->CastSpell(pMount, SPELL_RIDE_VEHICLE_HARDCODED, true); + + // set guid + m_ArenaChampionsGuids[m_uiIntroStage] = pChampion->GetObjectGuid(); + m_ArenaMountsGuids[m_uiIntroStage] = pMount->GetObjectGuid(); + } + } + + // summon helper champions + float fX, fY, fZ; + for (uint8 j = 0; j < 3; ++j) + { + pTrigger->GetNearPoint(pTrigger, fX, fY, fZ, 0, 5.0f, pTrigger->GetAngle(pCenterTrigger) - (M_PI_F * 0.25f) + j * (M_PI_F * 0.25f)); + if (Creature* pHelper = pHerald->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiChampion : aAllianceChampions[uiIndex].uiChampion, + fX, fY, fZ, pTrigger->GetAngle(pCenterTrigger), TEMPSUMMON_DEAD_DESPAWN, 0)) + m_sArenaHelpersGuids[m_uiIntroStage].insert(pHelper->GetObjectGuid()); + } + + if (m_uiIntroStage == MAX_CHAMPIONS_ARENA - 1) + m_uiIntroTimer = 5000; + else + m_uiIntroTimer = 2000; + } + // long intro + else + { + float fX, fY, fZ; + DoUseDoorOrButton(GO_MAIN_GATE); + m_uiGateResetTimer = 10000; // ToDo: set this as door reset timer when fixed in core + + // summon grand champion, mount and emote + if (Creature* pChampion = pHerald->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiEntry : aAllianceChampions[uiIndex].uiEntry, + aIntroPositions[0][0], aIntroPositions[0][1], aIntroPositions[0][2], aIntroPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + // text + DoScriptText(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].iYellEntry : aAllianceChampions[uiIndex].iYellEntry, pHerald); + pHerald->SetFacingToObject(pChampion); + + switch (m_uiIntroStage) + { + case 0: pHerald->CastSpell(pHerald, SPELL_ARGENT_SUMMON_CHAMPION_1, true); break; + case 1: pHerald->CastSpell(pHerald, SPELL_ARGENT_SUMMON_CHAMPION_2, true); break; + case 2: pHerald->CastSpell(pHerald, SPELL_ARGENT_SUMMON_CHAMPION_3, true); break; + } + + // handle emote + if (Creature* pStalker = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiCrowdStalker : aAllianceChampions[uiIndex].uiCrowdStalker)) + DoScriptText(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].iEmoteEntry : aAllianceChampions[uiIndex].iEmoteEntry, pStalker, pChampion); + + // summon champion mount + if (Creature* pMount = pChampion->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiMount : aAllianceChampions[uiIndex].uiMount, + aIntroPositions[0][0], aIntroPositions[0][1], aIntroPositions[0][2], aIntroPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pChampion->CastSpell(pMount, SPELL_RIDE_VEHICLE_HARDCODED, true); + + pMount->SetWalk(false); + pCenterTrigger->GetContactPoint(pChampion, fX, fY, fZ, 2 * INTERACTION_DISTANCE); + pMount->GetMotionMaster()->MovePoint(POINT_ID_CENTER, fX, fY, fZ, false); + + // set guid + m_ArenaChampionsGuids[m_uiIntroStage] = pChampion->GetObjectGuid(); + m_ArenaMountsGuids[m_uiIntroStage] = pMount->GetObjectGuid(); + + // summon helper champions + for (uint8 j = 0; j < 3; ++j) + { + if (Creature* pHelper = pChampion->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiChampion : aAllianceChampions[uiIndex].uiChampion, + aIntroPositions[j + 1][0], aIntroPositions[j + 1][1], aIntroPositions[j + 1][2], aIntroPositions[j + 1][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pHelper->GetMotionMaster()->MoveFollow(pMount, pHelper->GetDistance(pMount), M_PI_F / 2 + pHelper->GetAngle(pMount)); + m_sArenaHelpersGuids[m_uiIntroStage].insert(pHelper->GetObjectGuid()); + } + } + } + } + + // stop event; timer in InformChampionReachHome() + m_uiIntroTimer = 0; + } + break; + } + // complete intro - start arena challenge + case 3: + if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_FORDRING)) + DoScriptText(SAY_TIRION_CHALLENGE_BEGIN, pTirion); + + if (Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry)) + { + if (Creature* pCenterTrigger = GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER)) + pHerald->SetFacingToObject(pCenterTrigger); + } + + // start first half of the encounter + SetData(TYPE_ARENA_CHALLENGE, IN_PROGRESS); + m_uiIntroTimer = 0; + break; + } + ++m_uiIntroStage; + } + else + m_uiIntroTimer -= uiDiff; + } + + // ToDo: set this as door reset timer when fixed in core + if (m_uiGateResetTimer) + { + if (m_uiGateResetTimer <= uiDiff) + { + DoUseDoorOrButton(GO_MAIN_GATE); + m_uiGateResetTimer = 0; + } + else + m_uiGateResetTimer -= uiDiff; + } + + // summon champions for the second part of the encounter + if (m_uiChampionsTimer) + { + if (m_uiChampionsTimer <= uiDiff) + { + Creature* pHerald = GetSingleCreatureFromStorage(m_uiHeraldEntry); + if (!pHerald) + return; + + uint8 uiIndex = 0; + + for (uint8 i = 0; i < MAX_CHAMPIONS_ARENA; ++i) + { + uiIndex = m_vChampionsIndex[i]; + + if (Creature* pChampion = pHerald->SummonCreature(m_uiTeam == ALLIANCE ? aHordeChampions[uiIndex].uiEntry : aAllianceChampions[uiIndex].uiEntry, + aChampsPositions[i][0], aChampsPositions[i][1], aChampsPositions[i][2], aChampsPositions[i][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + m_ArenaChampionsGuids[i] = pChampion->GetObjectGuid(); + } + m_uiChampionsTimer = 0; + } + else + m_uiChampionsTimer -= uiDiff; + } +} + +InstanceData* GetInstanceData_instance_trial_of_the_champion(Map* pMap) +{ + return new instance_trial_of_the_champion(pMap); +} + void AddSC_instance_trial_of_the_champion() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_trial_of_the_champion"; + pNewScript->GetInstanceData = &GetInstanceData_instance_trial_of_the_champion; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp index 4bfe346c8..ec59514c7 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,14 +16,90 @@ /* ScriptData SDName: trial_of_the_champion -SD%Complete: 0 -SDComment: +SD%Complete: 20 +SDComment: Gossip SDCategory: Crusader Coliseum, Trial of the Champion EndScriptData */ #include "precompiled.h" #include "trial_of_the_champion.h" +/*###### +## npc_toc_herald +######*/ + +enum +{ + GOSSIP_ITEM_READY = -3650000, + GOSSIP_ITEM_READY_SKIP_INTRO = -3650001, + GOSSIP_ITEM_READY_NEXT_CHALLENGE = -3650002, + + TEXT_ID_READY_FIRST_CHALLENGE = 14688, + TEXT_ID_READY_NEXT_CHALLENGE = 14737, + TEXT_ID_READY_FINAL_CHALLENGE = 14738, +}; + +bool GossipHello_npc_toc_herald(Player* pPlayer, Creature* pCreature) +{ + instance_trial_of_the_champion* pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_GRAND_CHAMPIONS) == NOT_STARTED) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY_SKIP_INTRO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_READY_FIRST_CHALLENGE, pCreature->GetObjectGuid()); + } + else if (pInstance->GetData(TYPE_GRAND_CHAMPIONS) == DONE && pInstance->GetData(TYPE_ARGENT_CHAMPION) == NOT_STARTED) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY_NEXT_CHALLENGE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_READY_NEXT_CHALLENGE, pCreature->GetObjectGuid()); + } + else if (pInstance->GetData(TYPE_ARGENT_CHAMPION) == DONE && pInstance->GetData(TYPE_BLACK_KNIGHT) == NOT_STARTED) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_READY_FINAL_CHALLENGE, pCreature->GetObjectGuid()); + } + + return true; +} + +bool GossipSelect_npc_toc_herald(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) +{ + instance_trial_of_the_champion* pInstance = (instance_trial_of_the_champion*)pCreature->GetInstanceData(); + if (!pInstance) + return true; + + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pInstance->DoPrepareChampions(false); + break; + case GOSSIP_ACTION_INFO_DEF+2: + pInstance->DoPrepareChampions(true); + break; + case GOSSIP_ACTION_INFO_DEF+3: + pInstance->DoPrepareArgentChallenge(); + break; + case GOSSIP_ACTION_INFO_DEF+4: + pInstance->DoPrepareBlackKnight(); + break; + } + + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + + return true; +} + void AddSC_trial_of_the_champion() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_toc_herald"; + pNewScript->pGossipHello = &GossipHello_npc_toc_herald; + pNewScript->pGossipSelect = &GossipSelect_npc_toc_herald; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h index 39b55659b..3b539afa4 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_champion/trial_of_the_champion.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,11 +7,348 @@ enum { - MAX_ENCOUNTER = 3, + MAX_ENCOUNTER = 4, + MAX_CHAMPIONS_AVAILABLE = 5, + MAX_CHAMPIONS_ARENA = 3, + MAX_CHAMPIONS_MOUNTS = 24, + MAX_ARGENT_TRASH = 9, TYPE_GRAND_CHAMPIONS = 0, TYPE_ARGENT_CHAMPION = 1, TYPE_BLACK_KNIGHT = 2, + TYPE_ARENA_CHALLENGE = 3, // used to handle first challenge data; not saved + + // event handler + NPC_ARELAS_BRIGHTSTAR = 35005, // alliance + NPC_JAEREN_SUNSWORN = 35004, // horde + NPC_TIRION_FORDRING = 34996, + NPC_VARIAN_WRYNN = 34990, + NPC_THRALL = 34994, + NPC_GARROSH = 34995, + + // champions alliance + NPC_ALLIANCE_WARRIOR = 34705, // Jacob Alerius + NPC_ALLIANCE_WARRIOR_MOUNT = 35637, // Jacob vehicle mount + NPC_ALLIANCE_WARRIOR_CHAMPION = 35328, // Stormwind Champion + NPC_ALLIANCE_MAGE = 34702, // Ambrose Boltspark + NPC_ALLIANCE_MAGE_MOUNT = 35633, // Ambrose vehicle mount + NPC_ALLIANCE_MAGE_CHAMPION = 35331, // Gnomeregan Champion + NPC_ALLIANCE_SHAMAN = 34701, // Colosos + NPC_ALLIANCE_SHAMAN_MOUNT = 35768, // Colosos vehicle mount + NPC_ALLIANCE_SHAMAN_CHAMPION = 35330, // Exodar Champion + NPC_ALLIANCE_HUNTER = 34657, // Jaelyne Evensong + NPC_ALLIANCE_HUNTER_MOUNT = 34658, // Jaelyne vehicle mount + NPC_ALLIANCE_HUNTER_CHAMPION = 35332, // Darnassus Champion + NPC_ALLIANCE_ROGUE = 34703, // Lana Stouthammer + NPC_ALLIANCE_ROGUE_MOUNT = 35636, // Lana vehicle mount + NPC_ALLIANCE_ROGUE_CHAMPION = 35329, // Ironforge Champion + + // champions horde + NPC_HORDE_WARRIOR = 35572, // Mokra Skullcrusher + NPC_HORDE_WARRIOR_MOUNT = 35638, // Mokra vehicle mount + NPC_HORDE_WARRIOR_CHAMPION = 35314, // Orgrimmar Champion + NPC_HORDE_MAGE = 35569, // Eressea Dawnsinger + NPC_HORDE_MAGE_MOUNT = 35635, // Eressea vehicle mount + NPC_HORDE_MAGE_CHAMPION = 35326, // Silvermoon Champion + NPC_HORDE_SHAMAN = 35571, // Runok Wildmane + NPC_HORDE_SHAMAN_MOUNT = 35640, // Runok vehicle mount + NPC_HORDE_SHAMAN_CHAMPION = 35325, // Thunder Bluff Champion + NPC_HORDE_HUNTER = 35570, // Zul'tore + NPC_HORDE_HUNTER_MOUNT = 35641, // Zul'tore vehicle mount + NPC_HORDE_HUNTER_CHAMPION = 35323, // Sen'jin Champion + NPC_HORDE_ROGUE = 35617, // Deathstalker Visceri + NPC_HORDE_ROGUE_MOUNT = 35634, // Visceri vehicle mount + NPC_HORDE_ROGUE_CHAMPION = 35327, // Undercity Champion + + // spectators triggers + NPC_WORLD_TRIGGER = 22515, // arena center trigger + NPC_SPECTATOR_GENERIC = 35016, // generic trigger that marks the home location for champions + + NPC_SPECTATOR_HORDE = 34883, // creatures that handle emote and crowd + NPC_SPECTATOR_ALLIANCE = 34887, + + NPC_SPECTATOR_HUMAN = 34900, + NPC_SPECTATOR_ORC = 34901, + NPC_SPECTATOR_TROLL = 34902, + NPC_SPECTATOR_TAUREN = 34903, + NPC_SPECTATOR_BLOOD_ELF = 34904, + NPC_SPECTATOR_UNDEAD = 34905, + NPC_SPECTATOR_DWARF = 34906, + NPC_SPECTATOR_DRAENEI = 34908, + NPC_SPECTATOR_NIGHT_ELF = 34909, + NPC_SPECTATOR_GNOME = 34910, + + // mounts + NPC_WARHORSE_ALLIANCE = 36557, // alliance mount vehicle + NPC_WARHORSE_HORDE = 35644, // hostile - used by the champions + NPC_BATTLEWORG_ALLIANCE = 36559, // hostile - used by the champions + NPC_BATTLEWORG_HORDE = 36558, // horde mount vehicle + + // argent challegers + NPC_EADRIC = 35119, + NPC_PALETRESS = 34928, + // trash mobs + NPC_ARGENT_LIGHTWIELDER = 35309, + NPC_ARGENT_MONK = 35305, + NPC_ARGENT_PRIESTESS = 35307, + + // black knight + NPC_BLACK_KNIGHT = 35451, + NPC_BLACK_KNIGHT_GRYPHON = 35491, + + // doors + GO_MAIN_GATE = 195647, + GO_NORTH_GATE = 195650, // combat door + + // chests + GO_CHAMPIONS_LOOT = 195709, + GO_CHAMPIONS_LOOT_H = 195710, + GO_EADRIC_LOOT = 195374, + GO_EADRIC_LOOT_H = 195375, + GO_PALETRESS_LOOT = 195323, + GO_PALETRESS_LOOT_H = 195324, + + // fireworks + GO_FIREWORKS_RED_1 = 180703, + GO_FIREWORKS_RED_2 = 180708, + GO_FIREWORKS_BLUE_1 = 180720, + GO_FIREWORKS_BLUE_2 = 180723, + GO_FIREWORKS_WHITE_1 = 180728, + GO_FIREWORKS_WHITE_2 = 180730, + GO_FIREWORKS_YELLOW_1 = 180736, + GO_FIREWORKS_YELLOW_2 = 180738, + + // area triggers - purpose unk + // AREATRIGGER_ID_TOC_1 = 5491, + // AREATRIGGER_ID_TOC_2 = 5492, + + // emotes + EMOTE_BLOOD_ELVES = -1650018, + EMOTE_TROLLS = -1650019, + EMOTE_TAUREN = -1650020, + EMOTE_UNDEAD = -1650021, + EMOTE_ORCS = -1650022, + EMOTE_DWARVES = -1650023, + EMOTE_GNOMES = -1650024, + EMOTE_NIGHT_ELVES = -1650025, + EMOTE_HUMANS = -1650026, + EMOTE_DRAENEI = -1650027, + + // yells + SAY_HERALD_HORDE_WARRIOR = -1650001, + SAY_HERALD_HORDE_MAGE = -1650002, + SAY_HERALD_HORDE_SHAMAN = -1650003, + SAY_HERALD_HORDE_HUNTER = -1650004, + SAY_HERALD_HORDE_ROGUE = -1650005, + + SAY_HERALD_ALLIANCE_WARRIOR = -1650007, + SAY_HERALD_ALLIANCE_MAGE = -1650008, + SAY_HERALD_ALLIANCE_SHAMAN = -1650009, + SAY_HERALD_ALLIANCE_HUNTER = -1650010, + SAY_HERALD_ALLIANCE_ROGUE = -1650011, + + // other + POINT_ID_CENTER = 1, + POINT_ID_HOME = 2, + POINT_ID_COMBAT = 3, + POINT_ID_MOUNT = 4, + POINT_ID_EXIT = 5, + + // achievements + ACHIEV_CRIT_FACEROLLER = 11858, // Eadric achiev 3803 + ACHIEV_CRIT_HAD_WORSE = 11789, // Black Knight achiev 3804 +}; + +static const float aHeraldPositions[4][4] = +{ + {745.606f, 619.705f, 411.172f, 4.66003f}, // Spawn position + {732.524f, 663.007f, 412.393f, 0.0f}, // Gate movement position + {743.377f, 630.240f, 411.073f, 0.0f}, // Near center position + {744.764f, 628.512f, 411.172f, 0.0f}, // Black knight intro position +}; + +static const float aIntroPositions[4][4] = +{ + {746.683f, 685.050f, 412.384f, 4.744f}, // Champion gate spawn loc + {746.425f, 688.927f, 412.365f, 4.744f}, // Helpers gate spawn locs + {750.531f, 688.431f, 412.369f, 4.744f}, + {742.245f, 688.254f, 412.370f, 4.744f}, +}; + +static const float aChampsPositions[3][4] = // Champions spawn positions inside the arena +{ + {746.600f, 660.116f, 411.772f, 4.729f}, + {737.701f, 660.689f, 412.477f, 4.729f}, + {755.232f, 660.352f, 412.477f, 4.729f}, +}; + +static const float aKnightPositions[3][4] = +{ + {774.283f, 665.505f, 463.484f, 4.310f}, // Black Knight spawn position + {780.694f, 669.611f, 463.662f, 3.769f}, // Gryphon spawn position + {747.788f, 632.487f, 411.414f, 4.744f}, // Center position +}; + +// data that provides grand champion entry, vehicle mount, trash champions with the spawn locations as well as crowd stalker and emote entry +struct ChampionsData +{ + uint32 uiEntry, uiMount, uiChampion, uiCrowdStalker; + int32 iEmoteEntry, iYellEntry; +}; + +static const ChampionsData aAllianceChampions[MAX_CHAMPIONS_AVAILABLE] = +{ + { NPC_ALLIANCE_WARRIOR, NPC_ALLIANCE_WARRIOR_MOUNT, NPC_ALLIANCE_WARRIOR_CHAMPION, NPC_SPECTATOR_HUMAN, EMOTE_HUMANS, SAY_HERALD_ALLIANCE_WARRIOR }, + { NPC_ALLIANCE_MAGE, NPC_ALLIANCE_MAGE_MOUNT, NPC_ALLIANCE_MAGE_CHAMPION, NPC_SPECTATOR_GNOME, EMOTE_GNOMES, SAY_HERALD_ALLIANCE_MAGE }, + { NPC_ALLIANCE_SHAMAN, NPC_ALLIANCE_SHAMAN_MOUNT, NPC_ALLIANCE_SHAMAN_CHAMPION, NPC_SPECTATOR_DRAENEI, EMOTE_DRAENEI, SAY_HERALD_ALLIANCE_SHAMAN }, + { NPC_ALLIANCE_HUNTER, NPC_ALLIANCE_HUNTER_MOUNT, NPC_ALLIANCE_HUNTER_CHAMPION, NPC_SPECTATOR_NIGHT_ELF, EMOTE_NIGHT_ELVES, SAY_HERALD_ALLIANCE_HUNTER }, + { NPC_ALLIANCE_ROGUE, NPC_ALLIANCE_ROGUE_MOUNT, NPC_ALLIANCE_ROGUE_CHAMPION, NPC_SPECTATOR_DWARF, EMOTE_DWARVES, SAY_HERALD_ALLIANCE_ROGUE } +}; + +static const ChampionsData aHordeChampions[MAX_CHAMPIONS_AVAILABLE] = +{ + { NPC_HORDE_WARRIOR, NPC_HORDE_WARRIOR_MOUNT, NPC_HORDE_WARRIOR_CHAMPION, NPC_SPECTATOR_ORC, EMOTE_ORCS, SAY_HERALD_HORDE_WARRIOR }, + { NPC_HORDE_MAGE, NPC_HORDE_MAGE_MOUNT, NPC_HORDE_MAGE_CHAMPION, NPC_SPECTATOR_BLOOD_ELF, EMOTE_BLOOD_ELVES, SAY_HERALD_HORDE_MAGE }, + { NPC_HORDE_SHAMAN, NPC_HORDE_SHAMAN_MOUNT, NPC_HORDE_SHAMAN_CHAMPION, NPC_SPECTATOR_TAUREN, EMOTE_TAUREN, SAY_HERALD_HORDE_SHAMAN }, + { NPC_HORDE_HUNTER, NPC_HORDE_HUNTER_MOUNT, NPC_HORDE_HUNTER_CHAMPION, NPC_SPECTATOR_TROLL, EMOTE_TROLLS, SAY_HERALD_HORDE_HUNTER }, + { NPC_HORDE_ROGUE, NPC_HORDE_ROGUE_MOUNT, NPC_HORDE_ROGUE_CHAMPION, NPC_SPECTATOR_UNDEAD, EMOTE_UNDEAD, SAY_HERALD_HORDE_ROGUE } +}; + +// data that provides spawn coordinates and entry for the player mounts +struct ChampionsMountsData +{ + uint32 uiEntryAlliance, uiEntryHorde; + float fX, fY, fZ, fO; +}; + +static const ChampionsMountsData aTrialChampionsMounts[MAX_CHAMPIONS_MOUNTS] = +{ + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 720.569f, 571.285f, 412.475f, 1.064f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 722.363f, 660.745f, 412.468f, 4.834f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 699.943f, 643.370f, 412.474f, 5.777f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 768.255f, 661.606f, 412.470f, 4.555f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 787.439f, 584.969f, 412.476f, 2.478f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 793.009f, 592.667f, 412.475f, 2.652f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 704.943f, 651.330f, 412.475f, 5.602f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 702.967f, 587.649f, 412.475f, 0.610f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 712.594f, 576.260f, 412.476f, 0.890f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 774.898f, 573.736f, 412.475f, 2.146f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 790.490f, 646.533f, 412.474f, 3.717f}, + {NPC_WARHORSE_ALLIANCE, NPC_WARHORSE_HORDE, 777.564f, 660.300f, 412.467f, 4.345f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 705.497f, 583.944f, 412.476f, 0.698f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 790.177f, 589.059f, 412.475f, 2.565f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 702.165f, 647.267f, 412.475f, 5.689f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 717.443f, 660.646f, 412.467f, 4.921f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 716.665f, 573.495f, 412.475f, 0.977f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 793.052f, 642.851f, 412.474f, 3.630f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 726.826f, 661.201f, 412.472f, 4.660f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 773.097f, 660.733f, 412.467f, 4.450f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 788.016f, 650.788f, 412.475f, 3.804f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 700.531f, 591.927f, 412.475f, 0.523f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 770.486f, 571.552f, 412.475f, 2.059f}, + {NPC_BATTLEWORG_ALLIANCE, NPC_BATTLEWORG_HORDE, 778.741f, 576.049f, 412.476f, 2.234f}, +}; + +struct ArgentChallengeData +{ + uint32 uiEntry; + float fX, fY, fZ, fO; + float fTargetX, fTargetY, fTargetZ; +}; + +static const ArgentChallengeData aArgentChallengeHelpers[MAX_ARGENT_TRASH + 1] = +{ + { NPC_ARGENT_LIGHTWIELDER, 747.043f, 686.513f, 412.459f, 4.694f, 746.685f, 653.093f, 411.604f }, + { NPC_ARGENT_LIGHTWIELDER, 755.377f, 685.247f, 412.445f, 4.683f, 777.107f, 649.010f, 411.930f }, + { NPC_ARGENT_LIGHTWIELDER, 738.848f, 686.317f, 412.454f, 4.664f, 717.998f, 649.100f, 411.924f }, + { NPC_ARGENT_MONK, 749.762f, 686.441f, 412.460f, 4.712f, 751.685f, 653.040f, 411.917f }, + { NPC_ARGENT_MONK, 758.222f, 679.841f, 412.366f, 4.698f, 780.140f, 645.455f, 411.932f }, + { NPC_ARGENT_MONK, 744.207f, 680.438f, 412.372f, 4.668f, 721.592f, 652.499f, 411.965f }, + { NPC_ARGENT_PRIESTESS, 744.604f, 686.418f, 412.460f, 4.677f, 741.686f, 653.147f, 411.910f }, + { NPC_ARGENT_PRIESTESS, 755.309f, 682.928f, 412.381f, 4.668f, 773.451f, 652.419f, 411.935f }, + { NPC_ARGENT_PRIESTESS, 738.919f, 685.132f, 412.379f, 4.694f, 715.080f, 645.947f, 411.957f }, + { TYPE_ARGENT_CHAMPION, 746.758f, 687.635f, 412.467f, 4.695f, 746.816f, 661.640f, 411.702f }, +}; + +class instance_trial_of_the_champion : public ScriptedInstance, private DialogueHelper +{ + public: + instance_trial_of_the_champion(Map* pMap); + + void Initialize() override; + + void OnPlayerEnter(Player* pPlayer) override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature) override; + void OnCreatureDespawn(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + uint32 GetPlayerTeam() { return m_uiTeam; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void DoPrepareChampions(bool bSkipIntro); + void MoveChampionToHome(Creature* pChampion); + void InformChampionReachHome(); + void DoSendChampionsToExit(); + void DoSetChamptionsInCombat(Unit* pTarget); + + void SetHadWorseAchievFailed() { m_bHadWorseAchiev = false; } + + void DoPrepareArgentChallenge() { StartNextDialogueText(NPC_ARGENT_MONK); } + void DoPrepareBlackKnight() { StartNextDialogueText(TYPE_BLACK_KNIGHT); } + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + + uint32 GetMountEntryForChampion() { return m_uiTeam == ALLIANCE ? NPC_BATTLEWORG_ALLIANCE : NPC_WARHORSE_HORDE; } + bool IsArenaChallengeComplete(uint32 uiType); + + void Update(uint32 uiDiff) override; + + private: + void JustDidDialogueStep(int32 iEntry) override; + + void DoSummonHeraldIfNeeded(Unit* pSummoner); + void DoSendNextArenaWave(); + void DoCleanupArenaOnWipe(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + Team m_uiTeam; + + uint32 m_uiHeraldEntry; + uint32 m_uiGrandChampionEntry; + + uint32 m_uiIntroTimer; + uint32 m_uiIntroStage; + uint32 m_uiArenaStage; + uint32 m_uiGateResetTimer; + uint32 m_uiChampionsCount; + uint32 m_uiChampionsTimer; + + bool m_bSkipIntro; + bool m_bHadWorseAchiev; + + ObjectGuid m_ArenaChampionsGuids[MAX_CHAMPIONS_ARENA]; + ObjectGuid m_ArenaMountsGuids[MAX_CHAMPIONS_ARENA]; + + std::vector m_vChampionsIndex; + + GuidVector m_vAllianceTriggersGuids; + GuidVector m_vHordeTriggersGuids; + + GuidList m_lArenaMountsGuids; + GuidList m_lArgentTrashGuids; + GuidSet m_sArenaHelpersGuids[MAX_CHAMPIONS_ARENA]; }; #endif diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_anubarak_trial.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_anubarak_trial.cpp index 9db9b9118..e1804d39c 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_anubarak_trial.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_anubarak_trial.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,9 +16,9 @@ /* ScriptData SDName: boss_anubarak_trial -SD%Complete: 0 +SD%Complete: 100 SDComment: -SDCategory: +SDCategory: Crusader Coliseum EndScriptData */ #include "precompiled.h" @@ -26,6 +26,7 @@ EndScriptData */ enum { + SAY_INTRO = -1649038, SAY_AGGRO = -1649064, SAY_SLAY_1 = -1649065, SAY_SLAY_2 = -1649066, @@ -33,43 +34,366 @@ enum SAY_BERSERK = -1649068, SAY_SUBMERGE = -1649069, SAY_LEECHING_SWARM = -1649070, + + EMOTE_BURROW = -1649071, + EMOTE_PURSUE = -1649072, + EMOTE_EMERGE = -1649073, + EMOTE_LEECHING_SWARM = -1649074, + + // Anub'arak + SPELL_FREEZING_SLASH = 66012, + SPELL_PENETRATING_COLD = 66013, + SPELL_SUMMON_NERUBIAN_BURROWER = 66332, + SPELL_SUMMON_SCARAB = 66339, + SPELL_SUBMERGE = 65981, + SPELL_EMERGE = 65982, + SPELL_TELEPORT_TO_SPIKE = 66170, // used when the underground phase ends + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_SUMMON_SPIKES = 66169, + SPELL_LEECHING_SWARM = 66118, + SPELL_BERSERK = 26662, + + SPELL_SCARAB_ACHIEV_10 = 68186, // used for achiev 3800 + SPELL_SCARAB_ACHIEV_25 = 68515, // used for achiev 3816 + + // Pursuing Spikes + SPELL_PURSUING_SPIKES_FAIL = 66181, + SPELL_PURSUING_SPIKES_DUMMY = 67470, // target selection spell + SPELL_PURSUING_SPIKES_SPEED1 = 65920, + // SPELL_PURSUING_SPIKES_GROUND = 65921, // included in creature_template_addon + SPELL_PURSUING_SPIKES_SPEED2 = 65922, + SPELL_PURSUING_SPIKES_SPEED3 = 65923, + SPELL_MARK = 67574, + + // Frostsphere + SPELL_PERMAFROST_VISUAL = 65882, // triggers 65872 + SPELL_PERMAFROST_DUMMY = 65872, // dummy spell which handles the spike fail event + SPELL_PERMAFROST_TRANSFORM = 66185, + SPELL_PERMAFROST_SLOW = 66193, // slow spell + SPELL_FROSTSPHERE_VISUAL = 67539, + + POINT_GROUND = 0, + + // npcs + NPC_SCARAB = 34605, + NPC_FROSTSPHERE = 34606, + NPC_NERUBIAN_BURROWER = 34607, + NPC_ANUBARAK_SPIKE = 34660, + NPC_BURROW = 34862, + + MAX_FROSTSPHERES = 6, + MAX_BURROWS = 4 +}; + +enum Phases +{ + PHASE_GROUND = 0, + PHASE_UNDERGROUND = 1, + PHASE_LEECHING_SWARM = 2, + PHASE_SUBMERGING = 3, // virtual use only while casting SPELL_SUBMERGE (triggered by script!) }; -struct MANGOS_DLL_DECL boss_anubarak_trialAI : public ScriptedAI +enum PursuingSpikesPhases +{ + PHASE_NO_MOVEMENT = 0, + PHASE_IMPALE_NORMAL = 1, + PHASE_IMPALE_MIDDLE = 2, + PHASE_IMPALE_FAST = 3 +}; + +static const float aFrostSphereSpawnPositions[MAX_FROSTSPHERES][3] = +{ + { 701.4270f, 126.4739f, 158.0205f }, + { 712.5711f, 160.9948f, 158.4367f }, + { 736.0243f, 113.4201f, 158.0225f }, + { 747.9201f, 155.0920f, 158.0613f }, + { 769.6285f, 121.1024f, 158.0504f }, + { 779.8038f, 150.658f, 158.1426f } +}; + +static const float aBurrowSpawnPositions[MAX_BURROWS][4] = +{ + { 735.4028f, 75.35764f, 142.2023f, 2.094395f }, + { 692.9202f, 184.809f, 142.2026f, 5.358161f }, + { 688.2066f, 102.8472f, 142.2023f, 0.6457718f }, + { 740.5452f, 189.1129f, 142.1972f, 3.752458f } +}; + +/*###### +## boss_anubarak_trial +######*/ + +struct boss_anubarak_trialAI : public ScriptedAI { boss_anubarak_trialAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + m_bDidIntroYell = false; Reset(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; - void Reset() {} + Phases m_Phase; - void JustReachedHome() + uint32 m_PhaseSwitchTimer; + uint32 m_uiFreezingSlashTimer; + uint32 m_uiPenetratingColdTimer; + uint32 m_uiBurrowerSummonTimer; + uint32 m_uiBerserkTimer; + bool m_bDidIntroYell; + + ObjectGuid m_PursuingSpikesGuid; + GuidVector m_vSpheresGuidVector; + + void Reset() override + { + m_Phase = PHASE_GROUND; + m_PhaseSwitchTimer = 80000; + m_uiFreezingSlashTimer = 20000; + m_uiPenetratingColdTimer = urand(15000, 25000); + m_uiBurrowerSummonTimer = 10000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_vSpheresGuidVector.clear(); + m_vSpheresGuidVector.resize(MAX_FROSTSPHERES, ObjectGuid()); + } + + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_ANUBARAK, NOT_STARTED); + m_pInstance->SetData(TYPE_ANUBARAK, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { + DoScriptText(SAY_DEATH, m_creature); + if (m_pInstance) m_pInstance->SetData(TYPE_ANUBARAK, DONE); } - void Aggro(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bDidIntroYell && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + !m_creature->IsInEvadeMode() && pWho->IsWithinDistInMap(m_creature, 100) && pWho->IsWithinLOSInMap(m_creature)) + { + DoScriptText(SAY_INTRO, m_creature); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); + DoCastSpellIfCan(m_creature, SPELL_EMERGE); + + m_bDidIntroYell = true; + return; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* /*pWho*/) override { - m_creature->SetInCombatWithZone(); + DoScriptText(SAY_AGGRO, m_creature); + + // Summon the spheres on random points + for (uint8 i = 0; i < MAX_FROSTSPHERES; ++i) + { + if (Creature* pTemp = m_creature->SummonCreature(NPC_FROSTSPHERE, aFrostSphereSpawnPositions[i][0], aFrostSphereSpawnPositions[i][1], aFrostSphereSpawnPositions[i][2], 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + m_vSpheresGuidVector[i] = pTemp->GetObjectGuid(); + } + + // It's not clear if these should be spawned by DB or summoned + for (uint8 i = 0; i < MAX_BURROWS; ++i) + m_creature->SummonCreature(NPC_BURROW, aBurrowSpawnPositions[i][0], aBurrowSpawnPositions[i][1], aBurrowSpawnPositions[i][2], aBurrowSpawnPositions[i][3], TEMPSUMMON_DEAD_DESPAWN, 0); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ANUBARAK, IN_PROGRESS); } - void UpdateAI(const uint32 uiDiff) + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText((urand(0, 1)) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_SUBMERGE) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // Extra check here, because AnubArak must be submerged by default + if (m_Phase != PHASE_SUBMERGING) + return; + + m_Phase = PHASE_UNDERGROUND; + + // Refresh spheres only on normal difficulty + if (m_pInstance && !m_pInstance->IsHeroicDifficulty()) + DoRefreshSpheres(); + + DoCastSpellIfCan(m_creature, SPELL_CLEAR_ALL_DEBUFFS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIKES, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SCARAB, CAST_TRIGGERED); + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_ANUBARAK_SPIKE: + m_PursuingSpikesGuid = pSummoned->GetObjectGuid(); + // no break here + case NPC_NERUBIAN_BURROWER: + case NPC_SCARAB: + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + } + } + + // Wrapper to refresh frost spheres - it's not very clear how ofter should this happen + void DoRefreshSpheres() + { + for (uint8 i = 0; i < MAX_FROSTSPHERES; ++i) + { + // If the sphere is alive and hasn't transfomed to permafrost yet summon a new one + Creature* pTemp = m_creature->GetMap()->GetCreature(m_vSpheresGuidVector[i]); + if (pTemp && !pTemp->HasAura(SPELL_PERMAFROST_TRANSFORM)) + continue; + + // Summon a new frost sphere instead of the killed one + if (Creature* pTemp = m_creature->SummonCreature(NPC_FROSTSPHERE, aFrostSphereSpawnPositions[i][0], aFrostSphereSpawnPositions[i][1], aFrostSphereSpawnPositions[i][2], 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + m_vSpheresGuidVector[i] = pTemp->GetObjectGuid(); + } + } + + // Wrapper to despawn the Spikes + void DoDespawnPursuingSpikes() + { + if (Creature* pPursuingSpikes = m_creature->GetMap()->GetCreature(m_PursuingSpikesGuid)) + pPursuingSpikes->ForcedDespawn(); + + m_PursuingSpikesGuid.Clear(); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); + switch (m_Phase) + { + case PHASE_GROUND: + + // Switch to underground phase on timer + if (m_PhaseSwitchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUBMERGE) == CAST_OK) + { + DoScriptText(SAY_SUBMERGE, m_creature); + DoScriptText(EMOTE_BURROW, m_creature); + m_PhaseSwitchTimer = 63000; + m_Phase = PHASE_SUBMERGING; + return; + } + } + else + m_PhaseSwitchTimer -= uiDiff; + + // Switch to phase 3 when below 30% + if (m_creature->GetHealthPercent() <= 30.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_LEECHING_SWARM) == CAST_OK) + { + DoScriptText(SAY_LEECHING_SWARM, m_creature); + DoScriptText(EMOTE_LEECHING_SWARM, m_creature); + m_Phase = PHASE_LEECHING_SWARM; + } + } + + // No break - the spells are used in both phase 1 and 3 + case PHASE_LEECHING_SWARM: + + if (m_uiFreezingSlashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FREEZING_SLASH) == CAST_OK) + m_uiFreezingSlashTimer = 20000; + } + else + m_uiFreezingSlashTimer -= uiDiff; + + if (m_uiPenetratingColdTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PENETRATING_COLD) == CAST_OK) + m_uiPenetratingColdTimer = 15000; + } + else + m_uiPenetratingColdTimer -= uiDiff; + + // The Borrowers are summoned in Ground phase only on normal mode or during Ground and Swarm phase on heroic mode + if (m_Phase == PHASE_GROUND || (m_pInstance && m_pInstance->IsHeroicDifficulty())) + { + if (m_uiBurrowerSummonTimer < uiDiff) + { + // The number of targets is handled in core, based on difficulty + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_NERUBIAN_BURROWER) == CAST_OK) + m_uiBurrowerSummonTimer = 45000; + } + else + m_uiBurrowerSummonTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + + break; + + case PHASE_UNDERGROUND: + + // Underground phase is finished + if (m_PhaseSwitchTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_EMERGE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TELEPORT_TO_SPIKE, CAST_TRIGGERED); + DoScriptText(EMOTE_EMERGE, m_creature); + DoDespawnPursuingSpikes(); + + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // Refresh spheres only on normal difficulty + if (m_pInstance && !m_pInstance->IsHeroicDifficulty()) + DoRefreshSpheres(); + + m_PhaseSwitchTimer = 80000; + m_Phase = PHASE_GROUND; + } + else + m_PhaseSwitchTimer -= uiDiff; + + break; + case PHASE_SUBMERGING: // Do nothing, but continue berserk timer + break; + } + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (m_Phase != PHASE_UNDERGROUND) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + } + else + m_uiBerserkTimer -= uiDiff; + } } }; @@ -78,6 +402,223 @@ CreatureAI* GetAI_boss_anubarak_trial(Creature* pCreature) return new boss_anubarak_trialAI(pCreature); } +/*###### +## npc_anubarak_trial_spike +######*/ + +struct npc_anubarak_trial_spikeAI : public ScriptedAI +{ + npc_anubarak_trial_spikeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + PursuingSpikesPhases m_Phase; + uint32 m_PhaseSwitchTimer; + + void Reset() override + { + m_Phase = PHASE_NO_MOVEMENT; + m_PhaseSwitchTimer = 5000; + + SetCombatMovement(false); + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_PURSUING_SPIKES_DUMMY && pTarget->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(EMOTE_PURSUE, m_creature, pTarget); + DoCastSpellIfCan(pTarget, SPELL_MARK, CAST_TRIGGERED); + DoStartMovement(pTarget); + } + } + + // Handle permafrost hit from dummy spell + void PermafrostHit(Creature* pPermafrost) + { + // To prevent more than one call + if (m_Phase == PHASE_NO_MOVEMENT) + return; + + // Remove the speed auras + switch (m_Phase) + { + case PHASE_IMPALE_NORMAL: + m_creature->RemoveAurasDueToSpell(SPELL_PURSUING_SPIKES_SPEED1); + break; + case PHASE_IMPALE_MIDDLE: + m_creature->RemoveAurasDueToSpell(SPELL_PURSUING_SPIKES_SPEED2); + break; + case PHASE_IMPALE_FAST: + m_creature->RemoveAurasDueToSpell(SPELL_PURSUING_SPIKES_SPEED3); + break; + } + + // Set Spike fail animation and despawn + DoCastSpellIfCan(m_creature, SPELL_PURSUING_SPIKES_FAIL, CAST_TRIGGERED); + + if (pPermafrost) + pPermafrost->ForcedDespawn(2000); + + // After the spikes hit the icy surface they can't move for about ~5 seconds + m_Phase = PHASE_NO_MOVEMENT; + m_PhaseSwitchTimer = 5000; + DoResetThreat(); + + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_PhaseSwitchTimer) + { + if (m_PhaseSwitchTimer <= uiDiff) + { + switch (m_Phase) + { + case PHASE_NO_MOVEMENT: + if (DoCastSpellIfCan(m_creature, SPELL_PURSUING_SPIKES_SPEED1) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_PURSUING_SPIKES_DUMMY, CAST_TRIGGERED); + + m_Phase = PHASE_IMPALE_NORMAL; + m_PhaseSwitchTimer = 7000; + } + break; + case PHASE_IMPALE_NORMAL: + if (DoCastSpellIfCan(m_creature, SPELL_PURSUING_SPIKES_SPEED2) == CAST_OK) + { + m_Phase = PHASE_IMPALE_MIDDLE; + m_PhaseSwitchTimer = 7000; + } + break; + case PHASE_IMPALE_MIDDLE: + if (DoCastSpellIfCan(m_creature, SPELL_PURSUING_SPIKES_SPEED3) == CAST_OK) + { + m_Phase = PHASE_IMPALE_FAST; + m_PhaseSwitchTimer = 0; + } + break; + } + } + else + m_PhaseSwitchTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_anubarak_trial_spike(Creature* pCreature) +{ + return new npc_anubarak_trial_spikeAI(pCreature); +} + +bool EffectDummyCreature_spell_dummy_permafrost(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_PERMAFROST_DUMMY && uiEffIndex == EFFECT_INDEX_0) + { + if (npc_anubarak_trial_spikeAI* pSpikeAI = dynamic_cast(pCreatureTarget->AI())) + pSpikeAI->PermafrostHit((Creature*)pCaster); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_anubarak_trial_frostsphere +######*/ + +struct npc_anubarak_trial_frostsphereAI : public Scripted_NoMovementAI +{ + npc_anubarak_trial_frostsphereAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + bool m_bPermafrost; + + void Reset() override + { + m_bPermafrost = false; + + m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 15.0f); + } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (uiDamage < m_creature->GetHealth()) + return; + + // Set fake death in order to apply permafrost + uiDamage = 0; + + if (m_bPermafrost) + return; + + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetHealth(0); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->SetTargetGuid(ObjectGuid()); + + // Set proper Z position + m_creature->SetWalk(false); + float fZ = pDoneBy->GetPositionZ(); + MaNGOS::NormalizeMapCoord(fZ); + + // Note: This should be fall movement + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX(), m_creature->GetPositionY(), fZ); + m_bPermafrost = true; + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + DoCastSpellIfCan(m_creature, SPELL_PERMAFROST_VISUAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PERMAFROST_TRANSFORM, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PERMAFROST_SLOW, CAST_TRIGGERED); + } +}; + +CreatureAI* GetAI_npc_anubarak_trial_frostsphere(Creature* pCreature) +{ + return new npc_anubarak_trial_frostsphereAI(pCreature); +} + +/*###### +## npc_nerubian_borrow +######*/ + +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct npc_nerubian_borrowAI : public Scripted_NoMovementAI +{ + npc_nerubian_borrowAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_nerubian_borrow(Creature* pCreature) +{ + return new npc_nerubian_borrowAI(pCreature); +} + void AddSC_boss_anubarak_trial() { Script* pNewScript; @@ -86,4 +627,20 @@ void AddSC_boss_anubarak_trial() pNewScript->Name = "boss_anubarak_trial"; pNewScript->GetAI = &GetAI_boss_anubarak_trial; pNewScript->RegisterSelf(); -} \ No newline at end of file + + pNewScript = new Script; + pNewScript->Name = "npc_anubarak_spike"; + pNewScript->GetAI = &GetAI_npc_anubarak_trial_spike; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_dummy_permafrost; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_frost_sphere"; + pNewScript->GetAI = &GetAI_npc_anubarak_trial_frostsphere; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_nerubian_borrow"; + pNewScript->GetAI = &GetAI_npc_nerubian_borrow; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_faction_champions.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_faction_champions.cpp index 67f9078e4..f94e039c7 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_faction_champions.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_faction_champions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: faction_champions -SD%Complete: 0 -SDComment: +SD%Complete: 90 +SDComment: AI might require some tweaks and improvements SDCategory: Crusader Coliseum EndScriptData */ @@ -35,8 +35,1424 @@ enum SAY_VARIAN_PVP_H_SLAY_2 = -1649053, SAY_VARIAN_PVP_H_SLAY_3 = -1649054, SAY_VARIAN_PVP_H_SLAY_4 = -1649055, + + SPELL_PVP_TRINKET = 65547, + + // AI type defines + AI_TYPE_MELEE = 1, + AI_TYPE_RANGED = 2, + AI_TYPE_HEALER = 3, + + // misc + TARGET_TYPE_RANDOM = 0, + TARGET_TYPE_VICTIM = 1, + TARGET_TYPE_SELF = 2, + TARGET_TYPE_FRIENDLY = 3, + + CRUSADER_AIEVENT_THROW_RADIUS = 30, + CRUSADER_HEALTH_STEPS = 3, + + + // druid restoration spells + SPELL_THORNS = 66068, // aggro spell + SPELL_BARKSKIN = 65860, + SPELL_NATURES_GRASP = 66071, + SPELL_TRANQUILITY = 66086, + SPELL_LIFEBLOOM = 66093, + SPELL_NOURISH = 66066, + SPELL_REGROWTH = 66067, + SPELL_REJUVENATION = 66065, + + MAX_DRUID_RESTO_SPELLS = 7, + + + // paladin holy spells + SPELL_CLEANSE = 66116, // event spell + SPELL_DIVINE_SHIELD = 66010, + SPELL_FLASH_OF_LIGHT = 66113, + SPELL_FLASH_HEAL = 66104, + SPELL_HOLY_LIGHT = 66112, + SPELL_HAND_OF_PROTECTION = 66009, + SPELL_HAND_OF_FREEDOM = 68757, + SPELL_HOLY_SHOCK = 66114, + SPELL_HAMMER_OF_JUSTICE = 66613, + + MAX_PALADIN_HOLY_SPELLS = 8, + + + // priest discipline spells + SPELL_DISPEL_MAGIC = 65546, + // SPELL_FLASH_HEAL = 66104, // already defined + SPELL_PENANCE = 66097, // triggers 66098 + SPELL_POWER_WORD_SHIELD = 66099, + SPELL_RENEW = 66177, + SPELL_MANA_BURN = 66100, + SPELL_PSYCHIC_SCREAM = 65543, + + MAX_PRIEST_DISC_SPELLS = 7, + + + // shaman restoration spells + SPELL_CLEANSE_SPIRIT = 66056, + SPELL_EARTH_SHIELD = 66063, // triggers 66064 + SPELL_HEX = 66054, + SPELL_LESSER_HEALING_WAVE = 66055, + SPELL_RIPTIDE = 66053, + SPELL_HEROISM = 65983, + SPELL_BLOODLUST = 65980, // replace heroism for horde crusaders + SPELL_EARTH_SHOCK = 65973, + + MAX_SHAMAN_RESTO_SPELLS = 7, + + + // druid balance spells + // SPELL_BARKSKIN = 65860, // already defined + SPELL_CYCLONE = 65859, + SPELL_ENTANGLING_ROOTS = 65857, + SPELL_FAERIE_FIRE = 65863, + SPELL_FORCE_OF_NATURE = 65861, + SPELL_INSECT_SWARM = 65855, + SPELL_MOONFIRE = 65856, + SPELL_STARFIRE = 65854, + SPELL_WRATH = 65862, + + MAX_DRUID_BALANCE_SPELLS = 9, + + + // hunter spells + SPELL_CALL_PET = 67777, // aggro spell + SPELL_AIMED_SHOT = 65883, + SPELL_DETERRENCE = 65871, + SPELL_DISENGAGE = 65869, // triggers 65870 + SPELL_EXPLOSIVE_SHOT = 65866, + SPELL_FROST_TRAP = 65880, + SPELL_SHOOT = 65868, + SPELL_STEADY_SHOT = 65867, + SPELL_WING_CLIP = 66207, + SPELL_WYVERN_STING = 65877, // triggers 65878 on remove + + MAX_HUNTER_SPELLS = 9, + + + // mage spells + SPELL_ARCANE_BARRAGE = 65799, + SPELL_ARCANE_BLAST = 65791, + SPELL_ARCANE_EXPLOSION = 65800, + SPELL_BLINK = 65793, + SPELL_COUNTERSPELL = 65790, + SPELL_FROST_NOVA = 65792, + SPELL_FROSTBOLT = 65807, + SPELL_ICE_BLOCK = 65802, + SPELL_POLYMORPH = 65801, + + MAX_MAGE_SPELLS = 9, + + + // priest shadow spells + SPELL_DISPERSION = 65544, + SPELL_MIND_BLAST = 65492, + SPELL_MIND_FLAY = 65488, + SPELL_PSYCHIC_HORROR = 65545, + // SPELL_PSYCHIC_SCREAM = 65543, // already defined + SPELL_SHADOW_WORD_PAIN = 65541, + SPELL_SILENCE = 65542, + SPELL_VAMPIRIC_TOUCH = 65490, + SPELL_DISPEL = 65546, // event spell + + MAX_PRIEST_DAMAGE_SPELLS = 8, + + + // warlock spells + SPELL_SUMMON_FELHUNTER = 67514, // aggro spell + SPELL_CORRUPTION = 65810, + SPELL_CURSE_OF_AGONY = 65814, + SPELL_CURSE_OF_EXHAUSTION = 65815, + SPELL_DEATH_COIL_WARLOCK = 65820, + SPELL_FEAR = 65809, + SPELL_HELLFIRE = 65816, + SPELL_SEARING_PAIN = 65819, + SPELL_SHADOW_BOLT = 65821, + SPELL_UNSTABLE_AFFLICTION = 65812, + + MAX_WARLOCK_SPELLS = 9, + + + // death knight spells + SPELL_CHAINS_OF_ICE = 66020, + SPELL_DEATH_COIL = 66019, + SPELL_DEATH_GRIP = 66017, + SPELL_FROST_STRIKE = 66047, + SPELL_ICEBOUND_FORTITUDE = 66023, + SPELL_ICY_TOUCH = 66021, // triggers 67767 + SPELL_STRANGULATE = 66018, + + MAX_DEATH_KNIGHT_SPELLS = 7, + + + // warrior spells + SPELL_BLADESTORM = 65947, + SPELL_CHARGE = 65927, + SPELL_DISARM = 65935, + SPELL_INTIMIDATING_SHOUT = 65931, + SPELL_MORTAL_STRIKE = 65926, + SPELL_OVERPOWER = 65924, + SPELL_RETALIATION = 65932, + SPELL_SHATTERING_THROW = 65940, + SPELL_SUNDER_ARMOR = 65936, + + MAX_WARRIOR_SPELLS = 9, + + + // paladin retribution spells + SPELL_SEAL_OF_COMMAND = 66004, // aggro spell + SPELL_AVENGING_WRATH = 66011, + SPELL_CRUSADER_STRIKE = 66003, + SPELL_DIVINE_STORM = 66006, + SPELL_HAMMER_OF_JUSTICE_RETRI = 66007, + SPELL_JUDGEMENT_OF_COMMAND = 66005, + SPELL_REPENTANCE = 66008, + + MAX_PALADIN_DAMAGE_SPELLS = 6, + + + // shaman enhancement spells + //SPELL_EARTH_SHOCK = 65973, // already defined + //SPELL_HEROISM = 65983, // already defined + SPELL_LAVA_LASH = 65974, + SPELL_MAELSTROM_WEAPON = 65986, + SPELL_STORMSTRIKE = 65970, + SPELL_WINDFURY = 65976, + + MAX_SHAMAN_DAMAGE_SPELLS = 6, + + + // rogue spells + SPELL_BLADE_FURRY = 65956, + SPELL_BLIND = 65960, + SPELL_CLOAK_OF_SHADOWS = 65961, + SPELL_EVISCERATE = 65957, + SPELL_FAN_OF_KNIVES = 65955, + SPELL_HEMORRHAGE = 65954, + SPELL_SHADOWSTEP = 66178, + SPELL_WOUND_POISON = 65962, + + MAX_ROGUE_SPELLS = 8, }; +struct CrusaderAbilityStruct +{ + uint32 m_uiSpellId, m_uiTargetType; + uint32 m_uiInitialTimer, m_uiCooldown, m_uiMinHealth; + SelectFlags m_selectFlag; +}; + +/*###### +## trial_crusader_common +######*/ + +struct trial_crusader_commonAI : public ScriptedAI +{ + trial_crusader_commonAI(Creature* pCreature, CrusaderAbilityStruct const* pAbilityArray, uint32 uiMaxAbilities) : ScriptedAI(pCreature), + m_pAbilityArray(pAbilityArray), + m_uiMaxAbilities(uiMaxAbilities) + { + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + m_uiSpellTimer.resize(m_uiMaxAbilities); + Reset(); + } + + instance_trial_of_the_crusader* m_pInstance; + CrusaderAbilityStruct const* m_pAbilityArray; + + uint32 m_uiResetThreatTimer; + uint32 m_uiIsCCTimer; + uint32 m_uiTrinketTimer; + uint32 m_uiTrinketCooldownTimer; + + uint32 m_uiThrowAIEventStep; + + uint8 m_uiAIType; + + uint32 m_uiAbilityTimer; + uint32 m_uiMaxAbilities; + std::vector m_uiSpellTimer; + + void Reset() override + { + // NOTE: + // These guys does not follow normal threat system rules + // For later development, some alternative threat system should be made + // We do not know what this system is based upon, but one theory is class (healers=high threat, dps=medium, etc) + // We reset their threat frequently as an alternative until such a system exist + m_uiResetThreatTimer = urand(5000, 15000); + m_uiIsCCTimer = 2000; + m_uiTrinketCooldownTimer = 0; + + m_uiThrowAIEventStep = 0; + + m_uiAbilityTimer = 2000; + + for (uint8 i = 0; i < m_uiMaxAbilities; ++i) + m_uiSpellTimer[i] = m_pAbilityArray[i].m_uiInitialTimer; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void Aggro(Unit* pWho) override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_FACTION_CHAMPIONS) != IN_PROGRESS) + { + m_pInstance->SetData(TYPE_FACTION_CHAMPIONS, IN_PROGRESS); + m_pInstance->DoSetCrusadersInCombat(pWho); + } + } + } + + void AttackStart(Unit* pWho) override + { + // ranged and healer AI have ranged attack + if (m_uiAIType == AI_TYPE_HEALER || m_uiAIType == AI_TYPE_RANGED) + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 15.0f); + } + } + else + ScriptedAI::AttackStart(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + if (!m_pInstance) + return; + + Creature* pSpeaker = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetPlayerTeam() == ALLIANCE ? NPC_GARROSH : NPC_VARIAN); + if (!pSpeaker) + return; + + switch (urand(0, 3)) + { + case 0: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_1 : SAY_VARIAN_PVP_H_SLAY_1, pSpeaker); break; + case 1: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_2 : SAY_VARIAN_PVP_H_SLAY_2, pSpeaker); break; + case 2: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_3 : SAY_VARIAN_PVP_H_SLAY_3, pSpeaker); break; + case 3: DoScriptText(m_pInstance->GetPlayerTeam() == ALLIANCE ? SAY_GARROSH_PVP_A_SLAY_4 : SAY_VARIAN_PVP_H_SLAY_4, pSpeaker); break; + } + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_FACTION_CHAMPIONS) != FAIL) + m_pInstance->SetData(TYPE_FACTION_CHAMPIONS, FAIL); + } + } + + void DamageTaken(Unit* pDealer, uint32& uiDamage) override + { + uint32 uiStep = m_uiThrowAIEventStep != 100 ? m_uiThrowAIEventStep : 0; + if (uiStep < CRUSADER_HEALTH_STEPS) + { + // Throw at 90%, 50% and 10% health + float fHealthSteps[CRUSADER_HEALTH_STEPS] = { 90.0f, 50.0f, 10.0f }; + float fNewHealthPercent = (m_creature->GetHealth() - uiDamage) * 100.0f / m_creature->GetMaxHealth(); + AIEventType sendEvent[CRUSADER_HEALTH_STEPS] = { AI_EVENT_LOST_SOME_HEALTH, AI_EVENT_LOST_HEALTH, AI_EVENT_CRITICAL_HEALTH }; + + if (fNewHealthPercent > fHealthSteps[uiStep]) + return; // Not reached the next mark + + // search for highest reached mark (with actual event attached) + for (uint32 i = CRUSADER_HEALTH_STEPS - 1; i > uiStep; --i) + { + if (fNewHealthPercent < fHealthSteps[i]) + { + uiStep = i; + break; + } + } + + // send event around and to self + SendAIEventAround(sendEvent[uiStep], pDealer, 0, CRUSADER_AIEVENT_THROW_RADIUS); + SendAIEvent(sendEvent[uiStep], pDealer, m_creature); + m_uiThrowAIEventStep = uiStep + 1; + } + } + + void HealedBy(Unit* pHealer, uint32& uiHealedAmount) override + { + if (m_uiThrowAIEventStep == 100) + return; + + if (m_creature->GetHealth() + uiHealedAmount >= m_creature->GetMaxHealth()) + { + SendAIEventAround(AI_EVENT_GOT_FULL_HEALTH, pHealer, 0, CRUSADER_AIEVENT_THROW_RADIUS); + m_uiThrowAIEventStep = 100; + } + } + + void JustDied(Unit* pKiller) override + { + SendAIEventAround(AI_EVENT_JUST_DIED, pKiller, 0, CRUSADER_AIEVENT_THROW_RADIUS); + } + + bool CanUseSpecialAbility(uint32 uiSpellId, uint32 uiTargetType, SelectFlags selectFlag, uint32 uiMaxHpPct) + { + Unit* pTarget = NULL; + + switch (uiTargetType) + { + case TARGET_TYPE_SELF: + pTarget = m_creature; + break; + case TARGET_TYPE_VICTIM: + pTarget = m_creature->getVictim(); + break; + case TARGET_TYPE_RANDOM: + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(uiSpellId), selectFlag); + break; + case TARGET_TYPE_FRIENDLY: + // calculate HP deficit compared to caster health; this might not give very accurate results + pTarget = DoSelectLowestHpFriendly(40.0f, uint32(m_creature->GetMaxHealth() * (100 - uiMaxHpPct) * 0.01f)); + break; + } + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, uiSpellId) == CAST_OK) + return true; + } + + return false; + } + + // Return true to handle shared timers and MeleeAttack + virtual bool UpdateCrusaderAI(const uint32 /*uiDiff*/) { return true; } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Call specific virtual function + if (!UpdateCrusaderAI(uiDiff)) + return; + + if (m_uiAbilityTimer < uiDiff) + { + uint8 uiIndex = urand(0, m_uiMaxAbilities - 1); + uint32 uiMinHealth = m_pAbilityArray[uiIndex].m_uiMinHealth; + uint8 uiTargetType = m_pAbilityArray[uiIndex].m_uiTargetType; + + SelectFlags spellSelectFlag = m_pAbilityArray[uiIndex].m_selectFlag; + + // check timers and health condition + // only cast spells that have timers expired + // also check for health percentage for self cast spells + if (m_uiSpellTimer[uiIndex] || (uiTargetType == TARGET_TYPE_SELF && uiMinHealth && m_creature->GetHealthPercent() > uiMinHealth)) + { + m_uiAbilityTimer = 2000; + return; + } + else + { + uint32 uiSpellId = m_pAbilityArray[uiIndex].m_uiSpellId; + + // special case for heroism / bloodlust + if (uiSpellId == SPELL_HEROISM && m_pInstance && m_pInstance->GetPlayerTeam() == ALLIANCE) + uiSpellId = SPELL_BLOODLUST; + + if (CanUseSpecialAbility(uiSpellId, uiTargetType, spellSelectFlag, uiMinHealth)) + { + m_uiSpellTimer[uiIndex] = m_pAbilityArray[uiIndex].m_uiCooldown; + m_uiAbilityTimer = urand(2000, 6000); + } + else + m_uiAbilityTimer = 2000; + } + } + else + m_uiAbilityTimer -= uiDiff; + + // spell cooldown + for (uint8 i = 0; i < m_uiMaxAbilities; ++i) + { + if (m_uiSpellTimer[i]) + { + if (m_uiSpellTimer[i] <= uiDiff) + m_uiSpellTimer[i] = 0; + else + m_uiSpellTimer[i] -= uiDiff; + } + } + + // Change target + if (m_uiResetThreatTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + DoResetThreat(); + AttackStart(pTarget); + m_uiResetThreatTimer = urand(5000, 15000); + } + } + else + m_uiResetThreatTimer -= uiDiff; + + // CC check for PVP trinket + if (m_uiIsCCTimer < uiDiff) + { + if (m_creature->isFrozen() || m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT)) + { + // Pvp trinket only in heroic mode + if (m_pInstance && m_pInstance->IsHeroicDifficulty() && !m_uiTrinketCooldownTimer) + { + if (DoCastSpellIfCan(m_creature, SPELL_PVP_TRINKET, CAST_TRIGGERED) == CAST_OK) + m_uiTrinketCooldownTimer = 120000; + } + + SendAIEventAround(AI_EVENT_GOT_CCED, NULL, 0, CRUSADER_AIEVENT_THROW_RADIUS); + SendAIEvent(AI_EVENT_GOT_CCED, NULL, m_creature); + m_uiIsCCTimer = 5000; + } + else + m_uiIsCCTimer = 2000; + } + else + m_uiIsCCTimer -= uiDiff; + + // trinket cooldown + if (m_uiTrinketCooldownTimer) + { + if (m_uiTrinketCooldownTimer <= uiDiff) + m_uiTrinketCooldownTimer = 0; + else + m_uiTrinketCooldownTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## CRUSADER HEALERS +######*/ + +/*###### +## boss_crusader_druid_resto +######*/ + +static const CrusaderAbilityStruct m_aDruidHealerAbilities[MAX_DRUID_RESTO_SPELLS] = +{ + {SPELL_BARKSKIN, TARGET_TYPE_SELF, 5000, 60000, 50}, + {SPELL_NATURES_GRASP, TARGET_TYPE_SELF, 2000, 60000, 0}, + {SPELL_TRANQUILITY, TARGET_TYPE_SELF, 2000, 600000, 30}, + {SPELL_LIFEBLOOM, TARGET_TYPE_FRIENDLY, 2000, 2000, 0}, + {SPELL_NOURISH, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_REGROWTH, TARGET_TYPE_FRIENDLY, 2000, 2000, 0}, + {SPELL_REJUVENATION, TARGET_TYPE_FRIENDLY, 2000, 2000, 0}, +}; + +struct boss_crusader_druid_restoAI : public trial_crusader_commonAI +{ + boss_crusader_druid_restoAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aDruidHealerAbilities, MAX_DRUID_RESTO_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_HEALER; + + trial_crusader_commonAI::Reset(); + } + + void Aggro(Unit* pWho) override + { + DoCastSpellIfCan(m_creature, SPELL_THORNS); + + trial_crusader_commonAI::Aggro(pWho); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = urand(0, 1) ? 5 : 6; + break; + case AI_EVENT_LOST_HEALTH: + uiIndex = urand(0, 1) ? 4 : 5; + break; + case AI_EVENT_LOST_SOME_HEALTH: + uiIndex = urand(0, 1) ? 3 : 4; + break; + } + + if (uiIndex > MAX_DRUID_RESTO_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pSender, m_aDruidHealerAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aDruidHealerAbilities[uiIndex].m_uiCooldown; + } + } +}; + +CreatureAI* GetAI_boss_crusader_druid_resto(Creature* pCreature) +{ + return new boss_crusader_druid_restoAI(pCreature); +} + +/*###### +## boss_crusader_paladin_holy +######*/ + +static const CrusaderAbilityStruct m_aPaladinHealerAbilities[MAX_PALADIN_HOLY_SPELLS] = +{ + {SPELL_DIVINE_SHIELD, TARGET_TYPE_SELF, 0, 300000, 25}, + {SPELL_FLASH_OF_LIGHT, TARGET_TYPE_FRIENDLY, 2000, 2000, 0}, + {SPELL_HOLY_SHOCK, TARGET_TYPE_FRIENDLY, 2000, 6000, 0}, + {SPELL_FLASH_HEAL, TARGET_TYPE_FRIENDLY, 2000, 2000, 0}, + {SPELL_HOLY_LIGHT, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_HAND_OF_FREEDOM, TARGET_TYPE_FRIENDLY, 2000, 25000, 30}, + {SPELL_HAND_OF_PROTECTION, TARGET_TYPE_FRIENDLY, 0, 300000, 10}, + {SPELL_HAMMER_OF_JUSTICE, TARGET_TYPE_RANDOM, 15000, 40000, 0}, +}; + +struct boss_crusader_paladin_holyAI : public trial_crusader_commonAI +{ + boss_crusader_paladin_holyAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aPaladinHealerAbilities, MAX_PALADIN_HOLY_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_HEALER; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + uint32 uiSpellEntry = 0; + uint32 uiSpellTimer = 0; + + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = urand(0, 1) ? 3 : 4; + break; + case AI_EVENT_LOST_HEALTH: + uiIndex = urand(0, 1) ? 2 : 3; + break; + case AI_EVENT_LOST_SOME_HEALTH: + uiIndex = urand(0, 1) ? 1 : 2; + break; + case AI_EVENT_GOT_CCED: + uiSpellEntry = SPELL_CLEANSE; + break; + } + + if (!uiSpellEntry) + { + if (uiIndex > MAX_PALADIN_HOLY_SPELLS - 1) + return; + else + { + uiSpellEntry = m_aPaladinHealerAbilities[uiIndex].m_uiSpellId; + uiSpellTimer = m_aPaladinHealerAbilities[uiIndex].m_uiCooldown; + } + } + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pSender, uiSpellEntry) == CAST_OK) + { + if (uiSpellTimer) + m_uiSpellTimer[uiIndex] = uiSpellTimer; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_paladin_holy(Creature* pCreature) +{ + return new boss_crusader_paladin_holyAI(pCreature); +} + +/*###### +## boss_crusader_priest_disc +######*/ + +static const CrusaderAbilityStruct m_aPriestHealerAbilities[MAX_PRIEST_DISC_SPELLS] = +{ + {SPELL_PSYCHIC_SCREAM, TARGET_TYPE_SELF, 10000, 30000, 0}, + {SPELL_PENANCE, TARGET_TYPE_SELF, 2000, 10000, 0}, + {SPELL_RENEW, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_FLASH_HEAL, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_DISPEL_MAGIC, TARGET_TYPE_FRIENDLY, 2000, 2000, 0}, + {SPELL_POWER_WORD_SHIELD, TARGET_TYPE_FRIENDLY, 1500, 15000, 70}, + {SPELL_MANA_BURN, TARGET_TYPE_RANDOM, 2000, 7000, 0, SELECT_FLAG_POWER_MANA}, +}; + +struct boss_crusader_priest_discAI : public trial_crusader_commonAI +{ + boss_crusader_priest_discAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aPriestHealerAbilities, MAX_PRIEST_DISC_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_HEALER; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + uint32 uiSpellEntry = 0; + uint32 uiSpellTimer = 0; + + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = urand(0, 1) ? 2 : 3; + break; + case AI_EVENT_LOST_HEALTH: + uiIndex = 2; + break; + case AI_EVENT_LOST_SOME_HEALTH: + uiIndex = 1; + break; + case AI_EVENT_GOT_CCED: + uiSpellEntry = SPELL_DISPEL_MAGIC; + break; + } + + if (!uiSpellEntry) + { + if (uiIndex > MAX_PRIEST_DISC_SPELLS - 1) + return; + else + { + uiSpellEntry = m_aPriestHealerAbilities[uiIndex].m_uiSpellId; + uiSpellTimer = m_aPriestHealerAbilities[uiIndex].m_uiCooldown; + } + } + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pSender, uiSpellEntry) == CAST_OK) + { + if (uiSpellTimer) + m_uiSpellTimer[uiIndex] = uiSpellTimer; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_priest_disc(Creature* pCreature) +{ + return new boss_crusader_priest_discAI(pCreature); +} + +/*###### +## boss_crusader_shaman_resto +######*/ + +static const CrusaderAbilityStruct m_aShamanHealerAbilities[MAX_SHAMAN_RESTO_SPELLS] = +{ + {SPELL_HEROISM, TARGET_TYPE_SELF, 60000, 300000, 0}, + {SPELL_LESSER_HEALING_WAVE, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_RIPTIDE, TARGET_TYPE_FRIENDLY, 1500, 6000, 0}, + {SPELL_EARTH_SHIELD, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_CLEANSE_SPIRIT, TARGET_TYPE_FRIENDLY, 1500, 1500, 0}, + {SPELL_HEX, TARGET_TYPE_RANDOM, 2000, 45000, 0}, + {SPELL_EARTH_SHOCK, TARGET_TYPE_RANDOM, 2000, 6000, 0}, +}; + +struct boss_crusader_shaman_restoAI : public trial_crusader_commonAI +{ + boss_crusader_shaman_restoAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aShamanHealerAbilities, MAX_SHAMAN_RESTO_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_HEALER; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + uint32 uiSpellEntry = 0; + uint32 uiSpellTimer = 0; + + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = 1; + break; + case AI_EVENT_LOST_HEALTH: + uiIndex = 2; + break; + case AI_EVENT_LOST_SOME_HEALTH: + uiIndex = 3; + break; + case AI_EVENT_GOT_CCED: + uiSpellEntry = SPELL_CLEANSE_SPIRIT; + break; + } + + if (!uiSpellEntry) + { + if (uiIndex > MAX_SHAMAN_RESTO_SPELLS - 1) + return; + else + { + uiSpellEntry = m_aShamanHealerAbilities[uiIndex].m_uiSpellId; + uiSpellTimer = m_aShamanHealerAbilities[uiIndex].m_uiCooldown; + } + } + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pSender, uiSpellEntry) == CAST_OK) + { + if (uiSpellTimer) + m_uiSpellTimer[uiIndex] = uiSpellTimer; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_shaman_resto(Creature* pCreature) +{ + return new boss_crusader_shaman_restoAI(pCreature); +} + +/*###### +## CRUSADERS RANGED +######*/ + +/*###### +## boss_crusader_druid_balance +######*/ + +static const CrusaderAbilityStruct m_aDruidDamageAbilities[MAX_DRUID_BALANCE_SPELLS] = +{ + {SPELL_BARKSKIN, TARGET_TYPE_SELF, 5000, 60000, 50}, + {SPELL_MOONFIRE, TARGET_TYPE_VICTIM, 2000, 30000, 0}, + {SPELL_STARFIRE, TARGET_TYPE_VICTIM, 2000, 20000, 0}, + {SPELL_FAERIE_FIRE, TARGET_TYPE_VICTIM, 2000, 40000, 0}, + {SPELL_INSECT_SWARM, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_WRATH, TARGET_TYPE_VICTIM, 2000, 5000, 0}, + {SPELL_FORCE_OF_NATURE, TARGET_TYPE_RANDOM, 1500, 180000, 0}, + {SPELL_CYCLONE, TARGET_TYPE_RANDOM, 5000, 6000, 0}, + {SPELL_ENTANGLING_ROOTS, TARGET_TYPE_RANDOM, 5000, 10000, 0}, +}; + +struct boss_crusader_druid_balanceAI : public trial_crusader_commonAI +{ + boss_crusader_druid_balanceAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aDruidDamageAbilities, MAX_DRUID_BALANCE_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_RANGED; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_JUST_DIED: + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = urand(0, 1) ? 7 : 8; + break; + } + + if (uiIndex > MAX_DRUID_BALANCE_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aDruidDamageAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aDruidDamageAbilities[uiIndex].m_uiCooldown; + } + } +}; + +CreatureAI* GetAI_boss_crusader_druid_balance(Creature* pCreature) +{ + return new boss_crusader_druid_balanceAI(pCreature); +} + +/*###### +## boss_crusader_hunter +######*/ + +static const CrusaderAbilityStruct m_aHunterAbilities[MAX_HUNTER_SPELLS] = +{ + {SPELL_DETERRENCE, TARGET_TYPE_SELF, 2000, 90000, 30}, + {SPELL_DISENGAGE, TARGET_TYPE_SELF, 1000, 30000, 50}, + {SPELL_FROST_TRAP, TARGET_TYPE_SELF, 1500, 30000, 0}, + {SPELL_SHOOT, TARGET_TYPE_VICTIM, 2000, 3000, 0}, + {SPELL_STEADY_SHOT, TARGET_TYPE_VICTIM, 1500, 5000, 0}, + {SPELL_EXPLOSIVE_SHOT, TARGET_TYPE_VICTIM, 1500, 6000, 0}, + {SPELL_AIMED_SHOT, TARGET_TYPE_VICTIM, 1000, 10000, 0}, + {SPELL_WYVERN_STING, TARGET_TYPE_RANDOM, 1500, 60000, 0}, + {SPELL_WING_CLIP, TARGET_TYPE_RANDOM, 1500, 6000, 0, SELECT_FLAG_IN_MELEE_RANGE}, +}; + +struct boss_crusader_hunterAI : public trial_crusader_commonAI +{ + boss_crusader_hunterAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aHunterAbilities, MAX_HUNTER_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_RANGED; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A) + DoCastSpellIfCan(m_creature, SPELL_CALL_PET); + else + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + switch (urand(0, 2)) + { + case 0: uiIndex = 1; break; + case 1: uiIndex = 2; break; + case 2: uiIndex = 7; break; + } + break; + } + + if (uiIndex > MAX_HUNTER_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aHunterAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aHunterAbilities[uiIndex].m_uiCooldown; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_hunter(Creature* pCreature) +{ + return new boss_crusader_hunterAI(pCreature); +} + +/*###### +## boss_crusader_mage +######*/ + +static const CrusaderAbilityStruct m_aMageAbilities[MAX_MAGE_SPELLS] = +{ + {SPELL_ARCANE_EXPLOSION, TARGET_TYPE_SELF, 2000, 20000, 0}, + {SPELL_BLINK, TARGET_TYPE_SELF, 1000, 15000, 0}, + {SPELL_FROST_NOVA, TARGET_TYPE_SELF, 2000, 25000, 0}, + {SPELL_ICE_BLOCK, TARGET_TYPE_SELF, 2000, 300000, 20}, + {SPELL_ARCANE_BARRAGE, TARGET_TYPE_VICTIM, 2000, 30000, 0}, + {SPELL_ARCANE_BLAST, TARGET_TYPE_VICTIM, 2500, 20000, 0}, + {SPELL_FROSTBOLT, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_COUNTERSPELL, TARGET_TYPE_RANDOM, 1000, 24000, 0, SELECT_FLAG_POWER_MANA}, + {SPELL_POLYMORPH, TARGET_TYPE_RANDOM, 2000, 15000, 0}, +}; + +struct boss_crusader_mageAI : public trial_crusader_commonAI +{ + boss_crusader_mageAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aMageAbilities, MAX_MAGE_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_RANGED; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = 7; + break; + case AI_EVENT_GOT_CCED: + uiIndex = 1; + break; + } + + if (uiIndex > MAX_HUNTER_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aMageAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aMageAbilities[uiIndex].m_uiCooldown; + } + } +}; + +CreatureAI* GetAI_boss_crusader_mage(Creature* pCreature) +{ + return new boss_crusader_mageAI(pCreature); +} + +/*###### +## boss_crusader_priest_shadow +######*/ + +static const CrusaderAbilityStruct m_aPriestDamageAbilities[MAX_PRIEST_DAMAGE_SPELLS] = +{ + {SPELL_DISPERSION, TARGET_TYPE_SELF, 6000, 180000, 50}, + {SPELL_PSYCHIC_SCREAM, TARGET_TYPE_SELF, 1500, 30000, 0}, + {SPELL_MIND_BLAST, TARGET_TYPE_VICTIM, 1500, 8000, 0}, + {SPELL_MIND_FLAY, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_PSYCHIC_HORROR, TARGET_TYPE_VICTIM, 2000, 120000, 30}, + {SPELL_SHADOW_WORD_PAIN, TARGET_TYPE_VICTIM, 2000, 20000, 0}, + {SPELL_VAMPIRIC_TOUCH, TARGET_TYPE_VICTIM, 2000, 2000, 0}, + {SPELL_SILENCE, TARGET_TYPE_RANDOM, 2000, 45000, 0, SELECT_FLAG_POWER_MANA}, +}; + +struct boss_crusader_priest_shadowAI : public trial_crusader_commonAI +{ + boss_crusader_priest_shadowAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aPriestDamageAbilities, MAX_PRIEST_DAMAGE_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_RANGED; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + uint32 uiSpellEntry = 0; + uint32 uiSpellTimer = 0; + + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = 1; + break; + case AI_EVENT_GOT_CCED: + uiSpellEntry = SPELL_DISPEL; + break; + } + + if (!uiSpellEntry) + { + if (uiIndex > MAX_PRIEST_DAMAGE_SPELLS - 1) + return; + else + { + uiSpellEntry = m_aPriestDamageAbilities[uiIndex].m_uiSpellId; + uiSpellTimer = m_aPriestDamageAbilities[uiIndex].m_uiCooldown; + } + } + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pSender, uiSpellEntry) == CAST_OK) + { + if (uiSpellTimer) + m_uiSpellTimer[uiIndex] = uiSpellTimer; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_priest_shadow(Creature* pCreature) +{ + return new boss_crusader_priest_shadowAI(pCreature); +} + +/*###### +## boss_crusader_warlock +######*/ + +static const CrusaderAbilityStruct m_aWarlockAbilities[MAX_WARLOCK_SPELLS] = +{ + {SPELL_HELLFIRE, TARGET_TYPE_SELF, 1500, 30000, 0}, + {SPELL_SHADOW_BOLT, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_UNSTABLE_AFFLICTION, TARGET_TYPE_VICTIM, 2000, 20000, 0}, + {SPELL_CORRUPTION, TARGET_TYPE_VICTIM, 2000, 20000, 0}, + {SPELL_CURSE_OF_AGONY, TARGET_TYPE_VICTIM, 2000, 30000, 0}, + {SPELL_CURSE_OF_EXHAUSTION, TARGET_TYPE_VICTIM, 2000, 20000, 0}, + {SPELL_SEARING_PAIN, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_DEATH_COIL_WARLOCK, TARGET_TYPE_VICTIM, 2000, 120000, 50}, + {SPELL_FEAR, TARGET_TYPE_RANDOM, 2000, 30000, 0}, +}; + +struct boss_crusader_warlockAI : public trial_crusader_commonAI +{ + boss_crusader_warlockAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aWarlockAbilities, MAX_WARLOCK_SPELLS) { Reset(); } + + void Reset() override + { + m_uiAIType = AI_TYPE_RANGED; + + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_FELHUNTER); + else + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_JUST_DIED: + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = 8; + break; + } + + if (uiIndex > MAX_WARLOCK_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pSender, m_aWarlockAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aWarlockAbilities[uiIndex].m_uiCooldown; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_warlock(Creature* pCreature) +{ + return new boss_crusader_warlockAI(pCreature); +} + +/*###### +## MELEE CRUSADERS +######*/ + +/*###### +## boss_crusader_death_knight +######*/ + +static const CrusaderAbilityStruct m_aDeathKnightAbilities[MAX_DEATH_KNIGHT_SPELLS] = +{ + {SPELL_ICEBOUND_FORTITUDE, TARGET_TYPE_SELF, 10000, 60000, 0}, + {SPELL_CHAINS_OF_ICE, TARGET_TYPE_VICTIM, 1500, 20000, 0}, + {SPELL_FROST_STRIKE, TARGET_TYPE_VICTIM, 1500, 6000, 0}, + {SPELL_ICY_TOUCH, TARGET_TYPE_RANDOM, 2000, 8000, 0}, + {SPELL_DEATH_COIL, TARGET_TYPE_RANDOM, 2000, 8000, 0}, + {SPELL_DEATH_GRIP, TARGET_TYPE_RANDOM, 1000, 35000, 0}, + {SPELL_STRANGULATE, TARGET_TYPE_RANDOM, 40000, 120000, 0}, +}; + +struct boss_crusader_death_knightAI : public trial_crusader_commonAI +{ + boss_crusader_death_knightAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aDeathKnightAbilities, MAX_DEATH_KNIGHT_SPELLS) { Reset(); } + + void Reset() override + { + trial_crusader_commonAI::Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + uiIndex = urand(0, 1) ? 5 : 6; + break; + } + + if (uiIndex > MAX_DEATH_KNIGHT_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aDeathKnightAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aDeathKnightAbilities[uiIndex].m_uiCooldown; + } + } +}; + +CreatureAI* GetAI_boss_crusader_death_knight(Creature* pCreature) +{ + return new boss_crusader_death_knightAI(pCreature); +} + +/*###### +## boss_crusader_warrior +######*/ + +static const CrusaderAbilityStruct m_aWarriorAbilities[MAX_WARRIOR_SPELLS] = +{ + {SPELL_BLADESTORM, TARGET_TYPE_SELF, 10000, 90000, 0}, + {SPELL_RETALIATION, TARGET_TYPE_SELF, 30000, 300000, 0}, + {SPELL_SUNDER_ARMOR, TARGET_TYPE_VICTIM, 1500, 5000, 0}, + {SPELL_DISARM, TARGET_TYPE_VICTIM, 20000, 60000, 0}, + {SPELL_INTIMIDATING_SHOUT, TARGET_TYPE_VICTIM, 10000, 30000, 0}, + {SPELL_MORTAL_STRIKE, TARGET_TYPE_VICTIM, 2000, 10000, 0}, + {SPELL_OVERPOWER, TARGET_TYPE_VICTIM, 2000, 6000, 0}, + {SPELL_SHATTERING_THROW, TARGET_TYPE_RANDOM, 40000, 300000, 0}, + {SPELL_CHARGE, TARGET_TYPE_RANDOM, 1000, 15000, 0, SELECT_FLAG_NOT_IN_MELEE_RANGE}, +}; + +struct boss_crusader_warriorAI : public trial_crusader_commonAI +{ + boss_crusader_warriorAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aWarriorAbilities, MAX_WARRIOR_SPELLS) { Reset(); } + + void Reset() override { trial_crusader_commonAI::Reset(); } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + case AI_EVENT_LOST_HEALTH: + uiIndex = 8; + break; + } + + if (uiIndex > MAX_WARRIOR_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aWarriorAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aWarriorAbilities[uiIndex].m_uiCooldown; + } + } +}; + +CreatureAI* GetAI_boss_crusader_warrior(Creature* pCreature) +{ + return new boss_crusader_warriorAI(pCreature); +} + +/*###### +## boss_crusader_paladin_retri +######*/ + +static const CrusaderAbilityStruct m_aPaladinDamageAbilities[MAX_PALADIN_DAMAGE_SPELLS] = +{ + {SPELL_AVENGING_WRATH, TARGET_TYPE_SELF, 2000, 180000, 50}, + {SPELL_DIVINE_STORM, TARGET_TYPE_SELF, 10000, 20000, 0}, + {SPELL_CRUSADER_STRIKE, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_HAMMER_OF_JUSTICE_RETRI, TARGET_TYPE_RANDOM, 10000, 40000, 0}, + {SPELL_JUDGEMENT_OF_COMMAND, TARGET_TYPE_RANDOM, 5000, 20000, 0}, + {SPELL_REPENTANCE, TARGET_TYPE_RANDOM, 30000, 60000, 0}, +}; + +struct boss_crusader_paladin_retriAI : public trial_crusader_commonAI +{ + boss_crusader_paladin_retriAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aPaladinDamageAbilities, MAX_PALADIN_DAMAGE_SPELLS) { Reset(); } + + void Reset() override { trial_crusader_commonAI::Reset(); } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A) + DoCastSpellIfCan(m_creature, SPELL_SEAL_OF_COMMAND); + else + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + case AI_EVENT_LOST_HEALTH: + uiIndex = urand(0, 1) ? 3 : 5; + break; + } + + if (uiIndex > MAX_PALADIN_DAMAGE_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aPaladinDamageAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aPaladinDamageAbilities[uiIndex].m_uiCooldown; + } + } + } +}; + +CreatureAI* GetAI_boss_crusader_paladin_retri(Creature* pCreature) +{ + return new boss_crusader_paladin_retriAI(pCreature); +} + +/*###### +## boss_crusader_shaman_enha +######*/ + +static const CrusaderAbilityStruct m_aShamanDamageAbilities[MAX_SHAMAN_DAMAGE_SPELLS] = +{ + {SPELL_HEROISM, TARGET_TYPE_SELF, 60000, 300000, 0}, + {SPELL_MAELSTROM_WEAPON, TARGET_TYPE_SELF, 30000, 40000, 0}, + {SPELL_WINDFURY, TARGET_TYPE_SELF, 10000, 10000, 0}, + {SPELL_EARTH_SHOCK, TARGET_TYPE_VICTIM, 2000, 8000, 0}, + {SPELL_LAVA_LASH, TARGET_TYPE_VICTIM, 2000, 10000, 0}, + {SPELL_STORMSTRIKE, TARGET_TYPE_VICTIM, 7000, 15000, 0}, +}; + +struct boss_crusader_shaman_enhaAI : public trial_crusader_commonAI +{ + boss_crusader_shaman_enhaAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aShamanDamageAbilities, MAX_SHAMAN_DAMAGE_SPELLS) { Reset(); } + + void Reset() override { trial_crusader_commonAI::Reset(); } +}; + +CreatureAI* GetAI_boss_crusader_shaman_enha(Creature* pCreature) +{ + return new boss_crusader_shaman_enhaAI(pCreature); +} + +/*###### +## boss_crusader_rogue +######*/ + +static const CrusaderAbilityStruct m_aRogueAbilities[MAX_ROGUE_SPELLS] = +{ + {SPELL_BLADE_FURRY, TARGET_TYPE_SELF, 40000, 120000, 0}, + {SPELL_CLOAK_OF_SHADOWS, TARGET_TYPE_SELF, 2000, 90000, 50}, + {SPELL_FAN_OF_KNIVES, TARGET_TYPE_SELF, 1500, 15000, 0}, + {SPELL_SHADOWSTEP, TARGET_TYPE_SELF, 8000, 30000, 0}, + {SPELL_EVISCERATE, TARGET_TYPE_VICTIM, 3000, 20000, 0}, + {SPELL_HEMORRHAGE, TARGET_TYPE_VICTIM, 2000, 15000, 0}, + {SPELL_WOUND_POISON, TARGET_TYPE_VICTIM, 5000, 18000, 0}, + {SPELL_BLIND, TARGET_TYPE_RANDOM, 8000, 120000, 30}, +}; + +struct boss_crusader_rogueAI : public trial_crusader_commonAI +{ + boss_crusader_rogueAI(Creature* pCreature) : trial_crusader_commonAI(pCreature, m_aRogueAbilities, MAX_ROGUE_SPELLS) { Reset(); } + + void Reset() override { trial_crusader_commonAI::Reset(); } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + uint8 uiIndex = 99; + switch (eventType) + { + case AI_EVENT_CRITICAL_HEALTH: + case AI_EVENT_LOST_HEALTH: + uiIndex = 7; + break; + } + + if (uiIndex > MAX_ROGUE_SPELLS - 1) + return; + + if (!m_uiSpellTimer[uiIndex]) + { + if (DoCastSpellIfCan(pInvoker, m_aRogueAbilities[uiIndex].m_uiSpellId) == CAST_OK) + m_uiSpellTimer[uiIndex] = m_aRogueAbilities[uiIndex].m_uiCooldown; + } + } +}; + +CreatureAI* GetAI_boss_crusader_rogue(Creature* pCreature) +{ + return new boss_crusader_rogueAI(pCreature); +} + void AddSC_boss_faction_champions() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_death_knight"; + pNewScript->GetAI = &GetAI_boss_crusader_death_knight; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_druid_balance"; + pNewScript->GetAI = &GetAI_boss_crusader_druid_balance; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_druid_resto"; + pNewScript->GetAI = &GetAI_boss_crusader_druid_resto; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_hunter"; + pNewScript->GetAI = &GetAI_boss_crusader_hunter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_mage"; + pNewScript->GetAI = &GetAI_boss_crusader_mage; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_paladin_holy"; + pNewScript->GetAI = &GetAI_boss_crusader_paladin_holy; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_paladin_retri"; + pNewScript->GetAI = &GetAI_boss_crusader_paladin_retri; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_priest_disc"; + pNewScript->GetAI = &GetAI_boss_crusader_priest_disc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_priest_shadow"; + pNewScript->GetAI = &GetAI_boss_crusader_priest_shadow; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_rogue"; + pNewScript->GetAI = &GetAI_boss_crusader_rogue; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_shaman_enha"; + pNewScript->GetAI = &GetAI_boss_crusader_shaman_enha; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_shaman_resto"; + pNewScript->GetAI = &GetAI_boss_crusader_shaman_resto; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_warlock"; + pNewScript->GetAI = &GetAI_boss_crusader_warlock; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_crusader_warrior"; + pNewScript->GetAI = &GetAI_boss_crusader_warrior; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_jaraxxus.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_jaraxxus.cpp index 22943c4af..c51bd10b9 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_jaraxxus.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_jaraxxus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: trial_of_the_crusader -SD%Complete: 75 -SDComment: Evade handling must be fixed, this is currently totally wrong. Some issues with emotes and texts, generic improvements related to spells can be missing +SD%Complete: 90 +SDComment: Some issues with emotes and texts, generic improvements related to spells can be missing SDCategory: Crusader Coliseum EndScriptData */ @@ -57,7 +57,7 @@ enum NPC_NETHER_PORTAL = 34825 }; -struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI +struct boss_jaraxxusAI : public ScriptedAI { boss_jaraxxusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -77,7 +77,7 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI uint32 m_uiBerserkTimer; bool m_bVolcanoSummon; - void Reset() + void Reset() override { m_uiFelFireballTimer = urand(20000, 25000); // maybe too early, and too often! m_uiFelLightningTimer = urand(5000, 8000); @@ -85,48 +85,62 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI m_uiLegionFlameTimer = 10000; m_uiSummonTimer = 20000; m_uiNetherPowerTimer = urand(20000, 30000); - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; m_bVolcanoSummon = true; DoCastSpellIfCan(m_creature, SPELL_JARAXXUS_HITTIN_YA); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE | UNIT_FLAG_OOC_NOT_ATTACKABLE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_JARAXXUS, FAIL); - m_creature->ForcedDespawn(); + // ToDo: confirm if this is correct and if we are not missing something! + DoCastSpellIfCan(m_creature, SPELL_ENSLAVE_JARAXXUS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_JARAXXUS, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->GetEntry() == NPC_FIZZLEBANG) return; + DoScriptText(SAY_AGGRO, m_creature); + if (m_pInstance) m_pInstance->SetData(TYPE_JARAXXUS, IN_PROGRESS); DoCastSpellIfCan(m_creature, SPELL_NETHER_POWER); - m_creature->SetInCombatWithZone(); } - void EnterEvadeMode() + void EnterEvadeMode() override { - if (m_pInstance && m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + if (!m_pInstance) return; - ScriptedAI::EnterEvadeMode(); + // special evade mechanics when attacking Wilfred + if (m_pInstance->GetData(TYPE_JARAXXUS) != IN_PROGRESS) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + Reset(); + } + else + ScriptedAI::EnterEvadeMode(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetEntry() == NPC_FIZZLEBANG) return; @@ -134,9 +148,9 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_INFERNAL_VOLCANO: pSummoned->CastSpell(pSummoned, SPELL_ERUPTION, true, NULL, NULL, m_creature->GetObjectGuid()); @@ -145,9 +159,9 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI pSummoned->CastSpell(pSummoned, SPELL_NETHER_PORTAL, true, NULL, NULL, m_creature->GetObjectGuid()); break; } - } + } - void MovementInform(uint32 uiMovementType, uint32 uiPointId) + void MovementInform(uint32 uiMovementType, uint32 uiPointId) override { if (uiMovementType != POINT_MOTION_TYPE) return; @@ -157,7 +171,7 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI m_creature->SetFacingToObject(pFizzlebang); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -198,12 +212,12 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI if (m_uiSummonTimer < uiDiff) { - if(m_bVolcanoSummon) + if (m_bVolcanoSummon) { if (DoCastSpellIfCan(m_creature, SPELL_NETHER_PORTAL_SUMMON) == CAST_OK) { // TODO missing emote? - //DoScriptText(EMOTE_PORTAL, m_creature); + // DoScriptText(EMOTE_PORTAL, m_creature); m_bVolcanoSummon = false; m_uiSummonTimer = 60000; } @@ -214,7 +228,7 @@ struct MANGOS_DLL_DECL boss_jaraxxusAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, SPELL_INFERNAL_ERUPTION) == CAST_OK) { // TODO missing emote? - //DoScriptText(EMOTE_VOLCANO, m_creature); + // DoScriptText(EMOTE_VOLCANO, m_creature); m_bVolcanoSummon = true; m_uiSummonTimer = 60000; } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_northrend_beasts.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_northrend_beasts.cpp index 9ced6842e..5daf937ea 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_northrend_beasts.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_northrend_beasts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -15,10 +15,10 @@ */ /* ScriptData -SDName: -SD%Complete: 0 -SDComment: -SDCategory: +SDName: trial_of_the_crusader +SD%Complete: 90 +SDComment: Snobolds behavior can be improved +SDCategory: Crusader Coliseum EndScriptData */ #include "precompiled.h" @@ -33,23 +33,30 @@ enum SAY_TIRION_BEAST_2 = -1649005, SAY_TIRION_BEAST_3 = -1649006, + EMOTE_JORMUNGAR_ENRAGE = -1649076, + SPELL_BERSERK = 26662, + SPELL_JORMUNGAR_ENRAGE = 68335, + SPELL_JORMUNGAR_ACHIEV_CREDIT = 68523, // server side spell for achievs 3936, 3937 + + // NPC_MOBILE_BURROW_TARGET = 35226, // summoned by missing spell 66980 - purpose unk, related to jormungars event + // NPC_SESSILE_BURROW_TARGET = 35227, // summoned by missing spell 66981 - purpose unk, related to jormungars event PHASE_GORMOK = 0, PHASE_WORMS = 1, PHASE_ICEHOWL = 2, }; -struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI +struct npc_beast_combat_stalkerAI : public Scripted_NoMovementAI { npc_beast_combat_stalkerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); Reset(); - m_creature->SetInCombatWithZone(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + ObjectGuid m_aSummonedBossGuid[4]; bool m_bFirstWormDied; uint32 m_uiBerserkTimer; @@ -57,27 +64,27 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI uint32 m_uiNextBeastTimer; uint32 m_uiPhase; - void Reset() + uint32 m_uiWormPhaseTimer; + uint8 m_uiWormPhaseStage; + uint32 m_uiWormAchievTimer; + + void Reset() override { + m_uiWormPhaseTimer = 0; + m_uiWormPhaseStage = 0; m_uiAttackDelayTimer = 0; - m_uiNextBeastTimer = 0; - m_bFirstWormDied = false; - m_uiPhase = PHASE_GORMOK; + m_uiNextBeastTimer = 0; + m_uiWormAchievTimer = 0; + m_bFirstWormDied = false; + m_uiPhase = PHASE_GORMOK; if (m_creature->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL || m_creature->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) - m_uiBerserkTimer = 15*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; else - m_uiBerserkTimer = 9*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 9 * MINUTE * IN_MILLISECONDS; } - void MoveInLineOfSight(Unit* pWho) {} - - void DamageTaken(Unit* pDealer, uint32& uiDamage) - { - uiDamage = 0; - } - - void EnterEvadeMode() + void EnterEvadeMode() override { if (m_pInstance) m_pInstance->SetData(TYPE_NORTHREND_BEASTS, FAIL); @@ -91,13 +98,15 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI m_creature->ForcedDespawn(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NORTHREND_BEASTS, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void AttackStart(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -113,13 +122,17 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI m_aSummonedBossGuid[m_uiPhase] = pSummoned->GetObjectGuid(); - pSummoned->GetMotionMaster()->MovePoint(m_uiPhase, aMovePositions[m_uiPhase][0], aMovePositions[m_uiPhase][1], aMovePositions[m_uiPhase][2]); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(m_uiPhase, aMovePositions[m_uiPhase][0], aMovePositions[m_uiPhase][1], aMovePositions[m_uiPhase][2], false); // Next beasts are summoned only for heroic modes if (m_creature->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || m_creature->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC) - m_uiNextBeastTimer = 150*IN_MILLISECONDS; // 2 min 30 + m_uiNextBeastTimer = 150 * IN_MILLISECONDS; // 2 min 30 - m_uiAttackDelayTimer = 15000; // TODO, must be checked. + m_uiAttackDelayTimer = 10000; + + if (m_pInstance) + m_pInstance->DoOpenMainGate(10000); } // Only for Dreadscale and Icehowl @@ -141,7 +154,7 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (!m_pInstance) return; @@ -156,9 +169,28 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI case NPC_DREADSCALE: case NPC_ACIDMAW: if (m_bFirstWormDied && m_uiPhase == PHASE_WORMS) + { DoSummonNextBeast(NPC_ICEHOWL); + + // cast achiev spell if timer is still running + if (m_uiWormAchievTimer) + { + m_creature->CastSpell(m_creature, SPELL_JORMUNGAR_ACHIEV_CREDIT, true); + m_uiWormAchievTimer = 0; + } + } else + { m_bFirstWormDied = true; + + // jormungar brother enrages + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(pSummoned->GetEntry() == NPC_ACIDMAW ? NPC_DREADSCALE : NPC_ACIDMAW)) + { + pWorm->CastSpell(pWorm, SPELL_JORMUNGAR_ENRAGE, true); + DoScriptText(EMOTE_JORMUNGAR_ENRAGE, pWorm); + m_uiWormAchievTimer = 10000; + } + } break; case NPC_ICEHOWL: @@ -168,7 +200,7 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiNextBeastTimer) { @@ -189,11 +221,22 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI { if (m_uiAttackDelayTimer <= uiDiff) { + // for worm phase, summon brother on aggro if (m_uiPhase == PHASE_WORMS) + { m_creature->SummonCreature(NPC_ACIDMAW, aSpawnPositions[3][0], aSpawnPositions[3][1], aSpawnPositions[3][2], aSpawnPositions[3][3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiWormPhaseTimer = 45000; + } + // start combat if (Creature* pBeast = m_creature->GetMap()->GetCreature(m_aSummonedBossGuid[m_uiPhase])) - pBeast->SetInCombatWithZone(); + { + pBeast->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + + // first boss doesn't automatically attack + if (pBeast->GetEntry() != NPC_GORMOK) + pBeast->SetInCombatWithZone(); + } m_uiAttackDelayTimer = 0; } @@ -216,6 +259,88 @@ struct MANGOS_DLL_DECL npc_beast_combat_stalkerAI : public Scripted_NoMovementAI m_uiBerserkTimer -= uiDiff; } + // jormungars phase switch control + if (m_uiWormPhaseTimer) + { + if (m_uiWormPhaseTimer <= uiDiff) + { + if (!m_pInstance) + return; + + ++m_uiWormPhaseStage; + + switch (m_uiWormPhaseStage) + { + // submerge worms + case 1: + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW)) + { + if (pWorm->isAlive()) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pWorm); + } + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE)) + { + if (pWorm->isAlive()) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pWorm); + } + + m_uiWormPhaseTimer = 4000; + break; + + // change places + case 2: + float fX, fY, fZ; + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW)) + { + if (pWorm->isAlive()) + { + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 45.0f, fX, fY, fZ); + pWorm->MonsterMoveWithSpeed(fX, fY, fZ, 7.7f); + } + } + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE)) + { + if (pWorm->isAlive()) + { + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 45.0f, fX, fY, fZ); + pWorm->MonsterMoveWithSpeed(fX, fY, fZ, 7.7f); + } + } + + m_uiWormPhaseTimer = 6000; + break; + + // emerge and change phase + case 3: + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_ACIDMAW)) + { + if (pWorm->isAlive()) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pWorm); + } + if (Creature* pWorm = m_pInstance->GetSingleCreatureFromStorage(NPC_DREADSCALE)) + { + if (pWorm->isAlive()) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pWorm); + } + + m_uiWormPhaseStage = 0; + m_uiWormPhaseTimer = 45000; + break; + } + } + else + m_uiWormPhaseTimer -= uiDiff; + } + + // jormungars achiev timer + if (m_uiWormAchievTimer) + { + if (m_uiWormAchievTimer <= uiDiff) + m_uiWormAchievTimer = 0; + else + m_uiWormAchievTimer -= uiDiff; + } + m_creature->SelectHostileTarget(); } }; @@ -229,31 +354,159 @@ CreatureAI* GetAI_npc_beast_combat_stalker(Creature* pCreature) ## boss_gormok, vehicle driven by 34800 (multiple times) ######*/ -struct MANGOS_DLL_DECL boss_gormokAI : public ScriptedAI +enum +{ + // gormok spells + SPELL_IMPALE = 66331, + SPELL_STOMP = 66330, + + // snobold spells + SPELL_JUMP_TO_HAND = 66342, // prepare snobold to jump + SPELL_RISING_ANGER = 66636, + SPELL_SNOBOLLED = 66406, // throw snobold on players head +}; + +struct boss_gormokAI : public ScriptedAI { boss_gormokAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + + uint32 m_uiStompTimer; + uint32 m_uiImpaleTimer; + uint32 m_uiJumpTimer; + uint32 m_uiSnoboldTimer; - void Reset() {} + uint8 m_uiSnoboldsBoarded; - void JustReachedHome() + GuidVector m_vSnoboldGuidsVector; + + void Reset() override { + m_uiStompTimer = urand(20000, 25000); + m_uiImpaleTimer = 10000; + m_uiJumpTimer = 20000; + m_uiSnoboldTimer = 0; + + m_uiSnoboldsBoarded = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { + // trigger the controller combat + if (m_pInstance) + { + if (Creature* pStalker = m_pInstance->GetSingleCreatureFromStorage(NPC_BEASTS_COMBAT_STALKER)) + pStalker->SetInCombatWithZone(); + } } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override + { + for (GuidVector::const_iterator itr = m_vSnoboldGuidsVector.begin(); itr != m_vSnoboldGuidsVector.end(); ++itr) + { + if (Creature* pSnobold = m_creature->GetMap()->GetCreature(*itr)) + { + if (!pSnobold->isAlive()) + continue; + + // ToDo: check if there is any player vehicle mounting involved + SendAIEvent(AI_EVENT_CUSTOM_EVENTAI_A, m_creature, pSnobold); + } + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SNOBOLD_VASSAL) + { + m_vSnoboldGuidsVector.push_back(pSummoned->GetObjectGuid()); + ++m_uiSnoboldsBoarded; + } + } + + // get the current active snobold + Creature* GetActiveSnobold() { return m_creature->GetMap()->GetCreature(m_vSnoboldGuidsVector[m_uiSnoboldsBoarded - 1]); } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // snobold related spells + if (m_uiSnoboldsBoarded) + { + // snobold jumps from boss' back to boss' hand + if (m_uiJumpTimer < uiDiff) + { + if (Creature* pSnobold = GetActiveSnobold()) + { + m_creature->RemoveAurasByCasterSpell(SPELL_RIDE_VEHICLE_HARDCODED, pSnobold->GetObjectGuid()); + pSnobold->CastSpell(m_creature, SPELL_JUMP_TO_HAND, true); + + m_uiSnoboldTimer = 3000; + m_uiJumpTimer = 20000; + } + } + else + m_uiJumpTimer -= uiDiff; + } + + if (m_uiSnoboldTimer) + { + // snobold jumps from boss' hand to player's back + if (m_uiSnoboldTimer <= uiDiff) + { + if (Creature* pSnobold = GetActiveSnobold()) + { + pSnobold->CastSpell(m_creature, SPELL_RISING_ANGER, true); + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SNOBOLLED, SELECT_FLAG_PLAYER)) + { + // ToDo: change this to setup the player vehicle for the snobold. It seems that the spell that will handle this is missing + pSnobold->FixateTarget(pTarget); + // pTarget->SetVehicleId(pSnobold->GetCreatureInfo()->VehicleTemplateId, pSnobold->GetEntry()); + // pTarget->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); + + pSnobold->CastSpell(pTarget, SPELL_SNOBOLLED, true); + SendAIEvent(AI_EVENT_CUSTOM_EVENTAI_A, m_creature, pSnobold); + --m_uiSnoboldsBoarded; + } + } + m_uiSnoboldTimer = 0; + } + else + m_uiSnoboldTimer -= uiDiff; + } + + if (m_uiStompTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_STOMP) == CAST_OK) + m_uiStompTimer = 20000; + } + else + m_uiStompTimer -= uiDiff; + + if (m_uiImpaleTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_IMPALE) == CAST_OK) + m_uiImpaleTimer = 10000; + } + else + m_uiImpaleTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -264,38 +517,285 @@ CreatureAI* GetAI_boss_gormok(Creature* pCreature) } /*###### -## boss_acidmaw +## twin_jormungars_common ######*/ -struct MANGOS_DLL_DECL boss_acidmawAI : public ScriptedAI +enum { - boss_acidmawAI(Creature* pCreature) : ScriptedAI(pCreature) + // common spells + SPELL_SLIME_POOL = 66883, + SPELL_SWEEP = 66794, + SPELL_SPAWN_GROUND_VISUAL = 68302, // visual for stationary worm + + // transition spells + SPELL_STATIC_WORM_SUBMERGE = 66936, // triggers 66969; long cast + SPELL_MOBILE_WORM_SUBMERGE = 66948, // triggers 66969; short cast + SPELL_MOBILE_WORM_EMERGE = 66949, // triggers 63984; short cast + SPELL_STATIC_WORM_EMERGE = 66947, // triggers 63984; long cast + SPELL_HATE_TO_ZERO = 63984, + + // debuffs + SPELL_PARALYTIC_TOXIN = 66823, + SPELL_BURNING_BILE = 66869, + + // slime pool + SPELL_SLIME_POOL_AURA = 66882, + NPC_SLIME_POOL = 35176, + + // phases + PHASE_STATIONARY = 0, + PHASE_SUBMERGED = 1, + PHASE_MOBILE = 2, +}; + +struct twin_jormungars_commonAI : public ScriptedAI +{ + twin_jormungars_commonAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiPrevPhase; + uint8 m_uiNextPhase; + + // mobile + uint32 m_uiSpewTimer; + uint32 m_uiBiteTimer; + uint32 m_uiSlimePoolTimer; - void Reset() {} + // stationary + uint32 m_uiSpitTimer; + uint32 m_uiSprayTimer; + uint32 m_uiSweepTimer; - void JustReachedHome() + void Reset() override { + m_uiSpewTimer = 5000; + m_uiBiteTimer = urand(5000, 10000); + m_uiSlimePoolTimer = urand(12000, 15000); + + m_uiSpitTimer = 3000; + m_uiSprayTimer = urand(7000, 13000); + m_uiSweepTimer = urand(12000, 15000); } - void Aggro(Unit* pWho) + void JustSummoned(Creature* pSummned) override { + if (pSummned->GetEntry() == NPC_SLIME_POOL) + pSummned->CastSpell(pSummned, SPELL_SLIME_POOL_AURA, false); } - void UpdateAI(const uint32 uiDiff) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + // inform when submerged + if (eventType == AI_EVENT_CUSTOM_A) + { + // cast submerge spells + if (m_uiPhase == PHASE_MOBILE) + DoCastSpellIfCan(m_creature, SPELL_MOBILE_WORM_SUBMERGE, CAST_INTERRUPT_PREVIOUS); + else if (m_uiPhase == PHASE_STATIONARY) + DoCastSpellIfCan(m_creature, SPELL_STATIC_WORM_SUBMERGE, CAST_INTERRUPT_PREVIOUS); + + // stop movement + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_uiPrevPhase = m_uiPhase; + m_uiPhase = PHASE_SUBMERGED; + } + // inform when emerge start + else if (eventType == AI_EVENT_CUSTOM_B) + { + // prepare emerge + if (m_uiPrevPhase == PHASE_MOBILE) + { + DoCastSpellIfCan(m_creature, SPELL_STATIC_WORM_EMERGE, CAST_INTERRUPT_PREVIOUS); + m_creature->RemoveAurasDueToSpell(SPELL_MOBILE_WORM_SUBMERGE); + m_uiNextPhase = PHASE_STATIONARY; + } + else if (m_uiPrevPhase == PHASE_STATIONARY) + { + DoCastSpellIfCan(m_creature, SPELL_MOBILE_WORM_EMERGE, CAST_INTERRUPT_PREVIOUS); + m_creature->RemoveAurasDueToSpell(SPELL_STATIC_WORM_SUBMERGE); + m_uiNextPhase = PHASE_MOBILE; + } + + // inform the worm to change display id + OnJormungarPhaseChanged(m_uiNextPhase); + } + // inform when emerge complete + else if (eventType == AI_EVENT_CUSTOM_C) + { + DoCastSpellIfCan(m_creature, SPELL_HATE_TO_ZERO, CAST_TRIGGERED); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiPhase = m_uiNextPhase; + + // for mobile worm follow target + if (m_uiPhase == PHASE_MOBILE) + { + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + // for stationary set visual + else if (m_uiPhase == PHASE_STATIONARY) + DoCastSpellIfCan(m_creature, SPELL_SPAWN_GROUND_VISUAL, CAST_TRIGGERED); + } + } + + // Handle phase changed display id + virtual void OnJormungarPhaseChanged(uint8 uiPhase) { } + + // Return the specific spell + virtual uint32 GetSplitSpell() { return 0; } + virtual uint32 GetSpraySpell() { return 0; } + virtual uint32 GetSpewSpell() { return 0; } + virtual uint32 GetBiteSpell() { return 0; } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + switch (m_uiPhase) + { + // abilities for stationary phase + case PHASE_STATIONARY: + + if (m_uiSpitTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, GetSplitSpell()) == CAST_OK) + m_uiSpitTimer = 3000; + } + } + else + m_uiSpitTimer -= uiDiff; + + if (m_uiSprayTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), GetSpraySpell()) == CAST_OK) + m_uiSprayTimer = 21000; + } + else + m_uiSprayTimer -= uiDiff; + + if (m_uiSweepTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SWEEP) == CAST_OK) + m_uiSweepTimer = urand(10000, 15000); + } + else + m_uiSweepTimer -= uiDiff; + + break; + + // abilities for mobile phase + case PHASE_MOBILE: + + if (m_uiBiteTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), GetBiteSpell()) == CAST_OK) + m_uiBiteTimer = urand(5000, 7000); + } + else + m_uiBiteTimer -= uiDiff; + + if (m_uiSpewTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, GetSpewSpell()) == CAST_OK) + m_uiSpewTimer = 21000; + } + else + m_uiSpewTimer -= uiDiff; + + if (m_uiSlimePoolTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SLIME_POOL) == CAST_OK) + m_uiSlimePoolTimer = urand(17000, 23000); + } + else + m_uiSlimePoolTimer -= uiDiff; + + break; + + // combat break + case PHASE_SUBMERGED: + return; + } + DoMeleeAttackIfReady(); } }; +/*###### +## boss_acidmaw +######*/ + +enum +{ + // mobile + SPELL_ACID_SPEW = 66818, + SPELL_PARALYTIC_BITE = 66824, + + // stationary + SPELL_ACID_SPIT = 66880, + SPELL_PARALYTIC_SPRAY = 66901, + + // display ids + DISPLAY_ID_ACIDMAW_FIXED = 29815, + DISPLAY_ID_ACIDMWA_MOBILE = 29816, +}; + +struct boss_acidmawAI : public twin_jormungars_commonAI +{ + boss_acidmawAI(Creature* pCreature) : twin_jormungars_commonAI(pCreature) { Reset(); } + + void Reset() override + { + m_uiPhase = PHASE_STATIONARY; + SetCombatMovement(false); + + twin_jormungars_commonAI::Reset(); + + // ToDo: research if there is a spawn animation involved + DoCastSpellIfCan(m_creature, SPELL_SPAWN_GROUND_VISUAL); + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpellEntry) override + { + if (pTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // remove burning bile and add paralytic toxin + if (pSpellEntry->Id == SPELL_PARALYTIC_BITE || pSpellEntry->Id == SPELL_PARALYTIC_SPRAY) + { + pTarget->RemoveAurasDueToSpell(SPELL_BURNING_BILE); + pTarget->CastSpell(pTarget, SPELL_PARALYTIC_TOXIN, true); + } + } + + void OnJormungarPhaseChanged(uint8 uiPhase) + { + if (uiPhase == PHASE_STATIONARY) + m_creature->SetDisplayId(DISPLAY_ID_ACIDMAW_FIXED); + else if (uiPhase == PHASE_MOBILE) + m_creature->SetDisplayId(DISPLAY_ID_ACIDMWA_MOBILE); + } + + uint32 GetSplitSpell() { return SPELL_ACID_SPIT; } + uint32 GetSpewSpell() { return SPELL_ACID_SPEW; } + uint32 GetSpraySpell() { return SPELL_PARALYTIC_SPRAY; } + uint32 GetBiteSpell() { return SPELL_PARALYTIC_BITE; } +}; + CreatureAI* GetAI_boss_acidmaw(Creature* pCreature) { return new boss_acidmawAI(pCreature); @@ -305,33 +805,66 @@ CreatureAI* GetAI_boss_acidmaw(Creature* pCreature) ## boss_dreadscale ######*/ -struct MANGOS_DLL_DECL boss_dreadscaleAI : public ScriptedAI +enum { - boss_dreadscaleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } + // mobile + SPELL_MOLTEN_SPEW = 66821, + SPELL_BURNING_BITE = 66879, - ScriptedInstance* m_pInstance; + // stationary + SPELL_FIRE_SPIT = 66796, + SPELL_BURNING_SPRAY = 66902, - void Reset() {} + // display ids + DISPLAY_ID_DREADSCALE_FIXED = 26935, + DISPLAY_ID_DREADSCALE_MOBILE = 24564, +}; - void JustReachedHome() +struct boss_dreadscaleAI : public twin_jormungars_commonAI +{ + boss_dreadscaleAI(Creature* pCreature) : twin_jormungars_commonAI(pCreature) { Reset(); } + + void Reset() override { + m_uiPhase = PHASE_MOBILE; + + twin_jormungars_commonAI::Reset(); } - void Aggro(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { + // don't attack during intro + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + twin_jormungars_commonAI::MoveInLineOfSight(pWho); } - void UpdateAI(const uint32 uiDiff) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpellEntry) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (pTarget->GetTypeId() != TYPEID_PLAYER) return; - DoMeleeAttackIfReady(); + // remove paralytic toxin and add burning bile + if (pSpellEntry->Id == SPELL_BURNING_BITE || pSpellEntry->Id == SPELL_BURNING_SPRAY) + { + pTarget->RemoveAurasDueToSpell(SPELL_PARALYTIC_TOXIN); + pTarget->CastSpell(pTarget, SPELL_BURNING_BILE, true); + } + } + + void OnJormungarPhaseChanged(uint8 uiPhase) + { + if (uiPhase == PHASE_STATIONARY) + m_creature->SetDisplayId(DISPLAY_ID_DREADSCALE_FIXED); + else if (uiPhase == PHASE_MOBILE) + m_creature->SetDisplayId(DISPLAY_ID_DREADSCALE_MOBILE); } + + uint32 GetSplitSpell() { return SPELL_FIRE_SPIT; } + uint32 GetSpewSpell() { return SPELL_MOLTEN_SPEW; } + uint32 GetSpraySpell() { return SPELL_BURNING_SPRAY; } + uint32 GetBiteSpell() { return SPELL_BURNING_BITE; } }; CreatureAI* GetAI_boss_dreadscale(Creature* pCreature) @@ -339,6 +872,18 @@ CreatureAI* GetAI_boss_dreadscale(Creature* pCreature) return new boss_dreadscaleAI(pCreature); } +bool EffectDummyCreature_worm_emerge(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if ((uiSpellId == SPELL_STATIC_WORM_EMERGE || uiSpellId == SPELL_MOBILE_WORM_EMERGE) && uiEffIndex == EFFECT_INDEX_0) + { + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_C, pCaster, pCreatureTarget); + return true; + } + + return false; +} + /*###### ## boss_icehowl ######*/ @@ -346,33 +891,234 @@ CreatureAI* GetAI_boss_dreadscale(Creature* pCreature) enum { EMOTE_MASSIVE_CRASH = -1649039, + EMOTE_WALL_CRASH = -1649077, + + // standard combat spells + SPELL_ARCTIC_BREATH = 66689, + SPELL_WHIRL = 67345, + SPELL_FEROCIOUS_BUTT = 66770, + + // trample spells + SPELL_MASSIVE_CRASH = 66683, + SPELL_SURGE_OF_ADRENALINE = 68667, // buff for players - used only in non heroic + SPELL_ROAR = 66736, // turn to npc 35062 + SPELL_JUMP_BACK = 66733, // jump back; dummy effect on npc 35062 + SPELL_TRAMPLE = 66734, // cast when reached target 35062 + SPELL_STAGGERED_DAZE = 66758, // debuff on player miss during trample + SPELL_FROTHING_RAGE = 66759, // buff gained on player hit + + NPC_FURIOUS_CHARGE_STALKER = 35062, // summoned by missing spell 66729 + + POINT_ID_CHARGE_BEGIN = 101, + POINT_ID_CHARGE_END = 102, }; -struct MANGOS_DLL_DECL boss_icehowlAI : public ScriptedAI +struct boss_icehowlAI : public ScriptedAI { boss_icehowlAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + m_fSpeedRate = m_creature->GetSpeedRate(MOVE_RUN); Reset(); } - ScriptedInstance* m_pInstance; + instance_trial_of_the_crusader* m_pInstance; + + uint32 m_uiFerociousButtTimer; + uint32 m_uiArticBreathTimer; + uint32 m_uiWhirlTimer; + uint32 m_uiMassiveCrashTimer; + + uint32 m_uiFuriosChargeTimer; + uint8 m_uiFuriousChargeStage; + + bool m_bIsFuriousCharge; + + float m_fSpeedRate; + + ObjectGuid m_chargeStalkerGuid; + + void Reset() override + { + m_uiFerociousButtTimer = 30000; + m_uiArticBreathTimer = 20000; + m_uiWhirlTimer = 15000; + m_uiMassiveCrashTimer = 45000; + + m_uiFuriosChargeTimer = 0; + m_uiFuriousChargeStage = 0; + m_bIsFuriousCharge = false; + + m_creature->SetSpeedRate(MOVE_RUN, m_fSpeedRate); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } - void Reset() {} + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_FURIOUS_CHARGE_STALKER) + m_chargeStalkerGuid = pSummoned->GetObjectGuid(); + } - void JustReachedHome() + void MovementInform(uint32 uiType, uint32 uiPointId) override { + if (uiType == EFFECT_MOTION_TYPE && uiPointId == POINT_ID_CHARGE_BEGIN) + { + if (DoCastSpellIfCan(m_creature, SPELL_MASSIVE_CRASH) == CAST_OK) + m_uiFuriosChargeTimer = 4000; + } + else if (uiType == POINT_MOTION_TYPE && uiPointId == POINT_ID_CHARGE_END) + { + // cast trample and try to hit a player + if (DoCastSpellIfCan(m_creature, SPELL_TRAMPLE, CAST_TRIGGERED) == CAST_OK) + { + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + m_bIsFuriousCharge = false; + m_creature->SetSpeedRate(MOVE_RUN, m_fSpeedRate); + } + + // if player is missed then get the debuff + if (!m_creature->HasAura(SPELL_FROTHING_RAGE)) + { + DoScriptText(EMOTE_WALL_CRASH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_STAGGERED_DAZE, CAST_TRIGGERED); + } + } } - void Aggro(Unit* pWho) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpellEntry) override { + if (pTarget->GetTypeId() != TYPEID_PLAYER) + return; + + // cast frothing rage on player hit + if (pSpellEntry->Id == SPELL_TRAMPLE) + DoCastSpellIfCan(m_creature, SPELL_FROTHING_RAGE, CAST_TRIGGERED); } - void UpdateAI(const uint32 uiDiff) + // function that will apply the Surge of Adrenaline to all players + void DoApplySurgeOfAdrenaline() + { + Map::PlayerList const& PlayerList = m_creature->GetMap()->GetPlayers(); + + if (PlayerList.isEmpty()) + return; + + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (i->getSource()->isAlive()) + i->getSource()->CastSpell(i->getSource(), SPELL_SURGE_OF_ADRENALINE, true); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_bIsFuriousCharge) + { + if (m_uiFuriosChargeTimer < uiDiff) + { + switch (m_uiFuriousChargeStage) + { + case 0: + // pick a target + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER | SELECT_FLAG_IN_LOS)) + { + DoScriptText(EMOTE_MASSIVE_CRASH, m_creature, pTarget); + m_creature->SummonCreature(NPC_FURIOUS_CHARGE_STALKER, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 35000); + } + + // apply surge of adrenaline + if (m_pInstance && !m_pInstance->IsHeroicDifficulty()) + DoApplySurgeOfAdrenaline(); + + m_uiFuriosChargeTimer = 1000; + break; + + case 1: + // roar at target + if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_chargeStalkerGuid)) + DoCastSpellIfCan(pTarget, SPELL_ROAR); + + m_uiFuriosChargeTimer = 2000; + break; + + case 2: + // jump back and prepare to charge + if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_chargeStalkerGuid)) + DoCastSpellIfCan(pTarget, SPELL_JUMP_BACK); + + m_uiFuriosChargeTimer = 2000; + break; + + case 3: + // charge to the target + m_creature->SetSpeedRate(MOVE_RUN, m_fSpeedRate * 4); + if (Creature* pTarget = m_creature->GetMap()->GetCreature(m_chargeStalkerGuid)) + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CHARGE_END, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + + m_uiFuriosChargeTimer = 99999; + break; + } + ++m_uiFuriousChargeStage; + } + else + m_uiFuriosChargeTimer -= uiDiff; + + // no other actions during charge + return; + } + + if (m_uiMassiveCrashTimer < uiDiff) + { + SetCombatMovement(false); + m_creature->InterruptNonMeleeSpells(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveJump(aSpawnPositions[0][0], aSpawnPositions[0][1], aSpawnPositions[1][2], 2 * m_creature->GetSpeed(MOVE_RUN), 10.0f, POINT_ID_CHARGE_BEGIN); + + m_bIsFuriousCharge = true; + m_uiFuriousChargeStage = 0; + m_uiFuriosChargeTimer = 99999; + m_uiMassiveCrashTimer = urand(40000, 45000); + } + else + m_uiMassiveCrashTimer -= uiDiff; + + if (m_uiWhirlTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WHIRL) == CAST_OK) + m_uiWhirlTimer = urand(15000, 20000); + } + else + m_uiWhirlTimer -= uiDiff; + + if (m_uiArticBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCTIC_BREATH) == CAST_OK) + m_uiArticBreathTimer = urand(25000, 30000); + } + else + m_uiArticBreathTimer -= uiDiff; + + if (m_uiFerociousButtTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEROCIOUS_BUTT) == CAST_OK) + m_uiFerociousButtTimer = 15000; + } + else + m_uiFerociousButtTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -399,16 +1145,17 @@ void AddSC_northrend_beasts() pNewScript = new Script; pNewScript->Name = "boss_acidmaw"; pNewScript->GetAI = &GetAI_boss_acidmaw; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_worm_emerge; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "boss_dreadscale"; pNewScript->GetAI = &GetAI_boss_dreadscale; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_worm_emerge; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "boss_icehowl"; pNewScript->GetAI = &GetAI_boss_icehowl; pNewScript->RegisterSelf(); - } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_twin_valkyr.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_twin_valkyr.cpp index ae5837009..0ef6d3eff 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_twin_valkyr.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/boss_twin_valkyr.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: trial_of_the_crusader -SD%Complete: 0 +SD%Complete: 100 SDComment: SDCategory: Crusader Coliseum EndScriptData */ @@ -34,30 +34,240 @@ enum SAY_SLAY_2 = -1649061, SAY_TO_BLACK = -1649062, SAY_TO_WHITE = -1649063, + + // generic spells + SPELL_VALKYR_TWINS_HITTING_YA = 66073, + SPELL_POWER_OF_TWINS = 65916, // cast by the opposite twin during the Pact casting + SPELL_BERSERK = 64238, + SPELL_CLEAR_VALKYR_ESSENCE = 67547, + SPELL_CLEAR_VALKYR_TOUCH = 68084, + + // Fjola + SPELL_SURGE_OF_LIGHT = 65766, // aggro spell + SPELL_TWIN_SPIKE_LIGHT = 66075, + SPELL_LIGHT_TOUCH = 65950, + SPELL_SHIELD_OF_LIGHTS = 65858, // special abilities + SPELL_TWINS_PACT_LIGHT = 65876, + SPELL_LIGHT_VORTEX = 66046, + SPELL_LIGHT_BULLET_SUMMON_TRIGGER = 66140, // bullet summon spells (both cast by Fjola) + SPELL_DARK_BULLET_SUMMON_TRIGGER = 66141, + + // Eydis + SPELL_SURGE_OF_DARKNESS = 65768, // aggro spell + SPELL_TWIN_SPIKE_DARK = 66069, + SPELL_DARK_TOUCH = 66001, + SPELL_SHIELD_OF_DARKNESS = 65874, // special abilities + SPELL_TWINS_PACT_DARK = 65875, + SPELL_DARK_VORTEX = 66058, + + // Concentrated bullets + SPELL_LIGHT_BALL_PASSIVE = 65794, + SPELL_DARK_BALL_PASSIVE = 65796, + + NPC_CONCENTRATED_DARKNESS = 34628, + NPC_CONCENTRATED_LIGHT = 34630, }; /*###### ## boss_fjola ######*/ -struct MANGOS_DLL_DECL boss_fjolaAI : public ScriptedAI +struct boss_fjolaAI : public ScriptedAI { - boss_fjolaAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_fjolaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_crusader* m_pInstance; + + uint32 m_uiTwinSpikeTimer; + uint32 m_uiTouchTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiSpecialAbilityTimer; + uint32 m_uiSummonTimer; + + bool m_bIsVortex; + bool m_bIsLightTwin; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_VALKYR_TWINS_HITTING_YA); + + m_uiTwinSpikeTimer = 7000; + m_uiTouchTimer = 10000; + m_uiSpecialAbilityTimer = 45000; + m_uiSummonTimer = 25000; + m_uiBerserkTimer = 8 * MINUTE * IN_MILLISECONDS; + + // always start with light twin pact + m_bIsLightTwin = true; + m_bIsVortex = false; + + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + m_uiBerserkTimer = 6 * MINUTE * IN_MILLISECONDS; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SURGE_OF_LIGHT); + + if (m_pInstance && m_pInstance->GetData(TYPE_TWIN_VALKYR) != IN_PROGRESS) + m_pInstance->SetData(TYPE_TWIN_VALKYR, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance && m_pInstance->GetData(TYPE_TWIN_VALKYR) != DONE) + m_pInstance->SetData(TYPE_TWIN_VALKYR, DONE); - ScriptedInstance* m_pInstance; + DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_ESSENCE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_TOUCH, CAST_TRIGGERED); + } + + void EnterEvadeMode() override + { + if (m_pInstance && m_pInstance->GetData(TYPE_TWIN_VALKYR) != FAIL) + m_pInstance->SetData(TYPE_TWIN_VALKYR, FAIL); - void Reset() {} + DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_ESSENCE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CLEAR_VALKYR_TOUCH, CAST_TRIGGERED); - void Aggro(Unit* pWho) + // cleanup handled by creature linking + m_creature->ForcedDespawn(); + } + + void JustSummoned(Creature* pSummoned) override { - m_creature->SetInCombatWithZone(); + if (pSummoned->GetEntry() == NPC_CONCENTRATED_LIGHT) + pSummoned->CastSpell(pSummoned, SPELL_LIGHT_BALL_PASSIVE, true); + else if (pSummoned->GetEntry() == NPC_CONCENTRATED_DARKNESS) + pSummoned->CastSpell(pSummoned, SPELL_DARK_BALL_PASSIVE, true); + } + + // function that handles the special ability for both twins + bool DoCastSpecialAbility() + { + if (!m_pInstance) + return false; + + // choose the caster; it always alternates + Unit* pCaster = NULL; + uint32 uiSpell = 0; + uint32 uiShieldSpell = 0; + + if (m_bIsLightTwin) + pCaster = m_creature; + else + { + Creature* pEydis = m_pInstance->GetSingleCreatureFromStorage(NPC_EYDIS); + if (!pEydis) + return false; + + pCaster = pEydis; + } + + if (!pCaster) + return false; + + // select and cast ability + if (m_bIsVortex) + { + uiSpell = m_bIsLightTwin ? SPELL_LIGHT_VORTEX : SPELL_DARK_VORTEX; + pCaster->CastSpell(pCaster, uiSpell, false); + DoScriptText(m_bIsLightTwin ? SAY_TO_WHITE : SAY_TO_BLACK, pCaster); + } + else + { + uiSpell = m_bIsLightTwin ? SPELL_TWINS_PACT_LIGHT : SPELL_TWINS_PACT_DARK; + uiShieldSpell = m_bIsLightTwin ? SPELL_SHIELD_OF_LIGHTS : SPELL_SHIELD_OF_DARKNESS; + pCaster->CastSpell(pCaster, uiSpell, false); + pCaster->CastSpell(pCaster, uiShieldSpell, true); + DoScriptText(SAY_COLORSWITCH, pCaster); + } + + m_bIsVortex = urand(0, 1) ? true : false; + m_bIsLightTwin = !m_bIsLightTwin; + return true; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // special ability spell + if (m_uiSpecialAbilityTimer < uiDiff) + { + if (DoCastSpecialAbility()) + m_uiSpecialAbilityTimer = 45000; + } + else + m_uiSpecialAbilityTimer -= uiDiff; + + if (m_uiSummonTimer < uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_LIGHT_BULLET_SUMMON_TRIGGER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_DARK_BULLET_SUMMON_TRIGGER, CAST_TRIGGERED); + m_uiSummonTimer = 30000; + } + else + m_uiSummonTimer -= uiDiff; + + // berserk spell + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + // handle berserk for both twins + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + if (m_pInstance) + { + if (Creature* pEydis = m_pInstance->GetSingleCreatureFromStorage(NPC_EYDIS)) + { + pEydis->CastSpell(pEydis, SPELL_BERSERK, true); + DoScriptText(SAY_BERSERK, pEydis); + } + } + + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiTwinSpikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWIN_SPIKE_LIGHT) == CAST_OK) + m_uiTwinSpikeTimer = 10000; + } + else + m_uiTwinSpikeTimer -= uiDiff; + + // heroic abilities + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiTouchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LIGHT_TOUCH) == CAST_OK) + m_uiTouchTimer = 20000; + } + else + m_uiTouchTimer -= uiDiff; + } + DoMeleeAttackIfReady(); } }; @@ -71,22 +281,68 @@ CreatureAI* GetAI_boss_fjola(Creature* pCreature) ## boss_eydis ######*/ -struct MANGOS_DLL_DECL boss_eydisAI : public ScriptedAI +struct boss_eydisAI : public ScriptedAI { - boss_eydisAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_eydisAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_crusader* m_pInstance; - void Reset() {} + uint32 m_uiTwinSpikeTimer; + uint32 m_uiTouchTimer; - void Aggro(Unit* pWho) + void Reset() override { - m_creature->SetInCombatWithZone(); + DoCastSpellIfCan(m_creature, SPELL_VALKYR_TWINS_HITTING_YA); + + m_uiTwinSpikeTimer = 7000; + m_uiTouchTimer = 10000; } - void UpdateAI(const uint32 uiDiff) + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SURGE_OF_DARKNESS); + } + + void KilledUnit(Unit* pVictim) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiTwinSpikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TWIN_SPIKE_DARK) == CAST_OK) + m_uiTwinSpikeTimer = 10000; + } + else + m_uiTwinSpikeTimer -= uiDiff; + + // heroic abilities + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiTouchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_TOUCH) == CAST_OK) + m_uiTouchTimer = 20000; + } + else + m_uiTouchTimer -= uiDiff; + } + DoMeleeAttackIfReady(); } }; @@ -96,6 +352,76 @@ CreatureAI* GetAI_boss_eydis(Creature* pCreature) return new boss_eydisAI(pCreature); } +/*###### +## npc_concentrated_bullet +######*/ + +struct npc_concentrated_bulletAI : public ScriptedAI +{ + npc_concentrated_bulletAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_trial_of_the_crusader*)pCreature->GetInstanceData(); + Reset(); + } + + instance_trial_of_the_crusader* m_pInstance; + + GuidVector m_vStalkersGuids; + + void Reset() override + { + // get the list of summoned stalkers and move to a randome one + if (m_pInstance) + m_pInstance->GetStalkersGUIDVector(m_vStalkersGuids); + + if (m_vStalkersGuids.empty()) + return; + + m_creature->SetWalk(false); + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_vStalkersGuids[urand(0, m_vStalkersGuids.size() - 1)])) + m_creature->GetMotionMaster()->MovePoint(1, pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ()); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // move to another random stalker + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_vStalkersGuids[urand(0, m_vStalkersGuids.size() - 1)])) + m_creature->GetMotionMaster()->MovePoint(1, pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ()); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_concentrated_bullet(Creature* pCreature) +{ + return new npc_concentrated_bulletAI(pCreature); +} + +/*###### +## npc_valkyr_stalker +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_valkyr_stalkerAI : public Scripted_NoMovementAI +{ + npc_valkyr_stalkerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_valkyr_stalker(Creature* pCreature) +{ + return new npc_valkyr_stalkerAI(pCreature); +} + void AddSC_twin_valkyr() { Script* pNewScript; @@ -107,6 +433,16 @@ void AddSC_twin_valkyr() pNewScript = new Script; pNewScript->Name = "boss_eydis"; - pNewScript->GetAI = &GetAI_boss_fjola; + pNewScript->GetAI = &GetAI_boss_eydis; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_concentrated_bullet"; + pNewScript->GetAI = &GetAI_npc_concentrated_bullet; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_valkyr_stalker"; + pNewScript->GetAI = &GetAI_npc_valkyr_stalker; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/instance_trial_of_the_crusader.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/instance_trial_of_the_crusader.cpp index 998a60fa1..ac0a414fd 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/instance_trial_of_the_crusader.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/instance_trial_of_the_crusader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -82,7 +82,9 @@ enum SAY_TIRION_ABUN_INTRO_1 = -1649035, SAY_LKING_ANUB_INTRO_2 = -1649036, SAY_LKING_ANUB_INTRO_3 = -1649037, - SAY_ANUB_ANUB_INTRO_1 = -1649038, // NYI + + // Epilogue + SAY_TIRION_EPILOGUE = -1649075, }; static const DialogueEntryTwoSide aTocDialogues[] = @@ -108,6 +110,8 @@ static const DialogueEntryTwoSide aTocDialogues[] = {EVENT_KILL_FIZZLEBANG, 0, 0, 0, 5000}, // Kill Fizzlebang {SAY_TIRION_JARAXXUS_INTRO_2, NPC_TIRION_A, 0, 0, 6000}, {EVENT_JARAXXUS_START_ATTACK, 0, 0, 0, 0}, + {EVENT_JARAXXUS_RESET_DELAY, 0, 0, 0, 8000}, + {EVENT_JARAXXUS_START_ATTACK, 0, 0, 0, 0}, // Jaruxxus (Outro) {SAY_JARAXXUS_DEATH, NPC_JARAXXUS, 0, 0, 6000}, // Jaraxxus Death {SAY_TIRION_JARAXXUS_EXIT_1, NPC_TIRION_A, 0, 0, 5000}, @@ -120,13 +124,15 @@ static const DialogueEntryTwoSide aTocDialogues[] = {SAY_GARROSH_PVP_A_INTRO_1, NPC_GARROSH, SAY_VARIAN_PVP_H_INTRO_1, NPC_VARIAN, 14000}, {SAY_TIRION_PVP_INTRO_2, NPC_TIRION_A, 0, 0, 1000}, {TYPE_FACTION_CHAMPIONS, 0, 0, 0, 5000}, - {SAY_GARROSH_PVP_A_INTRO_2, NPC_GARROSH, SAY_VARIAN_PVP_H_INTRO_2, NPC_VARIAN, 0}, + {SAY_GARROSH_PVP_A_INTRO_2, NPC_GARROSH, SAY_VARIAN_PVP_H_INTRO_2, NPC_VARIAN, 4000}, + {EVENT_CHAMPIONS_ATTACK, 0, 0, 0, 0}, {SAY_VARIAN_PVP_A_WIN, NPC_VARIAN, SAY_GARROSH_PVP_H_WIN, NPC_GARROSH, 4000}, {SAY_TIRION_PVP_WIN, NPC_TIRION_A, 0, 0, 27000}, {NPC_RAMSEY_4, 0, 0, 0, 0}, // Twin Valkyrs {TYPE_TWIN_VALKYR, 0, 0, 0, 17000}, - {EVENT_SUMMON_TWINS, 0, 0, 0, 0}, + {EVENT_SUMMON_TWINS, 0, 0, 0, 18000}, + {EVENT_TWINS_ATTACK, 0, 0, 0, 0}, {EVENT_TWINS_KILLED, 0, 0, 0, 2000}, {NPC_RAMSEY_5, 0, 0, 0, 4000}, {SAY_VARIAN_TWINS_A_WIN, NPC_VARIAN, SAY_GARROSH_TWINS_H_WIN, NPC_GARROSH, 1000}, @@ -140,11 +146,16 @@ static const DialogueEntryTwoSide aTocDialogues[] = {SAY_LKING_ANUB_INTRO_2, NPC_THE_LICHKING_VISUAL, 0, 0, 18500}, {EVENT_DESTROY_FLOOR, 0, 0, 0, 2500}, {SAY_LKING_ANUB_INTRO_3, NPC_THE_LICHKING, 0, 0, 0}, - {0, 0, 0, 0 ,0} + {0, 0, 0, 0 , 0} }; instance_trial_of_the_crusader::instance_trial_of_the_crusader(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aTocDialogues), - m_uiTeam(TEAM_NONE) + m_uiTeam(TEAM_NONE), + m_uiGateResetTimer(0), + m_uiKilledCrusaders(0), + m_uiCrusadersAchievTimer(0), + m_bCrusadersSummoned(false), + m_bCrusadersAchievCheck(false) { Initialize(); } @@ -178,11 +189,25 @@ void instance_trial_of_the_crusader::OnCreatureCreate(Creature* pCreature) case NPC_GARROSH: case NPC_JARAXXUS: case NPC_OPEN_PORTAL_TARGET: + case NPC_FJOLA: case NPC_EYDIS: case NPC_WORLD_TRIGGER_LARGE: case NPC_THE_LICHKING: case NPC_THE_LICHKING_VISUAL: + case NPC_BEASTS_COMBAT_STALKER: + case NPC_ACIDMAW: + case NPC_DREADSCALE: + case NPC_ZHAAGRYM: + case NPC_CAT: break; + case NPC_SNOBOLD_VASSAL: + case NPC_MISTRESS_OF_PAIN: + m_lSummonedGuidsList.push_back(pCreature->GetObjectGuid()); + return; + case NPC_VALKYR_STALKER_DARK: + case NPC_VALKYR_STALKER_LIGHT: + m_vStalkersGuidsVector.push_back(pCreature->GetObjectGuid()); + return; default: return; } @@ -202,8 +227,26 @@ void instance_trial_of_the_crusader::OnObjectCreate(GameObject* pGo) pGo->SetGoState(GO_STATE_ACTIVE); } break; + case GO_TRIBUTE_CHEST_10H_01: + case GO_TRIBUTE_CHEST_10H_25: + case GO_TRIBUTE_CHEST_10H_45: + case GO_TRIBUTE_CHEST_10H_50: + case GO_TRIBUTE_CHEST_25H_01: + case GO_TRIBUTE_CHEST_25H_25: + case GO_TRIBUTE_CHEST_25H_45: + case GO_TRIBUTE_CHEST_25H_50: case GO_MAIN_GATE: + case GO_WEB_DOOR: + case GO_WEST_GATE: + case GO_NORTH_GATE: + case GO_PORTAL_DALARAN: break; + case GO_CRUSADERS_CACHE: + case GO_CRUSADERS_CACHE_25: + case GO_CRUSADERS_CACHE_10_H: + case GO_CRUSADERS_CACHE_25_H: + m_mGoEntryGuidStore[GO_CRUSADERS_CACHE] = pGo->GetObjectGuid(); + return; default: return; } @@ -212,6 +255,13 @@ void instance_trial_of_the_crusader::OnObjectCreate(GameObject* pGo) void instance_trial_of_the_crusader::OnPlayerEnter(Player* pPlayer) { + // Show wipe world state on heroic difficulty + if (IsHeroicDifficulty()) + { + pPlayer->SendUpdateWorldState(WORLD_STATE_WIPES, 1); + pPlayer->SendUpdateWorldState(WORLD_STATE_WIPES_COUNT, MAX_WIPES_ALLOWED >= GetData(TYPE_WIPE_COUNT) ? MAX_WIPES_ALLOWED - GetData(TYPE_WIPE_COUNT) : 0); + } + if (m_uiTeam) return; @@ -219,14 +269,24 @@ void instance_trial_of_the_crusader::OnPlayerEnter(Player* pPlayer) SetDialogueSide(m_uiTeam == ALLIANCE); DoSummonRamsey(0); + DoSelectCrusaders(); +} + +void instance_trial_of_the_crusader::OnPlayerDeath(Player* /*pPlayer*/) +{ + if (IsEncounterInProgress()) + SetData(TYPE_IMMORTALITY_FAILED, DONE); } void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_WIPE_COUNT: + // Update data before updating worldstate m_auiEncounter[uiType] = uiData; + if (IsHeroicDifficulty()) + DoUpdateWorldState(WORLD_STATE_WIPES_COUNT, MAX_WIPES_ALLOWED >= GetData(TYPE_WIPE_COUNT) ? MAX_WIPES_ALLOWED - GetData(TYPE_WIPE_COUNT) : 0); break; case TYPE_NORTHREND_BEASTS: if (uiData == SPECIAL) @@ -239,15 +299,22 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) { SetData(TYPE_WIPE_COUNT, m_auiEncounter[TYPE_WIPE_COUNT] + 1); StartNextDialogueText(SAY_TIRION_BEAST_WIPE); + m_lSummonedGuidsList.clear(); } else if (uiData == DONE) StartNextDialogueText(SAY_TIRION_BEAST_SLAY); + // combat doors + if (uiData != SPECIAL) + { + DoUseDoorOrButton(GO_WEST_GATE); + DoUseDoorOrButton(GO_NORTH_GATE); + } m_auiEncounter[uiType] = uiData; break; case TYPE_JARAXXUS: if (uiData == SPECIAL) - // TODO - What happen in wipe case? - StartNextDialogueText(TYPE_JARAXXUS); + // TODO - Confirm if we are not missing something + StartNextDialogueText(m_auiEncounter[uiType] != FAIL ? TYPE_JARAXXUS : EVENT_JARAXXUS_RESET_DELAY); else if (uiData == FAIL) { SetData(TYPE_WIPE_COUNT, m_auiEncounter[TYPE_WIPE_COUNT] + 1); @@ -255,6 +322,14 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) } else if (uiData == DONE) StartNextDialogueText(SAY_JARAXXUS_DEATH); + else if (uiData == IN_PROGRESS) + m_lSummonedGuidsList.clear(); + // combat doors + if (uiData != SPECIAL) + { + DoUseDoorOrButton(GO_WEST_GATE); + DoUseDoorOrButton(GO_NORTH_GATE); + } m_auiEncounter[uiType] = uiData; break; case TYPE_FACTION_CHAMPIONS: @@ -264,9 +339,25 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) { SetData(TYPE_WIPE_COUNT, m_auiEncounter[TYPE_WIPE_COUNT] + 1); StartNextDialogueText(NPC_RAMSEY_3); + + // cleanup and reset crusaders + DoCleanupCrusaders(); + m_uiKilledCrusaders = 0; + m_uiCrusadersAchievTimer = 0; + m_bCrusadersSummoned = false; + m_bCrusadersAchievCheck = false; } else if (uiData == DONE) + { + DoRespawnGameObject(GO_CRUSADERS_CACHE, 60 * MINUTE); StartNextDialogueText(SAY_VARIAN_PVP_A_WIN); + } + // combat doors + if (uiData != SPECIAL) + { + DoUseDoorOrButton(GO_WEST_GATE); + DoUseDoorOrButton(GO_NORTH_GATE); + } m_auiEncounter[uiType] = uiData; break; case TYPE_TWIN_VALKYR: @@ -274,7 +365,7 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) { if (Creature* pTirion = GetSingleCreatureFromStorage(NPC_TIRION_A)) DoScriptText(m_auiEncounter[uiType] != FAIL ? SAY_TIRION_TWINS_INTRO : SAY_RAID_INTRO_SHORT, pTirion); - + StartNextDialogueText(TYPE_TWIN_VALKYR); } else if (uiData == FAIL) { @@ -283,6 +374,14 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) } else if (uiData == DONE) StartNextDialogueText(EVENT_TWINS_KILLED); + else if (uiData == IN_PROGRESS) + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_VALKYRS_ID); + // combat doors + if (uiData != SPECIAL) + { + DoUseDoorOrButton(GO_WEST_GATE); + DoUseDoorOrButton(GO_NORTH_GATE); + } m_auiEncounter[uiType] = uiData; break; case TYPE_ANUBARAK: @@ -290,10 +389,18 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) StartNextDialogueText(TYPE_ANUBARAK); else if (uiData == FAIL) SetData(TYPE_WIPE_COUNT, m_auiEncounter[TYPE_WIPE_COUNT] + 1); + else if (uiData == DONE) + DoHandleEventEpilogue(); + // Handle combat door + if (uiData != SPECIAL) + DoUseDoorOrButton(GO_WEB_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_IMMORTALITY_FAILED: m_auiEncounter[uiType] = uiData; break; default: - error_log("SD2: Instance Trial of The Crusader: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Trial of The Crusader: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); return; } @@ -303,7 +410,8 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6]; m_strInstData = saveStream.str(); @@ -312,7 +420,7 @@ void instance_trial_of_the_crusader::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_trial_of_the_crusader::GetData(uint32 uiType) +uint32 instance_trial_of_the_crusader::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -332,15 +440,114 @@ void instance_trial_of_the_crusader::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; - for(uint8 i = TYPE_NORTHREND_BEASTS; i < MAX_ENCOUNTER; ++i) + for (uint8 i = TYPE_NORTHREND_BEASTS; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. m_auiEncounter[i] = NOT_STARTED; OUT_LOAD_INST_DATA_COMPLETE; } +void instance_trial_of_the_crusader::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_ALLY_DEATH_KNIGHT: + case NPC_ALLY_DRUID_BALANCE: + case NPC_ALLY_DRUID_RESTO: + case NPC_ALLY_HUNTER: + case NPC_ALLY_MAGE: + case NPC_ALLY_PALADIN_HOLY: + case NPC_ALLY_PALADIN_RETRI: + case NPC_ALLY_PRIEST_DISC: + case NPC_ALLY_PRIEST_SHADOW: + case NPC_ALLY_ROGUE: + case NPC_ALLY_SHAMAN_ENHA: + case NPC_ALLY_SHAMAN_RESTO: + case NPC_ALLY_WARLOCK: + case NPC_ALLY_WARRIOR: + case NPC_HORDE_DEATH_KNIGHT: + case NPC_HORDE_DRUID_BALANCE: + case NPC_HORDE_DRUID_RESTO: + case NPC_HORDE_HUNTER: + case NPC_HORDE_MAGE: + case NPC_HORDE_PALADIN_HOLY: + case NPC_HORDE_PALADIN_RETRI: + case NPC_HORDE_PRIEST_DISC: + case NPC_HORDE_PRIEST_SHADOW: + case NPC_HORDE_ROGUE: + case NPC_HORDE_SHAMAN_ENHA: + case NPC_HORDE_SHAMAN_RESTO: + case NPC_HORDE_WARLOCK: + case NPC_HORDE_WARRIOR: + ++m_uiKilledCrusaders; + + // start the Resilience will fix! it achiev + if (!m_bCrusadersAchievCheck) + { + m_uiCrusadersAchievTimer = 60000; + m_bCrusadersAchievCheck = true; + } + + // all crusaders are killed + if (m_uiKilledCrusaders == uint32(Is25ManDifficulty() ? MAX_CRUSADERS_25MAN : MAX_CRUSADERS_10MAN)) + { + SetData(TYPE_FACTION_CHAMPIONS, DONE); + + // kill credit + pCreature->CastSpell(pCreature, SPELL_ENCOUNTER_KILL_CREDIT, true); + + // cast the resilience fix credit + if (m_uiCrusadersAchievTimer) + pCreature->CastSpell(pCreature, SPELL_RESILIENCE_FIX_CREDIT, true); + } + break; + case NPC_SNOBOLD_VASSAL: + case NPC_MISTRESS_OF_PAIN: + m_lSummonedGuidsList.remove(pCreature->GetObjectGuid()); + break;; + } +} + +bool instance_trial_of_the_crusader::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscvalue1*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_UPPER_BACK_PAIN_10_N: + case ACHIEV_CRIT_UPPER_BACK_PAIN_10_H: + return m_lSummonedGuidsList.size() >= MIN_ACHIEV_SNOBOLDS_10; + case ACHIEV_CRIT_UPPER_BACK_PAIN_25_N: + case ACHIEV_CRIT_UPPER_BACK_PAIN_25_H: + return m_lSummonedGuidsList.size() >= MIN_ACHIEV_SNOBOLDS_25; + case ACHIEV_CRIT_PAIN_SPIKE_10_N: + case ACHIEV_CRIT_PAIN_SPIKE_10_H: + case ACHIEV_CRIT_PAIN_SPIKE_25_N: + case ACHIEV_CRIT_PAIN_SPIKE_25_H: + return m_lSummonedGuidsList.size() >= MIN_ACHIEV_MISTRESSES; + case ACHIEV_CRIT_TRIBUTE_IMMORTALITY_H: + case ACHIEV_CRIT_TRIBUTE_IMMORTALITY_A: + return GetData(TYPE_IMMORTALITY_FAILED) != DONE; + case ACHIEV_CRIT_TRIBUTE_INSANITY_10: + case ACHIEV_CRIT_TRIBUTE_INSANITY_25: + return GetData(TYPE_WIPE_COUNT) == 0; + case ACHIEV_CRIT_TRIBUTE_MAD_SKILL_10_1: + case ACHIEV_CRIT_TRIBUTE_MAD_SKILL_10_2: + case ACHIEV_CRIT_TRIBUTE_MAD_SKILL_25_1: + case ACHIEV_CRIT_TRIBUTE_MAD_SKILL_25_2: + return GetData(TYPE_WIPE_COUNT) <= 5; + case ACHIEV_CRIT_TRIBUTE_SKILL_10_1: + case ACHIEV_CRIT_TRIBUTE_SKILL_10_2: + case ACHIEV_CRIT_TRIBUTE_SKILL_10_3: + case ACHIEV_CRIT_TRIBUTE_SKILL_25_1: + case ACHIEV_CRIT_TRIBUTE_SKILL_25_2: + case ACHIEV_CRIT_TRIBUTE_SKILL_25_3: + return GetData(TYPE_WIPE_COUNT) <= 25; + } + + return false; +} + void instance_trial_of_the_crusader::DoSummonRamsey(uint32 uiEntry) { Player* pPlayer = GetPlayerInMap(); @@ -364,6 +571,118 @@ void instance_trial_of_the_crusader::DoSummonRamsey(uint32 uiEntry) pPlayer->SummonCreature(uiEntry, aRamsayPositions[0][0], aRamsayPositions[0][1], aRamsayPositions[0][2], aRamsayPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0); } +void instance_trial_of_the_crusader::DoHandleEventEpilogue() +{ + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + // Spawn Tirion and the mage + if (Creature* pTirion = pPlayer->SummonCreature(NPC_TIRION_B, aSpawnPositions[12][0], aSpawnPositions[12][1], aSpawnPositions[12][2], aSpawnPositions[12][3], TEMPSUMMON_CORPSE_DESPAWN, 0)) + DoScriptText(SAY_TIRION_EPILOGUE, pTirion); + + pPlayer->SummonCreature(NPC_ARGENT_MAGE, aSpawnPositions[13][0], aSpawnPositions[13][1], aSpawnPositions[13][2], aSpawnPositions[13][3], TEMPSUMMON_CORPSE_DESPAWN, 0); + + DoRespawnGameObject(GO_PORTAL_DALARAN, 60 * MINUTE); + + // Spawn the chest for heroic difficulty + if (IsHeroicDifficulty()) + { + if (GetData(TYPE_WIPE_COUNT) == 0) + DoRespawnGameObject(Is25ManDifficulty() ? GO_TRIBUTE_CHEST_25H_50 : GO_TRIBUTE_CHEST_10H_50, 60 * MINUTE); + else if (GetData(TYPE_WIPE_COUNT) < 5) + DoRespawnGameObject(Is25ManDifficulty() ? GO_TRIBUTE_CHEST_25H_45 : GO_TRIBUTE_CHEST_10H_45, 60 * MINUTE); + else if (GetData(TYPE_WIPE_COUNT) < 25) + DoRespawnGameObject(Is25ManDifficulty() ? GO_TRIBUTE_CHEST_25H_25 : GO_TRIBUTE_CHEST_10H_25, 60 * MINUTE); + else + DoRespawnGameObject(Is25ManDifficulty() ? GO_TRIBUTE_CHEST_25H_01 : GO_TRIBUTE_CHEST_10H_01, 60 * MINUTE); + } +} + +// Function that will set all the crusaders in combat with the target +void instance_trial_of_the_crusader::DoSetCrusadersInCombat(Unit* pTarget) +{ + uint8 uiMaxCrusaders = Is25ManDifficulty() ? MAX_CRUSADERS_25MAN : MAX_CRUSADERS_10MAN; + for (uint8 i = 0; i < uiMaxCrusaders; ++i) + { + if (Creature* pCrusader = instance->GetCreature(m_vCrusadersGuidsVector[i])) + pCrusader->AI()->AttackStart(pTarget); + } + + if (Creature* pPet = GetSingleCreatureFromStorage(NPC_ZHAAGRYM, true)) + pPet->AI()->AttackStart(pTarget); + if (Creature* pPet = GetSingleCreatureFromStorage(NPC_CAT, true)) + pPet->AI()->AttackStart(pTarget); +} + +// Function that will open and close the main gate +void instance_trial_of_the_crusader::DoOpenMainGate(uint32 uiResetTimer) +{ + DoUseDoorOrButton(GO_MAIN_GATE); + m_uiGateResetTimer = uiResetTimer; +} + +// Function that will select the faction champions entries +void instance_trial_of_the_crusader::DoSelectCrusaders() +{ + std::vector vCrusaderHealers; + std::vector vCrusaderOthers; + + // add all the healers and dps crusaders to vector + for (uint8 i = 0; i < MAX_CRUSADERS_HEALERS; ++i) + vCrusaderHealers.push_back(m_uiTeam == ALLIANCE ? aHordeHealerCrusaders[i] : aAllyHealerCrusaders[i]); + for (uint8 i = 0; i < MAX_CRUSADERS_OTHER; ++i) + vCrusaderOthers.push_back(m_uiTeam == ALLIANCE ? aHordeOtherCrusaders[i] : aAllyOtherCrusaders[i]); + + // replace random healers with corresponding dps + uint8 uiIndex = urand(0, vCrusaderHealers.size() - 1); + vCrusaderOthers.push_back(m_uiTeam == ALLIANCE ? aHordeReplacementCrusaders[uiIndex] : aAllyReplacementCrusaders[uiIndex]); + vCrusaderHealers.erase(vCrusaderHealers.begin() + uiIndex); + + if (!Is25ManDifficulty()) + { + // on 10 man we replace a second healer + uiIndex = urand(0, vCrusaderHealers.size() - 1); + + uint32 uiCrusaderEntry = vCrusaderHealers[uiIndex]; + for (uint8 i = 0; i < MAX_CRUSADERS_HEALERS; ++i) + { + if (uiCrusaderEntry == (m_uiTeam == ALLIANCE ? aHordeHealerCrusaders[i] : aAllyHealerCrusaders[i])) + { + vCrusaderOthers.push_back(m_uiTeam == ALLIANCE ? aHordeReplacementCrusaders[i] : aAllyReplacementCrusaders[i]); + break; + } + } + vCrusaderHealers.erase(vCrusaderHealers.begin() + uiIndex); + + // remove 4 random dps crusaders + for (uint8 i = 0; i < MAX_CRUSADERS_HEALERS; ++i) + vCrusaderOthers.erase(vCrusaderOthers.begin() + urand(0, vCrusaderOthers.size() - 1)); + } + + // set the final list of crusaders + for (uint8 i = 0; i < vCrusaderHealers.size(); ++i) + m_vCrusadersEntries.push_back(vCrusaderHealers[i]); + for (uint8 i = 0; i < vCrusaderOthers.size(); ++i) + m_vCrusadersEntries.push_back(vCrusaderOthers[i]); +} + +// Function that will cleanup the crusaders +void instance_trial_of_the_crusader::DoCleanupCrusaders() +{ + for (GuidVector::const_iterator itr = m_vCrusadersGuidsVector.begin(); itr != m_vCrusadersGuidsVector.end(); ++itr) + { + if (Creature* pCrusader = instance->GetCreature(*itr)) + pCrusader->ForcedDespawn(); + } + + // despawn pets as well + if (Creature* pPet = GetSingleCreatureFromStorage(NPC_ZHAAGRYM, true)) + pPet->ForcedDespawn(); + if (Creature* pPet = GetSingleCreatureFromStorage(NPC_CAT, true)) + pPet->ForcedDespawn(); +} + void instance_trial_of_the_crusader::JustDidDialogueStep(int32 iEntry) { switch (iEntry) @@ -378,8 +697,20 @@ void instance_trial_of_the_crusader::JustDidDialogueStep(int32 iEntry) case SAY_VARIAN_BEAST_1: if (Player* pPlayer = GetPlayerInMap()) { - if (Creature* pBeasts = pPlayer->SummonCreature(NPC_BEAST_COMBAT_STALKER, aSpawnPositions[0][0], aSpawnPositions[0][1], aSpawnPositions[0][2], aSpawnPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0)) - pBeasts->SummonCreature(NPC_GORMOK, aSpawnPositions[1][0], aSpawnPositions[1][1], aSpawnPositions[1][2], aSpawnPositions[1][3], TEMPSUMMON_DEAD_DESPAWN, 0); + if (Creature* pBeasts = pPlayer->SummonCreature(NPC_BEASTS_COMBAT_STALKER, aSpawnPositions[0][0], aSpawnPositions[0][1], aSpawnPositions[0][2], aSpawnPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + Creature* pGormok = pBeasts->SummonCreature(NPC_GORMOK, aSpawnPositions[1][0], aSpawnPositions[1][1], aSpawnPositions[1][2], aSpawnPositions[1][3], TEMPSUMMON_DEAD_DESPAWN, 0); + if (!pGormok) + return; + + // spawn the snobolds on his back + uint8 uiMaxSnobolds = Is25ManDifficulty() ? 5 : 4; + for (uint8 i = 0; i < uiMaxSnobolds; ++i) + { + if (Creature* pSnobold = pGormok->SummonCreature(NPC_SNOBOLD_VASSAL, pGormok->GetPositionX(), pGormok->GetPositionY(), pGormok->GetPositionZ(), 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000)) + pSnobold->CastSpell(pGormok, SPELL_RIDE_VEHICLE_HARDCODED, true); + } + } } break; case NPC_FIZZLEBANG: @@ -414,15 +745,101 @@ void instance_trial_of_the_crusader::JustDidDialogueStep(int32 iEntry) break; case EVENT_JARAXXUS_START_ATTACK: if (Creature* pJaraxxus = GetSingleCreatureFromStorage(NPC_JARAXXUS)) - pJaraxxus->SetInCombatWithZone(); + { + pJaraxxus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + pJaraxxus->RemoveAurasDueToSpell(SPELL_ENSLAVE_JARAXXUS); + } break; + case SAY_TIRION_PVP_INTRO_1: + case TYPE_FACTION_CHAMPIONS: + // skip if already summoned + if (m_bCrusadersSummoned) + break; + + if (Player* pPlayer = GetPlayerInMap()) + { + // safety check + uint8 uiMaxCrusaders = Is25ManDifficulty() ? MAX_CRUSADERS_25MAN : MAX_CRUSADERS_10MAN; + if (m_vCrusadersEntries.empty() || m_vCrusadersEntries.size() < uiMaxCrusaders) + { + script_error_log("Instance Trial of The Crusader: ERROR Crusaders entries are not properly selected. Please report this to the dev team!"); + return; + } + + // summon the crusaders + m_vCrusadersGuidsVector.clear(); + float fX, fY, fZ, fO; + for (uint8 i = 0; i < uiMaxCrusaders; ++i) + { + fX = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fSourceX : aAllyCrusadersLoc[i].fSourceX; + fY = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fSourceY : aAllyCrusadersLoc[i].fSourceY; + fZ = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fSourceZ : aAllyCrusadersLoc[i].fSourceZ; + fO = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fSourceO : aAllyCrusadersLoc[i].fSourceO; + + if (Creature* pCrusader = pPlayer->SummonCreature(m_vCrusadersEntries[i], fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + m_vCrusadersGuidsVector.push_back(pCrusader->GetObjectGuid()); + } + + m_bCrusadersSummoned = true; + } + break; + case SAY_GARROSH_PVP_A_INTRO_2: + { + // make the champions jump + uint8 uiMaxCrusaders = Is25ManDifficulty() ? MAX_CRUSADERS_25MAN : MAX_CRUSADERS_10MAN; + + float fX, fY, fZ; + for (uint8 i = 0; i < uiMaxCrusaders; ++i) + { + fX = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fTargetX : aAllyCrusadersLoc[i].fTargetX; + fY = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fTargetY : aAllyCrusadersLoc[i].fTargetY; + fZ = m_uiTeam == ALLIANCE ? aHordeCrusadersLoc[i].fTargetZ : aAllyCrusadersLoc[i].fTargetZ; + + // ToDo: use spell 67382 when proper implemented in the core + if (Creature* pCrusader = instance->GetCreature(m_vCrusadersGuidsVector[i])) + pCrusader->GetMotionMaster()->MoveJump(fX, fY, fZ, pCrusader->GetDistance2d(fX, fY) * 10.0f / 15.0f, 15.0f); + } + break; + } + case EVENT_CHAMPIONS_ATTACK: + { + // prepare champions combat + uint8 uiMaxCrusaders = Is25ManDifficulty() ? MAX_CRUSADERS_25MAN : MAX_CRUSADERS_10MAN; + for (uint8 i = 0; i < uiMaxCrusaders; ++i) + { + if (Creature* pCrusader = instance->GetCreature(m_vCrusadersGuidsVector[i])) + { + pCrusader->CastSpell(pCrusader, SPELL_ANCHOR_HERE, true); + pCrusader->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + + // some crusaders have to summon their pet + pCrusader->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCrusader, pCrusader); + } + } + break; + } case EVENT_SUMMON_TWINS: if (Player* pPlayer = GetPlayerInMap()) { + // spawn the twin valkyrs; movement and the rest of spawns are handled in DB + DoOpenMainGate(15000); + pPlayer->SummonCreature(NPC_FJOLA, aSpawnPositions[7][0], aSpawnPositions[7][1], aSpawnPositions[7][2], aSpawnPositions[7][3], TEMPSUMMON_DEAD_DESPAWN, 0); pPlayer->SummonCreature(NPC_EYDIS, aSpawnPositions[8][0], aSpawnPositions[8][1], aSpawnPositions[8][2], aSpawnPositions[8][3], TEMPSUMMON_DEAD_DESPAWN, 0); } break; + case EVENT_TWINS_ATTACK: + if (Creature* pTwin = GetSingleCreatureFromStorage(NPC_FJOLA)) + { + pTwin->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + pTwin->CastSpell(pTwin, SPELL_TWIN_EMPATHY_LIGHT, true); + } + if (Creature* pTwin = GetSingleCreatureFromStorage(NPC_EYDIS)) + { + pTwin->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + pTwin->CastSpell(pTwin, SPELL_TWIN_EMPATHY_DARK, true); + } + break; case SAY_LKING_ANUB_INTRO_1: if (Player* pPlayer = GetPlayerInMap()) pPlayer->SummonCreature(NPC_WORLD_TRIGGER_LARGE, aSpawnPositions[9][0], aSpawnPositions[9][1], aSpawnPositions[9][2], aSpawnPositions[9][3], TEMPSUMMON_DEAD_DESPAWN, 0); @@ -446,7 +863,7 @@ void instance_trial_of_the_crusader::JustDidDialogueStep(int32 iEntry) if (Creature* pLichKingVisual = GetSingleCreatureFromStorage(NPC_THE_LICHKING_VISUAL)) { pLichKingVisual->CastSpell(pLichKingVisual, SPELL_FROSTNOVA, true); - //pLichKingVisual->CastSpell(pLichKingVisual, SPELL_CORPSE_TELEPORT, true); // NYI + // pLichKingVisual->CastSpell(pLichKingVisual, SPELL_CORPSE_TELEPORT, true); // NYI pLichKingVisual->ForcedDespawn(); } @@ -459,6 +876,31 @@ void instance_trial_of_the_crusader::JustDidDialogueStep(int32 iEntry) } } +void instance_trial_of_the_crusader::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (m_uiCrusadersAchievTimer) + { + if (m_uiCrusadersAchievTimer <= uiDiff) + m_uiCrusadersAchievTimer = 0; + else + m_uiCrusadersAchievTimer -= uiDiff; + } + + // ToDo: set this as door reset timer when fixed in core + if (m_uiGateResetTimer) + { + if (m_uiGateResetTimer <= uiDiff) + { + DoUseDoorOrButton(GO_MAIN_GATE); + m_uiGateResetTimer = 0; + } + else + m_uiGateResetTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_trial_of_the_crusader(Map* pMap) { return new instance_trial_of_the_crusader(pMap); diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.cpp b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.cpp index d0c2e1ff3..c168c1b7b 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.cpp +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -52,22 +52,22 @@ enum GOSSIP_ITEM_BEAST_INIT = -3649000, GOSSIP_ITEM_BEAST_START = -3649001, GOSSIP_ITEM_BEAST_WIPE_INIT = -3649002, - GOSSIP_ITEM_BEAST_WIPE_START = -3000000, + GOSSIP_ITEM_BEAST_WIPE_START = -3649014, GOSSIP_ITEM_JARAXXUS_INIT = -3649003, - GOSSIP_ITEM_JARAXXUS_START = -3000000, + GOSSIP_ITEM_JARAXXUS_START = -3649011, GOSSIP_ITEM_JARAXXUS_WIPE_INIT = -3649004, - GOSSIP_ITEM_JARAXXUS_WIPE_START = -3000000, + GOSSIP_ITEM_JARAXXUS_WIPE_START = -3649015, GOSSIP_ITEM_PVP_INIT = -3649005, GOSSIP_ITEM_PVP_START = -3649006, - GOSSIP_ITEM_PVP_WIPE_INIT = -3000000, - GOSSIP_ITEM_PVP_WIPE_START = -3000000, + GOSSIP_ITEM_PVP_WIPE_INIT = -3649012, + GOSSIP_ITEM_PVP_WIPE_START = -3649013, GOSSIP_ITEM_TWINS_INIT = -3649007, GOSSIP_ITEM_TWINS_START = -3649008, - GOSSIP_ITEM_TWINS_WIPE_INIT = -3000000, - GOSSIP_ITEM_TWINS_WIPE_START = -3000000, + GOSSIP_ITEM_TWINS_WIPE_INIT = -3649016, + GOSSIP_ITEM_TWINS_WIPE_START = -3649017, GOSSIP_ITEM_ANUB_INIT = -3649009, GOSSIP_ITEM_ANUB_START = -3649010, @@ -105,15 +105,15 @@ static const RamseyInfo aRamseyInfo[] = {NPC_RAMSEY_5, GOSSIP_TEXT_ANUB_START, GOSSIP_ITEM_ANUB_START, 0, 0, TYPE_ANUBARAK}, }; -struct MANGOS_DLL_DECL npc_barrett_ramseyAI : public ScriptedAI +struct npc_barrett_ramseyAI : public ScriptedAI { npc_barrett_ramseyAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} ScriptedInstance* m_pInstance; - void Reset() {} + void Reset() override {} - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType == POINT_MOTION_TYPE && uiPointId == 1) m_creature->ForcedDespawn(); @@ -157,7 +157,7 @@ bool GossipHello_npc_barrett_ramsey(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_barrett_ramsey(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_barrett_ramsey(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); if (!pInstance) diff --git a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.h b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.h index 9c8165d4a..7cb06bc73 100644 --- a/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.h +++ b/scripts/northrend/crusaders_coliseum/trial_of_the_crusader/trial_of_the_crusader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,7 +7,16 @@ enum { - MAX_ENCOUNTER = 6, + MAX_ENCOUNTER = 7, + MAX_WIPES_ALLOWED = 50, + MAX_CRUSADERS_10MAN = 6, + MAX_CRUSADERS_25MAN = 10, + MAX_CRUSADERS_HEALERS = 4, + MAX_CRUSADERS_OTHER = 6, + + MIN_ACHIEV_MISTRESSES = 2, + MIN_ACHIEV_SNOBOLDS_10 = 2, + MIN_ACHIEV_SNOBOLDS_25 = 4, TYPE_WIPE_COUNT = 0, TYPE_NORTHREND_BEASTS = 1, @@ -15,6 +24,7 @@ enum TYPE_FACTION_CHAMPIONS = 3, TYPE_TWIN_VALKYR = 4, TYPE_ANUBARAK = 5, + TYPE_IMMORTALITY_FAILED = 6, // Achievements A Tribute to Immortality, needs to be saved to database EVENT_OPEN_PORTAL = 6, EVENT_KILL_FIZZLEBANG = 7, @@ -24,8 +34,17 @@ enum EVENT_ARTHAS_PORTAL = 11, EVENT_SUMMON_THE_LICHKING = 12, EVENT_DESTROY_FLOOR = 13, + EVENT_JARAXXUS_RESET_DELAY = 14, + EVENT_CHAMPIONS_ATTACK = 15, + EVENT_TWINS_ATTACK = 16, + + NPC_BEASTS_COMBAT_STALKER = 36549, + NPC_BEASTS_CONTROLLER = 35014, + NPC_CHAMPIONS_CONTROLLER = 34781, + NPC_VALKYR_TWINS_CONTROLLER = 34743, + NPC_VALKYR_STALKER_DARK = 34704, // summons 34628 using 66107 + NPC_VALKYR_STALKER_LIGHT = 34720, // summons 34630 using 66078 - NPC_BEAST_COMBAT_STALKER = 36549, NPC_GORMOK = 34796, NPC_ACIDMAW = 35144, NPC_DREADSCALE = 34799, @@ -35,8 +54,52 @@ enum NPC_EYDIS = 34496, NPC_ANUBARAK = 34564, + NPC_SNOBOLD_VASSAL = 34800, // used in Gormok encounter + NPC_MISTRESS_OF_PAIN = 34826, // used in Jaraxxus encounter + // NPC_JUMP_TARGET = 35376, // used to mark the jump spot for the crusaders; currently not used + // NPC_DARK_ESSENCE = 34567, // npc spell click for spell 65684 + // NPC_LIGHT_ESSENCE = 34568, // npc spell click for spell 65686 + + // NPC_BEASTS_TAPLIST = 35820, + // NPC_CHAMPION_TAPLIST = 35821, + // NPC_ANUBARAK_TAPLIST = 36099, + + NPC_ALLY_DEATH_KNIGHT = 34461, // Tyrius Duskblade + NPC_ALLY_DRUID_BALANCE = 34460, // Kavina Grovesong + NPC_ALLY_DRUID_RESTO = 34469, // Melador Valestrider + NPC_ALLY_HUNTER = 34467, // Alyssia Moonstalker + NPC_ALLY_MAGE = 34468, // Noozle Whizzlestick + NPC_ALLY_PALADIN_HOLY = 34465, // Velanaa + NPC_ALLY_PALADIN_RETRI = 34471, // Baelnor Lightbearer + NPC_ALLY_PRIEST_DISC = 34466, // Anthar Forgemender + NPC_ALLY_PRIEST_SHADOW = 34473, // Brienna Nightfell + NPC_ALLY_ROGUE = 34472, // Irieth Shadowstep + NPC_ALLY_SHAMAN_ENHA = 34463, // Shaabad + NPC_ALLY_SHAMAN_RESTO = 34470, // Saamul + NPC_ALLY_WARLOCK = 34474, // Serissa Grimdabbler + NPC_ALLY_WARRIOR = 34475, // Shocuul + + NPC_HORDE_DEATH_KNIGHT = 34458, // Gorgrim Shadowcleave + NPC_HORDE_DRUID_BALANCE = 34451, // Birana Stormhoof + NPC_HORDE_DRUID_RESTO = 34459, // Erin Misthoof + NPC_HORDE_HUNTER = 34448, // Ruj'kah + NPC_HORDE_MAGE = 34449, // Ginselle Blightslinger + NPC_HORDE_PALADIN_HOLY = 34445, // Liandra Suncaller + NPC_HORDE_PALADIN_RETRI = 34456, // Malithas Brightblade + NPC_HORDE_PRIEST_DISC = 34447, // Caiphus the Stern + NPC_HORDE_PRIEST_SHADOW = 34441, // Vivienne Blackwhisper + NPC_HORDE_ROGUE = 34454, // Maz'dinah + NPC_HORDE_SHAMAN_ENHA = 34455, // Broln Stouthorn + NPC_HORDE_SHAMAN_RESTO = 34444, // Thrakgar + NPC_HORDE_WARLOCK = 34450, // Harkzog + NPC_HORDE_WARRIOR = 34453, // Narrhok Steelbreaker + + NPC_ZHAAGRYM = 35465, + NPC_CAT = 35610, + NPC_TIRION_A = 34996, NPC_TIRION_B = 36095, // Summoned after his text (Champions, you're alive! Not only have you defeated every challenge of the Trial of the Crusader, but also thwarted Arthas' plans! Your skill and cunning will prove to be a powerful weapon against the Scourge. Well done! Allow one of the Crusade's mages to transport you to the surface!) is said.. + NPC_ARGENT_MAGE = 36097, // Summoned along with Tirion B NPC_VARIAN = 34990, NPC_GARROSH = 34995, NPC_FIZZLEBANG = 35458, @@ -56,11 +119,38 @@ enum NPC_PURPLE_RUNE = 35651, GO_MAIN_GATE = 195647, + GO_WEST_GATE = 195648, // entrance gate + // GO_SOUTH_GATE = 195649, // not used + GO_NORTH_GATE = 195650, // dummy entrance; used in Trial of the Champion GO_COLISEUM_FLOOR = 195527, + GO_WEB_DOOR = 195485, + GO_PORTAL_DALARAN = 195682, + + GO_CRUSADERS_CACHE = 195631, + GO_CRUSADERS_CACHE_25 = 195632, + GO_CRUSADERS_CACHE_10_H = 195633, + GO_CRUSADERS_CACHE_25_H = 195635, + + GO_TRIBUTE_CHEST_10H_01 = 195665, + GO_TRIBUTE_CHEST_10H_25 = 195666, + GO_TRIBUTE_CHEST_10H_45 = 195667, + GO_TRIBUTE_CHEST_10H_50 = 195668, + + GO_TRIBUTE_CHEST_25H_01 = 195669, + GO_TRIBUTE_CHEST_25H_25 = 195670, + GO_TRIBUTE_CHEST_25H_45 = 195671, + GO_TRIBUTE_CHEST_25H_50 = 195672, SPELL_OPEN_PORTAL = 67864, SPELL_FEL_LIGHTNING_KILL = 67888, SPELL_WILFRED_PORTAL = 68424, + SPELL_ENSLAVE_JARAXXUS = 67924, // dummy aura that will hold the boss after evade + // SPELL_LEAP = 67382, // crusader jump inside the arena to the provided coords + SPELL_ANCHOR_HERE = 45313, // change respawn coords to the current position + SPELL_ENCOUNTER_KILL_CREDIT = 68184, // kill credit for faction champions + SPELL_RESILIENCE_FIX_CREDIT = 68620, // server side spell for achievs 3798, 3814 + SPELL_TWIN_EMPATHY_LIGHT = 66132, // damage share aura; targets dark twin (Eydis) + SPELL_TWIN_EMPATHY_DARK = 66133, // damage share aura; targets light twin (Fjola) SPELL_ARTHAS_PORTAL = 51807, SPELL_FROSTNOVA = 68198, SPELL_CORPSE_TELEPORT = 69016, // NYI @@ -68,6 +158,89 @@ enum DISPLAYID_DESTROYED_FLOOR = 9060, POINT_COMBAT_POSITION = 10, + + WORLD_STATE_WIPES = 4390, + WORLD_STATE_WIPES_COUNT = 4389, + + ACHIEV_START_VALKYRS_ID = 21853, // Twin Valkyers achievs 3799, 3815 + ACHIEV_START_ANUBARAK_10_ID = 68186, // Anub timed achievs 3800, 3816 + ACHIEV_START_ANUBARAK_25_ID = 68515, + + ACHIEV_CRIT_UPPER_BACK_PAIN_10_N = 11779, // Icehowl achievs 3797, 3813 + ACHIEV_CRIT_UPPER_BACK_PAIN_10_H = 11802, + ACHIEV_CRIT_UPPER_BACK_PAIN_25_N = 11780, + ACHIEV_CRIT_UPPER_BACK_PAIN_25_H = 11801, + ACHIEV_CRIT_PAIN_SPIKE_10_N = 11838, // Jaraxxus achievs 3996, 3997 + ACHIEV_CRIT_PAIN_SPIKE_10_H = 11861, + ACHIEV_CRIT_PAIN_SPIKE_25_N = 11839, + ACHIEV_CRIT_PAIN_SPIKE_25_H = 11862, + // ACHIEV_CRIT_RESILIENCE_FIX_10_N = 11803, // Faction Champions achievs 3798, 3814 + // ACHIEV_CRIT_RESILIENCE_FIX_10_H = 11804, + // ACHIEV_CRIT_RESILIENCE_FIX_25_N = 11799, + // ACHIEV_CRIT_RESILIENCE_FIX_25_H = 11800, + // ACHIEV_CRIT_TWO_JORMUNGARS_10_N = 12280, // Twin Jormungars achievs 3936, 3937 + // ACHIEV_CRIT_TWO_JORMUNGARS_10_H = 12281, + // ACHIEV_CRIT_TWO_JORMUNGARS_25_N = 12278, + // ACHIEV_CRIT_TWO_JORMUNGARS_25_H = 12279, + + ACHIEV_CRIT_TRIBUTE_SKILL_10_1 = 12344, // Tribute chest achievs 3808, 3817 + ACHIEV_CRIT_TRIBUTE_SKILL_10_2 = 12345, + ACHIEV_CRIT_TRIBUTE_SKILL_10_3 = 12346, + ACHIEV_CRIT_TRIBUTE_SKILL_25_1 = 12338, + ACHIEV_CRIT_TRIBUTE_SKILL_25_2 = 12339, + ACHIEV_CRIT_TRIBUTE_SKILL_25_3 = 12340, + ACHIEV_CRIT_TRIBUTE_MAD_SKILL_10_1 = 12347, // Tribute chest achievs 3809, 3818 + ACHIEV_CRIT_TRIBUTE_MAD_SKILL_10_2 = 12348, + ACHIEV_CRIT_TRIBUTE_MAD_SKILL_25_1 = 12341, + ACHIEV_CRIT_TRIBUTE_MAD_SKILL_25_2 = 12342, + ACHIEV_CRIT_TRIBUTE_INSANITY_10 = 12349, // Tribute chest achievs 3810, 3819 + ACHIEV_CRIT_TRIBUTE_INSANITY_25 = 12343, + ACHIEV_CRIT_TRUBUTE_INSANITY_D = 12360, // Tribute chest achiev 4080 + ACHIEV_CRIT_TRIBUTE_IMMORTALITY_H = 12358, // Overall 25 heroic achievs 4079, 4156 + ACHIEV_CRIT_TRIBUTE_IMMORTALITY_A = 12359, + // ToDo: missing achiev criterias for the rest of the achievs? + +}; + +static const uint32 aAllyHealerCrusaders[MAX_CRUSADERS_HEALERS] = { NPC_ALLY_DRUID_RESTO, NPC_ALLY_PALADIN_HOLY, NPC_ALLY_PRIEST_DISC, NPC_ALLY_SHAMAN_RESTO }; +static const uint32 aAllyReplacementCrusaders[MAX_CRUSADERS_HEALERS] = { NPC_ALLY_DRUID_BALANCE, NPC_ALLY_PALADIN_RETRI, NPC_ALLY_PRIEST_SHADOW, NPC_ALLY_SHAMAN_ENHA }; +static const uint32 aAllyOtherCrusaders[MAX_CRUSADERS_OTHER] = { NPC_ALLY_DEATH_KNIGHT, NPC_ALLY_HUNTER, NPC_ALLY_MAGE, NPC_ALLY_ROGUE, NPC_ALLY_WARLOCK, NPC_ALLY_WARRIOR }; + +static const uint32 aHordeHealerCrusaders[MAX_CRUSADERS_HEALERS] = { NPC_HORDE_DRUID_RESTO, NPC_HORDE_PALADIN_HOLY, NPC_HORDE_PRIEST_DISC, NPC_HORDE_SHAMAN_RESTO }; +static const uint32 aHordeReplacementCrusaders[MAX_CRUSADERS_HEALERS] = { NPC_HORDE_DRUID_BALANCE, NPC_HORDE_PALADIN_RETRI, NPC_HORDE_PRIEST_SHADOW, NPC_HORDE_SHAMAN_ENHA }; +static const uint32 aHordeOtherCrusaders[MAX_CRUSADERS_OTHER] = { NPC_HORDE_DEATH_KNIGHT, NPC_HORDE_HUNTER, NPC_HORDE_MAGE, NPC_HORDE_ROGUE, NPC_HORDE_WARLOCK, NPC_HORDE_WARRIOR }; + +struct CrusadersLocation +{ + float fSourceX, fSourceY, fSourceZ, fSourceO, fTargetX, fTargetY, fTargetZ; +}; + +static const CrusadersLocation aAllyCrusadersLoc[MAX_CRUSADERS_25MAN] = +{ + {615.649f, 108.371f, 418.317f, 2.617f, 597.998f, 130.116f, 394.729f}, + {622.361f, 111.691f, 419.785f, 2.705f, 596.189f, 123.862f, 394.710f}, + {619.104f, 101.331f, 421.621f, 2.548f, 594.369f, 118.033f, 394.677f}, + {618.138f, 105.381f, 419.786f, 2.600f, 605.423f, 128.229f, 395.288f}, + {622.956f, 107.000f, 421.619f, 2.652f, 603.840f, 122.100f, 394.832f}, + {621.258f, 117.725f, 418.317f, 2.972f, 601.717f, 115.576f, 395.287f}, + {628.161f, 117.369f, 421.607f, 2.809f, 599.921f, 135.934f, 394.742f}, + {629.005f, 124.168f, 421.627f, 2.914f, 592.413f, 112.477f, 394.684f}, + {622.175f, 123.810f, 418.315f, 2.879f, 607.020f, 134.541f, 394.836f}, + {615.322f, 95.750f, 421.623f, 2.460f, 599.461f, 109.588f, 395.288f}, +}; + +static const CrusadersLocation aHordeCrusadersLoc[MAX_CRUSADERS_25MAN] = +{ + {510.069f, 111.784f, 418.317f, 0.488f, 528.958f, 131.470f, 394.729f}, + {510.208f, 103.791f, 419.787f, 0.593f, 531.399f, 125.630f, 394.708f}, + {505.691f, 124.593f, 418.315f, 0.279f, 533.647f, 119.147f, 394.646f}, + {501.770f, 121.961f, 419.778f, 0.296f, 521.901f, 128.487f, 394.832f}, + {508.244f, 98.039f, 421.546f, 0.645f, 524.237f, 122.411f, 394.819f}, + {497.338f, 124.774f, 421.595f, 0.244f, 526.309f, 116.666f, 394.833f}, + {500.499f, 113.415f, 421.552f, 0.304f, 529.479f, 112.130f, 394.742f}, // the last 4 are guesswork, but they are pretty close + {504.869f, 112.231f, 419.710f, 0.426f, 536.588f, 114.176f, 394.533f}, + {515.173f, 102.482f, 418.234f, 0.670f, 520.921f, 134.698f, 394.747f}, + {513.624f, 98.620f, 419.703f, 0.642f, 527.289f, 136.818f, 394.654f}, }; static const float aRamsayPositions[2][4] = @@ -90,6 +263,8 @@ static const float aSpawnPositions[][4] = {563.6996f, 175.9826f, 394.5042f, 4.694936f}, // World Trigger Large {563.5712f, 174.8351f, 394.4954f, 4.712389f}, // Lich King {563.6858f, 139.4323f, 393.9862f, 4.694936f}, // Purple Rune / Center Position + {648.9169f, 131.0209f, 141.6159f, 0.0f}, // Tirion B + {649.1610f, 142.0399f, 141.3060f, 0.0f}, // Argent mage }; static const float aMovePositions[][3] = @@ -100,35 +275,67 @@ static const float aMovePositions[][3] = {563.7223f, 131.2344f, 393.9901f}, // Jaraxxus }; -class MANGOS_DLL_DECL instance_trial_of_the_crusader : public ScriptedInstance, private DialogueHelper +class instance_trial_of_the_crusader : public ScriptedInstance, private DialogueHelper { public: instance_trial_of_the_crusader(Map* pMap); - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureDeath(Creature* pCreature) override; - void OnPlayerEnter(Player* pPlayer); + void OnPlayerEnter(Player* pPlayer) override; + void OnPlayerDeath(Player* pPlayer) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + // Difficulty wrappers + bool IsHeroicDifficulty() { return instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; } + bool Is25ManDifficulty() { return instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; } - void Update(uint32 uiDiff) { DialogueUpdate(uiDiff); } + uint32 GetPlayerTeam() { return m_uiTeam; } + void GetStalkersGUIDVector(GuidVector& vVector) { vVector = m_vStalkersGuidsVector; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget = NULL, uint32 uiMiscvalue1 = 0) const override; + + void DoSetCrusadersInCombat(Unit* pTarget); + void DoOpenMainGate(uint32 uiResetTimer); + + void Update(uint32 uiDiff) override; private: void DoSummonRamsey(uint32 uiEntry); - void JustDidDialogueStep(int32 iEntry); + void JustDidDialogueStep(int32 iEntry) override; + void DoHandleEventEpilogue(); + + void DoSelectCrusaders(); + void DoCleanupCrusaders(); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + std::vector m_vCrusadersEntries; + + GuidVector m_vCrusadersGuidsVector; + GuidVector m_vStalkersGuidsVector; + GuidList m_lSummonedGuidsList; + Team m_uiTeam; + + uint32 m_uiGateResetTimer; + uint32 m_uiKilledCrusaders; + uint32 m_uiCrusadersAchievTimer; + + bool m_bCrusadersSummoned; + bool m_bCrusadersAchievCheck; }; #endif diff --git a/scripts/northrend/dalaran.cpp b/scripts/northrend/dalaran.cpp index 1eb3e31d5..b9f72b2c1 100644 --- a/scripts/northrend/dalaran.cpp +++ b/scripts/northrend/dalaran.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,24 +29,35 @@ EndContentData */ enum { - SPELL_TRESPASSER_H = 54029, - SPELL_TRESPASSER_A = 54028, + SPELL_TRESPASSER_H = 54029, + SPELL_TRESPASSER_A = 54028, - AREA_ID_SUNREAVER = 4616, - AREA_ID_SILVER_ENCLAVE = 4740 + // Exception auras - used for quests 20439 and 24451 + SPELL_COVENANT_DISGUISE_1 = 70971, + SPELL_COVENANT_DISGUISE_2 = 70972, + SPELL_SUNREAVER_DISGUISE_1 = 70973, + SPELL_SUNREAVER_DISGUISE_2 = 70974, + + AREA_ID_SUNREAVER = 4616, + AREA_ID_SILVER_ENCLAVE = 4740 }; -struct MANGOS_DLL_DECL npc_dalaran_guardian_mageAI : public ScriptedAI +struct npc_dalaran_guardian_mageAI : public ScriptedAI { npc_dalaran_guardian_mageAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) return; if (pWho->isTargetableForAttack() && m_creature->IsHostileTo(pWho)) { + // exception for quests 20439 and 24451 + if (pWho->HasAura(SPELL_COVENANT_DISGUISE_1) || pWho->HasAura(SPELL_COVENANT_DISGUISE_2) || + pWho->HasAura(SPELL_SUNREAVER_DISGUISE_1) || pWho->HasAura(SPELL_SUNREAVER_DISGUISE_2)) + return; + if (m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho)) { if (Player* pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself()) @@ -62,11 +73,11 @@ struct MANGOS_DLL_DECL npc_dalaran_guardian_mageAI : public ScriptedAI } } - void AttackedBy(Unit* /*pAttacker*/) {} + void AttackedBy(Unit* /*pAttacker*/) override {} - void Reset() {} + void Reset() override {} - void UpdateAI(const uint32 /*uiDiff*/) {} + void UpdateAI(const uint32 /*uiDiff*/) override {} }; CreatureAI* GetAI_npc_dalaran_guardian_mage(Creature* pCreature) diff --git a/scripts/northrend/dragonblight.cpp b/scripts/northrend/dragonblight.cpp index a745f6776..4d75f0054 100644 --- a/scripts/northrend/dragonblight.cpp +++ b/scripts/northrend/dragonblight.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,60 +17,18 @@ /* ScriptData SDName: Dragonblight SD%Complete: 100 -SDComment: Quest support: 12166, 12261. Taxi paths Wyrmrest temple. +SDComment: Quest support: 12075, 12166, 12261. SDCategory: Dragonblight EndScriptData */ /* ContentData -npc_afrasastrasz npc_destructive_ward -npc_tariolstrasz -npc_torastrasza +npc_crystalline_ice_giant EndContentData */ #include "precompiled.h" /*###### -## npc_afrasastrasz -######*/ - -enum -{ - TAXI_PATH_ID_MIDDLE_DOWN = 882, - TAXI_PATH_ID_MIDDLE_TOP = 881 -}; - -#define GOSSIP_ITEM_TAXI_MIDDLE_DOWN "I would like to take a flight to the ground, Lord Of Afrasastrasz." -#define GOSSIP_ITEM_TAXI_MIDDLE_TOP "My Lord, I must go to the upper floor of the temple." - -bool GossipHello_npc_afrasastrasz(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TAXI_MIDDLE_DOWN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TAXI_MIDDLE_TOP, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_afrasastrasz(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_MIDDLE_DOWN); - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_MIDDLE_TOP); - } - return true; -} - -/*##### # npc_destructive_ward #####*/ @@ -98,7 +56,7 @@ enum // Probably caused by either a change in a patch (bugfix?) or the powerup has a condition (some // sources suggest this, but without any explanation about what this might be) -struct MANGOS_DLL_DECL npc_destructive_wardAI : public Scripted_NoMovementAI +struct npc_destructive_wardAI : public Scripted_NoMovementAI { npc_destructive_wardAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -116,14 +74,14 @@ struct MANGOS_DLL_DECL npc_destructive_wardAI : public Scripted_NoMovementAI bool m_bFirst; bool m_bCanPulse; - void Reset() { } + void Reset() override { } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bCanPulse) { @@ -140,7 +98,7 @@ struct MANGOS_DLL_DECL npc_destructive_wardAI : public Scripted_NoMovementAI else m_uiSummonTimer = 0; - switch(m_uiStack) + switch (m_uiStack) { case 0: DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOLDERING_SKELETON, CAST_TRIGGERED); @@ -208,84 +166,30 @@ CreatureAI* GetAI_npc_destructive_ward(Creature* pCreature) } /*###### -## npc_tariolstrasz +## npc_crystalline_ice_giant ######*/ enum { - QUEST_INFORM_QUEEN_A = 12123, //need to check if quests are required before gossip available - QUEST_INFORM_QUEEN_H = 12124, - TAXI_PATH_ID_BOTTOM_TOP = 878, - TAXI_PATH_ID_BOTTOM_MIDDLE = 883 + SPELL_FEIGN_DEATH_PERMANENT = 31261, + ITEM_ID_SAMPLE_ROCKFLESH = 36765, + NPC_CRYSTALLINE_GIANT = 26809, }; -#define GOSSIP_ITEM_TAXI_BOTTOM_TOP "My Lord, I must go to the upper floor of the temple." -#define GOSSIP_ITEM_TAXI_BOTTOM_MIDDLE "Can you spare a drake to travel to Lord Of Afrasastrasz, in the middle of the temple?" - -bool GossipHello_npc_tariolstrasz(Player* pPlayer, Creature* pCreature) +bool NpcSpellClick_npc_crystalline_ice_giant(Player* pPlayer, Creature* pClickedCreature, uint32 /*uiSpellId*/) { - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TAXI_BOTTOM_TOP, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TAXI_BOTTOM_MIDDLE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_tariolstrasz(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_BOTTOM_TOP); - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (pClickedCreature->GetEntry() == NPC_CRYSTALLINE_GIANT && pClickedCreature->HasAura(SPELL_FEIGN_DEATH_PERMANENT)) { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_BOTTOM_MIDDLE); - } - return true; -} - -/*###### -## npc_torastrasza -######*/ - -enum -{ - TAXI_PATH_ID_TOP_MIDDLE = 880, - TAXI_PATH_ID_TOP_BOTTOM = 879 -}; - -#define GOSSIP_ITEM_TAXI_TOP_MIDDLE "I would like to see Lord Of Afrasastrasz, in the middle of the temple." -#define GOSSIP_ITEM_TAXI_TOP_BOTTOM "Yes, Please. I would like to return to the ground floor of the temple." - -bool GossipHello_npc_torastrasza(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TAXI_TOP_MIDDLE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TAXI_TOP_BOTTOM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} + if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_ID_SAMPLE_ROCKFLESH, 1)) + { + pPlayer->SendNewItem(pItem, 1, true, false); + pClickedCreature->ForcedDespawn(); -bool GossipSelect_npc_torastrasza(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_TOP_MIDDLE); - } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID_TOP_BOTTOM); + // always return true when handled special npc spell click + return true; + } } + return true; } @@ -293,26 +197,13 @@ void AddSC_dragonblight() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_afrasastrasz"; - pNewScript->pGossipHello = &GossipHello_npc_afrasastrasz; - pNewScript->pGossipSelect = &GossipSelect_npc_afrasastrasz; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_destructive_ward"; pNewScript->GetAI = &GetAI_npc_destructive_ward; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_tariolstrasz"; - pNewScript->pGossipHello = &GossipHello_npc_tariolstrasz; - pNewScript->pGossipSelect = &GossipSelect_npc_tariolstrasz; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_torastrasza"; - pNewScript->pGossipHello = &GossipHello_npc_torastrasza; - pNewScript->pGossipSelect = &GossipSelect_npc_torastrasza; + pNewScript->Name = "npc_crystalline_ice_giant"; + pNewScript->pNpcSpellClick = &NpcSpellClick_npc_crystalline_ice_giant; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/draktharon_keep/boss_novos.cpp b/scripts/northrend/draktharon_keep/boss_novos.cpp index 1975cf7e1..6f026118d 100644 --- a/scripts/northrend/draktharon_keep/boss_novos.cpp +++ b/scripts/northrend/draktharon_keep/boss_novos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Novos -SD%Complete: 80% -SDComment: Summon Timers are vague, many visual spells fail (LoS) +SD%Complete: 90% +SDComment: Summon Timers are vague SDCategory: Drak'Tharon Keep EndScriptData */ @@ -65,8 +65,8 @@ enum // The Crystal Handlers are summoned around the two entrances of the room static const float aHandlerSummonPos[2][3] = { - {-342.894836f, -727.016846f, 28.581081f}, - {-410.644653f, -731.826904f, 28.580412f} + { -342.894836f, -727.016846f, 28.581081f}, + { -410.644653f, -731.826904f, 28.580412f} }; /*###### @@ -80,7 +80,7 @@ enum Phases PHASE_NORMAL = 2, }; -struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI +struct boss_novosAI : public Scripted_NoMovementAI { boss_novosAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -105,7 +105,7 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI uint8 m_uiLostCrystals; Phases m_uiPhase; - void Reset() + void Reset() override { m_uiSummonHandlerTimer = 25000; m_uiSummonShadowcasterTimer = 3000; @@ -134,7 +134,7 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI m_uiPhase = PHASE_WAITING; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { // An Add reached the ground, if its z-pos is near the z pos of Novos if (pWho->GetEntry() == NPC_HULKING_CORPSE || pWho->GetEntry() == NPC_FETID_TROLL_CORPSE || pWho->GetEntry() == NPC_RISON_SHADOWCASTER) @@ -148,7 +148,7 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -163,12 +163,12 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI m_pInstance->SetData(TYPE_NOVOS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_KILL, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -176,13 +176,13 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI m_pInstance->SetData(TYPE_NOVOS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NOVOS, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -194,7 +194,7 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_CRYSTAL_HANDLER) { @@ -207,7 +207,7 @@ struct MANGOS_DLL_DECL boss_novosAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -320,7 +320,7 @@ CreatureAI* GetAI_boss_novos(Creature* pCreature) } // Small helper script to handle summoned adds for Novos -struct MANGOS_DLL_DECL npc_crystal_channel_targetAI : public ScriptedAI +struct npc_crystal_channel_targetAI : public ScriptedAI { npc_crystal_channel_targetAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -329,12 +329,12 @@ struct MANGOS_DLL_DECL npc_crystal_channel_targetAI : public ScriptedAI instance_draktharon_keep* m_pInstance; - void Reset() {} - void MoveInLineOfSight(Unit* pWho) {} - void AttackStart(Unit* pWho) {} - void UpdateAI(const uint32 uiDiff) {} + void Reset() override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void AttackStart(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_HULKING_CORPSE || pSummoned->GetEntry() == NPC_FETID_TROLL_CORPSE || pSummoned->GetEntry() == NPC_RISON_SHADOWCASTER) { @@ -344,13 +344,13 @@ struct MANGOS_DLL_DECL npc_crystal_channel_targetAI : public ScriptedAI // The end of the stairs is approximately at 1/3 of the way between summoning-position and novos, height of Novos if (Creature* pNovos = m_pInstance->GetSingleCreatureFromStorage(NPC_NOVOS)) { - m_creature->GetRandomPoint(0.70*pNovos->GetPositionX() + 0.30*pSummoned->GetPositionX(), 0.70*pNovos->GetPositionY() + 0.30*pSummoned->GetPositionY(), pNovos->GetPositionZ() + 1.5f, 4.0f, fX, fY, fZ); + m_creature->GetRandomPoint(0.70 * pNovos->GetPositionX() + 0.30 * pSummoned->GetPositionX(), 0.70 * pNovos->GetPositionY() + 0.30 * pSummoned->GetPositionY(), pNovos->GetPositionZ() + 1.5f, 4.0f, fX, fY, fZ); pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override { if (uiPointId != 1 || uiMotionType != POINT_MOTION_TYPE || (pSummoned->GetEntry() != NPC_HULKING_CORPSE && pSummoned->GetEntry() != NPC_FETID_TROLL_CORPSE && pSummoned->GetEntry() != NPC_RISON_SHADOWCASTER)) return; @@ -371,7 +371,6 @@ CreatureAI* GetAI_npc_crystal_channel_target(Creature* pCreature) return new npc_crystal_channel_targetAI(pCreature); } - // Handling of the dummy auras of Crystal Handler Death spells, on remove the Crystal needs to be opened bool EffectAuraDummy_npc_crystal_channel_target(const Aura* pAura, bool bApply) { diff --git a/scripts/northrend/draktharon_keep/boss_tharonja.cpp b/scripts/northrend/draktharon_keep/boss_tharonja.cpp index 61d9fca43..d85fc2619 100644 --- a/scripts/northrend/draktharon_keep/boss_tharonja.cpp +++ b/scripts/northrend/draktharon_keep/boss_tharonja.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -73,7 +73,7 @@ enum Phases ## boss_tharonja ######*/ -struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI +struct boss_tharonjaAI : public ScriptedAI { boss_tharonjaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -95,7 +95,7 @@ struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI uint32 m_uiPoisonCloudTimer; uint32 m_uiReturnFleshTimer; - void Reset() + void Reset() override { m_uiPhase = PHASE_SKELETAL; @@ -108,7 +108,7 @@ struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI m_uiReturnFleshTimer = 26000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -116,12 +116,12 @@ struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI m_pInstance->SetData(TYPE_THARONJA, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -135,7 +135,7 @@ struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI m_pInstance->SetData(TYPE_THARONJA, DONE); } - void JustReachedHome() + void JustReachedHome() override { // Reset Display ID if (CreatureInfo const* pCreatureInfo = GetCreatureTemplateStore(NPC_THARONJA_SKELETAL)) @@ -149,7 +149,7 @@ struct MANGOS_DLL_DECL boss_tharonjaAI : public ScriptedAI m_pInstance->SetData(TYPE_THARONJA, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/draktharon_keep/boss_trollgore.cpp b/scripts/northrend/draktharon_keep/boss_trollgore.cpp index 80522d4c9..9936cd98f 100644 --- a/scripts/northrend/draktharon_keep/boss_trollgore.cpp +++ b/scripts/northrend/draktharon_keep/boss_trollgore.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,7 +43,7 @@ enum SPELL_SUMMON_INVADER_1 = 49456, // summon 27709 SPELL_SUMMON_INVADER_2 = 49457, // summon 27753 - //SPELL_SUMMON_INVADER_3 = 49458, // summon 27754 + // SPELL_SUMMON_INVADER_3 = 49458, // summon 27754 SPELL_INVADER_TAUNT = 49405, // triggers 49406 MAX_CONSOME_STACKS = 10, @@ -53,7 +53,7 @@ enum ## boss_trollgore ######*/ -struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI +struct boss_trollgoreAI : public ScriptedAI { boss_trollgoreAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -73,9 +73,9 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI uint32 m_uiWaveTimer; uint32 m_uiCorpseExplodeTimer; - GUIDVector m_vTriggers; + GuidVector m_vTriggers; - void Reset() + void Reset() override { m_uiCorpseExplodeTimer = 20000; m_uiConsumeTimer = 15000; @@ -85,7 +85,7 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI m_uiConsumeStacks = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -96,13 +96,13 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetCharmerOrOwnerPlayerOrPlayerItself()) DoScriptText(SAY_KILL, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -110,13 +110,13 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI m_pInstance->SetData(TYPE_TROLLGORE, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_TROLLGORE, FAIL); } - void SpellHit(Unit* pTarget, const SpellEntry* pSpell) + void SpellHit(Unit* /*pTarget*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_CONSUME_BUFF || pSpell->Id == SPELL_CONSUME_BUFF_H) { @@ -131,7 +131,7 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // This spell taunts the boss and the boss taunts back pSummoned->CastSpell(m_creature, SPELL_INVADER_TAUNT, true); @@ -166,7 +166,7 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI else { // Summon 3 trolls in the air - for(uint8 i = 0; i < m_vTriggers.size(); ++i) + for (uint8 i = 0; i < m_vTriggers.size(); ++i) { if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_vTriggers[i])) pTrigger->CastSpell(pTrigger, roll_chance_i(30) ? SPELL_SUMMON_INVADER_1 : SPELL_SUMMON_INVADER_2, true, NULL, NULL, m_creature->GetObjectGuid()); @@ -174,7 +174,7 @@ struct MANGOS_DLL_DECL boss_trollgoreAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/draktharon_keep/draktharon_keep.h b/scripts/northrend/draktharon_keep/draktharon_keep.h index c9bfd0069..7a73a489e 100644 --- a/scripts/northrend/draktharon_keep/draktharon_keep.h +++ b/scripts/northrend/draktharon_keep/draktharon_keep.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -43,7 +43,7 @@ enum }; static const uint32 aCrystalHandlerDeathSpells[MAX_CRYSTALS] = - {SPELL_CRYSTAL_HANDLER_DEATH_1, SPELL_CRYSTAL_HANDLER_DEATH_2, SPELL_CRYSTAL_HANDLER_DEATH_3, SPELL_CRYSTAL_HANDLER_DEATH_4}; +{SPELL_CRYSTAL_HANDLER_DEATH_1, SPELL_CRYSTAL_HANDLER_DEATH_2, SPELL_CRYSTAL_HANDLER_DEATH_3, SPELL_CRYSTAL_HANDLER_DEATH_4}; struct NovosCrystalInfo { @@ -52,31 +52,31 @@ struct NovosCrystalInfo bool m_bWasUsed; }; -class MANGOS_DLL_DECL instance_draktharon_keep : public ScriptedInstance +class instance_draktharon_keep : public ScriptedInstance { public: instance_draktharon_keep(Map* pMap); ~instance_draktharon_keep() {} - void Initialize(); + void Initialize() override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void GetTrollgoreOutsideTriggers(GUIDVector& vTriggers) { vTriggers = m_vTriggerGuids; } + void GetTrollgoreOutsideTriggers(GuidVector& vTriggers) { vTriggers = m_vTriggerGuids; } ObjectGuid GetTrollgoreCornerTrigger() { return m_trollgoreCornerTriggerGuid; } - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; Creature* GetNextCrystalTarget(Creature* pCrystalHandler, uint8& uiIndex); void DoHandleCrystal(uint8 uiIndex); @@ -97,9 +97,9 @@ class MANGOS_DLL_DECL instance_draktharon_keep : public ScriptedInstance NovosCrystalInfo m_aNovosCrystalInfo[MAX_CRYSTALS]; - GUIDVector m_vSummonDummyGuids; - GUIDList m_lNovosDummyGuids; - GUIDVector m_vTriggerGuids; + GuidVector m_vSummonDummyGuids; + GuidList m_lNovosDummyGuids; + GuidVector m_vTriggerGuids; }; #endif diff --git a/scripts/northrend/draktharon_keep/instance_draktharon_keep.cpp b/scripts/northrend/draktharon_keep/instance_draktharon_keep.cpp index 2454ec803..09d72a0aa 100644 --- a/scripts/northrend/draktharon_keep/instance_draktharon_keep.cpp +++ b/scripts/northrend/draktharon_keep/instance_draktharon_keep.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -105,7 +105,7 @@ void instance_draktharon_keep::DoSortNovosDummies() if (!pCrystal) continue; - for (GUIDList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) + for (GuidList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) { Creature* pDummy = instance->GetCreature(*itr); if (!pDummy) @@ -129,7 +129,7 @@ void instance_draktharon_keep::DoSortNovosDummies() // Find the crystal channel target (above Novos) float fNovosX, fNovosY, fNovosZ; pNovos->GetRespawnCoord(fNovosX, fNovosY, fNovosZ); - for (GUIDList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) + for (GuidList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) { Creature* pDummy = instance->GetCreature(*itr); if (!pDummy) @@ -150,7 +150,7 @@ void instance_draktharon_keep::DoSortNovosDummies() } // Summon positions (at end of stairs) - for (GUIDList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) + for (GuidList::iterator itr = m_lNovosDummyGuids.begin(); itr != m_lNovosDummyGuids.end();) { Creature* pDummy = instance->GetCreature(*itr); if (!pDummy) @@ -211,7 +211,7 @@ Creature* instance_draktharon_keep::GetSummonDummy() return instance->GetCreature(m_vSummonDummyGuids[urand(0, m_vSummonDummyGuids.size() - 1)]); } -bool instance_draktharon_keep::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_draktharon_keep::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { @@ -225,7 +225,7 @@ bool instance_draktharon_keep::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, void instance_draktharon_keep::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_TROLLGORE: if (uiData == IN_PROGRESS) @@ -311,7 +311,7 @@ void instance_draktharon_keep::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -320,9 +320,9 @@ void instance_draktharon_keep::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_draktharon_keep::GetData(uint32 uiType) +uint32 instance_draktharon_keep::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_TROLLGORE: return m_auiEncounter[uiType]; case TYPE_NOVOS: return m_auiEncounter[uiType]; diff --git a/scripts/northrend/grizzly_hills.cpp b/scripts/northrend/grizzly_hills.cpp index 3be7c5f52..75521a32d 100644 --- a/scripts/northrend/grizzly_hills.cpp +++ b/scripts/northrend/grizzly_hills.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,15 +17,17 @@ /* ScriptData SDName: Grizzly_Hills SD%Complete: -SDComment: Quest support: 12138, 12198 +SDComment: Quest support: 12027, 12082, 12138, 12198 SDCategory: Grizzly Hills EndScriptData */ /* ContentData npc_depleted_war_golem +npc_harrison_jones EndContentData */ #include "precompiled.h" +#include "escort_ai.h" #include "pet_ai.h" /*###### @@ -43,13 +45,13 @@ enum SPELL_GOLEM_CHARGE_CREDIT = 47797, }; -struct MANGOS_DLL_DECL npc_depleted_war_golemAI : public ScriptedPetAI +struct npc_depleted_war_golemAI : public ScriptedPetAI { npc_depleted_war_golemAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void OwnerKilledUnit(Unit* pVictim) + void OwnerKilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetEntry() == NPC_LIGHTNING_SENTRY) { @@ -95,6 +97,434 @@ bool EffectAuraDummy_npc_depleted_war_golem(const Aura* pAura, bool bApply) return true; } +/*###### +## npc_harrison_jones +######*/ + +enum +{ + // yells + SAY_HARRISON_ESCORT_START = -1001053, + SAY_HARRISON_CHAMBER_1 = -1001054, + SAY_HARRISON_CHAMBER_2 = -1001055, + SAY_HARRISON_CHAMBER_RELEASE = -1001056, + SAY_ADARRAH_THANK_YOU = -1001057, + SAY_HARRISON_CHAMBER_3 = -1001058, + SAY_HARRISON_CHAMBER_4 = -1001059, + SAY_HARRISON_CHAMBER_5 = -1001060, + SAY_HARRISON_CHAMBER_6 = -1001061, + SAY_HARRISON_CHAMBER_7 = -1001062, + SAY_HARRISON_ESCORT_COMPELTE = -1001063, + + // quest + QUEST_ID_DUN_DA_DUN_TAH = 12082, + + // npcs + NPC_ADARRAH = 24405, + NPC_TECAHUNA = 26865, + NPC_MUMMY_EFFECT_BUNNY = 26867, + NPC_ANCIENT_DRAKKARI_KING = 26871, + + // spells + SPELL_BUNNY_IMMOLATION = 48150, + SPELL_GONG_EFFECT = 47730, + SPELL_TECAHUNA_SPIRIT_BEAM = 47601, + SPELL_SUMMON_DRAKKARI_KING = 47602, + + // objects + GO_HARRISON_CAGE = 188465, + GO_ADARRAH_CAGE = 188487, + GO_FIRE_DOOR = 188480, +}; + +struct npc_harrison_jonesAI : public npc_escortAI +{ + npc_harrison_jonesAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_uiActivateMummiesTimer = 0; + Reset(); + } + + ObjectGuid m_tecahunaGuid; + ObjectGuid m_adarrahGuid; + + uint32 m_uiActivateMummiesTimer; + + GuidList m_lImmolationBunnyGuids; + + void Reset() override { } + + void JustDied(Unit* pKiller) override + { + DoCleanChamberRoom(); + + npc_escortAI::JustDied(pKiller); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_HARRISON_ESCORT_START, m_creature); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + + if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_HARRISON_CAGE, 5.0f)) + pCage->Use(m_creature); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_TECAHUNA) + { + m_tecahunaGuid = pSummoned->GetObjectGuid(); + + // sort the mummies based on the distance + std::list lBunniesInRange; + GetCreatureListWithEntryInGrid(lBunniesInRange, m_creature, NPC_MUMMY_EFFECT_BUNNY, 50.0f); + + lBunniesInRange.sort(ObjectDistanceOrder(pSummoned)); + + for (std::list::const_iterator itr = lBunniesInRange.begin(); itr != lBunniesInRange.end(); ++itr) + m_lImmolationBunnyGuids.push_back((*itr)->GetObjectGuid()); + } + else if (pSummoned->GetEntry() == NPC_ANCIENT_DRAKKARI_KING) + pSummoned->AI()->AttackStart(m_creature); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_TECAHUNA) + { + SetEscortPaused(false); + DoCleanChamberRoom(); + } + } + + void DoCleanChamberRoom() + { + // open door + if (GameObject* pDoor = GetClosestGameObjectWithEntry(m_creature, GO_FIRE_DOOR, 50.0f)) + pDoor->ResetDoorOrButton(); + + // clear auras + std::list lBunniesInRange; + GetCreatureListWithEntryInGrid(lBunniesInRange, m_creature, NPC_MUMMY_EFFECT_BUNNY, 50.0f); + + for (std::list::const_iterator itr = lBunniesInRange.begin(); itr != lBunniesInRange.end(); ++itr) + (*itr)->RemoveAurasDueToSpell(SPELL_BUNNY_IMMOLATION); + + m_uiActivateMummiesTimer = 0; + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 7: + DoScriptText(SAY_HARRISON_CHAMBER_1, m_creature); + break; + case 8: + DoScriptText(SAY_HARRISON_CHAMBER_2, m_creature); + break; + case 10: + m_creature->HandleEmote(EMOTE_ONESHOT_USESTANDING); + break; + case 11: + DoScriptText(SAY_HARRISON_CHAMBER_RELEASE, m_creature); + if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_ADARRAH_CAGE, 5.0f)) + pCage->Use(m_creature); + break; + case 12: + if (Creature* pAdarrah = GetClosestCreatureWithEntry(m_creature, NPC_ADARRAH, 5.0f)) + { + DoScriptText(SAY_ADARRAH_THANK_YOU, pAdarrah); + m_adarrahGuid = pAdarrah->GetObjectGuid(); + } + break; + case 13: + if (Creature* pAdarrah = m_creature->GetMap()->GetCreature(m_adarrahGuid)) + { + pAdarrah->SetWalk(false); + pAdarrah->GetMotionMaster()->MovePoint(0, 4878.416f, -4793.893f, 32.549f); + pAdarrah->ForcedDespawn(5000); + } + break; + case 15: + m_creature->SetFacingTo(0.2f); + m_creature->HandleEmote(EMOTE_ONESHOT_KNEEL); + break; + case 16: + { + // set mummies in fire + std::list lBunniesInRange; + GetCreatureListWithEntryInGrid(lBunniesInRange, m_creature, NPC_MUMMY_EFFECT_BUNNY, 50.0f); + + for (std::list::const_iterator itr = lBunniesInRange.begin(); itr != lBunniesInRange.end(); ++itr) + (*itr)->CastSpell((*itr), SPELL_BUNNY_IMMOLATION, true); + + m_creature->SetFacingTo(5.0f); + DoCastSpellIfCan(m_creature, SPELL_GONG_EFFECT); + break; + } + case 17: + DoScriptText(SAY_HARRISON_CHAMBER_3, m_creature); + break; + case 18: + DoScriptText(SAY_HARRISON_CHAMBER_4, m_creature); + break; + case 21: + // close door + if (GameObject* pDoor = GetClosestGameObjectWithEntry(m_creature, GO_FIRE_DOOR, 10.0f)) + pDoor->Use(m_creature); + break; + case 22: + DoScriptText(SAY_HARRISON_CHAMBER_5, m_creature); + SetRun(); + // summon snake + m_creature->SummonCreature(NPC_TECAHUNA, 4907.077f, -4819.035f, 32.55f, 2.32f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 23: + DoScriptText(SAY_HARRISON_CHAMBER_6, m_creature); + break; + case 24: + DoScriptText(SAY_HARRISON_CHAMBER_7, m_creature); + break; + case 25: + // attack snake + if (Creature* pTecahuna = m_creature->GetMap()->GetCreature(m_tecahunaGuid)) + AttackStart(pTecahuna); + SetEscortPaused(true); + m_uiActivateMummiesTimer = 10000; + break; + case 53: + DoScriptText(SAY_HARRISON_ESCORT_COMPELTE, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + { + pPlayer->GroupEventHappens(QUEST_ID_DUN_DA_DUN_TAH, m_creature); + m_creature->SetFacingToObject(pPlayer); + } + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // special script for snake fight + if (m_uiActivateMummiesTimer) + { + if (m_uiActivateMummiesTimer <= uiDiff) + { + if (Creature* pTecahuna = m_creature->GetMap()->GetCreature(m_tecahunaGuid)) + { + // activate 2 mummies at each turn + for (uint8 i = 0; i < 2; ++i) + { + if (Creature* pBunny = m_creature->GetMap()->GetCreature(m_lImmolationBunnyGuids.front())) + { + pTecahuna->CastSpell(pBunny, SPELL_TECAHUNA_SPIRIT_BEAM, true); + pBunny->CastSpell(pBunny, SPELL_SUMMON_DRAKKARI_KING, true, NULL, NULL, m_creature->GetObjectGuid()); + pBunny->RemoveAurasDueToSpell(SPELL_BUNNY_IMMOLATION); + m_lImmolationBunnyGuids.remove(m_lImmolationBunnyGuids.front()); + } + } + } + + // set timer based on the remaining mummies + if (m_lImmolationBunnyGuids.empty()) + m_uiActivateMummiesTimer = 0; + else + m_uiActivateMummiesTimer = urand(5000, 10000); + } + else + m_uiActivateMummiesTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_harrison_jones(Creature* pCreature) +{ + return new npc_harrison_jonesAI(pCreature); +} + +bool QuestAccept_npc_harrison_jones(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_DUN_DA_DUN_TAH) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + +/*###### +## npc_emily +######*/ + +enum +{ + SAY_ESCORT_START = -1001173, + SAY_FIRST_WOLF = -1001174, + SAY_FIRST_WOLF_ATTACK = -1001175, + SAY_HELP_FLOPPY_1 = -1001176, + SAY_FIRST_WOLF_DEFEAT = -1001177, + SAY_SECOND_WOLF = -1001178, + SAY_HELP_FLOPPY_2 = -1001179, + SAY_FLOPPY_ALMOST_DEAD = -1001180, + SAY_SECOND_WOLF_DEFEAT = -1001181, + SAY_RESUME_ESCORT = -1001182, + SAY_ESCORT_COMPLETE = -1001183, + + SPELL_FLOPPY_BECOMES_LUNCH = 47184, + + NPC_HUNGRY_WORG = 26586, + NPC_RAVENOUS_WORG = 26590, + NPC_MR_FLOPPY = 26589, + + QUEST_ID_MR_FLOPPY_ADVENTURE = 12027, +}; + +struct npc_emilyAI : public npc_escortAI +{ + npc_emilyAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + ObjectGuid m_floppyGuid; + + void Reset() override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + + if (Creature* pFloppy = GetClosestCreatureWithEntry(m_creature, NPC_MR_FLOPPY, 10.0f)) + m_floppyGuid = pFloppy->GetObjectGuid(); + } + else if (eventType == AI_EVENT_JUST_DIED && pSender->GetEntry() == NPC_MR_FLOPPY) + { + npc_escortAI::JustDied(m_creature); + m_creature->ForcedDespawn(); + } + else if (eventType == AI_EVENT_CRITICAL_HEALTH && pSender->GetEntry() == NPC_MR_FLOPPY) + DoScriptText(SAY_FLOPPY_ALMOST_DEAD, m_creature); + else if (eventType == AI_EVENT_LOST_SOME_HEALTH && pSender->GetEntry() == NPC_MR_FLOPPY) + DoScriptText(urand(0, 1) ? SAY_HELP_FLOPPY_1 : SAY_HELP_FLOPPY_2, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_RAVENOUS_WORG: + case NPC_HUNGRY_WORG: + if (Creature* pFloppy = m_creature->GetMap()->GetCreature(m_floppyGuid)) + { + float fX, fY, fZ; + pFloppy->GetContactPoint(pSummoned, fX, fY, fZ); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_RAVENOUS_WORG: + DoScriptText(SAY_SECOND_WOLF_DEFEAT, m_creature); + SetEscortPaused(false); + // resume follow after vehicle unboard + if (Creature* pFloppy = m_creature->GetMap()->GetCreature(m_floppyGuid)) + pFloppy->GetMotionMaster()->MoveFollow(m_creature, pFloppy->GetDistance(m_creature), M_PI_F - pFloppy->GetAngle(m_creature)); + break; + case NPC_HUNGRY_WORG: + DoScriptText(SAY_FIRST_WOLF_DEFEAT, m_creature); + SetEscortPaused(false); + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + switch (pSummoned->GetEntry()) + { + case NPC_RAVENOUS_WORG: + // board the ravenous worg vehicle + if (Creature* pFloppy = m_creature->GetMap()->GetCreature(m_floppyGuid)) + pFloppy->CastSpell(pSummoned, SPELL_FLOPPY_BECOMES_LUNCH, true); + // no break; + case NPC_HUNGRY_WORG: + if (Creature* pFloppy = m_creature->GetMap()->GetCreature(m_floppyGuid)) + pSummoned->AI()->AttackStart(pFloppy); + break; + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + DoScriptText(SAY_ESCORT_START, m_creature); + break; + case 10: + DoScriptText(SAY_FIRST_WOLF, m_creature); + m_creature->SummonCreature(NPC_HUNGRY_WORG, 4305.514f, -3799.008f, 237.034f, 2.20f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 11: + SetEscortPaused(true); + DoScriptText(SAY_FIRST_WOLF_ATTACK, m_creature); + break; + case 22: + SetEscortPaused(true); + DoScriptText(SAY_SECOND_WOLF, m_creature); + m_creature->SummonCreature(NPC_RAVENOUS_WORG, 4339.643f, -3948.972f, 194.904f, 0.90f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 24: + DoScriptText(SAY_RESUME_ESCORT, m_creature); + SetRun(); + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_MR_FLOPPY_ADVENTURE, m_creature); + break; + case 25: + DoScriptText(SAY_ESCORT_COMPLETE, m_creature); + break; + case 27: + if (Creature* pFloppy = m_creature->GetMap()->GetCreature(m_floppyGuid)) + pFloppy->ForcedDespawn(); + break; + } + } +}; + +CreatureAI* GetAI_npc_emily(Creature* pCreature) +{ + return new npc_emilyAI(pCreature); +} + +bool QuestAccept_npc_emily(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_MR_FLOPPY_ADVENTURE) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + void AddSC_grizzly_hills() { Script* pNewScript; @@ -104,4 +534,16 @@ void AddSC_grizzly_hills() pNewScript->GetAI = &GetAI_npc_depleted_war_golem; pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_depleted_war_golem; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_harrison_jones"; + pNewScript->GetAI = &GetAI_npc_harrison_jones; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_harrison_jones; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_emily"; + pNewScript->GetAI = &GetAI_npc_emily; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_emily; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/gundrak/boss_colossus.cpp b/scripts/northrend/gundrak/boss_colossus.cpp index e3f2a82e2..cb7b67c29 100644 --- a/scripts/northrend/gundrak/boss_colossus.cpp +++ b/scripts/northrend/gundrak/boss_colossus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Colossus -SD%Complete: 20% -SDComment: +SD%Complete: 95% +SDComment: Timers; May need small adjustments SDCategory: Gundrak EndScriptData */ @@ -31,6 +31,7 @@ enum EMOTE_GLOW = -1604010, // collosus' abilities + SPELL_FREEZE_ANIM = 16245, // Colossus stun aura SPELL_EMERGE = 54850, SPELL_MIGHTY_BLOW = 54719, SPELL_MORTAL_STRIKES = 54715, @@ -40,16 +41,119 @@ enum SPELL_MERGE = 54878, SPELL_SURGE = 54801, SPELL_MOJO_VOLLEY = 59453, - SPELL_MOJO_VOLLEY_H = 54849 + SPELL_MOJO_VOLLEY_H = 54849, + + // Living Mojo spells + SPELL_MOJO_WAVE = 55626, + SPELL_MOJO_WAVE_H = 58993, + SPELL_MOJO_PUDDLE = 55627, + SPELL_MOJO_PUDDLE_H = 58994, + + MAX_COLOSSUS_MOJOS = 5, }; /*###### -## boss_colossus +## boss_drakkari_elemental ######*/ -struct MANGOS_DLL_DECL boss_colossusAI : public ScriptedAI +struct boss_drakkari_elementalAI : public ScriptedAI { - boss_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_drakkari_elementalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_gundrak* m_pInstance; + bool m_bIsRegularMode; + bool m_bIsFirstEmerge; + + uint32 m_uiSurgeTimer; + + void Reset() override + { + m_bIsFirstEmerge = true; + m_uiSurgeTimer = urand(9000, 13000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_MOJO_VOLLEY : SPELL_MOJO_VOLLEY_H); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& /*uiDamage*/) override + { + if (!m_bIsFirstEmerge) + return; + + if (m_creature->GetHealthPercent() < 50.0f) + { + DoCastSpellIfCan(m_creature, SPELL_MERGE, CAST_INTERRUPT_PREVIOUS); + m_bIsFirstEmerge = false; + } + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (Creature* pColossus = m_pInstance->GetSingleCreatureFromStorage(NPC_COLOSSUS)) + pColossus->AI()->EnterEvadeMode(); + } + + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + // kill colossus on death - this will finish the encounter + if (Creature* pColossus = m_pInstance->GetSingleCreatureFromStorage(NPC_COLOSSUS)) + pColossus->DealDamage(pColossus, pColossus->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + + // Set the second emerge of the Elemental + void DoPrepareSecondEmerge() + { + m_bIsFirstEmerge = false; + m_creature->SetHealth(m_creature->GetMaxHealth()*.5); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSurgeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SURGE) == CAST_OK) + m_uiSurgeTimer = urand(12000, 17000); + } + } + else + m_uiSurgeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_drakkari_elemental(Creature* pCreature) +{ + return new boss_drakkari_elementalAI(pCreature); +} + +/*###### +## boss_drakkari_colossus +######*/ + +struct boss_drakkari_colossusAI : public ScriptedAI +{ + boss_drakkari_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -61,14 +165,23 @@ struct MANGOS_DLL_DECL boss_colossusAI : public ScriptedAI bool m_bFirstEmerge; uint32 m_uiMightyBlowTimer; + uint32 m_uiColossusStartTimer; + uint8 m_uiMojosGathered; - void Reset() + void Reset() override { - m_bFirstEmerge = false; + m_bFirstEmerge = true; m_uiMightyBlowTimer = 10000; + m_uiColossusStartTimer = 0; + m_uiMojosGathered = 0; + + // Reset unit flags + SetCombatMovement(true); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Agrro() + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_MORTAL_STRIKES : SPELL_MORTAL_STRIKES_H); @@ -76,48 +189,99 @@ struct MANGOS_DLL_DECL boss_colossusAI : public ScriptedAI m_pInstance->SetData(TYPE_COLOSSUS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_COLOSSUS, DONE); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_COLOSSUS, FAIL); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_MERGE) { // re-activate colossus here + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + ((Creature*)pCaster)->ForcedDespawn(); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_ELEMENTAL) { - // handle elemental stuff + // If this is the second summon, then set the health to half + if (!m_bFirstEmerge) + { + if (boss_drakkari_elementalAI* pBossAI = dynamic_cast(pSummoned->AI())) + pBossAI->DoPrepareSecondEmerge(); + } + + m_bFirstEmerge = false; + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { - if (!m_bFirstEmerge && m_creature->GetHealthPercent() < 50.0f) + if (m_bFirstEmerge && m_creature->GetHealthPercent() < 50.0f) + DoEmergeElemental(); + else if (uiDamage >= m_creature->GetHealth()) { - m_bFirstEmerge = true; - DoCastSpellIfCan(m_creature, SPELL_EMERGE); + uiDamage = 0; + DoEmergeElemental(); } - else if (m_creature->GetHealth() - uiDamage <= 0) + } + + void DoEmergeElemental() + { + // Avoid casting the merge spell twice + if (m_creature->HasAura(SPELL_FREEZE_ANIM)) + return; + + if (DoCastSpellIfCan(m_creature, SPELL_EMERGE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - // prevent boss from dying if players deal the final blow - if (pDoneBy->GetCharmerOrOwnerPlayerOrPlayerItself()) - { - uiDamage = 0; - DoCastSpellIfCan(m_creature, SPELL_EMERGE); - } + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM, CAST_TRIGGERED); } } - void UpdateAI(const uint32 uiDiff) + // Wrapper to prepare the Colossus + void DoPrepareColossus() + { + ++m_uiMojosGathered; + + if (m_uiMojosGathered == MAX_COLOSSUS_MOJOS) + m_uiColossusStartTimer = 1000; + } + + void UpdateAI(const uint32 uiDiff) override { + if (m_uiColossusStartTimer) + { + if (m_uiColossusStartTimer <= uiDiff) + { + m_creature->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_uiColossusStartTimer = 0; + } + else + m_uiColossusStartTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -133,17 +297,130 @@ struct MANGOS_DLL_DECL boss_colossusAI : public ScriptedAI } }; -CreatureAI* GetAI_boss_colossus(Creature* pCreature) +CreatureAI* GetAI_boss_drakkari_colossus(Creature* pCreature) { - return new boss_colossusAI(pCreature); + return new boss_drakkari_colossusAI(pCreature); } +/*###### +## npc_living_mojo +######*/ + +struct npc_living_mojoAI : public ScriptedAI +{ + npc_living_mojoAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); + m_bIsPartOfColossus = pCreature->GetPositionX() > 1650.0f ? true : false; + Reset(); + } + + instance_gundrak* m_pInstance; + bool m_bIsRegularMode; + bool m_bIsPartOfColossus; + + uint32 m_uiMojoWaveTimer; + + void Reset() override + { + m_uiMojoWaveTimer = urand(10000, 13000); + } + + void AttackStart(Unit* pWho) override + { + // Don't attack if is part of the Colossus event + if (m_bIsPartOfColossus) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (uiPointId) + { + m_creature->ForcedDespawn(1000); + + if (m_pInstance) + { + // Prepare to set the Colossus in combat + if (Creature* pColossus = m_pInstance->GetSingleCreatureFromStorage(NPC_COLOSSUS)) + { + if (boss_drakkari_colossusAI* pBossAI = dynamic_cast(pColossus->AI())) + pBossAI->DoPrepareColossus(); + } + } + } + } + + void EnterEvadeMode() override + { + if (!m_bIsPartOfColossus) + ScriptedAI::EnterEvadeMode(); + // Force the Mojo to move to the Colossus position + else + { + if (m_pInstance) + { + float fX, fY, fZ; + m_creature->GetPosition(fX, fY, fZ); + + if (Creature* pColossus = m_pInstance->GetSingleCreatureFromStorage(NPC_COLOSSUS)) + pColossus->GetPosition(fX, fY, fZ); + + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_MOJO_PUDDLE : SPELL_MOJO_PUDDLE_H, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiMojoWaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_MOJO_WAVE : SPELL_MOJO_WAVE_H) == CAST_OK) + m_uiMojoWaveTimer = urand(15000, 18000); + } + else + m_uiMojoWaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_living_mojo(Creature* pCreature) +{ + return new npc_living_mojoAI(pCreature); +}; + void AddSC_boss_colossus() { Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "boss_colossus"; - pNewScript->GetAI = &GetAI_boss_colossus; + pNewScript->Name = "boss_drakkari_colossus"; + pNewScript->GetAI = &GetAI_boss_drakkari_colossus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_drakkari_elemental"; + pNewScript->GetAI = &GetAI_boss_drakkari_elemental; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_living_mojo"; + pNewScript->GetAI = &GetAI_npc_living_mojo; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/gundrak/boss_eck.cpp b/scripts/northrend/gundrak/boss_eck.cpp index e35219296..b9b05fcea 100644 --- a/scripts/northrend/gundrak/boss_eck.cpp +++ b/scripts/northrend/gundrak/boss_eck.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ enum ## boss_eck ######*/ -struct MANGOS_DLL_DECL boss_eckAI : public ScriptedAI +struct boss_eckAI : public ScriptedAI { boss_eckAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -54,7 +54,7 @@ struct MANGOS_DLL_DECL boss_eckAI : public ScriptedAI uint32 m_uiBiteTimer; uint32 m_uiBerserkTimer; - void Reset() + void Reset() override { m_uiSpitTimer = urand(10000, 20000); m_uiSpringTimer = urand(15000, 25000); @@ -63,32 +63,32 @@ struct MANGOS_DLL_DECL boss_eckAI : public ScriptedAI m_bIsBerserk = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ECK, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ECK, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ECK, FAIL); } // As the Eck Spite spell has no dummy or similar effect, applying the residue aura has to be done with spellHitTarget - void SpellHitTarget (Unit* pUnit, const SpellEntry* pSpellEntry) + void SpellHitTarget(Unit* pUnit, const SpellEntry* pSpellEntry) override { if (pSpellEntry->Id == SPELL_ECK_SPIT && pUnit->GetTypeId() == TYPEID_PLAYER && !pUnit->HasAura(SPELL_ECK_RESIDUE)) pUnit->CastSpell(pUnit, SPELL_ECK_RESIDUE, true); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/gundrak/boss_galdarah.cpp b/scripts/northrend/gundrak/boss_galdarah.cpp index 53f913b37..e025a12ed 100644 --- a/scripts/northrend/gundrak/boss_galdarah.cpp +++ b/scripts/northrend/gundrak/boss_galdarah.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,9 +39,6 @@ enum EMOTE_IMPALED = -1604030, - ACHIEVEMENT_WHAT_THE_ECK = 1864, - ACHIEVEMENT_SHARE_THE_LOVE = 2152, - NPC_RHINO_SPIRIT = 29791, SPELL_STAMPEDE_RHINO = 55220, SPELL_STAMPEDE_RHINO_H = 59823, @@ -68,7 +65,7 @@ enum ## boss_galdarah ######*/ -struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI +struct boss_galdarahAI : public ScriptedAI { boss_galdarahAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -89,7 +86,7 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI uint32 m_uiEnrageTimer; uint8 m_uiAbilityCount; - void Reset() + void Reset() override { m_bIsTrollPhase = true; @@ -100,7 +97,7 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI m_uiAbilityCount = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -108,9 +105,9 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI m_pInstance->SetData(TYPE_GALDARAH , IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -118,13 +115,13 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_GALDARAH, NOT_STARTED); + m_pInstance->SetData(TYPE_GALDARAH, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -132,12 +129,18 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI m_pInstance->SetData(TYPE_GALDARAH, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_RHINO_SPIRIT) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, m_bIsRegularMode ? SPELL_STAMPEDE_RHINO : SPELL_STAMPEDE_RHINO_H, SELECT_FLAG_PLAYER)) + { pSummoned->CastSpell(pTarget, m_bIsRegularMode ? SPELL_STAMPEDE_RHINO : SPELL_STAMPEDE_RHINO_H, false, NULL, NULL, m_creature->GetObjectGuid()); + + // Store the player guid in order to count it for the achievement + if (m_pInstance) + m_pInstance->SetData(TYPE_ACHIEV_SHARE_LOVE, pTarget->GetGUIDLow()); + } } } @@ -164,7 +167,7 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI m_uiSpecialAbilityTimer = 12000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -189,7 +192,7 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI if (m_uiStampedeTimer < uiDiff) { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SUMMON_1, m_creature); break; case 1: DoScriptText(SAY_SUMMON_2, m_creature); break; @@ -211,7 +214,6 @@ struct MANGOS_DLL_DECL boss_galdarahAI : public ScriptedAI } else m_uiSpecialAbilityTimer -= uiDiff; - } else { diff --git a/scripts/northrend/gundrak/boss_moorabi.cpp b/scripts/northrend/gundrak/boss_moorabi.cpp index a0c65b377..71da96ee5 100644 --- a/scripts/northrend/gundrak/boss_moorabi.cpp +++ b/scripts/northrend/gundrak/boss_moorabi.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -54,7 +54,7 @@ enum ## boss_moorabi ######*/ -struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI +struct boss_moorabiAI : public ScriptedAI { boss_moorabiAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -74,7 +74,7 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI bool m_bMammothPhase; - void Reset() + void Reset() override { m_bMammothPhase = false; @@ -85,7 +85,7 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI m_uiPreviousTimer = 10000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); DoCastSpellIfCan(m_creature, SPELL_MOJO_FRENZY); @@ -94,9 +94,9 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI m_pInstance->SetData(TYPE_MOORABI, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -104,7 +104,7 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -112,7 +112,7 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI m_pInstance->SetData(TYPE_MOORABI, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -121,6 +121,10 @@ struct MANGOS_DLL_DECL boss_moorabiAI : public ScriptedAI { DoScriptText(EMOTE_TRANSFORMED, m_creature); m_bMammothPhase = true; + + // Set the achievement to failed + if (m_pInstance) + m_pInstance->SetLessRabiAchievementCriteria(false); } if (m_uiRoarTimer < uiDiff) diff --git a/scripts/northrend/gundrak/boss_sladran.cpp b/scripts/northrend/gundrak/boss_sladran.cpp index bf5dbeda5..974042415 100644 --- a/scripts/northrend/gundrak/boss_sladran.cpp +++ b/scripts/northrend/gundrak/boss_sladran.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -47,66 +47,37 @@ enum SPELL_SUMMON_VIPER = 55060, SPELL_SUMMON_CONSTRICTOR = 54969, + // Constrictor spells SPELL_GRIP_OF_SLADRAN = 55093, SPELL_GRIP_OF_SLADRAN_H = 61474, + // Snake Wrap spells - mechanics unk + SPELL_SNAKE_WRAP = 55099, + SPELL_SNAKE_WRAP_H = 61475, + SPELL_SNAKE_WRAP_SUMMON = 55126, + SPELL_SNAKE_WRAP_SUMMON_H = 61476, + SPELL_SNAKE_WRAP_EFFECT = 55128, + SPELL_SNAKE_WRAP_SNAKES = 55127, // kills all snakes + NPC_SLADRAN_CONSTRICTOR = 29713, NPC_SLADRAN_VIPER = 29680, NPC_SNAKE_WRAP = 29742, - NPC_SLADRAN_SUMMON_TARGET = 29682 }; -/*###### -## mob_sladran_summon_target -######*/ -struct MANGOS_DLL_DECL mob_sladran_summon_targetAI : public ScriptedAI -{ - mob_sladran_summon_targetAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); - Reset(); - } - - instance_gundrak* m_pInstance; - - void Reset() {} - void MoveInLineOfSight(Unit* pWho) {} - void AttackStart(Unit* pWho) {} - - void JustSummoned(Creature* pSummoned) - { - if (!m_pInstance) - return; - - if (Creature* pSladran = m_pInstance->GetSingleCreatureFromStorage(NPC_SLADRAN)) - { - float fPosX, fPosY, fPosZ; - pSladran->GetPosition(fPosX, fPosY, fPosZ); - pSummoned->GetMotionMaster()->MovePoint(0, fPosX, fPosY, fPosZ); - } - } - - void UpdateAI(const uint32 diff) {} -}; - -CreatureAI* GetAI_mob_sladran_summon_target(Creature* pCreature) -{ - return new mob_sladran_summon_targetAI(pCreature); -} - /*###### ## boss_sladran ######*/ -struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI + +struct boss_sladranAI : public ScriptedAI { boss_sladranAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_gundrak*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_gundrak* m_pInstance; bool m_bIsRegularMode; uint32 m_uiSummonTimer; @@ -114,7 +85,7 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI uint32 m_uiPowerfulBiteTimer; uint32 m_uiVenomBoltTimer; - void Reset() + void Reset() override { m_uiSummonTimer = m_bIsRegularMode ? 5000 : 3000; m_uiPoisonNovaTimer = 22000; @@ -122,7 +93,7 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI m_uiVenomBoltTimer = 15000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -130,9 +101,9 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI m_pInstance->SetData(TYPE_SLADRAN, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -140,7 +111,7 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -148,37 +119,43 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI m_pInstance->SetData(TYPE_SLADRAN, DONE); } - Creature* SelectRandomCreatureOfEntryInRange(uint32 uiEntry, float fRange) + void JustReachedHome() override { - std::list lCreatureList; - GetCreatureListWithEntryInGrid(lCreatureList, m_creature, uiEntry, fRange); - - if (lCreatureList.empty()) - return NULL; + if (m_pInstance) + m_pInstance->SetData(TYPE_SLADRAN, FAIL); + } - std::list::iterator iter = lCreatureList.begin(); - advance(iter, urand(0, lCreatureList.size()-1)); + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() != NPC_SLADRAN_CONSTRICTOR && pSummoned->GetEntry() != NPC_SLADRAN_VIPER) + return; - return *iter; + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), false); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiPoisonNovaTimer < uiDiff) { - DoScriptText(EMOTE_NOVA, m_creature); - DoCastSpellIfCan(m_creature->getVictim(),m_bIsRegularMode ? SPELL_POISON_NOVA : SPELL_POISON_NOVA_H); - m_uiPoisonNovaTimer = 22000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_POISON_NOVA : SPELL_POISON_NOVA_H) == CAST_OK) + { + DoScriptText(EMOTE_NOVA, m_creature); + m_uiPoisonNovaTimer = 22000; + } } else m_uiPoisonNovaTimer -= uiDiff; if (m_uiSummonTimer < uiDiff) { - if (Creature* pSummonTarget = SelectRandomCreatureOfEntryInRange(NPC_SLADRAN_SUMMON_TARGET, 75.0f)) + if (!m_pInstance) + return; + + if (Creature* pSummonTarget = m_creature->GetMap()->GetCreature(m_pInstance->SelectRandomSladranTargetGuid())) { if (urand(0, 3)) { @@ -186,7 +163,7 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI if (!urand(0, 4)) DoScriptText(SAY_SUMMON_CONSTRICTOR, m_creature); - pSummonTarget->CastSpell(pSummonTarget, SPELL_SUMMON_CONSTRICTOR, false); + pSummonTarget->CastSpell(pSummonTarget, SPELL_SUMMON_CONSTRICTOR, false, NULL, NULL, m_creature->GetObjectGuid()); } else { @@ -194,7 +171,7 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI if (!urand(0, 4)) DoScriptText(SAY_SUMMON_SNAKE, m_creature); - pSummonTarget->CastSpell(pSummonTarget, SPELL_SUMMON_VIPER, false); + pSummonTarget->CastSpell(pSummonTarget, SPELL_SUMMON_VIPER, false, NULL, NULL, m_creature->GetObjectGuid()); } } @@ -205,8 +182,8 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI if (m_uiPowerfulBiteTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_POWERFUL_BITE : SPELL_POWERFUL_BITE_H); - m_uiPowerfulBiteTimer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_POWERFUL_BITE : SPELL_POWERFUL_BITE_H) == CAST_OK) + m_uiPowerfulBiteTimer = 10000; } else m_uiPowerfulBiteTimer -= uiDiff; @@ -214,9 +191,10 @@ struct MANGOS_DLL_DECL boss_sladranAI : public ScriptedAI if (m_uiVenomBoltTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_VENOM_BOLT : SPELL_VENOM_BOLT_H); - - m_uiVenomBoltTimer = 15000; + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_VENOM_BOLT : SPELL_VENOM_BOLT_H) == CAST_OK) + m_uiVenomBoltTimer = 15000; + } } else m_uiVenomBoltTimer -= uiDiff; @@ -238,9 +216,4 @@ void AddSC_boss_sladran() pNewScript->Name = "boss_sladran"; pNewScript->GetAI = &GetAI_boss_sladran; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_sladran_summon_target"; - pNewScript->GetAI = &GetAI_mob_sladran_summon_target; - pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/gundrak/gundrak.h b/scripts/northrend/gundrak/gundrak.h index b957c4f0f..5591a5c8a 100644 --- a/scripts/northrend/gundrak/gundrak.h +++ b/scripts/northrend/gundrak/gundrak.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -14,6 +14,7 @@ enum { MAX_ENCOUNTER = 5, + MIN_LOVE_SHARE_PLAYERS = 5, TYPE_SLADRAN = 0, TYPE_MOORABI = 1, @@ -21,6 +22,10 @@ enum TYPE_GALDARAH = 3, TYPE_ECK = 4, + // Used to handle achievements + TYPE_ACHIEV_WHY_SNAKES = 5, + TYPE_ACHIEV_SHARE_LOVE = 6, + NPC_SLADRAN = 29304, NPC_MOORABI = 29305, NPC_COLOSSUS = 29307, @@ -29,6 +34,7 @@ enum NPC_GALDARAH = 29306, NPC_ECK = 29932, NPC_INVISIBLE_STALKER = 30298, // Caster and Target for visual spells on altar use + NPC_SLADRAN_SUMMON_T = 29682, GO_ECK_DOOR = 192632, GO_ECK_UNDERWATER_DOOR = 192569, @@ -55,29 +61,40 @@ enum TIMER_VISUAL_ALTAR = 3000, TIMER_VISUAL_BEAM = 2500, TIMER_VISUAL_KEY = 2000, + + ACHIEV_CRIT_LESS_RABI = 7319, // Moorabi achiev 2040 + ACHIEV_CRIT_WHY_SNAKES = 7363, // Sladran achiev 2058 + ACHIEV_CRIT_SHARE_LOVE = 7583, // Galdarah achiev 2152 }; typedef std::map TypeTimerMap; typedef std::pair TypeTimerPair; -class MANGOS_DLL_DECL instance_gundrak : public ScriptedInstance +class instance_gundrak : public ScriptedInstance { public: instance_gundrak(Map* pMap); ~instance_gundrak() {} - void Initialize(); + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureEnterCombat(Creature* pCreature) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + ObjectGuid SelectRandomSladranTargetGuid(); - void Update(uint32 uiDiff); + void SetLessRabiAchievementCriteria(bool bIsMet) { m_bLessRabi = bIsMet; } + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + + void Update(uint32 uiDiff) override; protected: void DoAltarVisualEffect(uint8 uiType); @@ -88,9 +105,16 @@ class MANGOS_DLL_DECL instance_gundrak : public ScriptedInstance TypeTimerMap m_mBeamInProgress; TypeTimerMap m_mKeyInProgress; - GUIDList m_luiStalkerGUIDs; - GUIDVector m_vStalkerCasterGuids; - GUIDVector m_vStalkerTargetGuids; + GuidList m_luiStalkerGUIDs; + GuidList m_lSummonTargetsGuids; + GuidVector m_vStalkerCasterGuids; + GuidVector m_vStalkerTargetGuids; + GuidSet m_sColossusMojosGuids; + + bool m_bLessRabi; + + std::set m_uisShareLoveAchievPlayers; + std::set m_uisWhySnakesAchievPlayers; }; #endif diff --git a/scripts/northrend/gundrak/instance_gundrak.cpp b/scripts/northrend/gundrak/instance_gundrak.cpp index 6081b706b..acc831abe 100644 --- a/scripts/northrend/gundrak/instance_gundrak.cpp +++ b/scripts/northrend/gundrak/instance_gundrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,14 +24,14 @@ EndScriptData */ #include "precompiled.h" #include "gundrak.h" -bool GOUse_go_gundrak_altar(Player* pPlayer, GameObject* pGo) +bool GOUse_go_gundrak_altar(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); if (!pInstance) return false; - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_ALTAR_OF_SLADRAN: pInstance->SetData(TYPE_SLADRAN, SPECIAL); break; case GO_ALTAR_OF_MOORABI: pInstance->SetData(TYPE_MOORABI, SPECIAL); break; @@ -42,7 +42,8 @@ bool GOUse_go_gundrak_altar(Player* pPlayer, GameObject* pGo) return true; } -instance_gundrak::instance_gundrak(Map* pMap) : ScriptedInstance(pMap) +instance_gundrak::instance_gundrak(Map* pMap) : ScriptedInstance(pMap), + m_bLessRabi(false) { Initialize(); } @@ -57,7 +58,7 @@ void instance_gundrak::Initialize() void instance_gundrak::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_SLADRAN: case NPC_ELEMENTAL: @@ -68,6 +69,15 @@ void instance_gundrak::OnCreatureCreate(Creature* pCreature) case NPC_INVISIBLE_STALKER: m_luiStalkerGUIDs.push_back(pCreature->GetObjectGuid()); break; + case NPC_SLADRAN_SUMMON_T: + m_lSummonTargetsGuids.push_back(pCreature->GetObjectGuid()); + break; + + case NPC_LIVIN_MOJO: + // Store only the Mojos used to activate the Colossus + if (pCreature->GetPositionX() > 1650.0f) + m_sColossusMojosGuids.insert(pCreature->GetObjectGuid()); + break; } } @@ -86,7 +96,7 @@ void instance_gundrak::OnCreatureCreate(Creature* pCreature) void instance_gundrak::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_ECK_DOOR: if (m_auiEncounter[TYPE_MOORABI] == DONE && !instance->IsRegularDifficulty()) @@ -118,7 +128,7 @@ void instance_gundrak::OnObjectCreate(GameObject* pGo) case GO_ALTAR_OF_COLOSSUS: if (m_auiEncounter[TYPE_COLOSSUS] == DONE) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); - break; + break; case GO_SNAKE_KEY: case GO_TROLL_KEY: case GO_MAMMOTH_KEY: @@ -146,7 +156,7 @@ void instance_gundrak::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[TYPE_SLADRAN] >> m_auiEncounter[TYPE_MOORABI] >> m_auiEncounter[TYPE_COLOSSUS] >> m_auiEncounter[TYPE_GALDARAH] >> m_auiEncounter[TYPE_ECK]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -163,13 +173,15 @@ void instance_gundrak::SetData(uint32 uiType, uint32 uiData) { debug_log("SD2: Instance Gundrak: SetData received for type %u with data %u", uiType, uiData); - switch(uiType) + switch (uiType) { case TYPE_SLADRAN: m_auiEncounter[TYPE_SLADRAN] = uiData; if (uiData == DONE) if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_ALTAR_OF_SLADRAN)) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + if (uiData == FAIL) + m_uisWhySnakesAchievPlayers.clear(); if (uiData == SPECIAL) m_mAltarInProgress.insert(TypeTimerPair(TYPE_SLADRAN, TIMER_VISUAL_ALTAR)); break; @@ -182,6 +194,8 @@ void instance_gundrak::SetData(uint32 uiType, uint32 uiData) if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_ALTAR_OF_MOORABI)) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); } + if (uiData == IN_PROGRESS) + SetLessRabiAchievementCriteria(true); if (uiData == SPECIAL) m_mAltarInProgress.insert(TypeTimerPair(TYPE_MOORABI, TIMER_VISUAL_ALTAR)); break; @@ -190,6 +204,14 @@ void instance_gundrak::SetData(uint32 uiType, uint32 uiData) if (uiData == DONE) if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_ALTAR_OF_COLOSSUS)) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + if (uiData == FAIL) + { + for (GuidSet::const_iterator itr = m_sColossusMojosGuids.begin(); itr != m_sColossusMojosGuids.end(); ++itr) + { + if (Creature* pMojo = instance->GetCreature(*itr)) + pMojo->Respawn(); + } + } if (uiData == SPECIAL) m_mAltarInProgress.insert(TypeTimerPair(TYPE_COLOSSUS, TIMER_VISUAL_ALTAR)); break; @@ -201,14 +223,26 @@ void instance_gundrak::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_EXIT_DOOR_L); DoUseDoorOrButton(GO_EXIT_DOOR_R); } + if (uiData == FAIL) + m_uisShareLoveAchievPlayers.clear(); break; case TYPE_ECK: m_auiEncounter[TYPE_ECK] = uiData; if (uiData == DONE) DoUseDoorOrButton(GO_ECK_UNDERWATER_DOOR); break; + case TYPE_ACHIEV_WHY_SNAKES: + // insert the players who failed the achiev and haven't been already inserted in the set + if (m_uisWhySnakesAchievPlayers.find(uiData) == m_uisWhySnakesAchievPlayers.end()) + m_uisWhySnakesAchievPlayers.insert(uiData); + break; + case TYPE_ACHIEV_SHARE_LOVE: + // insert players who got stampeled and haven't been already inserted in the set + if (m_uisShareLoveAchievPlayers.find(uiData) == m_uisShareLoveAchievPlayers.end()) + m_uisShareLoveAchievPlayers.insert(uiData); + break; default: - error_log("SD2: Instance Gundrak: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Gundrak: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); return; } @@ -218,7 +252,7 @@ void instance_gundrak::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[TYPE_SLADRAN] << " " << m_auiEncounter[TYPE_MOORABI] << " " << m_auiEncounter[TYPE_COLOSSUS] << " " << m_auiEncounter[TYPE_GALDARAH] << " " - << m_auiEncounter[TYPE_ECK]; + << m_auiEncounter[TYPE_ECK]; m_strInstData = saveStream.str(); @@ -227,7 +261,7 @@ void instance_gundrak::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_gundrak::GetData(uint32 uiType) +uint32 instance_gundrak::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -235,6 +269,53 @@ uint32 instance_gundrak::GetData(uint32 uiType) return 0; } +bool instance_gundrak::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_LESS_RABI: + return m_bLessRabi; + case ACHIEV_CRIT_SHARE_LOVE: + // Return true if all the players in the group got stampeled + return m_uisShareLoveAchievPlayers.size() == MIN_LOVE_SHARE_PLAYERS; + // ToDo: enable this criteria when the script will be implemented + // case ACHIEV_CRIT_WHY_SNAKES: + // // Return true if not found in the set + // return m_uisWhySnakesAchievPlayers.find(pSource->GetGUIDLow()) == m_uisWhySnakesAchievPlayers.end(); + + default: + return false; + } +} + +void instance_gundrak::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_LIVIN_MOJO) + { + // If not found in the set, or the event is already started, return + if (m_sColossusMojosGuids.find(pCreature->GetObjectGuid()) == m_sColossusMojosGuids.end()) + return; + + // Move all 4 Mojos to evade and move to the Colossus position + for (GuidSet::const_iterator itr = m_sColossusMojosGuids.begin(); itr != m_sColossusMojosGuids.end(); ++itr) + { + if (Creature* pMojo = instance->GetCreature(*itr)) + pMojo->AI()->EnterEvadeMode(); + } + } +} + +ObjectGuid instance_gundrak::SelectRandomSladranTargetGuid() +{ + if (m_lSummonTargetsGuids.empty()) + return ObjectGuid(); + + GuidList::iterator iter = m_lSummonTargetsGuids.begin(); + advance(iter, urand(0, m_lSummonTargetsGuids.size() - 1)); + + return *iter; +} + static bool sortFromEastToWest(Creature* pFirst, Creature* pSecond) { return pFirst && pSecond && pFirst->GetPositionY() < pSecond->GetPositionY(); @@ -250,7 +331,7 @@ void instance_gundrak::DoAltarVisualEffect(uint8 uiType) fHeight += pCollusAltar->GetPositionZ(); std::list lStalkerTargets, lStalkerCasters; - for (GUIDList::const_iterator itr = m_luiStalkerGUIDs.begin(); itr != m_luiStalkerGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiStalkerGUIDs.begin(); itr != m_luiStalkerGUIDs.end(); ++itr) { if (Creature* pStalker = instance->GetCreature(*itr)) { @@ -295,7 +376,7 @@ void instance_gundrak::DoAltarVisualEffect(uint8 uiType) uint32 auiFireBeamSpells[3] = {SPELL_BEAM_SNAKE, SPELL_BEAM_ELEMENTAL, SPELL_BEAM_MAMMOTH}; // Cast from Caster to Target - pCaster->CastSpell(pTarget, auiFireBeamSpells[uiIndex], true); + pCaster->CastSpell(pTarget, auiFireBeamSpells[uiIndex], false); } void instance_gundrak::Update(uint32 uiDiff) @@ -357,7 +438,7 @@ void instance_gundrak::Update(uint32 uiDiff) { // Activate Bridge (and all other Keys) if we are on the last Key, and all other keys are already set if (m_auiEncounter[0] == SPECIAL && m_auiEncounter[1] == SPECIAL && m_auiEncounter[2] == SPECIAL - && m_mAltarInProgress.empty() && m_mBeamInProgress.empty() && m_mKeyInProgress.size() == 1) + && m_mAltarInProgress.empty() && m_mBeamInProgress.empty() && m_mKeyInProgress.size() == 1) { DoUseDoorOrButton(GO_COLLISION); DoUseDoorOrButton(GO_RHINO_KEY, 0, true); diff --git a/scripts/northrend/howling_fjord.cpp b/scripts/northrend/howling_fjord.cpp index bdf5c858b..adf91410b 100644 --- a/scripts/northrend/howling_fjord.cpp +++ b/scripts/northrend/howling_fjord.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Howling_Fjord SD%Complete: ? -SDComment: Quest support: 11221, 11300, 11464, 11343 +SDComment: Quest support: 11154, 11241, 11300, 11343, 11344, 11464, 11476. SDCategory: Howling Fjord EndScriptData */ @@ -25,17 +25,21 @@ EndScriptData */ npc_ancient_male_vrykul at_ancient_male_vrykul npc_daegarn -npc_deathstalker_razael - TODO, can be moved to database -npc_dark_ranger_lyana - TODO, can be moved to database npc_silvermoon_harry +npc_lich_king_village +npc_king_ymiron +npc_firecrackers_bunny +npc_apothecary_hanes +npc_scalawag_frog EndContentData */ #include "precompiled.h" +#include "escort_ai.h" enum { SPELL_ECHO_OF_YMIRON = 42786, - SPELL_SECRET_OF_NIFFELVAR = 43458, + SPELL_SECRET_OF_WYRMSKULL = 43458, QUEST_ECHO_OF_YMIRON = 11343, NPC_MALE_VRYKUL = 24314, NPC_FEMALE_VRYKUL = 24315, @@ -49,7 +53,7 @@ enum SAY_VRYKUL_HIDE = -1000641, }; -struct MANGOS_DLL_DECL npc_ancient_male_vrykulAI : public ScriptedAI +struct npc_ancient_male_vrykulAI : public ScriptedAI { npc_ancient_male_vrykulAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -57,7 +61,7 @@ struct MANGOS_DLL_DECL npc_ancient_male_vrykulAI : public ScriptedAI uint32 m_uiPhase; uint32 m_uiPhaseTimer; - void Reset() + void Reset() override { m_bEventInProgress = false; m_uiPhase = 0; @@ -72,7 +76,7 @@ struct MANGOS_DLL_DECL npc_ancient_male_vrykulAI : public ScriptedAI m_bEventInProgress = true; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_bEventInProgress) return; @@ -87,7 +91,7 @@ struct MANGOS_DLL_DECL npc_ancient_male_vrykulAI : public ScriptedAI Creature* pFemale = GetClosestCreatureWithEntry(m_creature, NPC_FEMALE_VRYKUL, 10.0f); - switch(m_uiPhase) + switch (m_uiPhase) { case 0: DoScriptText(SAY_VRYKUL_CURSED, m_creature); @@ -110,7 +114,7 @@ struct MANGOS_DLL_DECL npc_ancient_male_vrykulAI : public ScriptedAI DoScriptText(SAY_VRYKUL_HIDE, pFemale); break; case 5: - DoCastSpellIfCan(m_creature, SPELL_SECRET_OF_NIFFELVAR); + DoCastSpellIfCan(m_creature, SPELL_SECRET_OF_WYRMSKULL); break; case 6: Reset(); @@ -126,10 +130,10 @@ CreatureAI* GetAI_npc_ancient_male_vrykul(Creature* pCreature) return new npc_ancient_male_vrykulAI(pCreature); } -bool AreaTrigger_at_ancient_male_vrykul(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_ancient_male_vrykul(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (pPlayer->isAlive() && pPlayer->GetQuestStatus(QUEST_ECHO_OF_YMIRON) == QUEST_STATUS_INCOMPLETE && - pPlayer->HasAura(SPELL_ECHO_OF_YMIRON)) + pPlayer->HasAura(SPELL_ECHO_OF_YMIRON)) { if (Creature* pCreature = GetClosestCreatureWithEntry(pPlayer, NPC_MALE_VRYKUL, 20.0f)) { @@ -163,14 +167,14 @@ static float afSummon[] = {838.81f, -4678.06f, -94.182f}; static float afCenter[] = {801.88f, -4721.87f, -96.143f}; // TODO: make prisoners help (unclear if summoned or using npc's from surrounding cages (summon inside small cages?)) -struct MANGOS_DLL_DECL npc_daegarnAI : public ScriptedAI +struct npc_daegarnAI : public ScriptedAI { npc_daegarnAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } bool m_bEventInProgress; ObjectGuid m_playerGuid; - void Reset() + void Reset() override { m_bEventInProgress = false; m_playerGuid.Clear(); @@ -186,7 +190,7 @@ struct MANGOS_DLL_DECL npc_daegarnAI : public ScriptedAI SummonGladiator(NPC_FIRJUS); } - void JustSummoned(Creature* pSummon) + void JustSummoned(Creature* pSummon) override { if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { @@ -203,10 +207,10 @@ struct MANGOS_DLL_DECL npc_daegarnAI : public ScriptedAI void SummonGladiator(uint32 uiEntry) { - m_creature->SummonCreature(uiEntry, afSummon[0], afSummon[1], afSummon[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20*IN_MILLISECONDS); + m_creature->SummonCreature(uiEntry, afSummon[0], afSummon[1], afSummon[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20 * IN_MILLISECONDS); } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 /*uiMotionType*/, uint32 /*uiPointId*/) override { Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); @@ -221,12 +225,12 @@ struct MANGOS_DLL_DECL npc_daegarnAI : public ScriptedAI pSummoned->AI()->AttackStart(pPlayer); } - void SummonedCreatureDespawn(Creature* pSummoned) + void SummonedCreatureDespawn(Creature* pSummoned) override { uint32 uiEntry = 0; // will eventually reset the event if something goes wrong - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_FIRJUS: uiEntry = NPC_JLARBORN; break; case NPC_JLARBORN: uiEntry = NPC_YOROS; break; @@ -254,149 +258,6 @@ CreatureAI* GetAI_npc_daegarn(Creature* pCreature) return new npc_daegarnAI(pCreature); } -/*###### -## npc_deathstalker_razael - TODO, can be moved to database -######*/ - -#define GOSSIP_ITEM_DEATHSTALKER_RAZAEL "High Executor Anselm requests your report." - -enum -{ - QUEST_REPORTS_FROM_THE_FIELD = 11221, - SPELL_RAZAEL_KILL_CREDIT = 42756, - GOSSIP_TEXTID_DEATHSTALKER_RAZAEL1 = 11562, - GOSSIP_TEXTID_DEATHSTALKER_RAZAEL2 = 11564 -}; - -bool GossipHello_npc_deathstalker_razael(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(QUEST_REPORTS_FROM_THE_FIELD) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DEATHSTALKER_RAZAEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEATHSTALKER_RAZAEL1, pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_deathstalker_razael(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DEATHSTALKER_RAZAEL2, pCreature->GetObjectGuid()); - pCreature->CastSpell(pPlayer, SPELL_RAZAEL_KILL_CREDIT, true); - break; - } - - return true; -} - -/*###### -## npc_dark_ranger_lyana - TODO, can be moved to database -######*/ - -#define GOSSIP_ITEM_DARK_RANGER_LYANA "High Executor Anselm requests your report." - -enum -{ - GOSSIP_TEXTID_DARK_RANGER_LYANA1 = 11586, - GOSSIP_TEXTID_DARK_RANGER_LYANA2 = 11588, - SPELL_DARK_RANGER_LYANA_KILL_CREDIT = 42799 -}; - -bool GossipHello_npc_dark_ranger_lyana(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(QUEST_REPORTS_FROM_THE_FIELD) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_DARK_RANGER_LYANA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DARK_RANGER_LYANA1, pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_dark_ranger_lyana(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_DARK_RANGER_LYANA2, pCreature->GetObjectGuid()); - pCreature->CastSpell(pPlayer, SPELL_DARK_RANGER_LYANA_KILL_CREDIT, true); - break; - } - - return true; -} - -/*###### -## npc_greer_orehammer -######*/ - -enum -{ - GOSSIP_ITEM_TAXI = -3000106, - GOSSIP_ITEM_GET_BOMBS = -3000107, - GOSSIP_ITEM_FLIGHT = -3000108, - - QUEST_MISSION_PLAGUE_THIS = 11332, - ITEM_PRECISION_BOMBS = 33634, - TAXI_PATH_PLAGUE_THIS = 745, -}; - -bool GossipHello_npc_greer_orehammer(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(QUEST_MISSION_PLAGUE_THIS) == QUEST_STATUS_INCOMPLETE) - { - if (!pPlayer->HasItemCount(ITEM_PRECISION_BOMBS, 1, true)) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_GET_BOMBS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FLIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - } - - if (pCreature->isTaxi()) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_TAXI, GOSSIP_ITEM_TAXI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_greer_orehammer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_PRECISION_BOMBS, 10)) - pPlayer->SendNewItem(pItem, 10, true, false); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_PLAGUE_THIS); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->GetSession()->SendTaxiMenu(pCreature); - break; - } - - return true; -} - /*###### ## npc_silvermoon_harry ######*/ @@ -418,7 +279,7 @@ enum FACTION_HOSTILE_SH = 90, // guessed, possibly not correct }; -struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI +struct npc_silvermoon_harryAI : public ScriptedAI { npc_silvermoon_harryAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -427,21 +288,18 @@ struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI uint32 m_uiScorchTimer; uint32 m_uiResetBeatenTimer; - void Reset() + void Reset() override { m_bHarryBeaten = false; // timers guessed - m_uiScorchTimer = 5*IN_MILLISECONDS; - m_uiBlastWaveTimer = 7*IN_MILLISECONDS; + m_uiScorchTimer = 5 * IN_MILLISECONDS; + m_uiBlastWaveTimer = 7 * IN_MILLISECONDS; - m_uiResetBeatenTimer = MINUTE*IN_MILLISECONDS; - - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); + m_uiResetBeatenTimer = MINUTE * IN_MILLISECONDS; } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -450,9 +308,9 @@ struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { - if (uiDamage > m_creature->GetHealth() || (m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() < 20) + if (uiDamage > m_creature->GetHealth() || (m_creature->GetHealth() - uiDamage) * 100 / m_creature->GetMaxHealth() < 20) { if (Player* pPlayer = pDoneBy->GetCharmerOrOwnerPlayerOrPlayerItself()) { @@ -460,13 +318,10 @@ struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI { uiDamage = 0; // Take 0 damage - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnDeath(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); - DoScriptText(SAY_BEATEN, m_creature); m_bHarryBeaten = true; } @@ -479,14 +334,14 @@ struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI return m_bHarryBeaten; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bHarryBeaten) { if (m_uiResetBeatenTimer < uiDiff) EnterEvadeMode(); else - m_uiResetBeatenTimer-= uiDiff; + m_uiResetBeatenTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -495,7 +350,7 @@ struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI if (m_uiScorchTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_SCORCH); - m_uiScorchTimer = 10*IN_MILLISECONDS; + m_uiScorchTimer = 10 * IN_MILLISECONDS; } else m_uiScorchTimer -= uiDiff; @@ -503,7 +358,7 @@ struct MANGOS_DLL_DECL npc_silvermoon_harryAI : public ScriptedAI if (m_uiBlastWaveTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE); - m_uiBlastWaveTimer = 50*IN_MILLISECONDS; + m_uiBlastWaveTimer = 50 * IN_MILLISECONDS; } else m_uiBlastWaveTimer -= uiDiff; @@ -541,9 +396,9 @@ bool GossipHello_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_TRADE: pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); @@ -552,7 +407,7 @@ bool GossipSelect_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature, uin pPlayer->CLOSE_GOSSIP_MENU(); DoScriptText(SAY_AGGRO, pCreature, pPlayer); - pCreature->setFaction(FACTION_HOSTILE_SH); + pCreature->SetFactionTemporary(FACTION_HOSTILE_SH, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_COMBAT_STOP); pCreature->AI()->AttackStart(pPlayer); break; case GOSSIP_ACTION_INFO_DEF+2: @@ -571,6 +426,584 @@ bool GossipSelect_npc_silvermoon_harry(Player* pPlayer, Creature* pCreature, uin return true; } +/*###### +## npc_lich_king_village +######*/ + +enum +{ + EMOTE_LICH_KING_FACE = -1000920, + SAY_LICH_KING_1 = -1000921, + SAY_PREPARE = -1000922, + SAY_LICH_KING_2 = -1000923, + SAY_LICH_KING_3 = -1000924, + SAY_LICH_KING_4 = -1000925, + SAY_LICH_KING_5 = -1000926, + SAY_PERSISTANCE = -1000927, + + SPELL_GRASP_OF_THE_LICH_KING = 43489, + SPELL_MAGNETIC_PULL = 29661, + SPELL_WRATH_LICH_KING_FIRST = 43488, + SPELL_WRATH_LICH_KING = 50156, + + NPC_VALKYR_SOULCLAIMER = 24327, + NPC_LICH_KING_WYRMSKULL = 24248, + + QUEST_ID_LK_FLAG = 12485, // Server side dummy quest +}; + +static const DialogueEntry aLichDialogue[] = +{ + // first time dialogue only + {EMOTE_LICH_KING_FACE, NPC_LICH_KING_WYRMSKULL, 4000}, + {QUEST_ID_LK_FLAG, 0, 3000}, + {SAY_LICH_KING_1, NPC_LICH_KING_WYRMSKULL, 20000}, + {NPC_VALKYR_SOULCLAIMER, 0, 4000}, + {SAY_LICH_KING_2, NPC_LICH_KING_WYRMSKULL, 10000}, + {SAY_LICH_KING_3, NPC_LICH_KING_WYRMSKULL, 25000}, + {SAY_LICH_KING_4, NPC_LICH_KING_WYRMSKULL, 25000}, + {SAY_LICH_KING_5, NPC_LICH_KING_WYRMSKULL, 20000}, + {SPELL_WRATH_LICH_KING_FIRST, 0, 10000}, + {NPC_LICH_KING_WYRMSKULL, 0, 0}, + // if the player persists... + {SAY_PERSISTANCE, NPC_LICH_KING_WYRMSKULL, 15000}, + {SPELL_WRATH_LICH_KING, 0, 10000}, + {NPC_LICH_KING_WYRMSKULL, 0, 0}, + {0, 0, 0}, +}; + +struct npc_lich_king_villageAI : public ScriptedAI, private DialogueHelper +{ + npc_lich_king_villageAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aLichDialogue) + { + Reset(); + } + + ObjectGuid m_pHeldPlayer; + bool m_bEventInProgress; + + void Reset() override + { + m_bEventInProgress = false; + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case QUEST_ID_LK_FLAG: + m_creature->HandleEmote(EMOTE_ONESHOT_LAUGH); + break; + case NPC_VALKYR_SOULCLAIMER: + if (Creature* pCreature = GetClosestCreatureWithEntry(m_creature, NPC_VALKYR_SOULCLAIMER, 20.0f)) + DoScriptText(SAY_PREPARE, pCreature); + break; + case SPELL_WRATH_LICH_KING_FIRST: + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_pHeldPlayer)) + { + DoCastSpellIfCan(pPlayer, SPELL_WRATH_LICH_KING_FIRST); + // handle spell scriptEffect in the script + m_creature->DealDamage(pPlayer, pPlayer->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + break; + case SPELL_WRATH_LICH_KING: + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_pHeldPlayer)) + { + DoCastSpellIfCan(pPlayer, SPELL_WRATH_LICH_KING); + // handle spell scriptEffect in the script + m_creature->DealDamage(pPlayer, pPlayer->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + break; + case NPC_LICH_KING_WYRMSKULL: + EnterEvadeMode(); + break; + } + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bEventInProgress && pWho->GetTypeId() == TYPEID_PLAYER) + { + if (pWho->isAlive() && m_creature->IsWithinDistInMap(pWho, 15.0) && pWho->HasAura(SPELL_ECHO_OF_YMIRON)) + { + m_pHeldPlayer = pWho->GetObjectGuid(); + m_bEventInProgress = true; + + DoCastSpellIfCan(pWho, SPELL_MAGNETIC_PULL, CAST_TRIGGERED); + DoCastSpellIfCan(pWho, SPELL_GRASP_OF_THE_LICH_KING, CAST_TRIGGERED); + + if (((Player*)pWho)->GetQuestStatus(QUEST_ID_LK_FLAG) == QUEST_STATUS_COMPLETE) + StartNextDialogueText(SAY_PERSISTANCE); + else + StartNextDialogueText(EMOTE_LICH_KING_FACE); + } + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_LICH_KING_WYRMSKULL) + return m_creature; + + return NULL; + } + + void UpdateAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); } +}; + +CreatureAI* GetAI_npc_lich_king_village(Creature* pCreature) +{ + return new npc_lich_king_villageAI(pCreature); +} + +/*###### +## npc_king_ymiron +######*/ + +enum +{ + EMOTE_KING_SILENCE = -1000928, + SAY_KING_YMIRON_SPEECH_1 = -1000929, + SAY_KING_YMIRON_SPEECH_2 = -1000930, + EMOTE_YMIRON_CROWD_1 = -1000931, + SAY_KING_YMIRON_SPEECH_3 = -1000932, + SAY_KING_YMIRON_SPEECH_4 = -1000933, + SAY_KING_YMIRON_SPEECH_5 = -1000934, + SAY_KING_YMIRON_SPEECH_6 = -1000935, + SAY_KING_YMIRON_SPEECH_7 = -1000936, + EMOTE_YMIRON_CROWD_2 = -1000937, + SAY_KING_YMIRON_SPEECH_8 = -1000938, + EMOTE_YMIRON_CROWD_3 = -1000939, + SAY_KING_YMIRON_SPEECH_9 = -1000940, + + SPELL_ECHO_OF_YMIRON_NIFFLEVAR = 43466, + SPELL_SECRETS_OF_NIFFLEVAR = 43468, + + NPC_CITIZEN_OF_NIFFLEVAR_MALE = 24322, + NPC_CITIZEN_OF_NIFFLEVAR_FEMALE = 24323, + NPC_KING_YMIRON = 24321, + + QUEST_ID_ANGUISH_OF_NIFFLEVAR = 11344, + + MAX_CROWD_TEXT_ENTRIES = 7 +}; + +static const DialogueEntry aNifflevarDialogue[] = +{ + {EMOTE_KING_SILENCE, NPC_KING_YMIRON, 3000}, + {SAY_KING_YMIRON_SPEECH_1, NPC_KING_YMIRON, 5000}, + {SAY_KING_YMIRON_SPEECH_2, NPC_KING_YMIRON, 2000}, + {EMOTE_YMIRON_CROWD_1, NPC_KING_YMIRON, 5000}, + {SAY_KING_YMIRON_SPEECH_3, NPC_KING_YMIRON, 10000}, + {SAY_KING_YMIRON_SPEECH_4, NPC_KING_YMIRON, 9000}, + {SAY_KING_YMIRON_SPEECH_5, NPC_KING_YMIRON, 7000}, + {SAY_KING_YMIRON_SPEECH_6, NPC_KING_YMIRON, 5000}, + {SAY_KING_YMIRON_SPEECH_7, NPC_KING_YMIRON, 9000}, + {EMOTE_YMIRON_CROWD_2, NPC_KING_YMIRON, 5000}, + {SAY_KING_YMIRON_SPEECH_8, NPC_KING_YMIRON, 8000}, + {EMOTE_YMIRON_CROWD_3, NPC_KING_YMIRON, 4000}, + {SAY_KING_YMIRON_SPEECH_9, NPC_KING_YMIRON, 10000}, + {SPELL_SECRETS_OF_NIFFLEVAR, 0, 10000}, + {QUEST_ID_ANGUISH_OF_NIFFLEVAR, 0, 0}, + {0, 0, 0}, +}; + +static const int32 aRandomTextEntries[MAX_CROWD_TEXT_ENTRIES] = { -1000941, -1000942, -1000943, -1000944, -1000945, -1000946, -1000947}; + +struct npc_king_ymironAI : public ScriptedAI, private DialogueHelper +{ + npc_king_ymironAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aNifflevarDialogue) + { + Reset(); + } + + uint32 m_uiCrowdSpeechTimer; + + bool m_bEventInProgress; + bool m_bEventInit; + + GuidList m_lCrowdGuidList; + + void Reset() override + { + m_uiCrowdSpeechTimer = 0; + m_bEventInit = false; + m_bEventInProgress = false; + m_lCrowdGuidList.clear(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bEventInit && pWho->GetTypeId() == TYPEID_PLAYER) + { + // Get all the citizen around the king for future use + if (pWho->isAlive() && m_creature->IsWithinDistInMap(pWho, 60.0) && ((Player*)pWho)->GetQuestStatus(QUEST_ID_ANGUISH_OF_NIFFLEVAR) == QUEST_STATUS_INCOMPLETE + && pWho->HasAura(SPELL_ECHO_OF_YMIRON_NIFFLEVAR)) + { + std::list lCrowdList; + GetCreatureListWithEntryInGrid(lCrowdList, m_creature, NPC_CITIZEN_OF_NIFFLEVAR_MALE, 60.0f); + GetCreatureListWithEntryInGrid(lCrowdList, m_creature, NPC_CITIZEN_OF_NIFFLEVAR_FEMALE, 60.0f); + + for (std::list::const_iterator itr = lCrowdList.begin(); itr != lCrowdList.end(); ++itr) + m_lCrowdGuidList.push_back((*itr)->GetObjectGuid()); + + m_uiCrowdSpeechTimer = 1000; + m_bEventInit = true; + } + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case SPELL_SECRETS_OF_NIFFLEVAR: + DoCastSpellIfCan(m_creature, SPELL_SECRETS_OF_NIFFLEVAR); + break; + case QUEST_ID_ANGUISH_OF_NIFFLEVAR: + EnterEvadeMode(); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + if (uiEntry == NPC_KING_YMIRON) + return m_creature; + + return NULL; + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + if (m_bEventInProgress) + return; + + StartNextDialogueText(EMOTE_KING_SILENCE); + m_uiCrowdSpeechTimer = 0; + m_bEventInProgress = true; + } + } + + ObjectGuid SelectRandomCrowdNpc() + { + if (m_lCrowdGuidList.empty()) + return ObjectGuid(); + + GuidList::iterator iter = m_lCrowdGuidList.begin(); + advance(iter, urand(0, m_lCrowdGuidList.size() - 1)); + + return *iter; + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (m_uiCrowdSpeechTimer) + { + if (m_uiCrowdSpeechTimer <= uiDiff) + { + // only 15% chance to yell (guessed) + if (roll_chance_i(15)) + { + if (Creature* pCitizen = m_creature->GetMap()->GetCreature(SelectRandomCrowdNpc())) + DoScriptText(aRandomTextEntries[urand(0, MAX_CROWD_TEXT_ENTRIES - 1)], pCitizen); + } + + m_uiCrowdSpeechTimer = 1000; + } + else + m_uiCrowdSpeechTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_king_ymiron(Creature* pCreature) +{ + return new npc_king_ymironAI(pCreature); +} + +bool AreaTrigger_at_nifflevar(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pPlayer->isAlive() && pPlayer->GetQuestStatus(QUEST_ID_ANGUISH_OF_NIFFLEVAR) == QUEST_STATUS_INCOMPLETE && pPlayer->HasAura(SPELL_ECHO_OF_YMIRON_NIFFLEVAR)) + { + if (Creature* pCreature = GetClosestCreatureWithEntry(pPlayer, NPC_KING_YMIRON, 30.0f)) + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pCreature); + + return true; + } + + return false; +} + +/*###### +## npc_firecrackers_bunny +######*/ + +enum +{ + SPELL_FIRECRACKER_VISUAL = 43314, + SPELL_SUMMON_DARKCLAW_GUANO = 43307, + + NPC_DARKCLAW_BAT = 23959, +}; + +struct npc_firecrackers_bunnyAI : public ScriptedAI +{ + npc_firecrackers_bunnyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiStartTimer; + bool m_bHasValidBat; + + ObjectGuid m_selectedBatGuid; + + void Reset() override + { + m_uiStartTimer = 1000; + m_bHasValidBat = false; + + DoCastSpellIfCan(m_creature, SPELL_FIRECRACKER_VISUAL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bHasValidBat && pWho->GetObjectGuid() == m_selectedBatGuid && m_creature->IsWithinDistInMap(pWho, 3.5f)) + { + // spawn the Guano loot + pWho->GetMotionMaster()->MoveIdle(); + pWho->CastSpell(m_creature, SPELL_SUMMON_DARKCLAW_GUANO, true); + m_bHasValidBat = false; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiStartTimer) + { + if (m_uiStartTimer <= uiDiff) + { + // get all the bats list in range; note: this will compare the 2D distance + std::list lBatsList; + GetCreatureListWithEntryInGrid(lBatsList, m_creature, NPC_DARKCLAW_BAT, 10.0f); + + if (lBatsList.empty()) + { + m_uiStartTimer = 5000; + return; + } + + // sort by distance and get only the closest + lBatsList.sort(ObjectDistanceOrder(m_creature)); + + std::list::const_iterator batItr = lBatsList.begin(); + Creature* pBat = NULL; + + do + { + // check for alive and out of combat only + if ((*batItr)->isAlive() && !(*batItr)->getVictim()) + pBat = *batItr; + + ++batItr; + } + while (!pBat && batItr != lBatsList.end()); + + if (!pBat) + { + m_uiStartTimer = 5000; + return; + } + + // Move bat to the point + float fX, fY, fZ; + pBat->SetWalk(false); + pBat->GetMotionMaster()->Clear(); + m_creature->GetContactPoint(pBat, fX, fY, fZ); + pBat->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + + m_selectedBatGuid = pBat->GetObjectGuid(); + m_uiStartTimer = 0; + m_bHasValidBat = true; + } + else + m_uiStartTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_firecrackers_bunny(Creature* pCreature) +{ + return new npc_firecrackers_bunnyAI(pCreature); +} + +/*###### +## npc_apothecary_hanes +######*/ + +enum +{ + // yells + SAY_HANES_ESCORT_START = -1001064, + SAY_HANES_FIRE_1 = -1001065, + SAY_HANES_FIRE_2 = -1001066, + SAY_HANES_SUPPLIES_1 = -1001067, + SAY_HANES_SUPPLIES_2 = -1001068, + SAY_HANES_SUPPLIES_ESCAPE = -1001069, + SAY_HANES_SUPPLIES_COMPLETE = -1001070, + SAY_HANES_ARRIVE_BASE = -1001071, + + // spells + SPELL_HEALING_POTION = 17534, + SPELL_LOW_POLY_FIRE = 51195, + + // misc + NPC_HANES_TRIGGER = 23968, + QUEST_ID_TRIAL_OF_FIRE = 11241, +}; + +struct npc_apothecary_hanesAI : public npc_escortAI +{ + npc_apothecary_hanesAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiHealingTimer; + + void Reset() override + { + m_uiHealingTimer = 0; + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + Start(true, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + DoScriptText(SAY_HANES_ESCORT_START, m_creature); + m_creature->SetFactionTemporary(FACTION_ESCORT_H_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + DoScriptText(SAY_HANES_FIRE_1, m_creature); + break; + case 3: + DoScriptText(SAY_HANES_FIRE_2, m_creature); + break; + case 14: + case 20: + case 21: + case 29: + { + m_creature->HandleEmote(EMOTE_ONESHOT_ATTACK1H); + + // set all nearby triggers on fire - ToDo: research if done by spell! + std::list lTriggersInRange; + GetCreatureListWithEntryInGrid(lTriggersInRange, m_creature, NPC_HANES_TRIGGER, 10.0f); + + for (std::list::const_iterator itr = lTriggersInRange.begin(); itr != lTriggersInRange.end(); ++itr) + { + (*itr)->CastSpell((*itr), SPELL_LOW_POLY_FIRE, true); + (*itr)->ForcedDespawn(30000); + } + break; + } + case 15: + DoScriptText(SAY_HANES_SUPPLIES_1, m_creature); + break; + case 22: + DoScriptText(SAY_HANES_SUPPLIES_2, m_creature); + break; + case 30: + m_creature->HandleEmote(EMOTE_ONESHOT_LAUGH_NOSHEATHE); + break; + case 31: + DoScriptText(SAY_HANES_SUPPLIES_COMPLETE, m_creature); + break; + case 32: + DoScriptText(SAY_HANES_SUPPLIES_ESCAPE, m_creature); + break; + case 40: + DoScriptText(SAY_HANES_ARRIVE_BASE, m_creature); + break; + case 44: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_TRIAL_OF_FIRE, m_creature); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_creature->GetHealthPercent() < 75.0f) + { + if (m_uiHealingTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HEALING_POTION) == CAST_OK) + m_uiHealingTimer = 10000; + } + else + m_uiHealingTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_apothecary_hanes(Creature* pCreature) +{ + return new npc_apothecary_hanesAI(pCreature); +} + +bool QuestAccept_npc_apothecary_hanes(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_TRIAL_OF_FIRE) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + +/*###### +## npc_scalawag_frog +######*/ + +enum +{ + ITEM_ID_SCALAWAG_FROG = 35803, + ITEM_ID_SHINY_KNIFE = 35813, + NPC_SCALAWAG_FROG = 26503, +}; + +bool NpcSpellClick_npc_scalawag_frog(Player* pPlayer, Creature* pClickedCreature, uint32 /*uiSpellId*/) +{ + if (pClickedCreature->GetEntry() == NPC_SCALAWAG_FROG && pPlayer->HasItemCount(ITEM_ID_SHINY_KNIFE, 1)) + { + if (Item* pItem = pPlayer->StoreNewItemInInventorySlot(ITEM_ID_SCALAWAG_FROG, 1)) + { + pPlayer->SendNewItem(pItem, 1, true, false); + pClickedCreature->ForcedDespawn(); + + // always return true when handled special npc spell click + return true; + } + } + + return true; +} + void AddSC_howling_fjord() { Script* pNewScript; @@ -592,27 +1025,40 @@ void AddSC_howling_fjord() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_deathstalker_razael"; - pNewScript->pGossipHello = &GossipHello_npc_deathstalker_razael; - pNewScript->pGossipSelect = &GossipSelect_npc_deathstalker_razael; + pNewScript->Name = "npc_silvermoon_harry"; + pNewScript->GetAI = &GetAI_npc_silvermoon_harry; + pNewScript->pGossipHello = &GossipHello_npc_silvermoon_harry; + pNewScript->pGossipSelect = &GossipSelect_npc_silvermoon_harry; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_dark_ranger_lyana"; - pNewScript->pGossipHello = &GossipHello_npc_dark_ranger_lyana; - pNewScript->pGossipSelect = &GossipSelect_npc_dark_ranger_lyana; + pNewScript->Name = "npc_lich_king_village"; + pNewScript->GetAI = &GetAI_npc_lich_king_village; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_greer_orehammer"; - pNewScript->pGossipHello = &GossipHello_npc_greer_orehammer; - pNewScript->pGossipSelect = &GossipSelect_npc_greer_orehammer; + pNewScript->Name = "npc_king_ymiron"; + pNewScript->GetAI = &GetAI_npc_king_ymiron; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_silvermoon_harry"; - pNewScript->GetAI = &GetAI_npc_silvermoon_harry; - pNewScript->pGossipHello = &GossipHello_npc_silvermoon_harry; - pNewScript->pGossipSelect = &GossipSelect_npc_silvermoon_harry; + pNewScript->Name = "at_nifflevar"; + pNewScript->pAreaTrigger = &AreaTrigger_at_nifflevar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_firecrackers_bunny"; + pNewScript->GetAI = &GetAI_npc_firecrackers_bunny; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_apothecary_hanes"; + pNewScript->GetAI = &GetAI_npc_apothecary_hanes; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_apothecary_hanes; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scalawag_frog"; + pNewScript->pNpcSpellClick = &NpcSpellClick_npc_scalawag_frog; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown.cpp b/scripts/northrend/icecrown.cpp index 258ba7108..0526a4da1 100644 --- a/scripts/northrend/icecrown.cpp +++ b/scripts/northrend/icecrown.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,48 +17,954 @@ /* ScriptData SDName: Icecrown SD%Complete: 100 -SDComment: Vendor support: 34885 +SDComment: Quest support: 12852, 13221, 13229, 13284, 13300, 13301, 13302, 13481, 13482. SDCategory: Icecrown EndScriptData */ /* ContentData -npc_dame_evniki_kapsalis +npc_squad_leader +npc_infantry +npc_father_kamaros +npc_saronite_mine_slave +npc_grand_admiral_westwind EndContentData */ #include "precompiled.h" +#include "escort_ai.h" /*###### -## npc_dame_evniki_kapsalis +## npc_squad_leader ######*/ enum { - TITLE_CRUSADER = 123 + // yells + SAY_HORDE_SQUAD_RUN = -1001018, + SAY_ALLIANCE_SQUAD_RUN = -1001019, + SAY_SQUAD_AGGRO_1 = -1001020, + SAY_SQUAD_AGGRO_2 = -1001021, + SAY_HORDE_SQUAD_AGGRO_1 = -1001022, + SAY_HORDE_SQUAD_AGGRO_2 = -1001023, + SAY_HORDE_SQUAD_AGGRO_3 = -1001024, + SAY_HORDE_SQUAD_AGGRO_4 = -1001025, + SAY_ALLIANCE_SQUAD_AGGRO_1 = -1001026, + SAY_ALLIANCE_SQUAD_AGGRO_2 = -1001027, + SAY_ALLIANCE_SQUAD_AGGRO_3 = -1001028, + SAY_ALLIANCE_SQUAD_AGGRO_4 = -1001029, + SAY_HORDE_SQUAD_BREAK = -1001030, + SAY_HORDE_SQUAD_BREAK_DONE = -1001031, + SAY_ALLIANCE_SQUAD_BREAK = -1001032, + SAY_ALLIANCE_SQUAD_BREAK_DONE = -1001033, + SAY_EVENT_COMPLETE = -1001034, + SAY_DEFENDER_AGGRO_1 = -1001035, + SAY_DEFENDER_AGGRO_2 = -1001036, + SAY_DEFENDER_AGGRO_3 = -1001037, + SAY_DEFENDER_AGGRO_4 = -1001038, + SAY_DEFENDER_AGGRO_5 = -1001039, + SAY_DEFENDER_AGGRO_6 = -1001040, + SAY_DEFENDER_AGGRO_7 = -1001041, + SAY_DEFENDER_AGGRO_8 = -1001042, + SAY_DEFENDER_AGGRO_9 = -1001043, + + // combat spells + SPELL_CLEAVE = 15496, + SPELL_FROST_SHOT = 12551, + SPELL_ALLIANCE_TROOP_CREDIT = 59677, + SPELL_HORDE_TROOP_CREDIT = 59764, + + NPC_SKYBREAKER_SQUAD_LEADER = 31737, + NPC_SKYBREAKER_INFANTRY = 31701, + NPC_KORKRON_SQUAD_LEADER = 31833, + NPC_KORKRON_INFANTRY = 31832, + NPC_YMIRHEIM_DEFENDER = 31746, + + // quests + QUEST_ID_ASSAULT_BY_GROUND_A = 13284, + QUEST_ID_ASSAULT_BY_GROUND_H = 13301, +}; + +struct npc_squad_leaderAI : public npc_escortAI +{ + npc_squad_leaderAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiCleaveTimer; + uint32 m_uiFrostShotTimer; + + void Reset() override + { + m_uiCleaveTimer = urand(3000, 5000); + m_uiFrostShotTimer = urand(1000, 3000); + } + + void Aggro(Unit* pWho) override + { + switch (urand(0, 5)) + { + case 0: DoScriptText(SAY_SQUAD_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_SQUAD_AGGRO_2, m_creature); break; + case 2: DoScriptText(m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER ? SAY_ALLIANCE_SQUAD_AGGRO_1 : SAY_HORDE_SQUAD_AGGRO_1, m_creature); break; + case 3: DoScriptText(m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER ? SAY_ALLIANCE_SQUAD_AGGRO_2 : SAY_HORDE_SQUAD_AGGRO_2, m_creature); break; + case 4: DoScriptText(m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER ? SAY_ALLIANCE_SQUAD_AGGRO_3 : SAY_HORDE_SQUAD_AGGRO_3, m_creature); break; + case 5: DoScriptText(m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER ? SAY_ALLIANCE_SQUAD_AGGRO_4 : SAY_HORDE_SQUAD_AGGRO_4, m_creature); break; + } + + if (pWho->GetEntry() == NPC_YMIRHEIM_DEFENDER && urand(0, 1)) + { + switch (urand(0, 8)) + { + case 0: DoScriptText(SAY_DEFENDER_AGGRO_1, pWho); break; + case 1: DoScriptText(SAY_DEFENDER_AGGRO_2, pWho); break; + case 2: DoScriptText(SAY_DEFENDER_AGGRO_3, pWho); break; + case 3: DoScriptText(SAY_DEFENDER_AGGRO_4, pWho); break; + case 4: DoScriptText(SAY_DEFENDER_AGGRO_5, pWho); break; + case 5: DoScriptText(SAY_DEFENDER_AGGRO_6, pWho); break; + case 6: DoScriptText(SAY_DEFENDER_AGGRO_7, pWho); break; + case 7: DoScriptText(SAY_DEFENDER_AGGRO_8, pWho); break; + case 8: DoScriptText(SAY_DEFENDER_AGGRO_9, pWho); break; + } + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + SendAIEventAround(AI_EVENT_CUSTOM_A, pInvoker, 0, 12.0f); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_YMIRHEIM_DEFENDER) + pSummoned->AI()->AttackStart(m_creature); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 2: + SetRun(); + DoScriptText(m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER ? SAY_ALLIANCE_SQUAD_RUN : SAY_HORDE_SQUAD_RUN, m_creature); + break; + case 4: + // first horde attack + if (m_creature->GetEntry() == NPC_KORKRON_SQUAD_LEADER) + { + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7433.193f, 1838.199f, 402.43f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7441.071f, 1848.997f, 401.03f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7451.976f, 1850.776f, 402.96f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + break; + case 6: + // first alliance attack + if (m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER) + { + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7217.792f, 1602.024f, 378.86f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7235.733f, 1597.831f, 381.08f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + break; + case 9: + // second horde attack + if (m_creature->GetEntry() == NPC_KORKRON_SQUAD_LEADER) + { + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7420.511f, 1813.180f, 425.14f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7411.768f, 1784.054f, 427.84f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7418.514f, 1805.596f, 425.50f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + break; + case 13: + if (m_creature->GetEntry() == NPC_KORKRON_SQUAD_LEADER) + { + DoScriptText(SAY_HORDE_SQUAD_BREAK, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + } + break; + case 14: + if (m_creature->GetEntry() == NPC_KORKRON_SQUAD_LEADER) + { + DoScriptText(SAY_HORDE_SQUAD_BREAK_DONE, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + } + break; + case 15: + // second alliance attack + if (m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER) + { + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7328.375f, 1631.935f, 416.06f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7334.475f, 1618.401f, 412.93f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7341.556f, 1632.023f, 423.01f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + break; + case 20: + if (m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER) + { + DoScriptText(SAY_ALLIANCE_SQUAD_BREAK, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + } + break; + case 21: + if (m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER) + { + DoScriptText(SAY_ALLIANCE_SQUAD_BREAK_DONE, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + } + break; + case 22: + // horde gate attack + if (m_creature->GetEntry() == NPC_KORKRON_SQUAD_LEADER) + { + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7280.229f, 1725.829f, 471.37f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7272.390f, 1732.530f, 472.43f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7285.863f, 1690.997f, 483.35f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7334.487f, 1690.376f, 443.32f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7371.765f, 1699.052f, 442.50f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + break; + case 25: + // alliance gate attack + if (m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER) + { + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7205.636f, 1648.500f, 453.59f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7224.602f, 1677.164f, 454.65f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7220.114f, 1667.603f, 451.01f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7220.528f, 1634.114f, 434.81f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_YMIRHEIM_DEFENDER, 7237.092f, 1687.461f, 459.81f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + break; + case 26: + { + // event complete + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + DoScriptText(SAY_EVENT_COMPLETE, m_creature); + + // get all the soldiers around + std::list lSoldiersList; + GetCreatureListWithEntryInGrid(lSoldiersList, m_creature, m_creature->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER ? NPC_SKYBREAKER_INFANTRY : NPC_KORKRON_INFANTRY, 30.0f); + + // for each soldier alive cast the kill credit + for (std::list::const_iterator itr = lSoldiersList.begin(); itr != lSoldiersList.end(); ++itr) + { + if ((*itr) && (*itr)->isAlive()) + { + (*itr)->CastSpell(*itr, (*itr)->GetEntry() == NPC_SKYBREAKER_INFANTRY ? SPELL_ALLIANCE_TROOP_CREDIT : SPELL_HORDE_TROOP_CREDIT, true); + (*itr)->ForcedDespawn(10000); + } + } + + // set to pause and despawn on timer + SetEscortPaused(true); + m_creature->ForcedDespawn(10000); + break; + } + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiFrostShotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOT) == CAST_OK) + m_uiFrostShotTimer = urand(1000, 3000); + } + else + m_uiFrostShotTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(3000, 5000); + } + else + m_uiCleaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_squad_leader(Creature* pCreature) +{ + return new npc_squad_leaderAI(pCreature); +} + +bool QuestAccept_npc_squad_leader(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_ASSAULT_BY_GROUND_A || pQuest->GetQuestId() == QUEST_ID_ASSAULT_BY_GROUND_H) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + +/*###### +## npc_infantry +######*/ + +enum +{ + SPELL_SHOOT = 15547, + SPELL_HEROIC_STRIKE = 29426, +}; + +struct npc_infantryAI : public ScriptedAI +{ + npc_infantryAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bEscortActive = false; + Reset(); + } + + uint32 m_uiShootTimer; + uint32 m_uiHeroicStrikeTimer; + + bool m_bEscortActive; + + ObjectGuid m_squadLeaderGuid; + + void Reset() override + { + m_uiShootTimer = urand(1000, 3000); + m_uiHeroicStrikeTimer = urand(3000, 5000); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + Reset(); + + if (!m_creature->isAlive()) + return; + + if (m_bEscortActive) + { + if (Creature* pLeader = m_creature->GetMap()->GetCreature(m_squadLeaderGuid)) + m_creature->GetMotionMaster()->MoveFollow(pLeader, m_creature->GetDistance(pLeader), M_PI_F / 2 + m_creature->GetAngle(pLeader)); + } + else + m_creature->GetMotionMaster()->MoveTargetedHome(); + } + + void JustRespawned() override + { + m_bEscortActive = false; + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 uiMiscValue) override + { + // start following the squad leader + if (eventType == AI_EVENT_CUSTOM_A && (pSender->GetEntry() == NPC_SKYBREAKER_SQUAD_LEADER || pSender->GetEntry() == NPC_KORKRON_SQUAD_LEADER)) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->GetMotionMaster()->MoveFollow(pSender, m_creature->GetDistance(pSender), M_PI_F / 2 + m_creature->GetAngle(pSender)); + m_squadLeaderGuid = pSender->GetObjectGuid(); + m_bEscortActive = true; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiShootTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOOT) == CAST_OK) + m_uiShootTimer = urand(1000, 3000); + } + else + m_uiShootTimer -= uiDiff; + + if (m_uiHeroicStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEROIC_STRIKE) == CAST_OK) + m_uiHeroicStrikeTimer = urand(3000, 5000); + } + else + m_uiHeroicStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_infantry(Creature* pCreature) +{ + return new npc_infantryAI(pCreature); +} + +/*###### +## npc_father_kamaros +######*/ + +enum +{ + // yells + SAY_KAMAROS_START_1 = -1001044, + SAY_KAMAROS_START_2 = -1001045, + SAY_KAMAROS_AGGRO_1 = -1001046, + SAY_KAMAROS_AGGRO_2 = -1001047, + SAY_KAMAROS_AGGRO_3 = -1001048, + SAY_KAMAROS_COMPLETE_1 = -1001050, + SAY_KAMAROS_COMPLETE_2 = -1001049, + + // combat spells + SPELL_HOLY_SMITE = 25054, + SPELL_POWER_WORD_FORTITUDE = 58921, + SPELL_POWER_WORD_SHIELD = 32595, + SPELL_SHADOW_WORD_PAIN = 17146, + + NPC_SPIKED_GHOUL = 30597, + NPC_KAMAROS_1 = 31279, // phase 1 npc + NPC_KAMAROS_2 = 32800, // phase 64 npc + + // quests + // all four quests have the same script; + // they depend only on faction and quest giver (same npc, different entries in different phases); + QUEST_ID_NOT_DEAD_YET_A = 13221, + QUEST_ID_NOT_DEAD_YET_H = 13229, + QUEST_ID_GET_OUT_OF_HERE_A = 13482, + QUEST_ID_GET_OUT_OF_HERE_H = 13481, }; -bool GossipHello_npc_dame_evniki_kapsalis(Player* pPlayer, Creature* pCreature) +struct npc_father_kamarosAI : public npc_escortAI { - if (pPlayer->HasTitle(TITLE_CRUSADER)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); + npc_father_kamarosAI(Creature* pCreature) : npc_escortAI(pCreature) + { + Reset(); + m_uiCurrentQuestId = 0; + } + + uint32 m_uiSmiteTimer; + uint32 m_uiShadowWordTimer; + uint32 m_uiCurrentQuestId; + + void Reset() override + { + m_uiSmiteTimer = urand(3000, 5000); + m_uiShadowWordTimer = urand(1000, 3000); + } + + void Aggro(Unit* /*pWho*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_KAMAROS_AGGRO_1, m_creature); break; + case 1: DoScriptText(SAY_KAMAROS_AGGRO_2, m_creature); break; + case 2: DoScriptText(SAY_KAMAROS_AGGRO_3, m_creature); break; + } + + if (DoCastSpellIfCan(m_creature, SPELL_POWER_WORD_SHIELD) != CAST_OK) + { + if (Player* pPlayer = GetPlayerForEscort()) + DoCastSpellIfCan(pPlayer, SPELL_POWER_WORD_SHIELD); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + m_uiCurrentQuestId = uiMiscValue; + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_KAMAROS_START_1, m_creature, pPlayer); + DoCastSpellIfCan(pPlayer, SPELL_POWER_WORD_FORTITUDE); + } + break; + case 1: + DoScriptText(SAY_KAMAROS_START_2, m_creature); + break; + case 11: + case 13: + case 16: + if (Creature* pGhoul = GetClosestCreatureWithEntry(m_creature, NPC_SPIKED_GHOUL, 25.0f)) + pGhoul->AI()->AttackStart(m_creature); + break; + case 23: + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + DoScriptText(SAY_KAMAROS_COMPLETE_1, m_creature); + break; + case 24: + SetRun(); + DoScriptText(SAY_KAMAROS_COMPLETE_2, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(m_uiCurrentQuestId, m_creature); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSmiteTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HOLY_SMITE) == CAST_OK) + m_uiSmiteTimer = urand(3000, 4000); + } + else + m_uiSmiteTimer -= uiDiff; + + if (m_uiShadowWordTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_WORD_PAIN) == CAST_OK) + m_uiShadowWordTimer = urand(15000, 20000); + } + else + m_uiShadowWordTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_father_kamaros(Creature* pCreature) +{ + return new npc_father_kamarosAI(pCreature); +} + +bool QuestAccept_npc_father_kamaros(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_NOT_DEAD_YET_A || pQuest->GetQuestId() == QUEST_ID_NOT_DEAD_YET_H || + pQuest->GetQuestId() == QUEST_ID_GET_OUT_OF_HERE_A || pQuest->GetQuestId() == QUEST_ID_GET_OUT_OF_HERE_H) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + +/*###### +## npc_saronite_mine_slave +######*/ - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); +enum +{ + SAY_MINER_SUICIDE_1 = -1001117, + SAY_MINER_SUICIDE_2 = -1001118, + SAY_MINER_SUICIDE_3 = -1001119, + SAY_MINER_SUICIDE_4 = -1001120, + SAY_MINER_SUICIDE_5 = -1001121, + SAY_MINER_SUICIDE_6 = -1001122, + SAY_MINER_SUICIDE_7 = -1001123, + SAY_MINER_SUICIDE_8 = -1001124, + + GOSSIP_ITEM_SLAVE_FREE = -3000113, + TEXT_ID = 14068, + + NPC_SARONITE_KILL_CREDIT_BUNNY = 31866, + + FACTION_HOSTILE = 14, + + QUEST_SLAVES_TO_SARONITE_A = 13300, + QUEST_SLAVES_TO_SARONITE_H = 13302, +}; + +static const float afPointSlaveSalvation[3] = {7030.59f, 1866.73f, 533.94f}; +static const float afPointSlaveSuicide1[3] = {6965.99f, 2051.44f, 519.49f}; +static const float afPointSlaveSuicide2[3] = {6920.47f, 1973.46f, 523.38f}; +static const float afPointSlaveSuicide3[3] = {6915.35f, 2026.35f, 518.53f}; + +bool GossipHello_npc_saronite_mine_slave(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_SLAVES_TO_SARONITE_A) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_SLAVES_TO_SARONITE_H) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_SLAVE_FREE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(TEXT_ID, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_dame_evniki_kapsalis(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_saronite_mine_slave(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); + if (uiAction != GOSSIP_ACTION_INFO_DEF + 1) + return false; + + pPlayer->CLOSE_GOSSIP_MENU(); + + switch (urand(0, 5)) + { + case 0: + case 1: + case 2: + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->KilledMonsterCredit(NPC_SARONITE_KILL_CREDIT_BUNNY); + + pCreature->SetWalk(false); + pCreature->GetMotionMaster()->MovePoint(0, afPointSlaveSalvation[0], afPointSlaveSalvation[1], afPointSlaveSalvation[2]); + pCreature->ForcedDespawn(20000); + break; + case 3: + case 4: + pCreature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_REACH_HOME); + pCreature->AI()->AttackStart(pPlayer); + break; + case 5: + switch (urand(0, 7)) + { + case 0: DoScriptText(SAY_MINER_SUICIDE_1, pCreature); break; + case 1: DoScriptText(SAY_MINER_SUICIDE_2, pCreature); break; + case 2: DoScriptText(SAY_MINER_SUICIDE_3, pCreature); break; + case 3: DoScriptText(SAY_MINER_SUICIDE_4, pCreature); break; + case 4: DoScriptText(SAY_MINER_SUICIDE_5, pCreature); break; + case 5: DoScriptText(SAY_MINER_SUICIDE_6, pCreature); break; + case 6: DoScriptText(SAY_MINER_SUICIDE_7, pCreature); break; + case 7: DoScriptText(SAY_MINER_SUICIDE_8, pCreature); break; + } + + pCreature->SetWalk(false); + switch (urand(0, 2)) + { + case 0: + pCreature->GetMotionMaster()->MovePoint(0, afPointSlaveSuicide1[0], afPointSlaveSuicide1[1], afPointSlaveSuicide1[2]); + break; + case 1: + pCreature->GetMotionMaster()->MovePoint(0, afPointSlaveSuicide2[0], afPointSlaveSuicide2[1], afPointSlaveSuicide2[2]); + break; + case 2: + pCreature->GetMotionMaster()->MovePoint(0, afPointSlaveSuicide3[0], afPointSlaveSuicide3[1], afPointSlaveSuicide3[2]); + break; + } + pCreature->ForcedDespawn(20000); + break; + } + return true; } +/*###### +## npc_grand_admiral_westwind +######*/ + +enum +{ + SAY_AGGRO = -1001184, + SAY_SPHERE = -1001185, + SAY_NO_MATTER = -1001186, + SAY_TRANSFORM = -1001187, + SAY_20_HP = -1001188, + SAY_DEFEATED = -1001189, + SAY_ESCAPE = -1001190, + + // admiral spells + SPELL_WHIRLWIND = 49807, + SPELL_HEROIC_STRIKE_ADMIRAL = 57846, + SPELL_CLEAVE_ADMIRAL = 15284, + SPELL_PROTECTION_SPHERE = 50161, + SPELL_NULLIFIER = 31699, + + // malganis spells + SPELL_SLEEP = 53045, + SPELL_MIND_BLAST = 60500, + SPELL_VAMPIRIC_TOUCH = 60501, + SPELL_CARRION_SWARM = 60502, + + SPELL_ADMIRAL_PORTAL = 27731, + SPELL_TELEPORT = 35502, + + MODEL_ID_MALGANIS = 26582, + NPC_WESTWIND_CREDIT_BUNNY = 29627, +}; + +static const float afPortalSpawnLoc[4] = {7494.89f, 4871.53f, -12.65f, 1.37f}; +static const float afExitLocation[3] = {7494.78f, 4872.56f, -12.72f}; + +struct npc_grand_admiral_westwindAI : public ScriptedAI +{ + npc_grand_admiral_westwindAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiWhirlwindTimer; + uint32 m_uiHeroicStrikeTimer; + uint32 m_uiCleaveTimer; + bool m_bIsShield; + bool m_bIsTransform; + + uint32 m_uiSleepTimer; + uint32 m_uiBlastTimer; + uint32 m_uiCarrionTimer; + uint32 m_uiEscapeTimer; + + bool m_bIsYell; + bool m_bIsDefeated; + + ObjectGuid m_playerGuid; + + void Reset() override + { + m_uiWhirlwindTimer = 15000; + m_uiHeroicStrikeTimer = 6000; + m_uiCleaveTimer = 13000; + + m_uiSleepTimer = 15000; + m_uiBlastTimer = 6000; + m_uiCarrionTimer = 13000; + m_uiEscapeTimer = 0; + + m_bIsYell = false; + m_bIsShield = false; + m_bIsTransform = false; + m_bIsDefeated = false; + + m_creature->SetDisplayId(m_creature->GetNativeDisplayId()); + SetEquipmentSlots(true); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_NO_MATTER, m_creature); + m_playerGuid = pInvoker->GetObjectGuid(); + m_creature->RemoveAurasDueToSpell(SPELL_PROTECTION_SPHERE); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_bIsDefeated) + m_creature->GetMotionMaster()->MoveIdle(); + else + { + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (!m_bIsDefeated) + { + m_bIsDefeated = true; + m_uiEscapeTimer = 5000; + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + EnterEvadeMode(); + + // Note: the portal entry is guesswork! + m_creature->SummonCreature(NPC_WESTWIND_CREDIT_BUNNY, afPortalSpawnLoc[0], afPortalSpawnLoc[1], afPortalSpawnLoc[2], afPortalSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 20000); + DoScriptText(SAY_DEFEATED, m_creature); + + // kill credit + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->RewardPlayerAndGroupAtEvent(NPC_WESTWIND_CREDIT_BUNNY, m_creature); + } + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + DoScriptText(SAY_ESCAPE, m_creature); + DoCastSpellIfCan(m_creature, SPELL_TELEPORT); + m_creature->ForcedDespawn(10000); + + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + m_creature->SetFacingToObject(pPlayer); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_WESTWIND_CREDIT_BUNNY) + pSummoned->CastSpell(pSummoned, SPELL_ADMIRAL_PORTAL, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiEscapeTimer) + { + if (m_uiEscapeTimer <= uiDiff) + { + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->MovePoint(1, afExitLocation[0], afExitLocation[1], afExitLocation[2]); + m_uiEscapeTimer = 0; + } + else + m_uiEscapeTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bIsTransform) + { + if (m_uiWhirlwindTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = urand(15000, 16000); + } + else + m_uiWhirlwindTimer -= uiDiff; + + if (m_uiHeroicStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HEROIC_STRIKE_ADMIRAL) == CAST_OK) + m_uiHeroicStrikeTimer = urand(6000, 7000); + } + else + m_uiHeroicStrikeTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE_ADMIRAL) == CAST_OK) + m_uiCleaveTimer = urand(6000, 7000); + } + else + m_uiCleaveTimer -= uiDiff; + + if (!m_bIsShield && m_creature->GetHealthPercent() <= 50.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_PROTECTION_SPHERE) == CAST_OK) + { + DoScriptText(SAY_SPHERE, m_creature); + m_bIsShield = true; + } + } + + if (m_creature->GetHealthPercent() <= 30.0f) + { + DoScriptText(SAY_TRANSFORM, m_creature); + m_creature->SetDisplayId(MODEL_ID_MALGANIS); + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); + m_bIsTransform = true; + } + } + else + { + if (m_uiSleepTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SLEEP) == CAST_OK) + m_uiSleepTimer = urand(15000, 16000); + } + } + else + m_uiSleepTimer -= uiDiff; + + if (m_uiBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MIND_BLAST) == CAST_OK) + m_uiBlastTimer = urand(8000, 9000); + } + } + else + m_uiBlastTimer -= uiDiff; + + if (m_uiCarrionTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CARRION_SWARM) == CAST_OK) + m_uiCarrionTimer = urand(6000, 7000); + } + else + m_uiCarrionTimer -= uiDiff; + + if (!m_bIsYell && m_creature->GetHealthPercent() <= 20.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_VAMPIRIC_TOUCH) == CAST_OK) + { + DoScriptText(SAY_20_HP, m_creature); + m_bIsYell = true; + } + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_grand_admiral_westwind(Creature* pCreature) +{ + return new npc_grand_admiral_westwindAI(pCreature); +} + +bool EffectDummyCreature_npc_grand_admiral_westwind(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_NULLIFIER && uiEffIndex == EFFECT_INDEX_0 && pCaster->GetTypeId() == TYPEID_PLAYER) + { + if (!pCreatureTarget->HasAura(SPELL_PROTECTION_SPHERE)) + return true; + + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + return true; + } + + return false; +} + void AddSC_icecrown() { Script* pNewScript; pNewScript = new Script; - pNewScript->Name = "npc_dame_evniki_kapsalis"; - pNewScript->pGossipHello = &GossipHello_npc_dame_evniki_kapsalis; - pNewScript->pGossipSelect = &GossipSelect_npc_dame_evniki_kapsalis; + pNewScript->Name = "npc_squad_leader"; + pNewScript->GetAI = &GetAI_npc_squad_leader; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_squad_leader; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_infantry"; + pNewScript->GetAI = &GetAI_npc_infantry; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_father_kamaros"; + pNewScript->GetAI = &GetAI_npc_father_kamaros; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_father_kamaros; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_saronite_mine_slave"; + pNewScript->pGossipHello = &GossipHello_npc_saronite_mine_slave; + pNewScript->pGossipSelect = &GossipSelect_npc_saronite_mine_slave; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_grand_admiral_westwind"; + pNewScript->GetAI = &GetAI_npc_grand_admiral_westwind; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_grand_admiral_westwind; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_bronjahm.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_bronjahm.cpp index f059e674e..a7c80c308 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_bronjahm.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_bronjahm.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -47,7 +47,7 @@ enum SPELL_FEAR = 68950, }; -struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI +struct boss_bronjahmAI : public ScriptedAI { boss_bronjahmAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -66,7 +66,7 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI uint32 m_uiFearTimer; uint32 m_uiShadowboltTimer; - void Reset() + void Reset() override { m_uiPhase = 0; m_uiMagicsBaneTimer = urand(8000, 12000); @@ -76,7 +76,7 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI SetCombatMovement(true); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature); @@ -87,7 +87,7 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI m_creature->RemoveAurasDueToSpell(SPELL_SOULSTORM_VISUAL_OOC); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -96,7 +96,7 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -104,13 +104,13 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI m_pInstance->SetData(TYPE_BRONJAHM, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_BRONJAHM, FAIL); } - void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override { if (pTarget == m_creature && pSpellEntry->Id == SPELL_TELEPORT) { @@ -121,7 +121,7 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -167,7 +167,7 @@ struct MANGOS_DLL_DECL boss_bronjahmAI : public ScriptedAI // Use ShadowBolt as default attack if victim is not in range // TODO - not entirely clear how this works in case the tank is out of shadow-bolt range - if (!m_uiShadowboltTimer && !m_creature->CanReachWithMeleeAttack(m_creature->getVictim()) && m_creature->GetCombatDistance(m_creature->getVictim()) < 20.0f) + if (!m_uiShadowboltTimer && !m_creature->CanReachWithMeleeAttack(m_creature->getVictim()) && m_creature->GetCombatDistance(m_creature->getVictim(), false) < 20.0f) { if (IsCombatMovement()) { @@ -211,7 +211,7 @@ CreatureAI* GetAI_boss_bronjahm(Creature* pCreature) return new boss_bronjahmAI(pCreature); } -struct MANGOS_DLL_DECL npc_corrupted_soul_fragmentAI : public ScriptedAI +struct npc_corrupted_soul_fragmentAI : public ScriptedAI { npc_corrupted_soul_fragmentAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -219,18 +219,18 @@ struct MANGOS_DLL_DECL npc_corrupted_soul_fragmentAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_BANISH_VISUAL); } - void Reset() + void Reset() override { SetCombatMovement(true); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (instance_forge_of_souls* pInstance = (instance_forge_of_souls*)m_creature->GetInstanceData()) pInstance->SetGuid(DATA_SOULFRAGMENT_REMOVE, m_creature->GetObjectGuid()); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (pWho->GetEntry() == NPC_BRONJAHM) { diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp index 944a20736..a795b52f6 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/boss_devourer_of_souls.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -74,15 +74,15 @@ enum static const int aTexts[6][3] = { - {SAY_MALE_1_AGGRO, SAY_FEMALE_AGGRO, 0}, // 0 - aggro + {SAY_MALE_1_AGGRO, SAY_FEMALE_AGGRO, 0}, // 0 - aggro {SAY_MALE_1_SLAY_1, SAY_FEMALE_SLAY_1, SAY_MALE_2_SLAY_1}, // 1 - slay1 {SAY_MALE_1_SLAY_2, SAY_FEMALE_SLAY_2, SAY_MALE_2_SLAY_2}, // 2 - slay2 {SAY_MALE_1_DEATH, SAY_FEMALE_DEATH, SAY_MALE_2_DEATH}, // 3 - death {SAY_MALE_1_SOUL_ATTACK, SAY_FEMALE_SOUL_ATTACK, SAY_MALE_2_SOUL_ATTACK}, // 4 - unleashing soul - {SAY_MALE_1_DARK_GLARE, SAY_FEMALE_DARK_GLARE, 0} // 5 - glare + {SAY_MALE_1_DARK_GLARE, SAY_FEMALE_DARK_GLARE, 0} // 5 - glare }; -struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI +struct boss_devourer_of_soulsAI : public ScriptedAI { boss_devourer_of_soulsAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -102,9 +102,9 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI uint32 m_uiWailingTimer; uint32 m_uiEndPhaseTimer; - GUIDList m_lWellGuids; + GuidList m_lWellGuids; - void Reset() + void Reset() override { m_uiFace = FACE_NORMAL; @@ -116,14 +116,14 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI m_uiEndPhaseTimer = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(aTexts[0][m_uiFace], m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_DEVOURER_OF_SOULS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -132,14 +132,14 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI DoScriptText(aTexts[urand(1, 2)][m_uiFace], m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(aTexts[3][m_uiFace], m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_DEVOURER_OF_SOULS, DONE); - for (GUIDList::const_iterator itr = m_lWellGuids.begin(); itr != m_lWellGuids.end(); ++itr) + for (GuidList::const_iterator itr = m_lWellGuids.begin(); itr != m_lWellGuids.end(); ++itr) { if (Creature* pWell = m_creature->GetMap()->GetCreature(*itr)) pWell->ForcedDespawn(); @@ -147,7 +147,7 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI m_lWellGuids.clear(); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -156,7 +156,7 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI m_pInstance->SetData(TYPE_ACHIEV_PHANTOM_BLAST, IN_PROGRESS); } - for (GUIDList::const_iterator itr = m_lWellGuids.begin(); itr != m_lWellGuids.end(); ++itr) + for (GuidList::const_iterator itr = m_lWellGuids.begin(); itr != m_lWellGuids.end(); ++itr) { if (Creature* pWell = m_creature->GetMap()->GetCreature(*itr)) pWell->ForcedDespawn(); @@ -164,15 +164,15 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI m_lWellGuids.clear(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_WELL_OF_SOULS) { m_lWellGuids.push_back(pSummoned->GetObjectGuid()); pSummoned->CastSpell(pSummoned, SPELL_WELL_OF_SOULS_TRIGGER, true, NULL, NULL, m_creature->GetObjectGuid()); // Commented as of not stacking auras - //pSummoned->CastSpell(pSummoned, SPELL_WELL_OF_SOULS_VISUAL1, true); - //pSummoned->CastSpell(pSummoned, SPELL_WELL_OF_SOULS_VISUAL2, true); + // pSummoned->CastSpell(pSummoned, SPELL_WELL_OF_SOULS_VISUAL1, true); + // pSummoned->CastSpell(pSummoned, SPELL_WELL_OF_SOULS_VISUAL2, true); } else if (pSummoned->GetEntry() == NPC_UNLEASHED_SOUL) { @@ -186,24 +186,24 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI } } - void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) + void SpellHitTarget(Unit* /*pTarget*/, SpellEntry const* pSpellEntry) override { switch (pSpellEntry->Id) { - // If we hit a target with phantom blast, the achievement_criteria is failed + // If we hit a target with phantom blast, the achievement_criteria is failed case SPELL_PHANTOM_BLAST: case SPELL_PHANTOM_BLAST_H: if (m_pInstance) m_pInstance->SetData(TYPE_ACHIEV_PHANTOM_BLAST, FAIL); break; - // Might be placed somewhere else better, important is to note that this text is said after the 3s cast time + // Might be placed somewhere else better, important is to note that this text is said after the 3s cast time case SPELL_WAILING_SOULS: DoScriptText(aTexts[5][m_uiFace], m_creature); break; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->isInCombat()) return; @@ -250,11 +250,11 @@ struct MANGOS_DLL_DECL boss_devourer_of_soulsAI : public ScriptedAI // Phantom Blast if (m_uiPhantomBlastTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_PHANTOM_BLAST : SPELL_PHANTOM_BLAST_H) == CAST_OK) m_uiPhantomBlastTimer = urand(5000, 10000); // TODO - } + } } else m_uiPhantomBlastTimer -= uiDiff; diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.h b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.h index b2c309312..586f74ee2 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.h +++ b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/forge_of_souls.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -88,26 +88,26 @@ const sExtroEventNpcLocations aEventEndLocations[18] = {NPC_COLISEUM_CHAMPION_H_M, NPC_COLISEUM_CHAMPION_A_M, 0.8726646f, 0.977384f, 5593.93652f, 2410.875f, 705.9351f, 5642.629f, 2474.331f, 708.6959f} }; -class MANGOS_DLL_DECL instance_forge_of_souls : public ScriptedInstance +class instance_forge_of_souls : public ScriptedInstance { public: instance_forge_of_souls(Map* pMap); ~instance_forge_of_souls() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - void SetData64(uint32 uiType, uint64 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + void SetData64(uint32 uiType, uint64 uiData) override; - void OnPlayerEnter(Player* pPlayer); + void OnPlayerEnter(Player* pPlayer) override; void ProcessEventNpcs(Player* pPlayer, bool bChanged); - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; @@ -117,8 +117,8 @@ class MANGOS_DLL_DECL instance_forge_of_souls : public ScriptedInstance uint32 m_uiTeam; // Team of first entered player, used to set if Jaina or Silvana to spawn - GUIDList m_luiSoulFragmentAliveGUIDs; - GUIDList m_lEventMobGUIDs; + GuidList m_luiSoulFragmentAliveGUIDs; + GuidList m_lEventMobGUIDs; }; #endif diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp index e49f1166c..8ea4ac374 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/forge_of_souls/instance_forge_of_souls.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -67,10 +67,10 @@ void instance_forge_of_souls::ProcessEventNpcs(Player* pPlayer, bool bChanged) if (m_auiEncounter[0] != DONE || m_auiEncounter[1] != DONE) { // Spawn Begin Mobs - for (uint8 i = 0; i < sizeof(aEventBeginLocations)/sizeof(sIntoEventNpcSpawnLocations); ++i) + for (uint8 i = 0; i < countof(aEventBeginLocations); ++i) { if (Creature* pSummon = pPlayer->SummonCreature(m_uiTeam == HORDE ? aEventBeginLocations[i].uiEntryHorde : aEventBeginLocations[i].uiEntryAlliance, - aEventBeginLocations[i].fSpawnX, aEventBeginLocations[i].fSpawnY, aEventBeginLocations[i].fSpawnZ, aEventBeginLocations[i].fSpawnO, TEMPSUMMON_DEAD_DESPAWN, 24*HOUR*IN_MILLISECONDS)) + aEventBeginLocations[i].fSpawnX, aEventBeginLocations[i].fSpawnY, aEventBeginLocations[i].fSpawnZ, aEventBeginLocations[i].fSpawnO, TEMPSUMMON_DEAD_DESPAWN, 24 * HOUR * IN_MILLISECONDS)) m_lEventMobGUIDs.push_back(pSummon->GetObjectGuid()); } } @@ -79,32 +79,33 @@ void instance_forge_of_souls::ProcessEventNpcs(Player* pPlayer, bool bChanged) // if bChanged, despawn Begin Mobs, spawn End Mobs at Spawn, else spawn EndMobs at End if (bChanged) { - for (GUIDList::const_iterator itr = m_lEventMobGUIDs.begin(); itr != m_lEventMobGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lEventMobGUIDs.begin(); itr != m_lEventMobGUIDs.end(); ++itr) { if (Creature* pSummoned = instance->GetCreature(*itr)) pSummoned->ForcedDespawn(); } - for (uint8 i = 0; i < sizeof(aEventEndLocations)/sizeof(sExtroEventNpcLocations); ++i) + for (uint8 i = 0; i < countof(aEventEndLocations); ++i) { pPlayer->SummonCreature(m_uiTeam == HORDE ? aEventEndLocations[i].uiEntryHorde : aEventEndLocations[i].uiEntryAlliance, - aEventEndLocations[i].fSpawnX, aEventEndLocations[i].fSpawnY, aEventEndLocations[i].fSpawnZ, aEventEndLocations[i].fStartO, TEMPSUMMON_DEAD_DESPAWN, 24*HOUR*IN_MILLISECONDS); + aEventEndLocations[i].fSpawnX, aEventEndLocations[i].fSpawnY, aEventEndLocations[i].fSpawnZ, aEventEndLocations[i].fStartO, TEMPSUMMON_DEAD_DESPAWN, 24 * HOUR * IN_MILLISECONDS); // TODO: Let the NPCs Move along their paths } } else - { // Summon at end, without event - for (uint8 i = 0; i < sizeof(aEventEndLocations)/sizeof(sExtroEventNpcLocations); ++i) + { + // Summon at end, without event + for (uint8 i = 0; i < countof(aEventEndLocations); ++i) { pPlayer->SummonCreature(m_uiTeam == HORDE ? aEventEndLocations[i].uiEntryHorde : aEventEndLocations[i].uiEntryAlliance, - aEventEndLocations[i].fEndX, aEventEndLocations[i].fEndY, aEventEndLocations[i].fEndZ, aEventEndLocations[i].fEndO, TEMPSUMMON_DEAD_DESPAWN, 24*HOUR*IN_MILLISECONDS); + aEventEndLocations[i].fEndX, aEventEndLocations[i].fEndY, aEventEndLocations[i].fEndZ, aEventEndLocations[i].fEndO, TEMPSUMMON_DEAD_DESPAWN, 24 * HOUR * IN_MILLISECONDS); } } } } -bool instance_forge_of_souls::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_forge_of_souls::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { @@ -119,13 +120,13 @@ bool instance_forge_of_souls::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, void instance_forge_of_souls::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_BRONJAHM: m_auiEncounter[0] = uiData; // Despawn remaining adds and clear list - for (GUIDList::const_iterator itr = m_luiSoulFragmentAliveGUIDs.begin(); itr != m_luiSoulFragmentAliveGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiSoulFragmentAliveGUIDs.begin(); itr != m_luiSoulFragmentAliveGUIDs.end(); ++itr) { if (Creature* pFragment = instance->GetCreature(*itr)) pFragment->ForcedDespawn(); @@ -169,7 +170,7 @@ void instance_forge_of_souls::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -178,9 +179,9 @@ void instance_forge_of_souls::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_forge_of_souls::GetData(uint32 uiType) +uint32 instance_forge_of_souls::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_BRONJAHM: return m_auiEncounter[0]; diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falric.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falric.cpp index 396a7817b..0a3c76b26 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falric.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_falric.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_lich_king.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_lich_king.cpp index 670f6ac9e..86aed8f08 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_lich_king.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_lich_king.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_marwyn.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_marwyn.cpp index b8d03004f..c7789c3ec 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_marwyn.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/boss_marwyn.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.cpp index 0600b7873..6fb3dcac0 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.h b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.h index 5871a49a1..6d929a93d 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.h +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/halls_of_reflection.h @@ -1,3 +1,118 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_ICECROWN_HOR_H +#define DEF_ICECROWN_HOR_H + +enum +{ + MAX_ENCOUNTER = 3, + + TYPE_FALRIC = 0, + TYPE_MARWYN = 1, + TYPE_LICH_KING = 2, + + NPC_FALRIC = 38112, + NPC_MARWYN = 38113, + NPC_LICH_KING = 36954, + NPC_FROSTSWORN_GENERAL = 36723, // miniboss between Marwyn and Lich King + + NPC_JAINA_PART1 = 37221, + NPC_JAINA_PART2 = 36955, + NPC_SYLVANAS_PART1 = 37223, + NPC_SYLVANAS_PART2 = 37554, + NPC_KILARA = 37583, + NPC_ELANDRA = 37774, + NPC_LORALEN = 37779, + NPC_KORELN = 37582, + + // intro related npcs + NPC_UTHER = 37225, + NPC_LICH_KING_INTRO = 37226, + NPC_FROSTMOURNE_ALTER_BUNNY = 37704, // dummy trigger for Quel'Delar + NPC_QUEL_DELAR = 37158, + + // spirit event creatures + NPC_PHANTOM_MAGE = 38172, + NPC_SPECTRAL_FOOTMAN = 38173, + NPC_GHOSTLY_PRIEST = 38175, + NPC_TORTURED_RIFLEMAN = 38176, + NPC_SHADOWY_MERCENARY = 38177, + + // escape event creatures + NPC_RAGING_GHOUL = 36940, + NPC_RISEN_WHITCH_DOCTOR = 36941, + NPC_LUMBERING_ABONIMATION = 37069, + NPC_ICE_WALL_TARGET = 37014, // dummy ice wall target + + // objects + GO_ICECROWN_DOOR_ENTRANCE = 201976, // entrance door; used in combat during the spirit event + GO_IMPENETRABLE_DOOR = 197341, // door after the spirit event + GO_ICECROWN_DOOR_LK_ENTRANCE = 197342, // door before the Lich King + GO_ICECROWN_DOOR_LK_EXIT = 197343, // door after the Lich King + GO_FROSTMOURNE_ALTAR = 202236, + GO_FROSTMOURNE = 202302, + + GO_ICE_WALL = 201385, // summoned during the Lich King escape + GO_CAVE_IN = 201596, // door after the final encounter + GO_PORTAL_DALARAN = 202079, + GO_THE_SKYBREAKER = 201598, + GO_OGRIMS_HAMMER = 201581, + + GO_CAPTAIN_CHEST_HORDE = 202212, + GO_CAPTAIN_CHEST_HORDE_H = 202337, + GO_CAPTAIN_CHEST_ALLIANCE = 201710, + GO_CAPTAIN_CHEST_ALLIANCE_H = 202336, + + // world states + WORLD_STATE_SPIRIT_WAVES = 4884, + WORLD_STATE_SPIRIT_WAVES_COUNT = 4882, + + // area triggers + AREATRIGGER_FROSTMOURNE_ALTAR = 5697, + AREATRIGGER_LICH_KING_ROOM = 5605, +}; + +struct EventNpcLocations +{ + uint32 uiEntryHorde, uiEntryAlliance; + float fX, fY, fZ, fO; + float fMoveX, fMoveY, fMoveZ; +}; + +const EventNpcLocations aEventBeginLocations[2] = +{ + {NPC_SYLVANAS_PART1, NPC_JAINA_PART1, 5236.659f, 1929.894f, 707.7781f, 0.87f}, + {NPC_LORALEN, NPC_KORELN, 5232.680f, 1931.460f, 707.7781f, 0.83f}, +}; + +class instance_halls_of_reflection : public ScriptedInstance +{ + public: + instance_halls_of_reflection(Map* pMap); + ~instance_halls_of_reflection() {} + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnPlayerEnter(Player* pPlayer) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + uint32 GetPlayerTeam() { return m_uiTeam; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + protected: + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiTeam; // Team of first entered player, used to set if Jaina or Silvana to spawn +}; + +#endif diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp index 05e0621d5..9c8b11283 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/halls_of_reflection/instance_halls_of_reflection.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,164 @@ /* ScriptData SDName: instance_halls_of_reflection -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 10 +SDComment: Basic support SDCategory: Halls of Reflection EndScriptData */ #include "precompiled.h" +#include "halls_of_reflection.h" + +instance_halls_of_reflection::instance_halls_of_reflection(Map* pMap) : ScriptedInstance(pMap), + m_uiTeam(TEAM_NONE) +{ + Initialize(); +} + +void instance_halls_of_reflection::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +void instance_halls_of_reflection::OnPlayerEnter(Player* pPlayer) +{ + if (!m_uiTeam) // very first player to enter + { + m_uiTeam = pPlayer->GetTeam(); + + // Spawn intro npcs + for (uint8 i = 0; i < countof(aEventBeginLocations); ++i) + { + pPlayer->SummonCreature(m_uiTeam == HORDE ? aEventBeginLocations[i].uiEntryHorde : aEventBeginLocations[i].uiEntryAlliance, + aEventBeginLocations[i].fX, aEventBeginLocations[i].fY, aEventBeginLocations[i].fZ, aEventBeginLocations[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } +} + +void instance_halls_of_reflection::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_JAINA_PART1: + case NPC_JAINA_PART2: + case NPC_SYLVANAS_PART1: + case NPC_SYLVANAS_PART2: + case NPC_FALRIC: + case NPC_MARWYN: + case NPC_LICH_KING: + break; + default: + return; + } + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); +} + +void instance_halls_of_reflection::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_IMPENETRABLE_DOOR: + if (m_auiEncounter[TYPE_MARWYN] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FROSTMOURNE: + case GO_FROSTMOURNE_ALTAR: + case GO_ICECROWN_DOOR_ENTRANCE: + case GO_ICECROWN_DOOR_LK_ENTRANCE: + case GO_ICECROWN_DOOR_LK_EXIT: + case GO_CAVE_IN: + + case GO_CAPTAIN_CHEST_HORDE: + case GO_CAPTAIN_CHEST_HORDE_H: + case GO_CAPTAIN_CHEST_ALLIANCE: + case GO_CAPTAIN_CHEST_ALLIANCE_H: + break; + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_halls_of_reflection::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_FALRIC: + m_auiEncounter[uiType] = uiData; + break; + case TYPE_MARWYN: + if (uiData == DONE) + DoUseDoorOrButton(GO_IMPENETRABLE_DOOR); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_LICH_KING: + if (uiData == DONE) + { + uint32 uiChestEntry = m_uiTeam == ALLIANCE ? (instance->IsRegularDifficulty() ? GO_CAPTAIN_CHEST_ALLIANCE : GO_CAPTAIN_CHEST_ALLIANCE_H) : + (instance->IsRegularDifficulty() ? GO_CAPTAIN_CHEST_HORDE : GO_CAPTAIN_CHEST_HORDE_H); + DoToggleGameObjectFlags(uiChestEntry, GO_FLAG_NO_INTERACT, false); + } + m_auiEncounter[uiType] = uiData; + break; + default: + return; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +void instance_halls_of_reflection::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +uint32 instance_halls_of_reflection::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +InstanceData* GetInstanceData_instance_halls_of_reflection(Map* pMap) +{ + return new instance_halls_of_reflection(pMap); +} void AddSC_instance_halls_of_reflection() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_halls_of_reflection"; + pNewScript->GetInstanceData = &GetInstanceData_instance_halls_of_reflection; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp index c042caf2b..ec5d89f0a 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_forgemaster_garfrost.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_forgemaster_garfrost -SD%Complete: 70 -SDComment: TODO movement to the forges currently workaround (need core support for Jump-MMGen) +SD%Complete: 90 +SDComment: Tyrannus outro event NYI. SDCategory: Pit of Saron EndScriptData */ @@ -32,13 +32,12 @@ enum SAY_DEATH = -1658017, SAY_FORGE_1 = -1658018, SAY_FORGE_2 = -1658019, - SAY_TYRANNUS_GARFROST = -1658020, - SAY_GENERAL_GARFROST = -1658021, EMOTE_THROW_SARONITE = -1658022, EMOTE_DEEP_FREEZE = -1658023, SPELL_PERMAFROST = 70326, + SPELL_PERMAFROST_AURA_H = 70336, SPELL_THROW_SARONITE = 68788, SPELL_THUNDERING_STOMP = 68771, SPELL_FORGE_FROZEN_BLADE = 68774, @@ -46,6 +45,8 @@ enum SPELL_FORGE_FROSTBORN_MACE = 68785, SPELL_DEEP_FREEZE = 70381, + MAX_PERMAFROST_STACK = 10, // the max allowed stacks for the achiev to pass + PHASE_NO_ENCHANTMENT = 1, PHASE_BLADE_ENCHANTMENT = 2, PHASE_MACE_ENCHANTMENT = 3, @@ -54,28 +55,33 @@ enum static const float aGarfrostMoveLocs[2][3] = { - {719.785f, -230.227f, 527.033f}, {657.539f, -203.564f, 526.691f}, + {719.785f, -230.227f, 527.033f}, }; -struct MANGOS_DLL_DECL boss_forgemaster_garfrostAI : public ScriptedAI +static const float afOutroNpcSpawnLoc[4] = {695.0146f, -123.7532f, 515.3067f, 4.59f}; +struct boss_forgemaster_garfrostAI : public ScriptedAI { boss_forgemaster_garfrostAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_pit_of_saron*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_pit_of_saron* m_pInstance; + bool m_bIsRegularMode; uint32 m_uiThrowSaroniteTimer; uint32 m_uiPhase; uint32 m_uiChillingWaveTimer; uint32 m_uiDeepFreezeTimer; + uint32 m_uiCheckPermafrostTimer; - void Reset() + void Reset() override { + m_uiCheckPermafrostTimer = 2000; m_uiThrowSaroniteTimer = 13000; m_uiChillingWaveTimer = 10000; m_uiDeepFreezeTimer = 10000; @@ -83,26 +89,61 @@ struct MANGOS_DLL_DECL boss_forgemaster_garfrostAI : public ScriptedAI m_uiPhase = PHASE_NO_ENCHANTMENT; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoScriptText(SAY_AGGRO, m_creature, pWho); DoCastSpellIfCan(m_creature, SPELL_PERMAFROST); + + if (m_pInstance) + m_pInstance->SetData(TYPE_GARFROST, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_DEATH, m_creature, pKiller); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_GARFROST, DONE); + + // Summon Ironskull or Victus for outro + m_creature->SummonCreature(m_pInstance->GetPlayerTeam() == HORDE ? NPC_IRONSKULL_PART1 : NPC_VICTUS_PART1, + afOutroNpcSpawnLoc[0], afOutroNpcSpawnLoc[1], afOutroNpcSpawnLoc[2], afOutroNpcSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 2 * MINUTE * IN_MILLISECONDS); + + // ToDo: handle the other npcs movement + } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY_1, m_creature); } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GARFROST, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_IRONSKULL_PART1: + case NPC_VICTUS_PART1: + { + float fX, fY, fZ; + pSummoned->SetWalk(false); + m_creature->GetContactPoint(pSummoned, fX, fY, fZ, 4 * INTERACTION_DISTANCE); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + break; + } + } + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { - // TODO Change to jump movement type when proper implemented - if (uiMotionType != POINT_MOTION_TYPE) + if (uiMotionType != EFFECT_MOTION_TYPE) return; if (uiPointId != PHASE_BLADE_ENCHANTMENT && uiPointId != PHASE_MACE_ENCHANTMENT) @@ -123,11 +164,42 @@ struct MANGOS_DLL_DECL boss_forgemaster_garfrostAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // This needs to be checked only on heroic + if (!m_bIsRegularMode && m_uiCheckPermafrostTimer) + { + if (m_uiCheckPermafrostTimer <= uiDiff) + { + ThreatList playerList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) + { + if (Player* pTarget = m_creature->GetMap()->GetPlayer((*itr)->getUnitGuid())) + { + Aura* pAuraIntenseCold = pTarget->GetAura(SPELL_PERMAFROST_AURA_H, EFFECT_INDEX_2); + + if (pAuraIntenseCold) + { + if (pAuraIntenseCold->GetStackAmount() > MAX_PERMAFROST_STACK) + { + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_DOESNT_GO_ELEVEN, false); + + m_uiCheckPermafrostTimer = 0; + return; + } + } + } + } + m_uiCheckPermafrostTimer = 1000; + } + else + m_uiCheckPermafrostTimer -= uiDiff; + } + // Do nothing more while moving if (m_uiPhase == PHASE_MOVEMENT) return; @@ -157,8 +229,7 @@ struct MANGOS_DLL_DECL boss_forgemaster_garfrostAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_THUNDERING_STOMP, CAST_INTERRUPT_PREVIOUS); SetCombatMovement(false); - // TODO This should actually be jump movement - m_creature->GetMotionMaster()->MovePoint(PHASE_BLADE_ENCHANTMENT, aGarfrostMoveLocs[0][0], aGarfrostMoveLocs[0][1], aGarfrostMoveLocs[0][2]); + m_creature->GetMotionMaster()->MoveJump(aGarfrostMoveLocs[0][0], aGarfrostMoveLocs[0][1], aGarfrostMoveLocs[0][2], 3 * m_creature->GetSpeed(MOVE_RUN), 10.0f, PHASE_BLADE_ENCHANTMENT); m_uiPhase = PHASE_MOVEMENT; // Stop further action @@ -173,8 +244,7 @@ struct MANGOS_DLL_DECL boss_forgemaster_garfrostAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_THUNDERING_STOMP, CAST_INTERRUPT_PREVIOUS); SetCombatMovement(false); - // TODO This should actually be jump movement - m_creature->GetMotionMaster()->MovePoint(PHASE_MACE_ENCHANTMENT, aGarfrostMoveLocs[1][0], aGarfrostMoveLocs[1][1], aGarfrostMoveLocs[1][2]); + m_creature->GetMotionMaster()->MoveJump(aGarfrostMoveLocs[1][0], aGarfrostMoveLocs[1][1], aGarfrostMoveLocs[1][2], 3 * m_creature->GetSpeed(MOVE_RUN), 10.0f, PHASE_MACE_ENCHANTMENT); m_uiPhase = PHASE_MOVEMENT; // Stop further action diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_krick_and_ick.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_krick_and_ick.cpp index 0ef2ea4a1..e24223ddf 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_krick_and_ick.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_krick_and_ick.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_krick_and_ick -SD%Complete: 0% -SDComment: +SD%Complete: 95 +SDComment: Timers may need adjustments. SDCategory: Pit of Saron EndScriptData */ @@ -34,26 +34,387 @@ enum SAY_TARGET_1 = -1658029, SAY_TARGET_2 = -1658030, SAY_TARGET_3 = -1658031, + SAY_OUTRO_1 = -1658035, EMOTE_KRICK_MINES = -1658032, EMOTE_ICK_POISON = -1658033, EMOTE_ICK_CHASING = -1658034, - SAY_OUTRO_1 = -1658035, - SAY_JAINA_KRICK_1 = -1658036, - SAY_SYLVANAS_KRICK_1 = -1658037, - SAY_OUTRO_2 = -1658038, - SAY_JAINA_KRICK_2 = -1658039, - SAY_SYLVANAS_KRICK_2 = -1658040, - SAY_OUTRO_3 = -1658041, - SAY_TYRANNUS_KRICK_1 = -1658042, - SAY_OUTRO_4 = -1658043, - SAY_TYRANNUS_KRICK_2 = -1658044, - SAY_JAINA_KRICK_3 = -1658045, - SAY_SYLVANAS_KRICK_3 = -1658046, + // ick spells + SPELL_POISON_NOVA = 68989, + SPELL_MIGHTY_KICK = 69021, + SPELL_PURSUIT = 68987, + SPELL_EXPLOSIVE_BARRAGE_ICK = 69263, + + // krick spells + SPELL_TOXIC_WASTE = 69024, + SPELL_SHADOW_BOLT = 69028, + SPELL_EXPLOSIVE_BARRAGE_KRICK = 69012, // Triggers 69015 every 2 sec + + NPC_EXPLODING_ORB = 36610, + + // exploding orb spells + // SPELL_EXPLOSIVE_BARRAGE_SUMMON = 69015, + SPELL_EXPLODING_ORB_VISUAL = 69017, + SPELL_AUTO_GROW_AND_SPEED_BOOST = 69020, + SPELL_EXPLOSIVE_BARRAGE_DMG = 69019, + SPELL_HASTY_GROW = 44851, // Orb explodes after the 15th stack + + MAX_HASTY_GROW_STACKS = 15, +}; + +static const float afOutroNpcSpawnLoc[4] = {777.2274f, 119.5521f, 510.0363f, 6.05f}; +static const float afTyrannusTeleLoc[4] = {841.01f, 196.245f, 573.964f, 4.46f}; + +/*###### +## boss_ick +######*/ + +struct boss_ickAI : public ScriptedAI +{ + boss_ickAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_pit_of_saron*)pCreature->GetInstanceData(); + m_uiMountTimer = 1000; + Reset(); + } + + instance_pit_of_saron* m_pInstance; + uint32 m_uiMountTimer; + + uint32 m_uiPoisonNovaTimer; + uint32 m_uiPursueTimer; + uint32 m_uiMightKickTimer; + uint32 m_uiToxicWasteTimer; + uint32 m_uiShadowboltTimer; + uint32 m_uiExplosivBarrageTimer; + uint32 m_uiCooldownTimer; + + void Reset() override + { + m_uiPoisonNovaTimer = urand(20000, 25000); + m_uiPursueTimer = 20000; + m_uiMightKickTimer = 1000; + m_uiToxicWasteTimer = urand(3000, 5000); + m_uiShadowboltTimer = urand(5000, 7000); + m_uiExplosivBarrageTimer = urand(30000, 35000); + m_uiCooldownTimer = 0; + } + + void Aggro(Unit* pWho) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_KRICK, IN_PROGRESS); + + // Say aggro and also put Krick in combat + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + { + DoScriptText(SAY_AGGRO, pKrick); + pKrick->AI()->AttackStart(pWho); + } + } + } + + void KilledUnit(Unit* /*pVictim*/) + { + if (m_pInstance) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, pKrick); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_KRICK, DONE); + + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + { + DoScriptText(SAY_OUTRO_1, pKrick); + pKrick->AI()->EnterEvadeMode(); + + // Summon Jaina or Sylvanas for epilogue + pKrick->SummonCreature(m_pInstance->GetPlayerTeam() == HORDE ? NPC_SYLVANAS_PART1 : NPC_JAINA_PART1, + afOutroNpcSpawnLoc[0], afOutroNpcSpawnLoc[1], afOutroNpcSpawnLoc[2], afOutroNpcSpawnLoc[3], TEMPSUMMON_TIMED_DESPAWN, 2 * MINUTE * IN_MILLISECONDS); + } + + if (Creature* pTyrannus = m_pInstance->GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO)) + pTyrannus->NearTeleportTo(afTyrannusTeleLoc[0], afTyrannusTeleLoc[1], afTyrannusTeleLoc[2], afTyrannusTeleLoc[3]); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KRICK, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + // He needs to be mounted manually, not by vehicle_accessories + if (m_uiMountTimer) + { + if (m_uiMountTimer <= uiDiff) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + pKrick->CastSpell(m_creature, SPELL_RIDE_VEHICLE_HARDCODED, true); + + m_uiMountTimer = 0; + } + else + m_uiMountTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Cooldown timer - we need to block all Krick spell during some events + if (m_uiCooldownTimer) + { + if (m_uiCooldownTimer <= uiDiff) + m_uiCooldownTimer = 0; + else + m_uiCooldownTimer -= uiDiff; + + return; + } + + if (m_uiPoisonNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_POISON_NOVA) == CAST_OK) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + { + DoScriptText(SAY_ORDER_BLOW, pKrick); + DoScriptText(EMOTE_ICK_POISON, pKrick); + } + + m_uiCooldownTimer = 5000; + m_uiPoisonNovaTimer = urand(20000, 25000); + } + } + else + m_uiPoisonNovaTimer -= uiDiff; + + if (m_uiPursueTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PURSUIT) == CAST_OK) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_TARGET_1, pKrick); break; + case 1: DoScriptText(SAY_TARGET_2, pKrick); break; + case 2: DoScriptText(SAY_TARGET_3, pKrick); break; + } + } + + m_uiCooldownTimer = 17000; + m_uiPursueTimer = urand(50000, 70000); + } + } + else + m_uiPursueTimer -= uiDiff; + + if (m_uiMightKickTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTY_KICK) == CAST_OK) + m_uiMightKickTimer = 10000; + } + else + m_uiMightKickTimer -= uiDiff; + + if (m_uiToxicWasteTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + pKrick->CastSpell(pTarget, SPELL_TOXIC_WASTE, true); + + m_uiToxicWasteTimer = urand(3000, 5000); + } + } + else + m_uiToxicWasteTimer -= uiDiff; + + if (m_uiShadowboltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + pKrick->CastSpell(pTarget, SPELL_SHADOW_BOLT, true); + + m_uiShadowboltTimer = urand(4000, 8000); + } + } + else + m_uiShadowboltTimer -= uiDiff; + + if (m_uiExplosivBarrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLOSIVE_BARRAGE_ICK) == CAST_OK) + { + if (Creature* pKrick = m_pInstance->GetSingleCreatureFromStorage(NPC_KRICK)) + { + pKrick->CastSpell(pKrick, SPELL_EXPLOSIVE_BARRAGE_KRICK, true); + + DoScriptText(SAY_ORDER_STOP, pKrick); + DoScriptText(EMOTE_KRICK_MINES, pKrick); + } + + m_uiCooldownTimer = 20000; + m_uiExplosivBarrageTimer = urand(25000, 30000); + } + } + else + m_uiExplosivBarrageTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ick(Creature* pCreature) +{ + return new boss_ickAI(pCreature); +} + +/*###### +## boss_krick +######*/ + +struct boss_krickAI : public ScriptedAI +{ + boss_krickAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() override { } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + Reset(); + + // Don't handle movement. Boss is on vehicle so he doesn't have to go anywhere. On epilogue he needs to stay in place + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_SYLVANAS_PART1: + case NPC_JAINA_PART1: + { + float fX, fY, fZ; + pSummoned->SetWalk(false); + m_creature->GetContactPoint(pSummoned, fX, fY, fZ, 2 * INTERACTION_DISTANCE); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + break; + } + case NPC_EXPLODING_ORB: + pSummoned->CastSpell(pSummoned, SPELL_EXPLODING_ORB_VISUAL, true); + pSummoned->CastSpell(pSummoned, SPELL_AUTO_GROW_AND_SPEED_BOOST, true); + break; + } + } + + void SummonedMovementInform(Creature* /*pSummoned*/, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (m_pInstance) + m_pInstance->SetData(TYPE_KRICK, SPECIAL); + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + } }; +CreatureAI* GetAI_boss_krick(Creature* pCreature) +{ + return new boss_krickAI(pCreature); +} + +/*###### +## npc_exploding_orb +######*/ + +struct npc_exploding_orbAI : public Scripted_NoMovementAI +{ + npc_exploding_orbAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint8 m_uiGrowCount; + + void Reset() override + { + m_uiGrowCount = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_HASTY_GROW) + { + ++m_uiGrowCount; + + if (m_uiGrowCount == MAX_HASTY_GROW_STACKS) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLOSIVE_BARRAGE_DMG) == CAST_OK) + { + m_creature->RemoveAllAuras(); + m_creature->ForcedDespawn(1000); + } + } + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_exploding_orb(Creature* pCreature) +{ + return new npc_exploding_orbAI(pCreature); +} + void AddSC_boss_krick_and_ick() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ick"; + pNewScript->GetAI = &GetAI_boss_ick; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_krick"; + pNewScript->GetAI = &GetAI_boss_krick; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_exploding_orb"; + pNewScript->GetAI = &GetAI_npc_exploding_orb; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp index e83052f1e..07941a751 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/boss_scourgelord_tyrannus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_scourgelord_tyrannus -SD%Complete: 0% -SDComment: +SD%Complete: 90 +SDComment: Small adjustments may be required SDCategory: Pit of Saron EndScriptData */ @@ -26,9 +26,6 @@ EndScriptData */ enum { - SAY_PREFIGHT_1 = -1658050, - SAY_GENERAL_TRASH = -1658051, - SAY_PREFIGHT_2 = -1658052, SAY_AGGRO = -1658053, SAY_SLAY_1 = -1658054, SAY_SLAY_2 = -1658055, @@ -38,9 +35,299 @@ enum EMOTE_RIMEFANG_ICEBOLT = -1658059, EMOTE_SMASH = -1658060, + + // Tyrannus spells + SPELL_FORCEFUL_SMASH = 69155, + SPELL_OVERLORDS_BRAND = 69172, // triggers 69189 and 69190 from target + SPELL_UNHOLY_POWER = 69167, + SPELL_MARK_OF_RIMEFANG = 69275, + + // Rimefang spells + SPELL_HOARFROST = 69246, + SPELL_ICY_BLAST = 69232, + SPELL_KILLING_ICE = 72531, + + // Icy blast + // SPELL_ICY_BLAST_AURA = 69238, + NPC_ICY_BLAST = 36731, // handled in eventAI +}; + +static const float afRimefangExitPos[3] = {1248.29f, 145.924f, 733.914f}; + +/*###### +## boss_tyrannus +######*/ + +struct boss_tyrannusAI : public ScriptedAI +{ + boss_tyrannusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_pit_of_saron*)pCreature->GetInstanceData(); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Reset(); + } + + instance_pit_of_saron* m_pInstance; + + uint32 m_uiForcefulSmashTimer; + uint32 m_uiOverlordsBrandTimer; + uint32 m_uiUnholyPowerTimer; + uint32 m_uiMarkOfRimefangTimer; + + void Reset() override + { + m_uiForcefulSmashTimer = 10000; + m_uiOverlordsBrandTimer = 9000; + m_uiUnholyPowerTimer = urand(30000, 35000); + m_uiMarkOfRimefangTimer = 20000; + } + + void Aggro(Unit* pWho) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_TYRANNUS, IN_PROGRESS); + + // Set Rimefang in combat - ToDo: research if it has some wp movement during combat + if (Creature* pRimefang = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG)) + pRimefang->AI()->AttackStart(pWho); + } + } + + void KilledUnit(Unit* /*pVictim*/) + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_TYRANNUS, DONE); + + // Move Rimefang out of the area + if (Creature* pRimefang = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG)) + { + pRimefang->AI()->EnterEvadeMode(); + pRimefang->SetWalk(false); + pRimefang->ForcedDespawn(25000); + pRimefang->GetMotionMaster()->MovePoint(0, afRimefangExitPos[0], afRimefangExitPos[1], afRimefangExitPos[2]); + } + + // Move the general near the boss - ToDo: move the other freed slaves as well + if (Creature* pGeneral = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetPlayerTeam() == HORDE ? NPC_IRONSKULL_PART2 : NPC_VICTUS_PART2)) + { + float fX, fY, fZ; + pGeneral->SetWalk(false); + m_creature->GetContactPoint(pGeneral, fX, fY, fZ, INTERACTION_DISTANCE); + pGeneral->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_TYRANNUS, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiForcefulSmashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FORCEFUL_SMASH) == CAST_OK) + m_uiForcefulSmashTimer = 50000; + } + else + m_uiForcefulSmashTimer -= uiDiff; + + if (m_uiOverlordsBrandTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_OVERLORDS_BRAND) == CAST_OK) + m_uiOverlordsBrandTimer = urand(10000, 13000); + } + } + else + m_uiOverlordsBrandTimer -= uiDiff; + + if (m_uiUnholyPowerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNHOLY_POWER) == CAST_OK) + { + DoScriptText(SAY_SMASH, m_creature); + DoScriptText(EMOTE_SMASH, m_creature); + m_uiUnholyPowerTimer = 60000; + } + } + else + m_uiUnholyPowerTimer -= uiDiff; + + if (m_uiMarkOfRimefangTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MARK_OF_RIMEFANG) == CAST_OK) + { + DoScriptText(SAY_MARK, m_creature); + if (m_pInstance) + { + if (Creature* pRimefang = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG)) + { + pRimefang->InterruptNonMeleeSpells(true); + pRimefang->CastSpell(pTarget, SPELL_HOARFROST, false); + DoScriptText(EMOTE_RIMEFANG_ICEBOLT, pRimefang, pTarget); + } + } + m_uiMarkOfRimefangTimer = urand(20000, 25000); + } + } + } + else + m_uiMarkOfRimefangTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } }; +CreatureAI* GetAI_boss_tyrannus(Creature* pCreature) +{ + return new boss_tyrannusAI(pCreature); +} + +/*###### +## boss_rimefang_pos +######*/ + +struct boss_rimefang_posAI : public ScriptedAI +{ + boss_rimefang_posAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_pit_of_saron*)pCreature->GetInstanceData(); + SetCombatMovement(false); + m_bHasDoneIntro = false; + m_uiMountTimer = 1000; + Reset(); + } + + instance_pit_of_saron* m_pInstance; + uint32 m_uiMountTimer; + + uint32 m_uiIcyBlastTimer; + bool m_bHasDoneIntro; + + void Reset() override + { + m_uiIcyBlastTimer = 8000; + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + Reset(); + + // Don't handle movement. + } + + void AttackStart(Unit* pWho) override + { + // Don't attack unless Tyrannus is in combat or Ambush is completed + if (m_pInstance && (m_pInstance->GetData(TYPE_AMBUSH) != DONE || m_pInstance->GetData(TYPE_TYRANNUS) != IN_PROGRESS)) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_pInstance) + return; + + // Check if ambush is done + if (m_pInstance->GetData(TYPE_AMBUSH) != DONE) + return; + + // Start the intro when possible + if (!m_bHasDoneIntro && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 85.0f) && m_creature->IsWithinLOSInMap(pWho)) + { + m_pInstance->SetData(TYPE_TYRANNUS, SPECIAL); + m_bHasDoneIntro = true; + return; + } + + // Check for out of range players - ToDo: confirm the distance + if (m_pInstance->GetData(TYPE_TYRANNUS) == IN_PROGRESS && pWho->GetTypeId() == TYPEID_PLAYER && !m_creature->IsWithinDistInMap(pWho, DEFAULT_VISIBILITY_INSTANCE)) + DoCastSpellIfCan(pWho, SPELL_KILLING_ICE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + // He needs to be mounted manually, not by vehicle_accessories + if (m_uiMountTimer) + { + if (m_uiMountTimer <= uiDiff) + { + if (Creature* pTyrannus = m_pInstance->GetSingleCreatureFromStorage(NPC_TYRANNUS)) + pTyrannus->CastSpell(m_creature, SPELL_RIDE_VEHICLE_HARDCODED, true); + + m_uiMountTimer = 0; + } + else + m_uiMountTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiIcyBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ICY_BLAST) == CAST_OK) + { + m_creature->SummonCreature(NPC_ICY_BLAST, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 90000); + m_uiIcyBlastTimer = 8000; + } + } + } + else + m_uiIcyBlastTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_rimefang_pos(Creature* pCreature) +{ + return new boss_rimefang_posAI(pCreature); +} + void AddSC_boss_tyrannus() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_tyrannus"; + pNewScript->GetAI = &GetAI_boss_tyrannus; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_rimefang_pos"; + pNewScript->GetAI = &GetAI_boss_rimefang_pos; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp index 7a9ae4b48..aa71e48a2 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/instance_pit_of_saron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: instance_pit_of_saron -SD%Complete: 50% +SD%Complete: 80% SDComment: SDCategory: Pit of Saron EndScriptData */ @@ -24,34 +24,237 @@ EndScriptData */ #include "precompiled.h" #include "pit_of_saron.h" -instance_pit_of_saron::instance_pit_of_saron(Map* pMap) : ScriptedInstance(pMap) +enum +{ + // Intro + SAY_TYRANNUS_INTRO_1 = -1658001, + SAY_JAINA_INTRO_1 = -1658002, + SAY_SYLVANAS_INTRO_1 = -1658003, + SAY_TYRANNUS_INTRO_2 = -1658004, + SAY_TYRANNUS_INTRO_3 = -1658005, + SAY_JAINA_INTRO_2 = -1658006, + SAY_SYLVANAS_INTRO_2 = -1658007, + SAY_TYRANNUS_INTRO_4 = -1658008, + SAY_JAINA_INTRO_3 = -1658009, + SAY_JAINA_INTRO_4 = -1658010, + SAY_SYLVANAS_INTRO_3 = -1658011, + SAY_JAINA_INTRO_5 = -1658012, + SAY_SYLVANAS_INTRO_4 = -1658013, + + // Intro spells + SPELL_NECROMATIC_POWER = 69347, + SPELL_FEIGN_DEATH = 28728, + SPELL_RAISE_DEAD = 69350, + + // Garfrost outro + SAY_TYRANNUS_GARFROST = -1658020, + SAY_GENERAL_GARFROST = -1658021, + + // Ick and Krick outro + SAY_JAINA_KRICK_1 = -1658036, + SAY_SYLVANAS_KRICK_1 = -1658037, + SAY_OUTRO_2 = -1658038, + SAY_JAINA_KRICK_2 = -1658039, + SAY_SYLVANAS_KRICK_2 = -1658040, + SAY_OUTRO_3 = -1658041, + SAY_TYRANNUS_KRICK_1 = -1658042, + SAY_OUTRO_4 = -1658043, + SAY_TYRANNUS_KRICK_2 = -1658044, + SAY_JAINA_KRICK_3 = -1658045, + SAY_SYLVANAS_KRICK_3 = -1658046, + + // Ick and Krick outro spells + SPELL_STRANGULATING = 69413, + SPELL_KRICK_KILL_CREDIT = 71308, + SPELL_SUICIDE = 7, + + // Ambush and Gauntlet + SAY_TYRANNUS_AMBUSH_1 = -1658047, + SAY_TYRANNUS_AMBUSH_2 = -1658048, + SAY_GAUNTLET = -1658049, + + // Gauntlet spells + SPELL_ICICLE_SUMMON = 69424, + SPELL_ACHIEVEMENT_CHECK = 72845, + + // Tyrannus intro + SAY_PREFIGHT_1 = -1658050, + SAY_VICTUS_TRASH = -1658051, + SAY_IRONSKULL_TRASH = -1658068, + SAY_PREFIGHT_2 = -1658052, + + SPELL_EJECT_ALL_PASSENGERS = 50630, + // SPELL_CSA_DUMMY_EFFECT_1 = 56685, // What is this? + + // Sindragosa outro + SAY_VICTUS_OUTRO_1 = -1658061, + SAY_IRONSKULL_OUTRO_2 = -1658069, + SAY_GENERAL_OUTRO_2 = -1658062, + SAY_JAINA_OUTRO_1 = -1658063, + SAY_SYLVANAS_OUTRO_1 = -1658064, + SAY_JAINA_OUTRO_2 = -1658065, + SAY_JAINA_OUTRO_3 = -1658066, + SAY_SYLVANAS_OUTRO_2 = -1658067, + + SPELL_FROST_BOMB = 70521, + SPELL_FROZEN_AFTERMATH = 70518, + SPELL_ARCANE_FORM = 70573, + SPELL_CALL_OF_SYLVANAS_1 = 70636, // triggers 70639 + SPELL_CALL_OF_SYLVANAS_2 = 70638, + // SPELL_CALL_OF_SYLVANAS_3 = 70642, + SPELL_JAINAS_CALL_1 = 70527, // triggers 70525 + SPELL_JAINAS_CALL_2 = 70623, +}; + +static const DialogueEntryTwoSide aPoSDialogues[] = +{ + // Instance intro + {NPC_TYRANNUS_INTRO, 0, 0, 0, 4000}, + {SAY_TYRANNUS_INTRO_1, NPC_TYRANNUS_INTRO, 0, 0, 6000}, + {SAY_TYRANNUS_INTRO_2, NPC_TYRANNUS_INTRO, 0, 0, 12000}, + {SAY_JAINA_INTRO_1, NPC_JAINA_PART1, SAY_SYLVANAS_INTRO_1, NPC_SYLVANAS_PART1, 5000}, // ToDo: move the soldiers to attack position + {SAY_TYRANNUS_INTRO_3, NPC_TYRANNUS_INTRO, 0, 0, 5000}, + {SPELL_NECROMATIC_POWER, 0, 0, 0, 3000}, + {SAY_JAINA_INTRO_2, NPC_JAINA_PART1, SAY_SYLVANAS_INTRO_2, NPC_SYLVANAS_PART1, 4000}, + {SAY_TYRANNUS_INTRO_4, NPC_TYRANNUS_INTRO, 0, 0, 4000}, // ToDo: send the solderis back to fight as zombies + {SAY_JAINA_INTRO_3, NPC_JAINA_PART1, 0, 0, 6000}, + {SAY_JAINA_INTRO_4, NPC_JAINA_PART1, SAY_SYLVANAS_INTRO_3, NPC_SYLVANAS_PART1, 5000}, + {SAY_JAINA_INTRO_5, NPC_JAINA_PART1, SAY_SYLVANAS_INTRO_4, NPC_SYLVANAS_PART1, 0}, + + // Garfrost outro + {NPC_GARFROST, 0, 0, 0, 4000}, // ToDo: move the freed slaves to position + {SAY_GENERAL_GARFROST, NPC_VICTUS_PART1, SAY_GENERAL_GARFROST, NPC_IRONSKULL_PART1, 2000}, + {SAY_TYRANNUS_GARFROST, NPC_TYRANNUS_INTRO, 0, 0, 0}, + + // Ick and Krick outro + {SAY_JAINA_KRICK_1, NPC_JAINA_PART1, SAY_SYLVANAS_KRICK_1, NPC_SYLVANAS_PART1, 6000}, + {SAY_OUTRO_2, NPC_KRICK, 0, 0, 16000}, + {SAY_JAINA_KRICK_2, NPC_JAINA_PART1, SAY_SYLVANAS_KRICK_2, NPC_SYLVANAS_PART1, 7000}, + {SAY_OUTRO_3, NPC_KRICK, 0, 0, 7000}, + {SAY_TYRANNUS_KRICK_1, NPC_TYRANNUS_INTRO, 0, 0, 3000}, + {SPELL_STRANGULATING, 0, 0, 0, 3000}, + {SAY_OUTRO_4, NPC_KRICK, 0, 0, 3000}, + {SAY_TYRANNUS_KRICK_2, NPC_TYRANNUS_INTRO, 0, 0, 11000}, + {SAY_JAINA_KRICK_3, NPC_JAINA_PART1, SAY_SYLVANAS_KRICK_3, NPC_SYLVANAS_PART1, 0}, + + // Tyrannus intro + {NPC_TYRANNUS, 0, 0, 0, 10000}, // ToDo: move the freed slaves to position + {SAY_PREFIGHT_1, NPC_TYRANNUS, 0, 0, 13000}, + {SAY_VICTUS_TRASH, NPC_VICTUS_PART2, SAY_IRONSKULL_TRASH, NPC_IRONSKULL_PART2, 9000}, + {SAY_PREFIGHT_2, NPC_TYRANNUS, 0, 0, 10000}, + {NPC_RIMEFANG, 0, 0, 0, 0}, + + // Tyrannus outro + {NPC_SINDRAGOSA, 0, 0, 0, 30000}, + {SAY_VICTUS_OUTRO_1, NPC_VICTUS_PART2, SAY_IRONSKULL_OUTRO_2, NPC_IRONSKULL_PART2, 17000}, + {SAY_GENERAL_OUTRO_2, NPC_VICTUS_PART2, SAY_GENERAL_OUTRO_2, NPC_IRONSKULL_PART2, 14000}, + {SAY_JAINA_OUTRO_1, NPC_JAINA_PART2, SAY_SYLVANAS_OUTRO_1, NPC_SYLVANAS_PART2, 1000}, + {SPELL_FROST_BOMB, 0, 0, 0, 7000}, + {NPC_JAINA_PART2, 0, 0, 0, 8000}, + {SAY_JAINA_OUTRO_2, NPC_JAINA_PART2, SAY_SYLVANAS_OUTRO_2, NPC_SYLVANAS_PART2, 15000}, + {SAY_JAINA_OUTRO_3, NPC_JAINA_PART2, 0, 0, 0}, + {0, 0, 0}, +}; + +instance_pit_of_saron::instance_pit_of_saron(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aPoSDialogues), + m_uiAmbushAggroCount(0), + m_uiTeam(TEAM_NONE), + m_uiIciclesTimer(0) { Initialize(); } - void instance_pit_of_saron::Initialize() +void instance_pit_of_saron::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + InitializeDialogueHelper(this); + + for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS; ++i) + m_abAchievCriteria[i] = false; +} + +void instance_pit_of_saron::OnPlayerEnter(Player* pPlayer) +{ + if (!m_uiTeam) // very first player to enter + { + m_uiTeam = pPlayer->GetTeam(); + SetDialogueSide(m_uiTeam == ALLIANCE); + ProcessIntroEventNpcs(pPlayer); + } +} + +void instance_pit_of_saron::ProcessIntroEventNpcs(Player* pPlayer) +{ + if (!pPlayer) + return; + + // Not if the bosses are already killed + if (GetData(TYPE_GARFROST) == DONE || GetData(TYPE_KRICK) == DONE) + return; + + StartNextDialogueText(NPC_TYRANNUS_INTRO); + + // Spawn Begin Mobs + for (uint8 i = 0; i < countof(aEventBeginLocations); ++i) + { + // ToDo: maybe despawn the intro npcs when the other events occur + if (Creature* pSummon = pPlayer->SummonCreature(m_uiTeam == HORDE ? aEventBeginLocations[i].uiEntryHorde : aEventBeginLocations[i].uiEntryAlliance, + aEventBeginLocations[i].fX, aEventBeginLocations[i].fY, aEventBeginLocations[i].fZ, aEventBeginLocations[i].fO, TEMPSUMMON_TIMED_DESPAWN, 24 * HOUR * IN_MILLISECONDS)) + { + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MovePoint(0, aEventBeginLocations[i].fMoveX, aEventBeginLocations[i].fMoveY, aEventBeginLocations[i].fMoveZ); + } + } } void instance_pit_of_saron::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_TYRANNUS_INTRO: + case NPC_JAINA_PART1: + case NPC_SYLVANAS_PART1: case NPC_GARFROST: case NPC_KRICK: case NPC_ICK: case NPC_TYRANNUS: case NPC_RIMEFANG: + case NPC_IRONSKULL_PART1: + case NPC_VICTUS_PART1: + case NPC_IRONSKULL_PART2: + case NPC_VICTUS_PART2: + case NPC_JAINA_PART2: + case NPC_SYLVANAS_PART2: + case NPC_SINDRAGOSA: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_STALKER: + m_lTunnelStalkersGuidList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_YMIRJAR_DEATHBRINGER: + case NPC_YMIRJAR_WRATHBRINGER: + case NPC_YMIRJAR_FLAMEBEARER: + case NPC_FALLEN_WARRIOR: + case NPC_COLDWRAITH: + // Sort only the temporary summons + if (pCreature->IsTemporarySummon()) + m_lAmbushNpcsGuidList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_GENERAL_BUNNY: + if (pCreature->GetPositionY() < 130.0f) + { + if (pCreature->GetOrientation() != 0) + m_lArcaneShieldBunniesGuidList.push_back(pCreature->GetObjectGuid()); + else + m_lFrozenAftermathBunniesGuidList.push_back(pCreature->GetObjectGuid()); + } + break; } } void instance_pit_of_saron::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_ICEWALL: if (m_auiEncounter[TYPE_GARFROST] == DONE && m_auiEncounter[TYPE_KRICK] == DONE) @@ -68,19 +271,48 @@ void instance_pit_of_saron::OnObjectCreate(GameObject* pGo) void instance_pit_of_saron::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_GARFROST: if (uiData == DONE && m_auiEncounter[TYPE_KRICK] == DONE) DoUseDoorOrButton(GO_ICEWALL); + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_DOESNT_GO_ELEVEN, true); + else if (uiData == DONE) + StartNextDialogueText(NPC_GARFROST); m_auiEncounter[uiType] = uiData; break; case TYPE_KRICK: if (uiData == DONE && m_auiEncounter[TYPE_GARFROST] == DONE) DoUseDoorOrButton(GO_ICEWALL); + if (uiData == SPECIAL) + { + // Used just to start the epilogue + StartNextDialogueText(SAY_JAINA_KRICK_1); + return; + } m_auiEncounter[uiType] = uiData; break; case TYPE_TYRANNUS: + if (uiData == DONE) + StartNextDialogueText(NPC_SINDRAGOSA); + else if (uiData == SPECIAL) + { + // Used just to start the intro + StartNextDialogueText(NPC_TYRANNUS); + return; + } + m_auiEncounter[uiType] = uiData; + break; + case TYPE_AMBUSH: + if (uiData == DONE) + { + // Complete tunnel achievement + if (Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS)) + pTyrannus->CastSpell(pTyrannus, SPELL_ACHIEVEMENT_CHECK, true); + + m_uiIciclesTimer = 0; + } m_auiEncounter[uiType] = uiData; break; default: @@ -92,7 +324,7 @@ void instance_pit_of_saron::SetData(uint32 uiType, uint32 uiData) OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; m_strInstData = saveStream.str(); @@ -112,9 +344,9 @@ void instance_pit_of_saron::Load(const char* chrIn) OUT_LOAD_INST_DATA(chrIn); std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -123,7 +355,7 @@ void instance_pit_of_saron::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_pit_of_saron::GetData(uint32 uiType) +uint32 instance_pit_of_saron::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -131,6 +363,278 @@ uint32 instance_pit_of_saron::GetData(uint32 uiType) return 0; } +void instance_pit_of_saron::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_YMIRJAR_DEATHBRINGER) + { + ++m_uiAmbushAggroCount; + + // Summon the rest of the mobs at the 2nd ambush + if (m_uiAmbushAggroCount == 2) + { + Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO); + if (!pTyrannus) + return; + + DoScriptText(SAY_TYRANNUS_AMBUSH_2, pTyrannus); + pTyrannus->SetWalk(false); + pTyrannus->GetMotionMaster()->MovePoint(0, afTyrannusMovePos[2][0], afTyrannusMovePos[2][1], afTyrannusMovePos[2][2]); + + // Spawn Mobs + for (uint8 i = 0; i < countof(aEventSecondAmbushLocations); ++i) + { + if (Creature* pSummon = pTyrannus->SummonCreature(aEventSecondAmbushLocations[i].uiEntryHorde, aEventSecondAmbushLocations[i].fX, aEventSecondAmbushLocations[i].fY, + aEventSecondAmbushLocations[i].fZ, aEventSecondAmbushLocations[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MovePoint(1, aEventSecondAmbushLocations[i].fMoveX, aEventSecondAmbushLocations[i].fMoveY, aEventSecondAmbushLocations[i].fMoveZ); + } + } + } + } +} + +void instance_pit_of_saron::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_YMIRJAR_DEATHBRINGER: + case NPC_YMIRJAR_WRATHBRINGER: + case NPC_YMIRJAR_FLAMEBEARER: + case NPC_FALLEN_WARRIOR: + case NPC_COLDWRAITH: + // Check for tunnel event end - these mobs are not summoned + if (pCreature->IsTemporarySummon()) + { + m_lAmbushNpcsGuidList.remove(pCreature->GetObjectGuid()); + + // If empty start tunnel event + if (m_lAmbushNpcsGuidList.empty()) + { + Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO); + if (!pTyrannus) + return; + + DoScriptText(SAY_GAUNTLET, pTyrannus); + pTyrannus->SetWalk(false); + pTyrannus->GetMotionMaster()->MovePoint(0, afTyrannusMovePos[0][0], afTyrannusMovePos[0][1], afTyrannusMovePos[0][2]); + pTyrannus->ForcedDespawn(20000); + + m_uiIciclesTimer = urand(3000, 5000); + SetSpecialAchievementCriteria(TYPE_ACHIEV_DONT_LOOK_UP, true); + } + } + break; + } +} + +void instance_pit_of_saron::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < MAX_SPECIAL_ACHIEV_CRITS) + m_abAchievCriteria[uiType] = bIsMet; +} + +bool instance_pit_of_saron::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_DOESNT_GO_ELEVEN: + return m_abAchievCriteria[TYPE_ACHIEV_DOESNT_GO_ELEVEN]; + case ACHIEV_CRIT_DONT_LOOK_UP: + return m_abAchievCriteria[TYPE_ACHIEV_DONT_LOOK_UP]; + + default: + return false; + } +} + +void instance_pit_of_saron::JustDidDialogueStep(int32 iEntry) +{ + switch (iEntry) + { + case SPELL_NECROMATIC_POWER: + // Transfor all soldiers into undead + if (Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO)) + pTyrannus->CastSpell(pTyrannus, SPELL_NECROMATIC_POWER, true); + break; + case SAY_OUTRO_3: + // Move Tyrannus into position + if (Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO)) + { + pTyrannus->SetWalk(false); + pTyrannus->GetMotionMaster()->MovePoint(0, afTyrannusMovePos[1][0], afTyrannusMovePos[1][1], afTyrannusMovePos[1][2]); + } + break; + case SPELL_STRANGULATING: + // Strangulate Krick + if (Creature* pKrick = GetSingleCreatureFromStorage(NPC_KRICK)) + { + pKrick->CastSpell(pKrick, SPELL_STRANGULATING, true); + pKrick->SetLevitate(true); + pKrick->GetMotionMaster()->MovePoint(0, pKrick->GetPositionX(), pKrick->GetPositionY(), pKrick->GetPositionZ() + 5.0f); + } + break; + case SAY_TYRANNUS_KRICK_2: + // Kill Krick + if (Creature* pKrick = GetSingleCreatureFromStorage(NPC_KRICK)) + { + pKrick->CastSpell(pKrick, SPELL_KRICK_KILL_CREDIT, true); + pKrick->CastSpell(pKrick, SPELL_SUICIDE, true); + } + break; + case SAY_JAINA_INTRO_3: + case SAY_JAINA_KRICK_3: + // Move Tyrannus to a safe position + if (Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO)) + pTyrannus->GetMotionMaster()->MovePoint(0, afTyrannusMovePos[0][0], afTyrannusMovePos[0][1], afTyrannusMovePos[0][2]); + break; + case NPC_TYRANNUS: + { + Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS); + if (!pTyrannus) + return; + + // Spawn tunnel end event mobs + for (uint8 i = 0; i < countof(aEventTunnelEndLocations); ++i) + { + if (Creature* pSummon = pTyrannus->SummonCreature(m_uiTeam == HORDE ? aEventTunnelEndLocations[i].uiEntryHorde : aEventTunnelEndLocations[i].uiEntryAlliance, + aEventTunnelEndLocations[i].fX, aEventTunnelEndLocations[i].fY, aEventTunnelEndLocations[i].fZ, aEventTunnelEndLocations[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MovePoint(0, aEventTunnelEndLocations[i].fMoveX, aEventTunnelEndLocations[i].fMoveY, aEventTunnelEndLocations[i].fMoveZ); + } + } + break; + } + case NPC_RIMEFANG: + // Eject Tyrannus and prepare for combat + if (Creature* pRimefang = GetSingleCreatureFromStorage(NPC_RIMEFANG)) + { + pRimefang->CastSpell(pRimefang, SPELL_EJECT_ALL_PASSENGERS, true); + pRimefang->SetWalk(false); + pRimefang->GetMotionMaster()->MovePoint(0, afTyrannusMovePos[3][0], afTyrannusMovePos[3][1], afTyrannusMovePos[3][2]); + } + if (Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS)) + pTyrannus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + break; + case SAY_VICTUS_OUTRO_1: + { + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + // Spawn Sindragosa + if (Creature* pSummon = pPlayer->SummonCreature(aEventOutroLocations[0].uiEntryHorde, aEventOutroLocations[0].fX, aEventOutroLocations[0].fY, + aEventOutroLocations[0].fZ, aEventOutroLocations[0].fO, TEMPSUMMON_TIMED_DESPAWN, 2 * MINUTE * IN_MILLISECONDS)) + { + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MovePoint(0, aEventOutroLocations[0].fMoveX, aEventOutroLocations[0].fMoveY, aEventOutroLocations[0].fMoveZ); + } + // Spawn Jaina or Sylvanas + if (Creature* pSummon = pPlayer->SummonCreature(m_uiTeam == HORDE ? aEventOutroLocations[1].uiEntryHorde : aEventOutroLocations[1].uiEntryAlliance, + aEventOutroLocations[1].fX, aEventOutroLocations[1].fY, aEventOutroLocations[1].fZ, aEventOutroLocations[1].fO, TEMPSUMMON_TIMED_DESPAWN, 24 * HOUR * IN_MILLISECONDS)) + { + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MovePoint(0, aEventOutroLocations[1].fMoveX, aEventOutroLocations[1].fMoveY, aEventOutroLocations[1].fMoveZ); + } + break; + } + case SAY_JAINA_OUTRO_1: + // Visual effect + for (GuidList::const_iterator itr = m_lArcaneShieldBunniesGuidList.begin(); itr != m_lArcaneShieldBunniesGuidList.end(); ++itr) + { + if (Creature* pBunny = instance->GetCreature(*itr)) + pBunny->CastSpell(pBunny, SPELL_ARCANE_FORM, true); + } + // Teleport players + if (Creature* pTemp = GetSingleCreatureFromStorage(m_uiTeam == HORDE ? NPC_SYLVANAS_PART2 : NPC_JAINA_PART2)) + { + pTemp->CastSpell(pTemp, m_uiTeam == HORDE ? SPELL_CALL_OF_SYLVANAS_2 : SPELL_JAINAS_CALL_2, true); + pTemp->CastSpell(pTemp, m_uiTeam == HORDE ? SPELL_CALL_OF_SYLVANAS_2 : SPELL_JAINAS_CALL_2, true); + } + break; + case SPELL_FROST_BOMB: + // Frost bomb on the platform + if (Creature* pSindragosa = GetSingleCreatureFromStorage(NPC_SINDRAGOSA)) + pSindragosa->CastSpell(pSindragosa, SPELL_FROST_BOMB, true); + // Visual effect + for (GuidList::const_iterator itr = m_lFrozenAftermathBunniesGuidList.begin(); itr != m_lFrozenAftermathBunniesGuidList.end(); ++itr) + { + if (Creature* pBunny = instance->GetCreature(*itr)) + pBunny->CastSpell(pBunny, SPELL_FROZEN_AFTERMATH, true); + } + break; + case NPC_JAINA_PART2: + // Visual effect remove + for (GuidList::const_iterator itr = m_lArcaneShieldBunniesGuidList.begin(); itr != m_lArcaneShieldBunniesGuidList.end(); ++itr) + { + if (Creature* pBunny = instance->GetCreature(*itr)) + pBunny->RemoveAurasDueToSpell(SPELL_ARCANE_FORM); + } + // Sindragosa exit + if (Creature* pSindragosa = GetSingleCreatureFromStorage(NPC_SINDRAGOSA)) + pSindragosa->GetMotionMaster()->MovePoint(0, 759.148f, 199.955f, 720.857f); + // Jaina / Sylvanas starts moving (should use wp) + if (Creature* pTemp = GetSingleCreatureFromStorage(m_uiTeam == HORDE ? NPC_SYLVANAS_PART2 : NPC_JAINA_PART2)) + { + pTemp->SetWalk(true); + pTemp->GetMotionMaster()->MovePoint(0, 1057.76f, 111.927f, 628.4123f); + } + break; + case SAY_JAINA_OUTRO_2: + if (Creature* pTemp = GetSingleCreatureFromStorage(m_uiTeam == HORDE ? NPC_SYLVANAS_PART2 : NPC_JAINA_PART2)) + pTemp->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + // ToDo: Jaina / Sylvanas should have some waypoint movement here and the door should be opened only when they get in front of it. + DoUseDoorOrButton(GO_HALLS_OF_REFLECT_PORT); + break; + } +} + +void instance_pit_of_saron::DoStartAmbushEvent() +{ + Creature* pTyrannus = GetSingleCreatureFromStorage(NPC_TYRANNUS_INTRO); + if (!pTyrannus) + return; + + DoScriptText(SAY_TYRANNUS_AMBUSH_1, pTyrannus); + + // Spawn Mobs + for (uint8 i = 0; i < countof(aEventFirstAmbushLocations); ++i) + { + if (Creature* pSummon = pTyrannus->SummonCreature(aEventFirstAmbushLocations[i].uiEntryHorde, aEventFirstAmbushLocations[i].fX, aEventFirstAmbushLocations[i].fY, + aEventFirstAmbushLocations[i].fZ, aEventFirstAmbushLocations[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MovePoint(1, aEventFirstAmbushLocations[i].fMoveX, aEventFirstAmbushLocations[i].fMoveY, aEventFirstAmbushLocations[i].fMoveZ); + } + } +} + +void instance_pit_of_saron::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (m_uiIciclesTimer) + { + if (m_uiIciclesTimer <= uiDiff) + { + for (GuidList::const_iterator itr = m_lTunnelStalkersGuidList.begin(); itr != m_lTunnelStalkersGuidList.end(); ++itr) + { + // Only 5% of the stalkers will actually spawn an icicle + if (roll_chance_i(95)) + continue; + + if (Creature* pStalker = instance->GetCreature(*itr)) + pStalker->CastSpell(pStalker, SPELL_ICICLE_SUMMON, true); + } + m_uiIciclesTimer = urand(3000, 5000); + } + else + m_uiIciclesTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_pit_of_saron(Map* pMap) { return new instance_pit_of_saron(pMap); diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.cpp b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.cpp index ff1e719bc..449e79e60 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.cpp +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: pit_of_saron -SD%Complete: 0 +SD%Complete: 100 SDComment: SDCategory: Pit of Saron EndScriptData */ @@ -29,37 +29,175 @@ EndContentData */ enum { - // Intro - SAY_TYRANNUS_INTRO_1 = -1658001, - SAY_JAINA_INTRO_1 = -1658002, - SAY_SYLVANAS_INTRO_1 = -1658003, - SAY_TYRANNUS_INTRO_2 = -1658004, - SAY_TYRANNUS_INTRO_3 = -1658005, - SAY_JAINA_INTRO_2 = -1658006, - SAY_SYLVANAS_INTRO_2 = -1658007, - SAY_TYRANNUS_INTRO_4 = -1658008, - SAY_JAINA_INTRO_3 = -1658009, - SAY_JAINA_INTRO_4 = -1658010, - SAY_SYLVANAS_INTRO_3 = -1658011, - SAY_JAINA_INTRO_5 = -1658012, - SAY_SYLVANAS_INTRO_4 = -1658013, - - // Ambush and Gauntlet - SAY_TYRANNUS_AMBUSH_1 = -1658047, - SAY_TYRANNUS_AMBUSH_2 = -1658048, - SAY_GAUNTLET = -1658049, - - // Sindragosa outro - SAY_GENERAL_OUTRO_1 = -1658061, - SAY_GENERAL_OUTRO_2 = -1658062, - SAY_JAINA_OUTRO_1 = -1658063, - SAY_SYLVANAS_OUTRO_1 = -1658064, - SAY_JAINA_OUTRO_2 = -1658065, - SAY_JAINA_OUTRO_3 = -1658066, - SAY_SYLVANAS_OUTRO_2 = -1658067, + // Ambush event + SPELL_EMPOWERED_SHADOW_BOLT = 69528, + SPELL_SUMMON_UNDEAD = 69516, + + // Icicles + SPELL_ICICLE = 69426, + SPELL_ICICLE_DUMMY = 69428, + SPELL_ICE_SHARDS_H = 70827, // used to check the tunnel achievement +}; + +/*###### +## npc_ymirjar_deathbringer +######*/ + +struct npc_ymirjar_deathbringerAI : public ScriptedAI +{ + npc_ymirjar_deathbringerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiShadowBoltTimer; + + void Reset() override + { + m_uiShadowBoltTimer = urand(1000, 3000); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_UNDEAD); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiShadowBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_EMPOWERED_SHADOW_BOLT) == CAST_OK) + m_uiShadowBoltTimer = urand(2000, 3000); + } + } + else + m_uiShadowBoltTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } }; +CreatureAI* GetAI_npc_ymirjar_deathbringer(Creature* pCreature) +{ + return new npc_ymirjar_deathbringerAI(pCreature); +} + +bool EffectDummyCreature_spell_summon_undead(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_SUMMON_UNDEAD && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() != NPC_YMIRJAR_DEATHBRINGER) + return true; + + float fX, fY, fZ; + for (uint8 i = 0; i < 4; ++i) + { + pCreatureTarget->GetNearPoint(pCreatureTarget, fX, fY, fZ, 0, frand(8.0f, 12.0f), M_PI_F * 0.5f * i); + pCreatureTarget->SummonCreature(i % 2 ? NPC_YMIRJAR_WRATHBRINGER : NPC_YMIRJAR_FLAMEBEARER, fX, fY, fZ, 3.75f, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_collapsing_icicle +######*/ + +struct npc_collapsing_icicleAI : public ScriptedAI +{ + npc_collapsing_icicleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_pit_of_saron*)pCreature->GetInstanceData(); + Reset(); + } + + instance_pit_of_saron* m_pInstance; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_ICICLE_DUMMY, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ICICLE, CAST_TRIGGERED); + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + // Mark the achiev failed + if (pSpell->Id == SPELL_ICE_SHARDS_H && pTarget->GetTypeId() == TYPEID_PLAYER && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_DONT_LOOK_UP, false); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_collapsing_icicle(Creature* pCreature) +{ + return new npc_collapsing_icicleAI(pCreature); +} + +/*###### +## at_pit_of_saron +######*/ + +bool AreaTrigger_at_pit_of_saron(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; + + instance_pit_of_saron* pInstance = (instance_pit_of_saron*)pPlayer->GetInstanceData(); + if (!pInstance) + return false; + + if (pAt->id == AREATRIGGER_ID_TUNNEL_START) + { + if (pInstance->GetData(TYPE_GARFROST) != DONE || pInstance->GetData(TYPE_KRICK) != DONE || + pInstance->GetData(TYPE_AMBUSH) != NOT_STARTED) + return false; + + pInstance->DoStartAmbushEvent(); + pInstance->SetData(TYPE_AMBUSH, IN_PROGRESS); + return true; + } + else if (pAt->id == AREATRIGGER_ID_TUNNEL_END) + { + if (pInstance->GetData(TYPE_AMBUSH) != IN_PROGRESS) + return false; + + pInstance->SetData(TYPE_AMBUSH, DONE); + return true; + } + + return false; +} + void AddSC_pit_of_saron() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_ymirjar_deathbringer"; + pNewScript->GetAI = &GetAI_npc_ymirjar_deathbringer; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_summon_undead; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_collapsing_icicle"; + pNewScript->GetAI = &GetAI_npc_collapsing_icicle; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "at_pit_of_saron"; + pNewScript->pAreaTrigger = &AreaTrigger_at_pit_of_saron; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.h b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.h index 27d3f3ce0..ed6982a55 100644 --- a/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.h +++ b/scripts/northrend/icecrown_citadel/frozen_halls/pit_of_saron/pit_of_saron.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,12 +7,18 @@ enum { - MAX_ENCOUNTER = 3, + MAX_ENCOUNTER = 4, + MAX_SPECIAL_ACHIEV_CRITS = 2, TYPE_GARFROST = 0, TYPE_KRICK = 1, TYPE_TYRANNUS = 2, + TYPE_AMBUSH = 3, + TYPE_ACHIEV_DOESNT_GO_ELEVEN = 0, + TYPE_ACHIEV_DONT_LOOK_UP = 1, + + // Bosses NPC_TYRANNUS_INTRO = 36794, NPC_GARFROST = 36494, NPC_KRICK = 36477, @@ -21,43 +27,161 @@ enum NPC_RIMEFANG = 36661, NPC_SINDRAGOSA = 37755, + // Intro part npcs NPC_SYLVANAS_PART1 = 36990, NPC_SYLVANAS_PART2 = 38189, NPC_JAINA_PART1 = 36993, NPC_JAINA_PART2 = 38188, NPC_KILARA = 37583, NPC_ELANDRA = 37774, - NPC_KORALEN = 37779, - NPC_KORLAEN = 37582, + NPC_LORALEN = 37779, + NPC_KORELN = 37582, NPC_CHAMPION_1_HORDE = 37584, NPC_CHAMPION_2_HORDE = 37587, + NPC_CHAMPION_3_HORDE = 37588, NPC_CHAMPION_1_ALLIANCE = 37496, NPC_CHAMPION_2_ALLIANCE = 37497, + NPC_CHAMPION_3_ALLIANCE = 37498, + NPC_CORRUPTED_CHAMPION = 36796, + + // Enslaved npcs + NPC_IRONSKULL_PART1 = 37592, + NPC_IRONSKULL_PART2 = 37581, + NPC_VICTUS_PART1 = 37591, + NPC_VICTUS_PART2 = 37580, + NPC_FREE_HORDE_SLAVE_1 = 37577, + NPC_FREE_HORDE_SLAVE_2 = 37578, + NPC_FREE_HORDE_SLAVE_3 = 37579, + NPC_FREE_ALLIANCE_SLAVE_1 = 37572, + NPC_FREE_ALLIANCE_SLAVE_2 = 37575, + NPC_FREE_ALLIANCE_SLAVE_3 = 37576, + + // Ambush npcs + NPC_YMIRJAR_DEATHBRINGER = 36892, + NPC_YMIRJAR_WRATHBRINGER = 36840, + NPC_YMIRJAR_FLAMEBEARER = 36893, + NPC_FALLEN_WARRIOR = 36841, + NPC_COLDWRAITH = 36842, + NPC_STALKER = 32780, // used to handle icicles during the tunnel event + NPC_GENERAL_BUNNY = 24110, // used to handle visuals for the last encounter + + // epilog npcs - used during the Tyrannus encounter + NPC_WRATHBONE_SORCERER = 37728, + NPC_WRATHBONE_REAVER = 37729, + NPC_FALLEN_WARRIOR_EPILOG = 38487, GO_ICEWALL = 201885, // open after gafrost/krick GO_HALLS_OF_REFLECT_PORT = 201848, // unlocked by jaina/sylvanas at last outro + + AREATRIGGER_ID_TUNNEL_START = 5578, + AREATRIGGER_ID_TUNNEL_END = 5581, + + ACHIEV_CRIT_DOESNT_GO_ELEVEN = 12993, // Garfrost, achiev 4524 + ACHIEV_CRIT_DONT_LOOK_UP = 12994, // Gauntlet, achiev 4525 +}; + +static const float afTyrannusMovePos[4][3] = +{ + {922.6365f, 145.877f, 643.2216f}, // Hide position + {835.5887f, 139.4345f, 530.9526f}, // Ick position + {906.9048f, -49.03813f, 618.8016f}, // Tunnel position + {966.3345f, 159.2058f, 665.0453f}, // Rimefang position +}; + +struct EventNpcLocations +{ + uint32 uiEntryHorde, uiEntryAlliance; + float fX, fY, fZ, fO; + float fMoveX, fMoveY, fMoveZ; +}; + +const EventNpcLocations aEventBeginLocations[3] = +{ + {NPC_SYLVANAS_PART1, NPC_JAINA_PART1, 430.3012f, 212.204f, 530.1146f, 0.042f, 440.7882f, 213.7587f, 528.7103f}, + {NPC_KILARA, NPC_ELANDRA, 429.7142f, 212.3021f, 530.2822f, 0.14f, 438.9462f, 215.4271f, 528.7087f}, + {NPC_LORALEN, NPC_KORELN, 429.5675f, 211.7748f, 530.3246f, 5.972f, 438.5052f, 211.5399f, 528.7085f}, + // ToDo: add the soldiers here when proper waypoint movement is supported +}; + +const EventNpcLocations aEventFirstAmbushLocations[2] = +{ + {NPC_YMIRJAR_DEATHBRINGER, 0, 951.6696f, 53.06405f, 567.5153f, 1.51f, 914.7256f, 76.66406f, 553.8029f}, + {NPC_YMIRJAR_DEATHBRINGER, 0, 950.9911f, 60.26712f, 566.7658f, 1.79f, 883.1805f, 52.69792f, 527.6385f}, }; -class MANGOS_DLL_DECL instance_pit_of_saron : public ScriptedInstance +const EventNpcLocations aEventSecondAmbushLocations[] = +{ + {NPC_FALLEN_WARRIOR, 0, 916.658f, -55.94097f, 591.6827f, 1.85f, 950.5694f, 31.85649f, 572.2693f}, + {NPC_FALLEN_WARRIOR, 0, 923.8055f, -55.63195f, 591.8663f, 1.85f, 941.3954f, 35.83769f, 571.4308f}, + {NPC_FALLEN_WARRIOR, 0, 936.0625f, -53.52778f, 592.0226f, 1.85f, 934.8011f, 8.024931f, 577.3419f}, + {NPC_FALLEN_WARRIOR, 0, 919.7518f, -68.39236f, 592.2916f, 1.85f, 932.5734f, -22.54153f, 587.403f}, + {NPC_FALLEN_WARRIOR, 0, 926.8993f, -68.08334f, 592.0798f, 1.85f, 922.6043f, -22.07627f, 585.6684f}, + {NPC_FALLEN_WARRIOR, 0, 939.1563f, -65.97916f, 592.2205f, 1.85f, 927.0928f, -32.97949f, 589.3028f}, + {NPC_COLDWRAITH, 0, 924.0261f, -62.3316f, 592.0191f, 2.01f, 929.4673f, 9.722589f, 577.4904f}, + {NPC_COLDWRAITH, 0, 936.4531f, -60.45486f, 592.1215f, 1.63f, 936.1395f, -4.003471f, 581.3139f}, + {NPC_COLDWRAITH, 0, 935.8055f, -72.76736f, 592.077f, 1.66f, 933.8441f, -47.83234f, 591.7538f}, + {NPC_COLDWRAITH, 0, 923.3785f, -74.6441f, 592.368f, 2.37f, 920.726f, -42.32272f, 589.9808f} +}; + +const EventNpcLocations aEventTunnelEndLocations[] = +{ + {NPC_IRONSKULL_PART2, NPC_VICTUS_PART2, 1071.45f, 48.23907f, 630.4871f, 1.68f, 1046.361f, 124.7031f, 628.2811f}, + // ToDo: add the freed slaves here when proper waypoint movement is supported +}; +const EventNpcLocations aEventOutroLocations[] = +{ + {NPC_SINDRAGOSA, 0, 842.8611f, 194.5556f, 531.6536f, 6.108f, 900.106f, 181.677f, 659.374f}, + {NPC_SYLVANAS_PART2, NPC_JAINA_PART2, 1062.85f, 100.075f, 631.0021f, 1.77f, 1062.85f, 100.075f, 631.0021f}, +}; + + +class instance_pit_of_saron : public ScriptedInstance, private DialogueHelper { public: instance_pit_of_saron(Map* pMap); ~instance_pit_of_saron() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + uint32 GetPlayerTeam() { return m_uiTeam; } + + void DoStartAmbushEvent(); + + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff); protected: + void JustDidDialogueStep(int32 iEntry) override; + void ProcessIntroEventNpcs(Player* pPlayer); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + + bool m_abAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; + + uint8 m_uiAmbushAggroCount; + uint32 m_uiTeam; // Team of first entered player, used to set if Jaina or Silvana to spawn + uint32 m_uiIciclesTimer; + + GuidList m_lTunnelStalkersGuidList; + GuidList m_lAmbushNpcsGuidList; + GuidList m_lArcaneShieldBunniesGuidList; + GuidList m_lFrozenAftermathBunniesGuidList; }; #endif diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/blood_prince_council.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/blood_prince_council.cpp index 1101ffe18..83ed63f8d 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/blood_prince_council.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/blood_prince_council.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,37 +16,889 @@ /* ScriptData SDName: blood_prince_council -SD%Complete: 0% -SDComment: +SD%Complete: 80% +SDComment: Timers; Some details are not very clear about this encounter: spells 72087 and 73001 require additional research. SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { + // Yells SAY_COUNCIL_INTRO_1 = -1631101, // Intro by Bloodqueen SAY_COUNCIL_INTRO_2 = -1631102, + SAY_KELESETH_INVOCATION = -1631103, SAY_KELESETH_SPECIAL = -1631104, SAY_KELESETH_SLAY_1 = -1631105, SAY_KELESETH_SLAY_2 = -1631106, SAY_KELESETH_BERSERK = -1631107, SAY_KELESETH_DEATH = -1631108, + SAY_TALDARAM_INVOCATION = -1631109, SAY_TALDARAM_SPECIAL = -1631110, SAY_TALDARAM_SLAY_1 = -1631111, SAY_TALDARAM_SLAY_2 = -1631112, SAY_TALDARAM_BERSERK = -1631113, SAY_TALDARAM_DEATH = -1631114, + SAY_VALANAR_INVOCATION = -1631115, SAY_VALANAR_SPECIAL = -1631116, SAY_VALANAR_SLAY_1 = -1631117, SAY_VALANAR_SLAY_2 = -1631118, SAY_VALANAR_BERSERK = -1631119, SAY_VALANAR_DEATH = -1631120, + + EMOTE_INVOCATION = -1631197, + EMOTE_SHOCK_VORTEX = -1631198, + EMOTE_FLAMES = -1631199, + + // Generic spells + SPELL_BERSERK = 26662, + SPELL_FEIGN_DEATH = 71598, + + SPELL_INVOCATION_BLOOD = 70934, + SPELL_INVOCATION_BLOOD_2 = 71596, + SPELL_INVOCATION_V_MOVE = 71075, + SPELL_INVOCATION_K_MOVE = 71079, + SPELL_INVOCATION_T_MOVE = 71082, + + // Valanar spells + SPELL_INVOCATION_VALANAR = 70952, + SPELL_KINETIC_BOMB_TARGET = 72053, // summons 38458 - the target of the bomb + SPELL_KINETIC_BOMB = 72080, // summons 38454 + SPELL_SHOCK_VORTEX = 72037, // summons 38422 + SPELL_EMP_SHOCK_VORTEX = 72039, + + NPC_KINETIC_BOMB = 38454, + NPC_KINETIC_BOMB_TARGET = 38458, + + // shock vortex spells - in eventAI + // SPELL_SHOCK_VORTEX_AURA = 71945, + // SPELL_SHOCK_VORTEX_VISUAL = 72633, + + // kinetic bomb spells + SPELL_KINETIC_BOMB_DMG = 72052, + SPELL_KINETIC_BOMB_VISUAL = 72054, + SPELL_UNSTABLE = 72059, // procs 72087 + SPELL_KINETIC_KNOCKBACK = 72087, + + // Keleseth spells + SPELL_INVOCATION_KELESETH = 70981, + SPELL_SHADOW_LANCE = 71405, + SPELL_EMP_SHADOW_LANCE = 71815, + SPELL_SHADOW_RESONANCE = 71943, // summons 38369 + // SPELL_SHADOW_PRISON = 73001, // on heroic - not sure how to use + + // dark nucleus spells + SPELL_SHADOW_RESONANCE_AURA = 71911, // purpose unk - maybe range check + SPELL_SHADOW_RESONANCE_BUFF = 71822, // channeled from the dark nucleus + SPELL_SHADOW_RESONANCE_DMG = 72980, // self destruction spell + + // Taldaram spells + SPELL_INVOCATION_TALDARAM = 70982, + SPELL_GLITTERING_SPARKS = 71806, // triggers 71807 + SPELL_CONJURE_FLAME = 71718, // triggers 71719 which summons 38332 + SPELL_CONJURE_EMP_FLAME = 72040, // triggers 72041 which summons 38451 + + NPC_BALL_OF_FLAME = 38332, + NPC_BALL_OF_INFERNO_FLAME = 38451, + + // ball of flame spells + SPELL_BALL_FLAMES_VISUAL = 71706, + SPELL_FLAMES = 71393, // cast on the impact + SPELL_BALL_FLAMES_PERIODIC = 71709, // triggers 71708 + SPELL_FLAMES_PROC = 71756, + + MAX_PRINCES = 3, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_COUNCIL_INTRO_1, NPC_LANATHEL_INTRO, 15000}, + {SAY_COUNCIL_INTRO_2, NPC_LANATHEL_INTRO, 10000}, + {NPC_BLOOD_ORB_CONTROL, 0, 0}, + {0, 0, 0}, +}; + +static const float aLanathelFlyPos[3] = {4660.49f, 2769.2f, 430.0f}; + +/*###### +## npc_queen_lanathel_intro +######*/ + +struct npc_queen_lanathel_introAI : public ScriptedAI, private DialogueHelper +{ + npc_queen_lanathel_introAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + m_bEventStarted = false; + Reset(); + } + + ScriptedInstance* m_pInstance; + + bool m_bEventStarted; + + void Reset() override + { + // Flying animation + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // The range distance is not sure + if (!m_bEventStarted && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + pWho->IsWithinDistInMap(m_creature, 100.0f) && pWho->IsWithinLOSInMap(m_creature)) + { + StartNextDialogueText(SAY_COUNCIL_INTRO_1); + m_bEventStarted = true; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case SAY_COUNCIL_INTRO_2: + m_creature->GetMotionMaster()->MovePoint(1, aLanathelFlyPos[0], aLanathelFlyPos[1], aLanathelFlyPos[2]); + break; + case NPC_BLOOD_ORB_CONTROL: + if (m_pInstance) + { + if (Creature* pTaldaram = m_pInstance->GetSingleCreatureFromStorage(NPC_TALDARAM)) + { + pTaldaram->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pTaldaram->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + pTaldaram->SetHealth(1); + } + if (Creature* pKeleseth = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + { + pKeleseth->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pKeleseth->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + pKeleseth->SetHealth(1); + } + if (Creature* pValanar = m_pInstance->GetSingleCreatureFromStorage(NPC_VALANAR)) + { + pValanar->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + pValanar->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + pValanar->SetHealth(1); + } + } + break; + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Emote here, and force them to stand up - this needs to be done as a workaround for some core issues + if (m_pInstance) + { + // This should be casted when they stand up - but because of the workaround, it will be casted here + if (Creature* pOrb = m_pInstance->GetSingleCreatureFromStorage(NPC_BLOOD_ORB_CONTROL)) + pOrb->CastSpell(pOrb, SPELL_INVOCATION_VALANAR, false); + if (Creature* pTaldaram = m_pInstance->GetSingleCreatureFromStorage(NPC_TALDARAM)) + pTaldaram->HandleEmote(EMOTE_ONESHOT_ROAR); + if (Creature* pKeleseth = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + pKeleseth->HandleEmote(EMOTE_ONESHOT_ROAR); + if (Creature* pValanar = m_pInstance->GetSingleCreatureFromStorage(NPC_VALANAR)) + pValanar->HandleEmote(EMOTE_ONESHOT_ROAR); + } + + // Despawn when reached point + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) { DialogueUpdate(uiDiff); } +}; + +CreatureAI* GetAI_npc_queen_lanathel_intro(Creature* pCreature) +{ + return new npc_queen_lanathel_introAI(pCreature); +} + +/*###### +## npc_ball_of_flame +######*/ + +struct npc_ball_of_flameAI : public ScriptedAI +{ + npc_ball_of_flameAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bHasFlamesCasted; + + uint32 m_uiTargetGuidLow; + + void Reset() override + { + m_bHasFlamesCasted = false; + + DoCastSpellIfCan(m_creature, SPELL_BALL_FLAMES_VISUAL, CAST_TRIGGERED); + + // Empowered flame + if (m_creature->GetEntry() == NPC_BALL_OF_INFERNO_FLAME) + { + DoCastSpellIfCan(m_creature, SPELL_BALL_FLAMES_PERIODIC, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FLAMES_PROC, CAST_TRIGGERED); + } + } + + void DoInitializeTarget(uint32 uiGuid) { m_uiTargetGuidLow = uiGuid; } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasFlamesCasted && pWho->GetTypeId() == TYPEID_PLAYER && pWho->GetGUIDLow() == m_uiTargetGuidLow && + pWho->IsWithinDist(m_creature, ATTACK_DISTANCE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAMES) == CAST_OK) + { + m_bHasFlamesCasted = true; + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->ForcedDespawn(1000); + } + } + } + + void AttackStart(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_ball_of_flame(Creature* pCreature) +{ + return new npc_ball_of_flameAI(pCreature); +}; + +/*###### +## npc_kinetic_bomb +######*/ + +struct npc_kinetic_bombAI : public ScriptedAI +{ + npc_kinetic_bombAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_UNSTABLE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_VISUAL, CAST_TRIGGERED); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + // Note: this npc shouldn't take any damage - however this has an issue in the core, because the Unstanble spell doesn't proc on 0 damage + uiDamage = 0; + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_DMG); + m_creature->ForcedDespawn(1000); + } + + void AttackStart(Unit* /*pWho*/) override { } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_kinetic_bomb(Creature* pCreature) +{ + return new npc_kinetic_bombAI(pCreature); }; +/*###### +## npc_dark_nucleus +######*/ + +struct npc_dark_nucleusAI : public ScriptedAI +{ + npc_dark_nucleusAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiDistanceCheck; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_SHADOW_RESONANCE_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SHADOW_RESONANCE_DMG, CAST_TRIGGERED); + + m_uiDistanceCheck = 1000; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 10.0f); + } + } + + void DamageTaken(Unit* pDealer, uint32& /*uiDamage*/) override + { + if (m_creature->getVictim() && pDealer != m_creature->getVictim()) + { + DoResetThreat(); + m_creature->AddThreat(pDealer, 100000.0f); + m_creature->InterruptNonMeleeSpells(true); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiDistanceCheck < uiDiff) + { + if (m_creature->GetDistance(m_creature->getVictim()) < 15.0f) + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_RESONANCE_BUFF); + + m_uiDistanceCheck = 1000; + } + else + m_uiDistanceCheck -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_dark_nucleus(Creature* pCreature) +{ + return new npc_dark_nucleusAI(pCreature); +}; + +/*###### +## npc_blood_orb_control +######*/ + +struct npc_blood_orb_controlAI : public Scripted_NoMovementAI +{ + npc_blood_orb_controlAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint8 m_uiLastResult; + uint32 m_uiInvocationTimer; + + void Reset() override + { + m_uiInvocationTimer = 30000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BLOOD_PRINCE_COUNCIL, IN_PROGRESS); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_BLOOD_PRINCE_COUNCIL, DONE); + + // Kill the 3 princes + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_VALANAR)) + m_creature->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_KELESETH)) + m_creature->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + + if (Creature* pTmp = m_pInstance->GetSingleCreatureFromStorage(NPC_TALDARAM)) + m_creature->DealDamage(pTmp, pTmp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BLOOD_PRINCE_COUNCIL, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // every 30 seconds cast Invocation of Blood on random prince + if (m_uiInvocationTimer < uiDiff) + { + uint8 uiResult = urand(0, MAX_PRINCES - 1); + uiResult = uiResult == m_uiLastResult ? (uiResult + 1) % MAX_PRINCES : uiResult; + m_uiLastResult = uiResult; + + switch (uiResult) + { + case 0: + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_V_MOVE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_VALANAR, CAST_TRIGGERED); + break; + case 1: + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_K_MOVE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_KELESETH, CAST_TRIGGERED); + break; + case 2: + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_T_MOVE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_INVOCATION_TALDARAM, CAST_TRIGGERED); + break; + } + + m_uiInvocationTimer = 47000; + } + else + m_uiInvocationTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_blood_orb_control(Creature* pCreature) +{ + return new npc_blood_orb_controlAI(pCreature); +} + +/*###### +## blood_prince_council_base +######*/ + +struct blood_prince_council_baseAI : public ScriptedAI +{ + blood_prince_council_baseAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH); + m_uiResetTimer = 0; + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiInvocationSpellEntry; + int32 m_iSayInvocationEntry; + int32 m_iSayBerserkEntry; + + uint32 m_uiEmpowermentTimer; + uint32 m_uiResetTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiSphereTimer; + + bool m_bIsSaidSpecial; // 1st spell cast after being empowered is followed by special say + + void Reset() override + { + m_bIsSaidSpecial = false; + m_uiEmpowermentTimer = 0; + m_uiSphereTimer = urand(5000, 15000); + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + } + + void EnterEvadeMode() override + { + // Reset the health to 1 + m_creature->SetHealth(1); + + // Reset blood orb + if (m_creature->GetEntry() == NPC_VALANAR) + m_uiResetTimer = 5000; + + ScriptedAI::EnterEvadeMode(); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + // Damage is shared by the Blood Orb Control npc + if (!m_uiEmpowermentTimer) + uiDamage = 0; + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // When hit by the Invocation spell, then set the health of the blood control npc + if (pSpell->Id == m_uiInvocationSpellEntry) + { + m_creature->SetHealth(pCaster->GetHealth()); + DoScriptText(EMOTE_INVOCATION, m_creature); + DoScriptText(m_iSayInvocationEntry, m_creature); + m_uiEmpowermentTimer = 30000; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // On evade, reset the blood orb on Valanar + if (m_uiResetTimer) + { + if (m_uiResetTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pOrb = m_pInstance->GetSingleCreatureFromStorage(NPC_BLOOD_ORB_CONTROL)) + pOrb->CastSpell(pOrb, SPELL_INVOCATION_VALANAR, false); + + m_uiResetTimer = 0; + } + } + else + m_uiResetTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Invocation of Blood + if (m_uiEmpowermentTimer) + { + if (m_uiEmpowermentTimer <= uiDiff) + { + m_creature->RemoveAurasDueToSpell(m_uiInvocationSpellEntry); + m_creature->SetHealth(1); + m_bIsSaidSpecial = false; + m_uiEmpowermentTimer = 00; + } + else + m_uiEmpowermentTimer -= uiDiff; + } + + // Berserk + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(m_iSayBerserkEntry, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + } +}; + +/*###### +## boss_valanar_icc +######*/ + +struct boss_valanar_iccAI : public blood_prince_council_baseAI +{ + boss_valanar_iccAI(Creature* pCreature) : blood_prince_council_baseAI(pCreature) + { + m_uiInvocationSpellEntry = SPELL_INVOCATION_VALANAR; + m_iSayInvocationEntry = SAY_VALANAR_INVOCATION; + m_iSayBerserkEntry = SAY_VALANAR_BERSERK; + Reset(); + } + + uint32 m_uiVortexTimer; + + void Reset() override + { + blood_prince_council_baseAI::Reset(); + + m_uiVortexTimer = urand(5000, 10000); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(urand(0, 1) ? SAY_VALANAR_SLAY_1 : SAY_VALANAR_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_VALANAR_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_KINETIC_BOMB_TARGET) + pSummoned->CastSpell(pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ() + 20.0f, SPELL_KINETIC_BOMB, true, NULL, NULL, m_creature->GetObjectGuid()); + else if (pSummoned->GetEntry() == NPC_KINETIC_BOMB) + { + // Handle Kinetic bomb movement + pSummoned->SetLevitate(true); + pSummoned->GetMotionMaster()->MovePoint(1, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ() - 20.0f, false); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + blood_prince_council_baseAI::UpdateAI(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSphereTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_KINETIC_BOMB_TARGET) == CAST_OK) + m_uiSphereTimer = 27000; + } + else + m_uiSphereTimer -= uiDiff; + + if (m_uiVortexTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_uiEmpowermentTimer ? SPELL_EMP_SHOCK_VORTEX : SPELL_SHOCK_VORTEX) == CAST_OK) + { + if (m_uiEmpowermentTimer) + DoScriptText(EMOTE_SHOCK_VORTEX, m_creature); + + if (m_uiEmpowermentTimer && !m_bIsSaidSpecial) + { + DoScriptText(SAY_VALANAR_SPECIAL, m_creature); + m_bIsSaidSpecial = false; + } + + m_uiVortexTimer = 17000; + } + } + } + else + m_uiVortexTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_valanar_icc(Creature* pCreature) +{ + return new boss_valanar_iccAI(pCreature); +} + +/*###### +## boss_keleseth_icc +######*/ + +struct boss_keleseth_iccAI : public blood_prince_council_baseAI +{ + boss_keleseth_iccAI(Creature* pCreature) : blood_prince_council_baseAI(pCreature) + { + m_uiInvocationSpellEntry = SPELL_INVOCATION_KELESETH; + m_iSayInvocationEntry = SAY_KELESETH_INVOCATION; + m_iSayBerserkEntry = SAY_KELESETH_BERSERK; + Reset(); + } + + uint32 m_uiShadowLanceTimer; + + void Reset() override + { + blood_prince_council_baseAI::Reset(); + + m_uiShadowLanceTimer = urand(2000, 3000); + m_uiSphereTimer = 4000; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(urand(0, 1) ? SAY_KELESETH_SLAY_1 : SAY_KELESETH_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_KELESETH_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + blood_prince_council_baseAI::UpdateAI(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSphereTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_RESONANCE) == CAST_OK) + m_uiSphereTimer = 25000; + } + else + m_uiSphereTimer -= uiDiff; + + if (m_uiShadowLanceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_uiEmpowermentTimer ? SPELL_EMP_SHADOW_LANCE : SPELL_SHADOW_LANCE) == CAST_OK) + { + if (m_uiEmpowermentTimer && !m_bIsSaidSpecial) + { + DoScriptText(SAY_KELESETH_SPECIAL, m_creature); + m_bIsSaidSpecial = true; + } + + m_uiShadowLanceTimer = urand(2000, 3000); + } + } + else + m_uiShadowLanceTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_keleseth_icc(Creature* pCreature) +{ + return new boss_keleseth_iccAI(pCreature); +} + +/*###### +## boss_taldaram_icc +######*/ + +struct boss_taldaram_iccAI : public blood_prince_council_baseAI +{ + boss_taldaram_iccAI(Creature* pCreature) : blood_prince_council_baseAI(pCreature) + { + m_uiInvocationSpellEntry = SPELL_INVOCATION_TALDARAM; + m_iSayInvocationEntry = SAY_TALDARAM_INVOCATION; + m_iSayBerserkEntry = SAY_TALDARAM_BERSERK; + Reset(); + } + + uint32 m_uiSparksTimer; + + void Reset() override + { + blood_prince_council_baseAI::Reset(); + + m_uiSparksTimer = urand(8000, 15000); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(urand(0, 1) ? SAY_TALDARAM_SLAY_1 : SAY_TALDARAM_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_TALDARAM_DEATH, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + // We need to initialize the target which is the ball of flame should follow + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_NOT_IN_MELEE_RANGE | SELECT_FLAG_PLAYER)) + { + if (npc_ball_of_flameAI* pBallAI = dynamic_cast(pSummoned->AI())) + pBallAI->DoInitializeTarget(pTarget->GetGUIDLow()); + + DoScriptText(EMOTE_FLAMES, pSummoned, pTarget); + pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0, 0); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + blood_prince_council_baseAI::UpdateAI(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiSphereTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_uiEmpowermentTimer ? SPELL_CONJURE_EMP_FLAME : SPELL_CONJURE_FLAME) == CAST_OK) + { + if (m_uiEmpowermentTimer && !m_bIsSaidSpecial) + { + DoScriptText(SAY_TALDARAM_SPECIAL, m_creature); + m_bIsSaidSpecial = true; + } + + m_uiSphereTimer = 20000; + } + } + else + m_uiSphereTimer -= uiDiff; + + if (m_uiSparksTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GLITTERING_SPARKS) == CAST_OK) + m_uiSparksTimer = 30000; + } + else + m_uiSparksTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_taldaram_icc(Creature* pCreature) +{ + return new boss_taldaram_iccAI(pCreature); +} + void AddSC_blood_prince_council() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_queen_lanathel_intro"; + pNewScript->GetAI = &GetAI_npc_queen_lanathel_intro; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ball_of_flame"; + pNewScript->GetAI = &GetAI_npc_ball_of_flame; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_kinetic_bomb"; + pNewScript->GetAI = &GetAI_npc_kinetic_bomb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dark_nucleus"; + pNewScript->GetAI = &GetAI_npc_dark_nucleus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_blood_orb_control"; + pNewScript->GetAI = &GetAI_npc_blood_orb_control; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_taldaram_icc"; + pNewScript->GetAI = &GetAI_boss_taldaram_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_keleseth_icc"; + pNewScript->GetAI = &GetAI_boss_keleseth_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_valanar_icc"; + pNewScript->GetAI = &GetAI_boss_valanar_icc; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_blood_queen_lanathel.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_blood_queen_lanathel.cpp index a6c2d52e0..5a33ce963 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_blood_queen_lanathel.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_blood_queen_lanathel.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_blood_queen_lanathel -SD%Complete: 0% -SDComment: +SD%Complete: 60% +SDComment: Timers; Most spells are dummy targeting spells and need core support; Quest 24756 event NYI. SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { @@ -34,8 +35,303 @@ enum SAY_AIR_PHASE = -1631127, SAY_BERSERK = -1631128, SAY_DEATH = -1631129, + SAY_SLAY_1 = -1631195, + SAY_SLAY_2 = -1631196, + + // all phases + SPELL_BERSERK = 26662, + SPELL_SHROUD_OF_SORROW = 70986, + + // ground phase + SPELL_BLOOD_MIRROR = 70837, // triggers 70445 and other similar spells + SPELL_SWARMING_SHADOWS = 71861, // triggers 71264 and 71267 + SPELL_PACT_OF_THE_DARKFALLEN = 71336, // triggers 71340 + SPELL_VAMPIRIC_BITE = 71837, // triggers 71726 and 70946 + SPELL_TWILIGHT_BLOODBOLT = 71445, // triggers 72313, 71446 and 71818 + SPELL_DELIRIOUS_SLASH = 72261, // heroic only - triggers 71623 and 72264 + SPELL_PRESENCE_OF_DARKFALLEN = 70994, // heroic only - triggers 71958, 71959 and 71952 + SPELL_THIRST_QUENCHED = 72154, // related to quest 24756 + + // air phase + SPELL_INCITE_TERROR = 73070, + SPELL_BLOODBOLT_WHIRL = 71772, + + // others + // NPC_SWARMING_SHADOWS = 38163, // has aura 71267 (or 71277?) + + // encounter phases + PHASE_GROUND = 1, + PHASE_RUNNING = 2, + PHASE_AIR = 3, + PHASE_FLYING = 4, + + // movement points + POINT_CENTER_GROUND = 1, + POINT_CENTER_AIR = 2 }; +static const float aQueenPosition[2][3] = +{ + {4595.64f, 2769.19f, 400.13f}, + {4595.90f, 2769.31f, 421.83f}, +}; + +struct boss_blood_queen_lanathelAI : public ScriptedAI +{ + boss_blood_queen_lanathelAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint8 m_uiPhase; + uint32 m_uiPhaseTimer; + + uint32 m_uiBloodMirrorTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiVampiricBiteTimer; + uint32 m_uiBloodboltTimer; + uint32 m_uiPactDarkfallenTimer; + uint32 m_uiSwarmingShadowsTimer; + uint32 m_uiDeliriousSlashTimer; + + void Reset() override + { + m_uiPhase = PHASE_GROUND; + m_uiPhaseTimer = 120000; // 2 min + + m_uiEnrageTimer = 330000; // 5 min and 30 secs + m_uiBloodMirrorTimer = 0; + m_uiDeliriousSlashTimer = 20000; + m_uiVampiricBiteTimer = 15000; + m_uiBloodboltTimer = urand(15000, 20000); + m_uiPactDarkfallenTimer = 15000; + m_uiSwarmingShadowsTimer = 30000; + + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_QUEEN_LANATHEL, FAIL); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SHROUD_OF_SORROW, CAST_TRIGGERED); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_QUEEN_LANATHEL, IN_PROGRESS); + + if (m_pInstance->IsHeroicDifficulty()) + DoCastSpellIfCan(m_creature, SPELL_PRESENCE_OF_DARKFALLEN, CAST_TRIGGERED); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_QUEEN_LANATHEL, DONE); + } + + void MovementInform(uint32 uiMovementType, uint32 uiPointId) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiPointId == POINT_CENTER_GROUND) + { + if (m_uiPhase == PHASE_RUNNING) + { + if (DoCastSpellIfCan(m_creature, SPELL_INCITE_TERROR) == CAST_OK) + { + m_uiPhase = PHASE_FLYING; + + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_AIR, aQueenPosition[1][0], aQueenPosition[1][1], aQueenPosition[1][2], false); + } + } + else if (m_uiPhase == PHASE_FLYING) + { + m_uiPhase = PHASE_GROUND; + m_uiPhaseTimer = 120000; + SetCombatMovement(true); + + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_creature->GetMotionMaster()->Clear(); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + } + else if (uiPointId == POINT_CENTER_AIR) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLOODBOLT_WHIRL) == CAST_OK) + { + DoScriptText(SAY_AIR_PHASE, m_creature); + m_uiPhase = PHASE_AIR; + m_uiPhaseTimer = 7000; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiEnrageTimer) + { + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiEnrageTimer = 0; + } + } + else + m_uiEnrageTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_GROUND: + { + // Air phase change timer + if (m_uiPhaseTimer < uiDiff) + { + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_GROUND, aQueenPosition[0][0], aQueenPosition[0][1], aQueenPosition[0][2]); + + m_uiPhase = PHASE_RUNNING; + m_uiPhaseTimer = 0; + } + else + m_uiPhaseTimer -= uiDiff; + + // Only one bite per fight + if (m_uiVampiricBiteTimer) + { + if (m_uiVampiricBiteTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VAMPIRIC_BITE) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_BITE_1 : SAY_BITE_2, m_creature); + m_uiVampiricBiteTimer = 0; + } + } + else + m_uiVampiricBiteTimer -= uiDiff; + } + + if (m_uiBloodMirrorTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_MIRROR) == CAST_OK) + m_uiBloodMirrorTimer = 5000; + } + else + m_uiBloodMirrorTimer -= uiDiff; + + if (m_uiBloodboltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_BLOODBOLT) == CAST_OK) + m_uiBloodboltTimer = urand(15000, 20000); + } + else + m_uiBloodboltTimer -= uiDiff; + + if (m_uiPactDarkfallenTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PACT_OF_THE_DARKFALLEN) == CAST_OK) + { + DoScriptText(SAY_PACT, m_creature); + m_uiPactDarkfallenTimer = urand(20000, 25000); + } + } + else + m_uiPactDarkfallenTimer -= uiDiff; + + if (m_uiSwarmingShadowsTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SWARMING_SHADOWS) == CAST_OK) + { + DoScriptText(SAY_SHADOWS, m_creature); + m_uiSwarmingShadowsTimer = urand(30000, 35000); + } + } + else + m_uiSwarmingShadowsTimer -= uiDiff; + + // Heroic spells + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiDeliriousSlashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DELIRIOUS_SLASH) == CAST_OK) + m_uiDeliriousSlashTimer = 15000; + } + else + m_uiDeliriousSlashTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + + break; + } + case PHASE_RUNNING: + case PHASE_FLYING: + { + // Nothing here. Wait for arriving at the point + break; + } + case PHASE_AIR: + { + if (m_uiPhaseTimer < uiDiff) + { + m_uiPhase = PHASE_FLYING; + m_uiPhaseTimer = 0; + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_GROUND, aQueenPosition[0][0], aQueenPosition[0][1], aQueenPosition[0][2]); + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + } + } +}; + +CreatureAI* GetAI_boss_blood_queen_lanathel(Creature* pCreature) +{ + return new boss_blood_queen_lanathelAI(pCreature); +} + void AddSC_boss_blood_queen_lanathel() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_blood_queen_lanathel"; + pNewScript->GetAI = &GetAI_boss_blood_queen_lanathel; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_deathbringer_saurfang.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_deathbringer_saurfang.cpp index 0390debdb..34378f940 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_deathbringer_saurfang.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_deathbringer_saurfang.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_deathbringer_saurfang -SD%Complete: 0% -SDComment: +SD%Complete: 80% +SDComment: Intro and Outro event NYI. SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { @@ -32,6 +33,9 @@ enum SAY_SLAY_2 = -1631032, SAY_BERSERK = -1631033, SAY_DEATH = -1631034, + EMOTE_FRENZY = -1631193, + EMOTE_SCENT = -1631194, + SAY_INTRO_ALLY_0 = -1631035, SAY_INTRO_ALLY_1 = -1631036, SAY_INTRO_ALLY_2 = -1631037, @@ -67,8 +71,293 @@ enum SAY_OUTRO_HORDE_2 = -1631067, SAY_OUTRO_HORDE_3 = -1631068, SAY_OUTRO_HORDE_4 = -1631069, + + // intro event related + SPELL_GRIP_OF_AGONY = 70572, + SPELL_VEHICLE_HARDCODED = 46598, + + // aggro spells + SPELL_BLOOD_LINK = 72178, + SPELL_MARK_FALLEN_DAMAGE = 72256, // procs 72255 on Saurfang melee attack + SPELL_RUNE_OF_BLOOD_PROC = 72408, // procs 72409 on Saurfang melee attack + + // combat spells + SPELL_BLOOD_POWER = 72371, // triggered by 72195 + // SPELL_BLOOD_POWER_SCALE = 72370, // purpose unk + // SPELL_ZERO_POWER = 72242, // included in creature_template_addon + + SPELL_MARK_FALLEN_CHAMPION = 72254, // triggers 72293 which procs 72260 on target death + SPELL_RUNE_OF_BLOOD = 72410, + SPELL_BLOOD_NOVA = 72378, + SPELL_BOILING_BLOOD = 72385, + + SPELL_CALL_BLOOD_BEAST_1 = 72172, // summons 38508 + SPELL_CALL_BLOOD_BEAST_2 = 72173, + SPELL_CALL_BLOOD_BEAST_3 = 72356, + SPELL_CALL_BLOOD_BEAST_4 = 72357, + SPELL_CALL_BLOOD_BEAST_5 = 72358, + SPELL_SCENT_OF_BLOOD = 72769, // triggers 72771 on the blood beasts + + SPELL_BERSERK = 26662, + SPELL_FRENZY = 72737, + + // evade / death spells + SPELL_REMOVE_MARKS = 72257, + SPELL_ACHIEVEMENT = 72928, + + // Summoned spells + SPELL_RESISTANT_SKIN = 72723, + SPELL_BLOOD_LINK_BEAST = 72176, + + FACTION_ID_UNDEAD = 974, + + POINT_ID_INTRO = 1, }; +static const float fIntroPosition[4] = { -491.30f, 2211.35f, 541.11f, 3.16f}; + +struct boss_deathbringer_saurfangAI : public ScriptedAI +{ + boss_deathbringer_saurfangAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + m_bIsIntroDone = false; + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiRuneOfBloodTimer; + uint32 m_uiBoilingBloodTimer; + uint32 m_uiBloodNovaTimer; + uint32 m_uiBloodBeastsTimer; + uint32 m_uiScentOfBloodTimer; + uint32 m_uiBerserkTimer; + + bool m_bIsFrenzied; + bool m_bIsIntroDone; + + void Reset() override + { + m_uiRuneOfBloodTimer = 25000; + m_uiBoilingBloodTimer = 19000; + m_uiBloodNovaTimer = 20000; + m_uiBloodBeastsTimer = 40000; + m_uiScentOfBloodTimer = 47000; + m_uiBerserkTimer = 8 * MINUTE * IN_MILLISECONDS; + + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + m_uiBerserkTimer = 6 * MINUTE * IN_MILLISECONDS; + + m_bIsFrenzied = false; + + m_creature->SetPower(m_creature->GetPowerType(), 0); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_BLOOD_LINK, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_MARK_FALLEN_DAMAGE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_RUNE_OF_BLOOD_PROC, CAST_TRIGGERED); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DEATHBRINGER_SAURFANG, IN_PROGRESS); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIsIntroDone && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->GetDistance2d(pWho) < 50.0f) + { + m_creature->GetMotionMaster()->MovePoint(POINT_ID_INTRO, fIntroPosition[0], fIntroPosition[1], fIntroPosition[2]); + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_SAURFANG_DOOR); + m_bIsIntroDone = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_REMOVE_MARKS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ACHIEVEMENT, CAST_TRIGGERED); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DEATHBRINGER_SAURFANG, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_DEATHBRINGER_SAURFANG, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_REMOVE_MARKS, CAST_TRIGGERED); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + if (uiPointId == POINT_ID_INTRO) + { + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_SAURFANG_DOOR); + + // Note: this should be done only after the intro event is finished + // ToDo: move this to the proper place after the intro will be implemented + // Also the faction needs to be checked if it should be handled in database + m_creature->SetFactionTemporary(FACTION_ID_UNDEAD, TEMPFACTION_NONE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PASSIVE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->SetRespawnCoord(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation()); + } + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->CastSpell(pSummoned, SPELL_RESISTANT_SKIN, true); + pSummoned->CastSpell(pSummoned, SPELL_BLOOD_LINK_BEAST, true); + + // Note: the summoned should be activated only after 2-3 seconds after summon - can be done in eventAI + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Mark of the Fallen Champion + if (m_creature->GetPower(m_creature->GetPowerType()) == 100) + { + if (DoCastSpellIfCan(m_creature, SPELL_MARK_FALLEN_CHAMPION) == CAST_OK) + { + DoScriptText(SAY_FALLENCHAMPION, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_BLOOD_POWER); + m_creature->SetPower(m_creature->GetPowerType(), 0); + } + } + + // Frenzy (soft enrage) + if (!m_bIsFrenzied) + { + if (m_creature->GetHealthPercent() <= 30.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(EMOTE_FRENZY, m_creature); + m_bIsFrenzied = true; + } + } + } + + // Berserk (hard enrage) + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + // Rune of Blood + if (m_uiRuneOfBloodTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_RUNE_OF_BLOOD) == CAST_OK) + m_uiRuneOfBloodTimer = 25000; + } + else + m_uiRuneOfBloodTimer -= uiDiff; + + // Boiling Blood + if (m_uiBoilingBloodTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BOILING_BLOOD) == CAST_OK) + m_uiBoilingBloodTimer = 15000; + } + else + m_uiBoilingBloodTimer -= uiDiff; + + // Blood Nova + if (m_uiBloodNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLOOD_NOVA) == CAST_OK) + m_uiBloodNovaTimer = 20000; + } + else + m_uiBloodNovaTimer -= uiDiff; + + // Call Blood Beasts + if (m_uiBloodBeastsTimer < uiDiff) + { + DoScriptText(SAY_BLOODBEASTS, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_CALL_BLOOD_BEAST_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CALL_BLOOD_BEAST_2, CAST_TRIGGERED); + + if (m_pInstance && m_pInstance->Is25ManDifficulty()) + { + DoCastSpellIfCan(m_creature, SPELL_CALL_BLOOD_BEAST_3, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CALL_BLOOD_BEAST_4, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CALL_BLOOD_BEAST_5, CAST_TRIGGERED); + } + + m_uiBloodBeastsTimer = 40000; + m_uiScentOfBloodTimer = 7000; + } + else + m_uiBloodBeastsTimer -= uiDiff; + + // Scent of Blood + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiScentOfBloodTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SCENT_OF_BLOOD) == CAST_OK) + { + DoScriptText(EMOTE_SCENT, m_creature); + m_uiScentOfBloodTimer = 40000; + } + } + else + m_uiScentOfBloodTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_deathbringer_saurfang(Creature* pCreature) +{ + return new boss_deathbringer_saurfangAI(pCreature); +} + void AddSC_boss_deathbringer_saurfang() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_deathbringer_saurfang"; + pNewScript->GetAI = &GetAI_boss_deathbringer_saurfang; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_festergut.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_festergut.cpp index 70ec76748..db9054bc9 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_festergut.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_festergut.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,16 +16,54 @@ /* ScriptData SDName: boss_festergut -SD%Complete: 0% +SD%Complete: 90% SDComment: SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum +{ + SPELL_BERSERK = 47008, + + // Gastric Bloat + SPELL_GASTRIC_BLOAT = 72214, // proc aura, ~8 sec cooldown, cooldown for Creature requires implementation in core + + // Inhale Blight + SPELL_INHALE_BLIGHT = 69165, + SPELL_INHALED_BLIGHT_10 = 69166, + SPELL_INHALED_BLIGHT_25 = 71912, + + // Pungent Blight + SPELL_PUNGENT_BLIGHT = 69195, + + // Gaseous Blight + SPELL_GASEUS_BLIGHT_DUMMY = 69125, // gas is spread into the room on aggro + // periodic auras spells + SPELL_GASEOUS_BLIGHT_1 = 69157, + SPELL_GASEOUS_BLIGHT_2 = 69162, + SPELL_GASEOUS_BLIGHT_3 = 69164, + + // visual gas dummy auras + SPELL_GASEOUS_BLIGHT_DUMMY1 = 69126, + SPELL_GASEOUS_BLIGHT_DUMMY2 = 69152, + SPELL_GASEOUS_BLIGHT_DUMMY3 = 69154, + + // Inoculent + SPELL_REMOVE_INOCULENT = 69298, + + // Gas Spore + SPELL_GAS_SPORE = 69278, + + // Vile Gas + SPELL_VILE_GAS_SUMMON = 72288, + SPELL_VILE_GAS = 71307 +}; enum { - SAY_STINKY_DIES = -1631081, SAY_AGGRO = -1631082, SAY_BLIGHT = -1631083, SAY_SPORE = -1631084, @@ -38,6 +76,152 @@ enum SAY_FESTERGUT_DEATH = -1631091, }; +struct boss_festergutAI : public ScriptedAI +{ + boss_festergutAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetMap()->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiBerserkTimer; + uint32 m_uiGastricBloatTimer; + uint32 m_uiInhaleBlightTimer; + uint32 m_uiGasSporeTimer; + uint32 m_uiVileGasTimer; + + void Reset() override + { + m_uiBerserkTimer = 5 * MINUTE * IN_MILLISECONDS; + m_uiGastricBloatTimer = 10000; + m_uiInhaleBlightTimer = 30000; + m_uiGasSporeTimer = 20000; + m_uiVileGasTimer = 10000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_GASTRIC_BLOAT, CAST_TRIGGERED); // not working as intended currently + DoCastSpellIfCan(m_creature, SPELL_GASEOUS_BLIGHT_1, CAST_TRIGGERED); // DoT aura + DoCastSpellIfCan(m_creature, SPELL_GASEUS_BLIGHT_DUMMY, CAST_TRIGGERED); // visual cast on dummy npc + + if (m_pInstance) + m_pInstance->SetData(TYPE_FESTERGUT, IN_PROGRESS); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FESTERGUT, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_REMOVE_INOCULENT, CAST_TRIGGERED); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FESTERGUT, DONE); + + DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_REMOVE_INOCULENT, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Berserk + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 5 * MINUTE * IN_MILLISECONDS; + } + } + else + m_uiBerserkTimer -= uiDiff; + + // Inhale Blight and Pungent Blight + if (m_uiInhaleBlightTimer <= uiDiff) + { + SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(SPELL_INHALED_BLIGHT_10); + + if (!holder) + holder = m_creature->GetSpellAuraHolder(SPELL_INHALED_BLIGHT_25); + + // inhale the gas or if already have 3 stacks - release it + if (holder && holder->GetStackAmount() >= 3) + { + if (DoCastSpellIfCan(m_creature, SPELL_PUNGENT_BLIGHT) == CAST_OK) + { + DoScriptText(SAY_PUNGUENT_BLIGHT_EMOTE, m_creature); + DoScriptText(SAY_PUNGUENT_BLIGHT, m_creature); + m_uiInhaleBlightTimer = 35000; + } + } + else if (DoCastSpellIfCan(m_creature, SPELL_INHALE_BLIGHT) == CAST_OK) + { + if (m_pInstance) + { + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + DoScriptText(SAY_BLIGHT, pProfessor); + } + m_uiInhaleBlightTimer = 30000; + } + } + else + m_uiInhaleBlightTimer -= uiDiff; + + // Gas Spore + if (m_uiGasSporeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GAS_SPORE) == CAST_OK) + { + DoScriptText(SAY_SPORE, m_creature); + m_uiGasSporeTimer = 40000; + } + } + else + m_uiGasSporeTimer -= uiDiff; + + // Vile Gas + if (m_uiVileGasTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VILE_GAS_SUMMON, CAST_TRIGGERED) == CAST_OK) + { + if (DoCastSpellIfCan(m_creature, SPELL_VILE_GAS) == CAST_OK) + m_uiVileGasTimer = 30000; + } + } + else + m_uiVileGasTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_festergut(Creature* pCreature) +{ + return new boss_festergutAI(pCreature); +} + void AddSC_boss_festergut() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_festergut"; + pNewScript->GetAI = &GetAI_boss_festergut; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lady_deathwhisper.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lady_deathwhisper.cpp index 3fab148fa..41b692c36 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lady_deathwhisper.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lady_deathwhisper.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,22 +16,17 @@ /* ScriptData SDName: boss_lady_deathwhisper -SD%Complete: 0% -SDComment: +SD%Complete: 95% +SDComment: Minor adjustments may be required SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { - SAY_SPEECH_1 = -1631011, - SAY_SPEECH_2 = -1631012, - SAY_SPEECH_3 = -1631013, - SAY_SPEECH_4 = -1631014, - SAY_SPEECH_5 = -1631015, - SAY_SPEECH_6 = -1631016, - SAY_SPEECH_7 = -1631017, + // yells SAY_AGGRO = -1631018, SAY_PHASE_TWO = -1631019, SAY_DARK_EMPOWERMENT = -1631020, @@ -42,8 +37,473 @@ enum SAY_DEATH = -1631025, SAY_SLAY_1 = -1631026, SAY_SLAY_2 = -1631027, + + // spells - phase 1 + SPELL_SHADOW_CHANNELING = 43897, + SPELL_MANA_BARRIER = 70842, + SPELL_SHADOW_BOLT = 71254, + + // phase 2 + SPELL_INSIGNIFICANCE = 71204, + SPELL_FROSTBOLT = 71420, + SPELL_FROSTBOLT_VOLLEY = 72905, + SPELL_SUMMON_SPIRIT = 71363, // triggers 71426 + + // common + SPELL_BERSERK = 26662, + SPELL_DOMINATE_MIND = 71289, + SPELL_DEATH_AND_DECAY = 71001, + SPELL_DARK_EMPOWERMENT = 70896, // dummy - triggers 70901 - only on Adherents - transforms target into 38136 + SPELL_DARK_TRANSFORMATION = 70895, // dummy - triggers 70900 - only on Fanatics - transforms target into 38135 + SPELL_DARK_MARTYRDOM = 70897, // dummy - triggers 70903 on Adherents or 71236 on Fanatics + // SPELL_SUMMON_ADHERENT = 70820, // cast by the stalkers - only server side + // SPELL_SUMMON_FANATIC = 70819, // cast by the stalkers - only server side + + // npcs + NPC_CULT_ADHERENT = 37949, + NPC_CULT_FANATIC = 37890, + NPC_VENGEFUL_SHADE = 38222, // has aura 71494 }; +static const uint32 aLeftSummonedCultists[3] = {NPC_CULT_ADHERENT, NPC_CULT_FANATIC, NPC_CULT_ADHERENT}; +static const uint32 aRightSummonedCultists[3] = {NPC_CULT_FANATIC, NPC_CULT_ADHERENT, NPC_CULT_FANATIC}; + +struct boss_lady_deathwhisperAI : public ScriptedAI +{ + boss_lady_deathwhisperAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + bool m_bIsPhaseOne; + bool m_bIsLeftSideSummon; + + uint32 m_uiBerserkTimer; + uint32 m_uiSummonWaveTimer; + uint32 m_uiCultistBuffTimer; + uint32 m_uiDarkMartyrdomTimer; + uint32 m_uiTouchOfInsignificanceTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiDeathAndDecayTimer; + uint32 m_uiFrostboltTimer; + uint32 m_uiFrostboltVolleyTimer; + uint32 m_uiDominateMindTimer; + uint32 m_uiVengefulShadeTimer; + + uint8 m_uiMindControlCount; + + GuidList m_lCultistSpawnedGuidList; + GuidVector m_vRightStalkersGuidVector; + GuidVector m_vLeftStalkersGuidVector; + ObjectGuid m_middleStalkerGuid; + + void Reset() override + { + m_bIsPhaseOne = true; + m_bIsLeftSideSummon = roll_chance_i(50) ? true : false; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiSummonWaveTimer = 10000; + m_uiCultistBuffTimer = 0; + m_uiDarkMartyrdomTimer = 30000; + m_uiTouchOfInsignificanceTimer = 7000; + m_uiShadowBoltTimer = 2000; + m_uiDeathAndDecayTimer = urand(10000, 15000); + m_uiFrostboltTimer = urand(5000, 10000); + m_uiFrostboltVolleyTimer = 5000; + m_uiDominateMindTimer = urand(30000, 45000); + m_uiVengefulShadeTimer = 10000; + m_uiMindControlCount = 0; + + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_SHADOW_CHANNELING); + + // Set the max allowed mind control targets + if (m_pInstance) + { + if (m_pInstance->Is25ManDifficulty()) + m_uiMindControlCount = m_pInstance->IsHeroicDifficulty() ? 3 : 1; + else + m_uiMindControlCount = m_pInstance->IsHeroicDifficulty() ? 1 : 0; + } + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_MANA_BARRIER, CAST_TRIGGERED); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LADY_DEATHWHISPER, IN_PROGRESS); + + // Sort the summoning stalkers + GuidList lStalkersGuidList; + m_pInstance->GetDeathwhisperStalkersList(lStalkersGuidList); + DoSortSummoningStalkers(lStalkersGuidList); + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_LADY_DEATHWHISPER, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LADY_DEATHWHISPER, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_CULT_ADHERENT: + case NPC_CULT_FANATIC: + m_lCultistSpawnedGuidList.push_back(pSummoned->GetObjectGuid()); + break; + } + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() != NPC_VENGEFUL_SHADE) + m_lCultistSpawnedGuidList.remove(pSummoned->GetObjectGuid()); + } + + // Wrapper to help sort the summoning stalkers + void DoSortSummoningStalkers(GuidList& lDeathwhisperStalkers) + { + std::list lRightStalkers; + std::list lLeftStalkers; + + if (!lDeathwhisperStalkers.empty()) + { + for (GuidList::const_iterator itr = lDeathwhisperStalkers.begin(); itr != lDeathwhisperStalkers.end(); ++itr) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(*itr)) + { + if (pStalker->GetPositionZ() > 60.0f) + m_middleStalkerGuid = pStalker->GetObjectGuid(); + else if (pStalker->GetPositionY() < 2215.0f) + lLeftStalkers.push_back(pStalker); + else + lRightStalkers.push_back(pStalker); + } + } + + lLeftStalkers.sort(sortFromNorthToSouth); + lRightStalkers.sort(sortFromNorthToSouth); + + // Store the sorted stalkers in a vector for each side + for (std::list::const_iterator itr = lLeftStalkers.begin(); itr != lLeftStalkers.end(); ++itr) + m_vLeftStalkersGuidVector.push_back((*itr)->GetObjectGuid()); + for (std::list::const_iterator itr = lRightStalkers.begin(); itr != lRightStalkers.end(); ++itr) + m_vRightStalkersGuidVector.push_back((*itr)->GetObjectGuid()); + } + } + + static bool sortFromNorthToSouth(Creature* pFirst, Creature* pSecond) + { + return pFirst && pSecond && pFirst->GetPositionX() < pSecond->GetPositionX(); + } + + // Wrapper to select a random cultist + Creature* DoSelectRandomCultist(uint32 uiEntry = 0) + { + std::vector vCultists; + vCultists.reserve(m_lCultistSpawnedGuidList.size()); + + for (GuidList::const_iterator itr = m_lCultistSpawnedGuidList.begin(); itr != m_lCultistSpawnedGuidList.end(); ++itr) + { + if (Creature* pCultist = m_creature->GetMap()->GetCreature(*itr)) + { + // Allow to be sorted them by entry + if (!uiEntry) + vCultists.push_back(pCultist); + else if (pCultist->GetEntry() == uiEntry) + vCultists.push_back(pCultist); + } + } + + if (vCultists.empty()) + return NULL; + + return vCultists[urand(0, vCultists.size() - 1)]; + } + + // Wrapper to handle the adds summmoning + void DoSummonCultistWave() + { + if (!m_pInstance) + return; + + // On 25 man mode we need to summon on all points + if (m_pInstance->Is25ManDifficulty()) + { + for (uint8 i = 0; i < 3; ++i) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_vLeftStalkersGuidVector[i])) + m_creature->SummonCreature(aLeftSummonedCultists[i], pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_vRightStalkersGuidVector[i])) + m_creature->SummonCreature(aRightSummonedCultists[i], pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_middleStalkerGuid)) + m_creature->SummonCreature(roll_chance_i(50) ? NPC_CULT_FANATIC : NPC_CULT_ADHERENT, pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + // On 10 man mode we summon on the left or on the right + else + { + // Summon just 1 add in phase 2 heroic + if (m_pInstance->IsHeroicDifficulty() && !m_bIsPhaseOne) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_middleStalkerGuid)) + m_creature->SummonCreature(roll_chance_i(50) ? NPC_CULT_FANATIC : NPC_CULT_ADHERENT, pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + else + { + GuidVector vTempVector = m_bIsLeftSideSummon ? m_vLeftStalkersGuidVector : m_vRightStalkersGuidVector; + for (uint8 i = 0; i < 3; ++i) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(vTempVector[i])) + m_creature->SummonCreature(m_bIsLeftSideSummon ? aLeftSummonedCultists[i] : aRightSummonedCultists[i], pStalker->GetPositionX(), pStalker->GetPositionY(), pStalker->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + // change sides for next summoning + m_bIsLeftSideSummon = !m_bIsLeftSideSummon; + } + } + } + + // Wrapper to handle the second phase start + void DoStartSecondPhase() + { + DoScriptText(SAY_PHASE_TWO, m_creature); + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_bIsPhaseOne = false; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiDeathAndDecayTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEATH_AND_DECAY) == CAST_OK) + m_uiDeathAndDecayTimer = 20000; + } + } + else + m_uiDeathAndDecayTimer -= uiDiff; + + if (m_uiMindControlCount) + { + if (m_uiDominateMindTimer < uiDiff) + { + for (uint8 i = 0; i < m_uiMindControlCount; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_DOMINATE_MIND, SELECT_FLAG_PLAYER)) + DoCastSpellIfCan(pTarget, SPELL_DOMINATE_MIND, CAST_TRIGGERED); + } + + DoScriptText(SAY_DOMINATE_MIND, m_creature); + m_uiDominateMindTimer = 40000; + } + else + m_uiDominateMindTimer -= uiDiff; + } + + // Summon waves - in phase 1 or on heroic + if (m_pInstance && (m_pInstance->IsHeroicDifficulty() || m_bIsPhaseOne)) + { + if (m_uiSummonWaveTimer < uiDiff) + { + DoSummonCultistWave(); + m_uiCultistBuffTimer = 10000; + m_uiDarkMartyrdomTimer = 40000; + m_uiSummonWaveTimer = m_pInstance->IsHeroicDifficulty() ? 45000 : 60000; + } + else + m_uiSummonWaveTimer -= uiDiff; + + if (m_uiCultistBuffTimer) + { + if (m_uiCultistBuffTimer <= uiDiff) + { + // Choose a random of Fanatic or Adherent + bool bIsFanatic = roll_chance_i(50) ? true : false; + uint32 uiNpcEntry = bIsFanatic ? NPC_CULT_FANATIC : NPC_CULT_ADHERENT; + uint32 uiSpellEntry = bIsFanatic ? SPELL_DARK_TRANSFORMATION : SPELL_DARK_EMPOWERMENT; + int32 iTextEntry = bIsFanatic ? SAY_DARK_TRANSFORMATION : SAY_DARK_EMPOWERMENT; + + Creature* pTarget = DoSelectRandomCultist(uiNpcEntry); + if (pTarget && DoCastSpellIfCan(pTarget, uiSpellEntry) == CAST_OK) + { + // Remove the selected cultist from the list because we don't want it selected twice + m_lCultistSpawnedGuidList.remove(pTarget->GetObjectGuid()); + DoScriptText(iTextEntry, m_creature); + m_uiCultistBuffTimer = 0; + } + } + else + m_uiCultistBuffTimer -= uiDiff; + } + + if (m_uiDarkMartyrdomTimer) + { + if (m_uiDarkMartyrdomTimer <= uiDiff) + { + // Try to get a target on which to cast Martyrdom + if (Creature* pTarget = DoSelectRandomCultist()) + { + if (DoCastSpellIfCan(pTarget, SPELL_DARK_MARTYRDOM) == CAST_OK) + { + DoScriptText(SAY_ANIMATE_DEAD, m_creature); + m_uiDarkMartyrdomTimer = 0; + } + } + else + m_uiDarkMartyrdomTimer = 0; + } + else + m_uiDarkMartyrdomTimer -= uiDiff; + } + } + + // Phase 1 specific spells + if (m_bIsPhaseOne) + { + if (m_uiShadowBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_BOLT) == CAST_OK) + m_uiShadowBoltTimer = 2000; + } + } + else + m_uiShadowBoltTimer -= uiDiff; + } + // Phase 2 specific spells + else + { + if (m_uiTouchOfInsignificanceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INSIGNIFICANCE) == CAST_OK) + m_uiTouchOfInsignificanceTimer = 7000; + } + else + m_uiTouchOfInsignificanceTimer -= uiDiff; + + if (m_uiFrostboltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FROSTBOLT) == CAST_OK) + m_uiFrostboltTimer = urand(2000, 4000); + } + } + else + m_uiFrostboltTimer -= uiDiff; + + if (m_uiFrostboltVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FROSTBOLT_VOLLEY) == CAST_OK) + m_uiFrostboltVolleyTimer = urand(15000, 20000); + } + else + m_uiFrostboltVolleyTimer -= uiDiff; + + if (m_uiVengefulShadeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIRIT) == CAST_OK) + m_uiVengefulShadeTimer = 10000; + } + else + m_uiVengefulShadeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + } +}; + +CreatureAI* GetAI_boss_lady_deathwhisper(Creature* pCreature) +{ + return new boss_lady_deathwhisperAI(pCreature); +} + +bool EffectDummyCreature_spell_mana_barrier(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_MANA_BARRIER && uiEffIndex == EFFECT_INDEX_0) + { + uint32 uiDamage = pCreatureTarget->GetMaxHealth() - pCreatureTarget->GetHealth(); + if (!uiDamage) + return true; + + if (pCreatureTarget->GetPower(POWER_MANA) < uiDamage) + { + uiDamage = pCreatureTarget->GetPower(POWER_MANA); + pCreatureTarget->RemoveAurasDueToSpell(SPELL_MANA_BARRIER); + + if (boss_lady_deathwhisperAI* pBossAI = dynamic_cast(pCreatureTarget->AI())) + pBossAI->DoStartSecondPhase(); + } + + pCreatureTarget->DealHeal(pCreatureTarget, uiDamage, GetSpellStore()->LookupEntry(SPELL_MANA_BARRIER)); + pCreatureTarget->ModifyPower(POWER_MANA, -int32(uiDamage)); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + void AddSC_boss_lady_deathwhisper() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lady_deathwhisper"; + pNewScript->GetAI = &GetAI_boss_lady_deathwhisper; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_mana_barrier; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lord_marrowgar.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lord_marrowgar.cpp index 5fb503d98..17998bdef 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lord_marrowgar.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_lord_marrowgar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,16 +16,17 @@ /* ScriptData SDName: boss_lord_marrowgar -SD%Complete: 0% -SDComment: +SD%Complete: 90% +SDComment: Achiev NYI. SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" +#include "TemporarySummon.h" enum { - SAY_INTRO = -1631001, SAY_AGGRO = -1631002, SAY_BONE_STORM = -1631003, SAY_BONE_SPIKE_1 = -1631004, @@ -35,8 +36,367 @@ enum SAY_SLAY_2 = -1631008, SAY_DEATH = -1631009, SAY_BERSERK = -1631010, + + // spells + SPELL_BERSERK = 47008, + SPELL_BONE_SLICE = 69055, + SPELL_BONE_STORM = 69076, + SPELL_COLDFLAME = 69140, + SPELL_COLDFLAME_STORM = 72705, + SPELL_BONE_SPIKE = 69057, // triggers spell 69062 + SPELL_BONE_SPIKE_STORM = 73142, // triggers spell 69062 / 72669 / 72670 + + // summoned spells + SPELL_COLDFLAME_AURA = 69145, + SPELL_IMPALED = 69065, + + // npcs + NPC_BONE_SPIKE_1 = 36619, // summoned by spell 69062 + NPC_BONE_SPIKE_2 = 38711, // summoned by spell 72670 + NPC_BONE_SPIKE_3 = 38712, // summoned by spell 72669 + NPC_COLDFLAME = 36672, + + // phases and max cold flame charges + PHASE_NORMAL = 1, + PHASE_BONE_STORM_CHARGE = 2, + PHASE_BONE_STORM_CHARGING = 3, + PHASE_BONE_STORM_COLDFLAME = 4, + + MAX_CHARGES_NORMAL = 4, + MAX_CHARGES_HEROIC = 5, }; +struct boss_lord_marrowgarAI : public ScriptedAI +{ + boss_lord_marrowgarAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + // on heroic, there is 1 more Bone Storm charge + m_uiMaxCharges = m_pInstance && m_pInstance->IsHeroicDifficulty() ? MAX_CHARGES_HEROIC : MAX_CHARGES_NORMAL; + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiChargesCount; + uint8 m_uiMaxCharges; + uint32 m_uiBerserkTimer; + uint32 m_uiBoneSliceTimer; + uint32 m_uiColdflameTimer; + uint32 m_uiBoneSpikeTimer; + uint32 m_uiBoneStormTimer; + uint32 m_uiBoneStormChargeTimer; + uint32 m_uiBoneStormColdflameTimer; + + void Reset() override + { + SetCombatMovement(true); + + m_uiPhase = PHASE_NORMAL; + m_uiChargesCount = 0; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiBoneSliceTimer = 1000; + m_uiColdflameTimer = 5000; + m_uiBoneSpikeTimer = 15000; + m_uiBoneStormTimer = 45000; + m_uiBoneStormChargeTimer = 3000; + m_uiBoneStormColdflameTimer = 1000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MARROWGAR, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MARROWGAR, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MARROWGAR, FAIL); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE) + return; + + if (uiPointId) + { + m_uiPhase = PHASE_BONE_STORM_COLDFLAME; + ++m_uiChargesCount; + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_COLDFLAME) + { + pSummoned->CastSpell(pSummoned, SPELL_COLDFLAME_AURA, true); + + float fX, fY; + float fZ = pSummoned->GetPositionZ(); + // Note: the NearPoint2D function may not be correct here, because we may use a wrong Z value + m_creature->GetNearPoint2D(fX, fY, 80.0f, m_creature->GetAngle(pSummoned)); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ, false); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_NORMAL: + + // Coldflame + if (m_uiColdflameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_COLDFLAME) == CAST_OK) + m_uiColdflameTimer = 5000; + } + else + m_uiColdflameTimer -= uiDiff; + + // Bone Storm + if (m_uiBoneStormTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BONE_STORM) == CAST_OK) + { + // ToDo: research if we need to increase the speed here + DoScriptText(SAY_BONE_STORM, m_creature); + m_uiPhase = PHASE_BONE_STORM_CHARGE; + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_uiBoneStormTimer = 90000; + } + } + else + m_uiBoneStormTimer -= uiDiff; + + // Bone Slice + if (m_uiBoneSliceTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BONE_SLICE) == CAST_OK) + m_uiBoneSliceTimer = 1000; + } + else + m_uiBoneSliceTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + case PHASE_BONE_STORM_CHARGE: + + // next charge to random enemy + if (m_uiBoneStormChargeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + { + float fX, fY, fZ; + pTarget->GetPosition(fX, fY, fZ); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_uiBoneStormChargeTimer = 3000; + m_uiPhase = PHASE_BONE_STORM_CHARGING; + } + } + else + m_uiBoneStormChargeTimer -= uiDiff; + + break; + case PHASE_BONE_STORM_CHARGING: + // waiting to arrive at target position + break; + case PHASE_BONE_STORM_COLDFLAME: + + if (m_uiBoneStormColdflameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_COLDFLAME_STORM) == CAST_OK) + { + // When the max cold flame charges are reached, remove Bone storm aura + if (m_uiChargesCount == m_uiMaxCharges) + { + m_creature->RemoveAurasDueToSpell(SPELL_BONE_STORM); + m_uiBoneStormTimer = 60000; + m_uiBoneSliceTimer = 10000; + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiChargesCount = 0; + m_uiPhase = PHASE_NORMAL; + } + else + m_uiPhase = PHASE_BONE_STORM_CHARGE; + + m_uiBoneStormColdflameTimer = 1000; + } + } + else + m_uiBoneStormColdflameTimer -= uiDiff; + + break; + } + + // Bone spike - different spells for the normal phase or storm phase + if (m_pInstance && (m_pInstance->IsHeroicDifficulty() || m_uiPhase == PHASE_NORMAL)) + { + if (m_uiBoneSpikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_uiPhase == PHASE_NORMAL ? SPELL_BONE_SPIKE : SPELL_BONE_SPIKE_STORM) == CAST_OK) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_BONE_SPIKE_1, m_creature); break; + case 1: DoScriptText(SAY_BONE_SPIKE_2, m_creature); break; + case 2: DoScriptText(SAY_BONE_SPIKE_3, m_creature); break; + } + m_uiBoneSpikeTimer = 18000; + } + } + else + m_uiBoneSpikeTimer -= uiDiff; + } + + // Berserk + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK)) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_lord_marrowgar(Creature* pCreature) +{ + return new boss_lord_marrowgarAI(pCreature); +} + +/*###### +## npc_bone_spike +######*/ + +struct npc_bone_spikeAI : public Scripted_NoMovementAI +{ + npc_bone_spikeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bHasImpaled = false; + Reset(); + } + + bool m_bHasImpaled; + + void Reset() override { } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void KilledUnit(Unit* pVictim) override + { + // remove the aura as it's death persistent (I wonder why...) + pVictim->RemoveAurasDueToSpell(SPELL_IMPALED); + m_creature->ForcedDespawn(); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + // remove impale on death + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + pSummoner->RemoveAurasDueToSpell(SPELL_IMPALED); + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_bHasImpaled) + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + // Impale player + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + DoCastSpellIfCan(pSummoner, SPELL_IMPALED); + } + + m_bHasImpaled = true; + } + } +}; + +CreatureAI* GetAI_npc_bone_spike(Creature* pCreature) +{ + return new npc_bone_spikeAI(pCreature); +} + +/*###### +## npc_coldflame +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_coldflameAI : public ScriptedAI +{ + npc_coldflameAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_coldflame(Creature* pCreature) +{ + return new npc_coldflameAI(pCreature); +} + void AddSC_boss_lord_marrowgar() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_lord_marrowgar"; + pNewScript->GetAI = &GetAI_boss_lord_marrowgar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_bone_spike"; + pNewScript->GetAI = &GetAI_npc_bone_spike; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_coldflame"; + pNewScript->GetAI = &GetAI_npc_coldflame; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_professor_putricide.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_professor_putricide.cpp index a225f0885..40d1d3605 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_professor_putricide.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_professor_putricide.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,14 @@ /* ScriptData SDName: boss_professor_putricide -SD%Complete: 0% -SDComment: +SD%Complete: 70% +SDComment: NYI: Abomination and table handling, Malleable Goo, + possibly Green Ooze and Orange Gas scripts require handling in sd2, but need further research on their spells SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { @@ -36,6 +38,463 @@ enum SAY_DEATH = -1631100, }; +enum +{ + SPELL_BERSERK = 47008, + + // controlled abomination + SPELL_MUTATED_TRANSFORMATION = 70308, + SPELL_EAT_OOZE = 72527, + SPELL_REGURGITATED_OOZE = 70539, + SPELL_MUTATED_SLASH = 70542, + SPELL_MUTATED_AURA = 70405, + SPELL_ABOMINATION_POWER_DRAIN = 70385, // prevents normal regen of abomination's power + + SPELL_UNSTABLE_EXPERIMENT = 70351, // ooze and gas summoning spells in basepoints of effects of this spell suggest that they should be handled in core + + // Volatile Experiment on heroic difficulties + SPELL_VOLATILE_EXPERIMENT = 72840, // single target dummy effect + SPELL_VOLATILE_EXPERIMENT_2 = 72841, // single target dummy effect + SPELL_VOLATILE_EXPERIMENT_3 = 72842, // radius target dummy effect + SPELL_VOLATILE_EXPERIMENT_4 = 72843, // radius target dummy effect + + SPELL_GREEN_OOZE_SUMMON = 71412, + SPELL_ORANGE_OOZE_SUMMON = 71415, + + SPELL_OOZE_ADHESIVE = 70447, + SPELL_OOZE_ERUPTION = 70492, + + SPELL_GASEOUS_BLOAT = 70672, + SPELL_EXPUNGED_GAS = 70701, + SPELL_GASEOUS_BLOAT_VISUAL = 70215, + + SPELL_SLIME_PUDDLE = 70341, + SPELL_SLIME_PUDDLE_SUMMON = 70342, + SPELL_SLIME_PUDDLE_AURA = 70343, +// SPELL_SLIME_PUDDLE_TRIGGER = 71424, // trigger summon spell from target? +// SPELL_SLIME_PUDDLE_SUMMON_TRIG = 71425, + SPELL_GROW_STACKER = 70345, + SPELL_GROW_STACKER_GROW_AURA = 70347, + + SPELL_MALLEABLE_GOO_MISSILE = 70852, + + SPELL_CHOKING_GAS_BOMB = 71255, + SPELL_CHOKING_GAS_BOMB_AURA = 71259, + SPELL_CHOKING_GAS_BOMB_EXPL_AUR = 71280, + SPELL_CHOKING_GAS_EXPLOSION = 71279, + + // phase transitions + SPELL_TEAR_GAS = 71617, // stuns players + SPELL_TEAR_GAS_PERIODIC_AURA = 73170, // stuns summoned creatures? + SPELL_TEAR_GAS_CANCEL = 71620, + + SPELL_CREATE_CONCOCTION = 71621, + SPELL_GUZZLE_POTIONS = 71893, + + SPELL_MUTATED_PLAGUE = 72451, + + // heroic + SPELL_UNBOUND_PLAGUE = 70911, + SPELL_OOZE_VARIABLE = 70352, // aura 303 - dont allow taking damage from attacker with linked aura303? + SPELL_OOZE_VARIABLE_OOZE = 74118, // anyway, implemented as hardcoded in script + SPELL_GAS_VARIABLE = 70353, + SPELL_GAS_VARIABLE_GAS = 74119, + + SPELL_OOZE_TANK_PROTECTION = 71770 +}; + +enum Phase +{ + PHASE_ONE = 1, + PHASE_RUNNING_ONE = 2, + PHASE_TRANSITION_ONE = 3, + PHASE_TWO = 4, + PHASE_RUNNING_TWO = 5, + PHASE_TRANSITION_TWO = 6, + PHASE_THREE = 7 +}; + +enum Waypoint +{ + POINT_PUTRICIDE_SPAWN = 1 +}; + +static const float fPutricidePosition[1][3] = +{ + {4356.78f, 3263.51f, 389.40f} // 0 Putricide spawn point +}; + +struct boss_professor_putricideAI : public ScriptedAI +{ + boss_professor_putricideAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiPhase; + + uint32 m_uiHealthCheckTimer; + uint32 m_uiTransitionTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiPuddleTimer; + uint32 m_uiUnstableExperimentTimer; + uint32 m_uiUnboundPlagueTimer; + uint32 m_uiChokingGasBombTimer; + + void Reset() override + { + m_uiPhase = PHASE_ONE; + m_uiHealthCheckTimer = 1000; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiPuddleTimer = 10000; + m_uiUnstableExperimentTimer = 20000; + m_uiUnboundPlagueTimer = 10000; + m_uiChokingGasBombTimer = urand(10000, 15000); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_PROFESSOR_PUTRICIDE, FAIL); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiData == POINT_PUTRICIDE_SPAWN) + { + if (m_uiPhase == PHASE_RUNNING_ONE) + { + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + DoScriptText(SAY_PHASE_CHANGE, m_creature); + m_uiTransitionTimer = 30000; + } + else + { + DoCastSpellIfCan(m_creature, SPELL_CREATE_CONCOCTION); + DoScriptText(SAY_TRANSFORM_1, m_creature); + m_uiTransitionTimer = 15000; + } + + m_uiPhase = PHASE_TRANSITION_ONE; // waiting for entering phase 2 + } + else if (m_uiPhase == PHASE_RUNNING_TWO) + { + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + DoScriptText(SAY_PHASE_CHANGE, m_creature); + m_uiTransitionTimer = 30000; + } + else + { + DoCastSpellIfCan(m_creature, SPELL_GUZZLE_POTIONS); + DoScriptText(SAY_TRANSFORM_2, m_creature); + m_uiTransitionTimer = 15000; + } + + m_uiPhase = PHASE_TRANSITION_TWO; // waiting for entering phase 3 + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Enrage + if (m_uiEnrageTimer) + { + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiEnrageTimer = 0; + } + } + else + m_uiEnrageTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_ONE: + { + // health check + if (m_uiHealthCheckTimer <= uiDiff) + { + if (m_creature->GetHealthPercent() <= 80.0f) + { + uint32 spellId = (m_pInstance && m_pInstance->IsHeroicDifficulty() ? SPELL_VOLATILE_EXPERIMENT : SPELL_TEAR_GAS); + + if (DoCastSpellIfCan(m_creature, spellId) == CAST_OK) + { + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(POINT_PUTRICIDE_SPAWN, fPutricidePosition[0][0], fPutricidePosition[0][1], fPutricidePosition[0][2]); + m_uiPhase = PHASE_RUNNING_ONE; + return; + } + } + m_uiHealthCheckTimer = 1000; + } + else + m_uiHealthCheckTimer -= uiDiff; + + // Unbound Plague + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiUnboundPlagueTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_UNBOUND_PLAGUE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_UNBOUND_PLAGUE) == CAST_OK) + m_uiUnboundPlagueTimer = 70000; + } + } + else + m_uiUnboundPlagueTimer -= uiDiff; + } + + // Slime Puddle + if (m_uiPuddleTimer <= uiDiff) + { + for (int i = 0; i < 2; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SLIME_PUDDLE_SUMMON, SELECT_FLAG_PLAYER)) + DoCastSpellIfCan(pTarget, SPELL_SLIME_PUDDLE, CAST_TRIGGERED); + } + m_uiPuddleTimer = 30000; + } + else + m_uiPuddleTimer -= uiDiff; + + // Unstable Experiment + if (m_uiUnstableExperimentTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNSTABLE_EXPERIMENT) == CAST_OK) + m_uiUnstableExperimentTimer = 30000; + } + else + m_uiUnstableExperimentTimer -= uiDiff; + + break; + } + case PHASE_TRANSITION_ONE: + { + if (m_uiTransitionTimer <= uiDiff) + { + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiPhase = PHASE_TWO; + + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + DoCastSpellIfCan(m_creature, SPELL_CREATE_CONCOCTION); + DoScriptText(SAY_TRANSFORM_1, m_creature); + } + else + DoCastSpellIfCan(m_creature, SPELL_TEAR_GAS_CANCEL, CAST_INTERRUPT_PREVIOUS); + } + else + m_uiTransitionTimer -= uiDiff; + + return; + } + case PHASE_TWO: + { + // health check + if (m_uiHealthCheckTimer <= uiDiff) + { + if (m_creature->GetHealthPercent() <= 35.0f) + { + uint32 spellId = (m_pInstance && m_pInstance->IsHeroicDifficulty() ? SPELL_VOLATILE_EXPERIMENT : SPELL_TEAR_GAS); + + if (DoCastSpellIfCan(m_creature, spellId) == CAST_OK) + { + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(POINT_PUTRICIDE_SPAWN, fPutricidePosition[0][0], fPutricidePosition[0][1], fPutricidePosition[0][2]); + m_uiPhase = PHASE_RUNNING_TWO; + + // TODO: remove Mutated Abomination + + return; + } + } + m_uiHealthCheckTimer = 1000; + } + else + m_uiHealthCheckTimer -= uiDiff; + + // Unbound Plague + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiUnboundPlagueTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_UNBOUND_PLAGUE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_UNBOUND_PLAGUE) == CAST_OK) + m_uiUnboundPlagueTimer = 70000; + } + } + else + m_uiUnboundPlagueTimer -= uiDiff; + } + + // Slime Puddle + if (m_uiPuddleTimer <= uiDiff) + { + for (int i = 0; i < 2; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SLIME_PUDDLE_SUMMON, SELECT_FLAG_PLAYER)) + DoCastSpellIfCan(pTarget, SPELL_SLIME_PUDDLE, CAST_TRIGGERED); + } + + m_uiPuddleTimer = 30000; + } + else + m_uiPuddleTimer -= uiDiff; + + // Unstable Experiment + if (m_uiUnstableExperimentTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNSTABLE_EXPERIMENT) == CAST_OK) + m_uiUnstableExperimentTimer = 30000; + } + else + m_uiUnstableExperimentTimer -= uiDiff; + + // Choking Gas + if (m_uiChokingGasBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CHOKING_GAS_BOMB) == CAST_OK) + m_uiChokingGasBombTimer = urand(25000, 30000); + } + else + m_uiChokingGasBombTimer -= uiDiff; + + // TODO: Malleable Goo + + break; + } + case PHASE_TRANSITION_TWO: + { + if (m_uiTransitionTimer <= uiDiff) + { + m_creature->GetMotionMaster()->Clear(); + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiPhase = PHASE_THREE; + + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + DoCastSpellIfCan(m_creature, SPELL_GUZZLE_POTIONS); + DoScriptText(SAY_TRANSFORM_2, m_creature); + } + else + DoCastSpellIfCan(m_creature, SPELL_TEAR_GAS_CANCEL, CAST_INTERRUPT_PREVIOUS); + } + else + m_uiTransitionTimer -= uiDiff; + + return; + } + case PHASE_THREE: + { + // Unbound Plague + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiUnboundPlagueTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_UNBOUND_PLAGUE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_UNBOUND_PLAGUE) == CAST_OK) + m_uiUnboundPlagueTimer = 70000; + } + } + else + m_uiUnboundPlagueTimer -= uiDiff; + } + + // Slime Puddle + if (m_uiPuddleTimer <= uiDiff) + { + for (int i = 0; i < 2; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_SLIME_PUDDLE_SUMMON, SELECT_FLAG_PLAYER)) + DoCastSpellIfCan(pTarget, SPELL_SLIME_PUDDLE, CAST_TRIGGERED); + } + m_uiPuddleTimer = 30000; + } + else + m_uiPuddleTimer -= uiDiff; + + // Choking Gas + if (m_uiChokingGasBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CHOKING_GAS_BOMB) == CAST_OK) + m_uiChokingGasBombTimer = urand(25000, 30000); + } + else + m_uiChokingGasBombTimer -= uiDiff; + + // TODO: Malleable Goo + + break; + } + case PHASE_RUNNING_ONE: + case PHASE_RUNNING_TWO: + { + // wait for arriving at the table (during phase transition) + break; + } + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_professor_putricide(Creature* pCreature) +{ + return new boss_professor_putricideAI(pCreature); +} + void AddSC_boss_professor_putricide() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_professor_putricide"; + pNewScript->GetAI = &GetAI_boss_professor_putricide; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_rotface.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_rotface.cpp index bfab41b7d..a3bcd5cd0 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_rotface.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_rotface.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,16 +16,16 @@ /* ScriptData SDName: boss_rotface -SD%Complete: 0% +SD%Complete: 70% SDComment: SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { - SAY_PRECIOUS_DIES = -1631070, SAY_AGGRO = -1631071, SAY_SLIME_SPRAY = -1631072, SAY_OOZE_EXPLODE = -1631073, @@ -38,6 +38,304 @@ enum SAY_ROTFACE_DEATH = -1631080, }; +enum +{ + // Mutated Infection + SPELL_MUTATED_INFECTION_1 = 70090, // periodic trigger auras + SPELL_MUTATED_INFECTION_2 = 70003, + SPELL_MUTATED_INFECTION_3 = 70004, + SPELL_MUTATED_INFECTION_4 = 70005, + SPELL_MUTATED_INFECTION_5 = 70006, + + // Slime Spray +// SPELL_SLIME_SPRAY_SUMMON = 70882, // precast of Slime Spray dmg spell + SPELL_SLIME_SPRAY = 69508, + + // Ooze Flood + SPELL_OOZE_FLOOD_PERIODIC = 70069, // periodically trigger ooze flood + SPELL_OOZE_FLOOD_REMOVE = 70079, + + // Little Ooze + SPELL_STICKY_OOZE = 69774, + SPELL_STICKY_AURA = 69776, // aura on dummy Sticky Ooze NPC + SPELL_WEAK_RADIATING_OOZE = 69750, + SPELL_LITTLE_OOZE_COMBINE = 69537, // periodic check +// SPELL_MERGE = 69889, + + // Big Ooze + SPELL_UNSTABLE_OOZE = 69558, // stacking buff + SPELL_RADIATING_OOZE = 69760, + SPELL_BIG_OOZE_COMBINE = 69552, // periodic check + SPELL_BIG_OOZE_BUFF_COMB = 69611, // periodic check + SPELL_UNSTABLE_EXPLOSION = 69839, + + MAX_MUTATE_INFACTION_STEPS = 5, +}; + +static const uint32 uiMutatedInfections[MAX_MUTATE_INFACTION_STEPS] = +{ + SPELL_MUTATED_INFECTION_1, + SPELL_MUTATED_INFECTION_2, + SPELL_MUTATED_INFECTION_3, + SPELL_MUTATED_INFECTION_4, + SPELL_MUTATED_INFECTION_5 +}; + +struct boss_rotfaceAI : public ScriptedAI +{ + boss_rotfaceAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiSlimeSprayTimer; + uint32 m_uiSlimeFlowTimer; + uint32 m_uiMutatedInfectionTimer; + uint32 m_uiInfectionsRate; + + void Reset() override + { + m_uiSlimeSprayTimer = urand(17000, 23000); + m_uiSlimeFlowTimer = 20000; + m_uiMutatedInfectionTimer = 60000; + m_uiInfectionsRate = 1; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ROTFACE, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_MUTATED_INFECTION_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_OOZE_FLOOD_PERIODIC, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ROTFACE, FAIL); + + DoCastSpellIfCan(m_creature, SPELL_OOZE_FLOOD_REMOVE, CAST_TRIGGERED); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature, pVictim); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ROTFACE, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Slime Spray + if (m_uiSlimeSprayTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SLIME_SPRAY) == CAST_OK) + { + DoScriptText(SAY_SLIME_SPRAY, m_creature); + m_uiSlimeSprayTimer = urand(17000, 23000); + } + } + else + m_uiSlimeSprayTimer -= uiDiff; + + // Mutated Infection - faster with time + // implemented this instead of phases + if (m_uiInfectionsRate < MAX_MUTATE_INFACTION_STEPS) + { + if (m_uiMutatedInfectionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, uiMutatedInfections[m_uiInfectionsRate], CAST_TRIGGERED) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(uiMutatedInfections[m_uiInfectionsRate - 1]); + // every next 15 seconds faster + m_uiMutatedInfectionTimer = 60000 - m_uiInfectionsRate * 15000; + ++m_uiInfectionsRate; + } + } + else + m_uiMutatedInfectionTimer -= uiDiff; + } + + // Slime Flow + if (m_uiSlimeFlowTimer <= uiDiff) + { + if (Creature* pProfessor = m_pInstance->GetSingleCreatureFromStorage(NPC_PROFESSOR_PUTRICIDE)) + DoScriptText(urand(0, 1) ? SAY_SLIME_FLOW_1 : SAY_SLIME_FLOW_2, pProfessor); + + m_uiSlimeFlowTimer = 20000; + } + else + m_uiSlimeFlowTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_rotface(Creature* pCreature) +{ + return new boss_rotfaceAI(pCreature); +} + +struct mob_little_oozeAI : public ScriptedAI +{ + mob_little_oozeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + uint32 m_uiStickyOozeTimer; + + void Reset() override + { + m_uiStickyOozeTimer = 5000; + } + + void EnterEvadeMode() override + { + m_creature->ForcedDespawn(); + } + + void Aggro(Unit* pWho) override + { + m_creature->AddThreat(pWho, 500000.0f); // not sure about the threat amount but should be very high + DoCastSpellIfCan(m_creature, SPELL_WEAK_RADIATING_OOZE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_LITTLE_OOZE_COMBINE, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiStickyOozeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STICKY_OOZE) == CAST_OK) + m_uiStickyOozeTimer = urand(10000, 15000); + } + else + m_uiStickyOozeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_little_ooze(Creature* pCreature) +{ + return new mob_little_oozeAI(pCreature); +} + +struct mob_big_oozeAI : public ScriptedAI +{ + mob_big_oozeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + uint32 m_uiStickyOozeTimer; + uint32 m_uiUnstableExplosionCheckTimer; + + void Reset() override + { + m_uiStickyOozeTimer = 5000; + m_uiUnstableExplosionCheckTimer = 1000; + } + + void EnterEvadeMode() override + { + m_creature->ForcedDespawn(); + } + + void Aggro(Unit* pWho) override + { + m_creature->AddThreat(pWho, 500000.0f); + DoCastSpellIfCan(m_creature, SPELL_RADIATING_OOZE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_BIG_OOZE_COMBINE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_BIG_OOZE_BUFF_COMB, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Unstable Ooze + if (m_uiUnstableExplosionCheckTimer) + { + if (m_uiUnstableExplosionCheckTimer <= uiDiff) + { + m_uiUnstableExplosionCheckTimer = 1000; + + SpellAuraHolder* holder = m_creature->GetSpellAuraHolder(SPELL_UNSTABLE_OOZE); + if (holder && holder->GetStackAmount() >= 5) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNSTABLE_EXPLOSION) == CAST_OK) + { + if (m_pInstance) + { + if (Creature* pRotface = m_pInstance->GetSingleCreatureFromStorage(NPC_ROTFACE)) + DoScriptText(SAY_OOZE_EXPLODE, pRotface); + } + } + } + } + else + m_uiUnstableExplosionCheckTimer -= uiDiff; + } + + // Sticky Ooze + if (m_uiStickyOozeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STICKY_OOZE) == CAST_OK) + m_uiStickyOozeTimer = urand(10000, 15000); + } + else + m_uiStickyOozeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_mob_big_ooze(Creature* pCreature) +{ + return new mob_big_oozeAI(pCreature); +} + void AddSC_boss_rotface() { + Script* pNewscript; + + pNewscript = new Script; + pNewscript->Name = "boss_rotface"; + pNewscript->GetAI = &GetAI_boss_rotface; + pNewscript->RegisterSelf(); + + pNewscript = new Script; + pNewscript->Name = "mob_little_ooze"; + pNewscript->GetAI = &GetAI_mob_little_ooze; + pNewscript->RegisterSelf(); + + pNewscript = new Script; + pNewscript->Name = "mob_big_ooze"; + pNewscript->GetAI = &GetAI_mob_big_ooze; + pNewscript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_sindragosa.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_sindragosa.cpp index 26cbded0e..25077d8bf 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_sindragosa.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_sindragosa.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_sindragosa -SD%Complete: 0% -SDComment: +SD%Complete: 80% +SDComment: requires core support for ice blocks (spells and GO in LoS checking) SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { @@ -35,8 +36,840 @@ enum SAY_SLAY_2 = -1631155, SAY_BERSERK = -1631156, SAY_DEATH = -1631157, + + // Spells + + // Sindragosa + + // all phases + SPELL_BERSERK = 26662, + + // Phase 1 and 3 + SPELL_TAIL_SMASH = 71077, + SPELL_CLEAVE = 19983, + SPELL_FROST_AURA = 70084, + SPELL_FROST_BREATH = 69649, + SPELL_ICY_GRIP = 70117, + SPELL_PERMEATING_CHILL = 70109, + SPELL_UNCHAINED_MAGIC = 69762, + + // Phase 2 + SPELL_ICE_TOMB = 69712, // triggers Frost Beacon on random targets, which triggers actual Ice Tomb after 7 sec. + SPELL_ICE_TOMB_PROTECTION = 69700, // protects from taking dmg while in Ice Tomb, should be triggered by Ice Tomb stunning spell + // Frost Bomb related + SPELL_FROST_BOMB = 69846, // summons dummy target npc + SPELL_FROST_BOMB_DMG = 69845, + SPELL_FROST_BOMB_VISUAL = 70022, // circle mark +// SPELL_FROST_BOMB_OTHER = 70521, // no idea where it is used, wowhead says it is used by some other Sindragosa (37755) + + // Phase 3 + SPELL_MYSTIC_BUFFET = 70128, + SPELL_ICE_TOMB_SINGLE = 69675, + + // Rimefang + SPELL_RIMEFANG_FROST_AURA = 71387, + SPELL_RIMEFANG_FROST_BREATH = 71386, + SPELL_RIMEFANG_ICY_BLAST = 71376, + + // Spinestalker + SPELL_SPINESTALKER_BELLOWING_ROAR = 36922, + SPELL_SPINESTALKER_CLEAVE = 40505, + SPELL_SPINESTALKER_TAIL_SWEEP = 71369 +}; + +enum SindragosaPhase +{ + SINDRAGOSA_PHASE_OOC = 0, + SINDRAGOSA_PHASE_AGGRO = 1, + SINDRAGOSA_PHASE_GROUND = 2, + SINDRAGOSA_PHASE_FLYING_TO_AIR = 3, + SINDRAGOSA_PHASE_AIR = 4, + SINDRAGOSA_PHASE_FLYING_TO_GROUND = 5, + SINDRAGOSA_PHASE_THREE = 6 +}; + +enum SindragosaPoint +{ + SINDRAGOSA_POINT_GROUND_CENTER = 0, + SINDRAGOSA_POINT_AIR_CENTER = 1, + SINDRAGOSA_POINT_AIR_PHASE_2 = 2, + SINDRAGOSA_POINT_AIR_EAST = 3, + SINDRAGOSA_POINT_AIR_WEST = 4 +}; + +enum RimefangPhase +{ + RIMEFANG_PHASE_GROUND = 0, + RIMEFANG_PHASE_FLYING = 1, + RIMEFANG_PHASE_AIR = 2 +}; + +enum RimefangPoint +{ + RIMEFANG_POINT_GROUND = 0, + RIMEFANG_POINT_AIR = 1, + RIMEFANG_POINT_INITIAL_LAND_AIR = 2, + RIMEFANG_POINT_INITIAL_LAND = 3 +}; + +enum SpinestalkerPoint +{ + SPINESTALKER_POINT_INITIAL_LAND_AIR = 0, + SPINESTALKER_POINT_INITIAL_LAND = 1 +}; + +#define FROST_BOMB_MIN_X 4367.0f +#define FROST_BOMB_MAX_X 4424.0f +#define FROST_BOMB_MIN_Y 2437.0f +#define FROST_BOMB_MAX_Y 2527.0f + +static const float SindragosaPosition[10][3] = +{ + {4407.44f, 2484.37f, 203.37f}, // 0 center, ground + {4407.44f, 2484.37f, 235.37f}, // 1 center, air + {4470.00f, 2484.37f, 235.37f}, // 2 Sindragosa air phase point + {4414.32f, 2456.94f, 203.37f}, // 3 Rimefang landing point + {4414.32f, 2456.94f, 228.37f}, // 4 Rimefang above landing point + {4414.32f, 2512.73f, 203.37f}, // 5 Spinestalker landing point + {4414.32f, 2512.73f, 228.37f}, // 6 Spinestalker above landing point + {4505.00f, 2484.37f, 235.37f}, // 7 Sindragosa spawn point + {4505.00f, 2444.37f, 235.37f}, // 8 Sindragosa east flying point + {4505.00f, 2524.37f, 235.37f}, // 9 Sindragosa west flying point +}; + +struct boss_sindragosaAI : public ScriptedAI +{ + boss_sindragosaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiFrostBreathTimer; + uint32 m_uiTailSmashTimer; + uint32 m_uiIcyGripTimer; + uint32 m_uiUnchainedMagicTimer; + uint32 m_uiFrostBombTimer; + uint32 m_uiIceTombSingleTimer; + + void Reset() override + { + m_uiPhase = SINDRAGOSA_PHASE_OOC; + m_uiPhaseTimer = 45000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiCleaveTimer = urand(5000, 15000); + m_uiTailSmashTimer = 20000; + m_uiFrostBreathTimer = 5000; + m_uiIcyGripTimer = 35000; + m_uiIceTombSingleTimer = 15000; + m_uiUnchainedMagicTimer = urand(15000, 30000); + } + + void SetFlying(bool bIsFlying) + { + if (bIsFlying) + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + else + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_creature->SetLevitate(bIsFlying); + m_creature->SetWalk(bIsFlying); + } + + void EnterEvadeMode() override + { + SetFlying(true); + ScriptedAI::EnterEvadeMode(); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SINDRAGOSA, FAIL); + + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_EAST, SindragosaPosition[8][0], SindragosaPosition[8][1], SindragosaPosition[8][2], false); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void AttackStart(Unit* pWho) override + { + ScriptedAI::AttackStart(pWho); + + // on aggro: land first, then start the encounter + if (m_uiPhase == SINDRAGOSA_PHASE_OOC) + { + m_uiPhase = SINDRAGOSA_PHASE_AGGRO; + SetCombatMovement(false); + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_CENTER, SindragosaPosition[1][0], SindragosaPosition[1][1], SindragosaPosition[1][2], false); + } + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + // instance data set when sindragosa lands + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SINDRAGOSA, DONE); + } + + void MovementInform(uint32 uiMovementType, uint32 uiPointId) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiPointId == SINDRAGOSA_POINT_AIR_EAST) + { + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_WEST, SindragosaPosition[9][0], SindragosaPosition[9][1], SindragosaPosition[9][2], false); + } + else if (uiPointId == SINDRAGOSA_POINT_AIR_WEST) + { + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_EAST, SindragosaPosition[8][0], SindragosaPosition[8][1], SindragosaPosition[8][2], false); + } + else if (uiPointId == SINDRAGOSA_POINT_GROUND_CENTER) + { + // fly up + if (m_uiPhase == SINDRAGOSA_PHASE_GROUND) + { + m_uiPhase = SINDRAGOSA_PHASE_FLYING_TO_AIR; + SetFlying(true); + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_CENTER, SindragosaPosition[1][0], SindragosaPosition[1][1], SindragosaPosition[1][2], false); + } + else // land and attack + { + // on aggro, after landing: set instance data and cast initial spells + if (m_uiPhase == SINDRAGOSA_PHASE_AGGRO) + { + DoCastSpellIfCan(m_creature, SPELL_FROST_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PERMEATING_CHILL, CAST_TRIGGERED); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SINDRAGOSA, IN_PROGRESS); + } + + m_uiPhase = SINDRAGOSA_PHASE_GROUND; + SetFlying(false); + SetCombatMovement(true); + + if (Unit* pVictim = m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(pVictim); + } + } + else if (uiPointId == SINDRAGOSA_POINT_AIR_CENTER) + { + if (m_uiPhase == SINDRAGOSA_PHASE_AGGRO || m_uiPhase == SINDRAGOSA_PHASE_FLYING_TO_GROUND) + { + // land + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_GROUND_CENTER, SindragosaPosition[0][0], SindragosaPosition[0][1], SindragosaPosition[0][2], false); + } + else if (m_uiPhase == SINDRAGOSA_PHASE_FLYING_TO_AIR) + { + // fly up (air phase) + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_PHASE_2, SindragosaPosition[2][0], SindragosaPosition[2][1], SindragosaPosition[2][2], false); + } + } + else if (uiPointId == SINDRAGOSA_POINT_AIR_PHASE_2) + { + m_creature->SetOrientation(M_PI_F); // face the platform + m_uiFrostBombTimer = 10000; // set initial Frost Bomb timer + DoCastSpellIfCan(m_creature, SPELL_ICE_TOMB); + m_uiPhase = SINDRAGOSA_PHASE_AIR; + } + } + + void DoFrostBomb() + { + float x, y, z; + x = frand(FROST_BOMB_MIN_X, FROST_BOMB_MAX_X); + y = frand(FROST_BOMB_MIN_Y, FROST_BOMB_MAX_Y); + z = SindragosaPosition[0][2]; // platform height + + m_creature->CastSpell(x, y, z, SPELL_FROST_BOMB, false); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Berserk + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case SINDRAGOSA_PHASE_THREE: + { + // Ice Tomb + if (m_uiIceTombSingleTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_ICE_TOMB_SINGLE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ICE_TOMB) == CAST_OK) + m_uiIceTombSingleTimer = 15000; + } + } + else + m_uiIceTombSingleTimer -= uiDiff; + + // no break + } + case SINDRAGOSA_PHASE_GROUND: + { + // Phase 1 only + if (m_uiPhase == SINDRAGOSA_PHASE_GROUND) + { + // Health Check + if (m_creature->GetHealthPercent() <= 30.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_MYSTIC_BUFFET) == CAST_OK) + { + m_uiPhase = SINDRAGOSA_PHASE_THREE; + DoScriptText(SAY_PHASE_3, m_creature); + } + } + + // Phase 2 (air) + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhaseTimer = 33000; + DoScriptText(SAY_TAKEOFF, m_creature); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_GROUND_CENTER, SindragosaPosition[0][0], SindragosaPosition[0][1], SindragosaPosition[0][2], false); + } + else + m_uiPhaseTimer -= uiDiff; + } + + // Cleave + if (m_uiCleaveTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(5000, 15000); + } + else + m_uiCleaveTimer -= uiDiff; + + // Tail Smash + if (m_uiTailSmashTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_SMASH) == CAST_OK) + m_uiTailSmashTimer = urand(10000, 20000); + } + else + m_uiTailSmashTimer -= uiDiff; + + // Frost Breath + if (m_uiFrostBreathTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_BREATH) == CAST_OK) + m_uiFrostBreathTimer = urand(15000, 20000); + } + else + m_uiFrostBreathTimer -= uiDiff; + + // Unchained Magic + if (m_uiUnchainedMagicTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_UNCHAINED_MAGIC) == CAST_OK) + { + m_uiUnchainedMagicTimer = urand(40000, 60000); + DoScriptText(SAY_UNCHAINED_MAGIC, m_creature); + } + } + else + m_uiUnchainedMagicTimer -= uiDiff; + + // Icy Grip and Blistering Cold + if (m_uiIcyGripTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ICY_GRIP) == CAST_OK) + { + m_uiIcyGripTimer = 70000; + DoScriptText(SAY_BLISTERING_COLD, m_creature); + } + } + else + m_uiIcyGripTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + } + case SINDRAGOSA_PHASE_FLYING_TO_GROUND: + case SINDRAGOSA_PHASE_FLYING_TO_AIR: + break; + case SINDRAGOSA_PHASE_AIR: + { + // Phase One (ground) + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhase = SINDRAGOSA_PHASE_FLYING_TO_GROUND; + m_uiPhaseTimer = 42000; + m_creature->GetMotionMaster()->MovePoint(SINDRAGOSA_POINT_AIR_CENTER, SindragosaPosition[1][0], SindragosaPosition[1][1], SindragosaPosition[1][2], false); + } + else + m_uiPhaseTimer -= uiDiff; + + // Frost Bomb + if (m_uiFrostBombTimer <= uiDiff) + { + DoFrostBomb(); + m_uiFrostBombTimer = 6000; + } + else + m_uiFrostBombTimer -= uiDiff; + + break; + } + } + + // evade on top of the stairs + EnterEvadeIfOutOfCombatArea(uiDiff); + } +}; + +CreatureAI* GetAI_boss_sindragosa(Creature* pCreature) +{ + return new boss_sindragosaAI(pCreature); +} + +struct npc_rimefang_iccAI : public ScriptedAI +{ + npc_rimefang_iccAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + + // Icy Blast - 3 casts on 10man, 6 on 25man + m_uiIcyBlastMaxCount = 3; + if (m_pInstance && m_pInstance->Is25ManDifficulty()) + m_uiIcyBlastMaxCount = 6; + + m_bHasLanded = false; + m_bIsReady = false; + + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + uint32 m_uiFrostBreathTimer; + uint32 m_uiIcyBlastCounter; + uint32 m_uiIcyBlastMaxCount; + uint32 m_uiIcyBlastTimer; + bool m_bHasLanded; // landed after player entered areatrigger + bool m_bIsReady; + + void Reset() override + { + m_uiPhase = RIMEFANG_PHASE_GROUND; + m_uiPhaseTimer = 25000; + m_uiFrostBreathTimer = urand(5000, 8000); + m_uiIcyBlastTimer = 0; + m_uiIcyBlastCounter = 0; + + SetCombatMovement(true); + } + + void SetFlying(bool bIsFlying) + { + if (bIsFlying) + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + else + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_creature->SetLevitate(bIsFlying); + m_creature->SetWalk(bIsFlying); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_RIMEFANG_FROST_AURA, CAST_TRIGGERED); + } + + void AttackStart(Unit* pWho) override + { + if (!m_bIsReady) + { + if (!m_bHasLanded) + { + m_bHasLanded = true; + m_creature->GetMotionMaster()->MovePoint(RIMEFANG_POINT_INITIAL_LAND_AIR, SindragosaPosition[4][0], SindragosaPosition[4][1], SindragosaPosition[4][2], false); + } + + return; + } + + ScriptedAI::AttackStart(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + Creature* pSpinestalker = m_pInstance->GetSingleCreatureFromStorage(NPC_SPINESTALKER); + if (!pSpinestalker || !pSpinestalker->isAlive()) + { + if (Creature* pSindragosa = m_creature->SummonCreature(NPC_SINDRAGOSA, SindragosaPosition[7][0], SindragosaPosition[7][1], SindragosaPosition[7][2], 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) + pSindragosa->SetInCombatWithZone(); + } + } + + // evade to point on platform + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(RIMEFANG_POINT_INITIAL_LAND, SindragosaPosition[3][0], SindragosaPosition[3][1], SindragosaPosition[3][2], false); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MovementInform(uint32 uiMovementType, uint32 uiPointId) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiPointId == RIMEFANG_POINT_INITIAL_LAND_AIR) + { + m_creature->GetMotionMaster()->MovePoint(RIMEFANG_POINT_INITIAL_LAND, SindragosaPosition[3][0], SindragosaPosition[3][1], SindragosaPosition[3][2], false); + } + else if (uiPointId == RIMEFANG_POINT_INITIAL_LAND) + { + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetFacingTo(M_PI_F); + m_bIsReady = true; + SetFlying(false); + } + else if (uiPointId == RIMEFANG_POINT_GROUND) + { + m_uiPhase = RIMEFANG_PHASE_GROUND; + SetFlying(false); + SetCombatMovement(true); + + if (Unit* pVictim = m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(pVictim); + } + else if (uiPointId == RIMEFANG_POINT_AIR) + { + m_uiPhase = RIMEFANG_PHASE_AIR; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPhase == RIMEFANG_PHASE_GROUND) + { + // Frost Breath + if (m_uiFrostBreathTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_RIMEFANG_FROST_BREATH) == CAST_OK) + m_uiFrostBreathTimer = urand(5000, 8000); + } + else + m_uiFrostBreathTimer -= uiDiff; + + // Icy Blast - air phase + if (m_uiPhaseTimer <= uiDiff) + { + m_uiPhaseTimer = 40000; + m_uiPhase = RIMEFANG_PHASE_FLYING; + SetFlying(true); + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(RIMEFANG_POINT_AIR, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 20.0f, false); + return; + } + else + m_uiPhaseTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + else if (m_uiPhase == RIMEFANG_PHASE_AIR) + { + // Icy Blast + if (m_uiIcyBlastTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_RIMEFANG_ICY_BLAST, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_RIMEFANG_ICY_BLAST) == CAST_OK) + { + m_uiIcyBlastTimer = 3000; + ++m_uiIcyBlastCounter; + + // phase end + if (m_uiIcyBlastCounter >= m_uiIcyBlastMaxCount) + { + m_uiIcyBlastCounter = 0; + m_uiIcyBlastTimer = 0; + m_uiPhase = RIMEFANG_PHASE_FLYING; + m_creature->GetMotionMaster()->MovePoint(RIMEFANG_POINT_GROUND, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() - 20.0f, false); + } + } + } + } + else + m_uiIcyBlastTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_rimefang_icc(Creature* pCreature) +{ + return new npc_rimefang_iccAI(pCreature); +} + + +struct npc_spinestalker_iccAI : public ScriptedAI +{ + npc_spinestalker_iccAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + m_bHasLanded = false; + m_bIsReady = false; + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiBellowingRoarTimer; + uint32 m_uiTailSweepTimer; + uint32 m_uiCleaveTimer; + bool m_bHasLanded; + bool m_bIsReady; + + void Reset() override + { + m_uiBellowingRoarTimer = urand(8000, 24000); + m_uiTailSweepTimer = urand(4000, 8000); + m_uiCleaveTimer = urand(5000, 8000); + } + + void SetFlying(bool bIsFlying) + { + if (bIsFlying) + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + else + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_creature->SetLevitate(bIsFlying); + m_creature->SetWalk(bIsFlying); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + Creature* pRimefang = m_pInstance->GetSingleCreatureFromStorage(NPC_RIMEFANG); + if (!pRimefang || !pRimefang->isAlive()) + { + if (Creature* pSindragosa = m_creature->SummonCreature(NPC_SINDRAGOSA, SindragosaPosition[7][0], SindragosaPosition[7][1], SindragosaPosition[7][2], 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 0)) + pSindragosa->SetInCombatWithZone(); + } + } + + void AttackStart(Unit* pWho) override + { + if (!m_bIsReady) + { + if (!m_bHasLanded) + { + m_bHasLanded = true; + m_creature->GetMotionMaster()->MovePoint(SPINESTALKER_POINT_INITIAL_LAND_AIR, SindragosaPosition[6][0], SindragosaPosition[6][1], SindragosaPosition[6][2], false); + } + + return; + } + + ScriptedAI::AttackStart(pWho); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(SPINESTALKER_POINT_INITIAL_LAND, SindragosaPosition[5][0], SindragosaPosition[5][1], SindragosaPosition[5][2]); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MovementInform(uint32 uiMovementType, uint32 uiPointId) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + if (uiPointId == SPINESTALKER_POINT_INITIAL_LAND_AIR) + { + m_creature->GetMotionMaster()->MovePoint(SPINESTALKER_POINT_INITIAL_LAND, SindragosaPosition[5][0], SindragosaPosition[5][1], SindragosaPosition[5][2], false); + } + else if (uiPointId == SPINESTALKER_POINT_INITIAL_LAND) + { + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetFacingTo(M_PI_F); + m_bIsReady = true; + SetFlying(false); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Cleave + if (m_uiCleaveTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SPINESTALKER_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(5000, 8000); + } + else + m_uiCleaveTimer -= uiDiff; + + // Tail Sweep + if (m_uiTailSweepTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SPINESTALKER_TAIL_SWEEP) == CAST_OK) + m_uiTailSweepTimer = urand(4000, 8000); + } + else + m_uiTailSweepTimer -= uiDiff; + + // Bellowing Roar + if (m_uiBellowingRoarTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SPINESTALKER_BELLOWING_ROAR) == CAST_OK) + m_uiBellowingRoarTimer = urand(8000, 24000); + } + else + m_uiBellowingRoarTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } }; +CreatureAI* GetAI_npc_spinestalker_icc(Creature* pCreature) +{ + return new npc_spinestalker_iccAI(pCreature); +} + +/** + * Frost Bomb - npc marking the target of Frost Bomb + */ +struct mob_frost_bombAI : public ScriptedAI +{ + mob_frost_bombAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + uint32 m_uiFrostBombTimer; + + void Reset() override + { + SetCombatMovement(false); + DoCastSpellIfCan(m_creature, SPELL_FROST_BOMB_VISUAL, CAST_TRIGGERED); + m_uiFrostBombTimer = 6000; + } + + void AttackStart(Unit* /*pWho*/) override {} + + void UpdateAI(const uint32 uiDiff) override + { + // Frost Bomb (dmg) + if (m_uiFrostBombTimer) + { + if (m_uiFrostBombTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pSindragosa = m_pInstance->GetSingleCreatureFromStorage(NPC_SINDRAGOSA)) + { + if (pSindragosa->AI()->DoCastSpellIfCan(m_creature, SPELL_FROST_BOMB_DMG) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_FROST_BOMB_VISUAL); + m_creature->ForcedDespawn(2000); + m_uiFrostBombTimer = 0; + } + } + } + } + else + m_uiFrostBombTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_mob_frost_bomb(Creature* pCreature) +{ + return new mob_frost_bombAI(pCreature); +} + void AddSC_boss_sindragosa() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_sindragosa"; + pNewScript->GetAI = &GetAI_boss_sindragosa; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_rimefang_icc"; + pNewScript->GetAI = &GetAI_npc_rimefang_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_spinestalker_icc"; + pNewScript->GetAI = &GetAI_npc_spinestalker_icc; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "mob_frost_bomb"; + pNewScript->GetAI = &GetAI_mob_frost_bomb; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_the_lich_king.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_the_lich_king.cpp index a8a3a474e..657b980a7 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_the_lich_king.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_the_lich_king.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_the_lich_king -SD%Complete: 0% +SD%Complete: 5% SDComment: SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum { @@ -62,6 +63,658 @@ enum SAY_OUTRO_14 = -1631192, }; +enum +{ + SPELL_BERSERK = 47008, + SPELL_SIT_EMOTE_NO_SHEATH = 73220, + SPELL_PLAGUE_AVOIDANCE = 72846, + + // Intro + SPELL_ICE_LOCK = 71614, + + // Outro + SPELL_FURY_OF_FROSTMOURNE = 72350, + SPELL_FURY_OF_FROSTMOURNE2 = 72351, // cannot resurect aura + SPELL_RAISE_DEAD = 71769, + SPELL_THROW_FROSTMOURNE = 73017, // 1 + SPELL_BROKEN_FROSTMOURNE = 72398, // 2 + SPELL_SUMMON_FROSTMOURNE = 72407, // 3 summon npc which casts 4 and 5 and LK enters this npc as vehicle + SPELL_FROSTMOURNE_DESPAWN = 72726, // 4 + SPELL_FROSTMOURNE_SPIRITS = 72405, // 5 + SPELL_SOUL_BARRAGE = 72305, // strangulation and sounds + SPELL_LK_CINEMATIC = 73159, + + // Tirion + SPELL_LIGHTS_BLESSING = 71797, // after 5secs smashes Ice Lock + + // Terenas Menethil + SPELL_MASS_RESURRECTION = 72429, // dummy + SPELL_MASS_RESURRECTION2 = 72423, // actual res + + // Phase One + SPELL_NECROTIC_PLAGUE = 70337, + SPELL_NECROTIC_PLAGUE_STACK = 70338, + SPELL_INFEST = 70541, + SPELL_SUMMON_GHOULS = 70358, + SPELL_SUMMON_HORROR = 70372, + SPELL_SHADOW_TRAP = 73539, + + // Phase transition + SPELL_REMORSELESS_WINTER_1 = 68981, // rooting caster and with Activate Object effect + SPELL_REMORSELESS_WINTER_2 = 72259, // rooting caster and with Send Script Event (23507) effect + SPELL_QUAKE = 72262, + SPELL_PAIN_AND_SUFFERING = 72133, + SPELL_RAGING_SPIRIT = 69200, + SPELL_SUMMON_RAGING_SPIRIT = 69201, + SPELL_SUMMON_ICE_SPHERE = 69103, + SPELL_ICE_SPHERE = 69104, // missile and summon effect + + // Phase Two + SPELL_SUMMON_VALKYR = 69037, + SPELL_SUMMON_VALKYRS = 74361, // 25man + SPELL_SOUL_REAPER = 69409, + SPELL_DEFILE = 72762, + + // Phase Three + SPELL_VILE_SPIRITS = 70498, + SPELL_HARVEST_SOUL = 68980, // stun aura and periodic damage, triggers summoning of vehicle + SPELL_HARVEST_SOUL_TP_FM_N = 72546, // teleports to Frostmourne Room and applies 60sec dummy aura (normal) + SPELL_HARVEST_SOUL_TP_FM_H = 73655, // teleports to Frostmourne Room and applies 60sec DoT aura (heroic) + SPELL_HARVEST_SOUL_CLONE = 71372, + SPELL_HARVEST_SOULS = 74296, + SPELL_HARVESTED_SOUL_1 = 73028, + SPELL_HARVESTED_SOUL_2 = 74321, + SPELL_HARVESTED_SOUL_3 = 74322, + SPELL_HARVESTED_SOUL_4 = 74323, + + SPELL_FROSTMOURNE_TP_VISUAL = 73078, + + // Shambling Horror + SPELL_FRENZY = 28747, + SPELL_ENRAGE = 72143, + SPELL_SHOCKWAVE = 72149, + + // Shadow Trap + SPELL_SHADOW_TRAP_VISUAL = 73530, + SPELL_SHADOW_TRAP_AURA = 73525, + + // Raging Spirit + SPELL_SOUL_SHRIEK = 69242, + SPELL_RAGING_SPIRIT_VISUAL = 69198, // clone effect (clone of player) + + // Ice Sphere + SPELL_ICE_SPHERE_VISUAL = 69090, + SPELL_ICE_BURST_AURA = 69109, + SPELL_ICE_BURST = 69108, + SPELL_ICE_PULSE = 69091, + + // Val'kyr Shadowguard + SPELL_LIFE_SIPHON = 73783, + SPELL_VALKYR_CHARGE = 74399, + SPELL_HARVEST_SOUL_VEHICLE = 68985, + SPELL_EJECT_PASSENGERS = 68576, + SPELL_WINGS_OF_THE_DAMNED = 74352, + + // Defile + SPELL_DEFILE_AURA = 72743, + SPELL_DEFILE_GROW = 72756, + + // Vile Spirit and Wicked Spirit + SPELL_SPIRIT_BURST_AURA = 70502, + + // Spirit Warden + SPELL_DARK_HUNGER = 69383, + SPELL_DESTROY_SOUL = 74086, + SPELL_SOUL_RIP = 69397, // 3500, each next one x2 (maybe based on HP of target?) + + // Terenas in Frostmourne + SPELL_RESTORE_SOUL = 72595, + SPELL_RESTORE_SOUL_HEROIC = 73650, + SPELL_LIGHTS_FAVOR = 69382, + SPELL_SUMMON_SPIRIT_BOMBS_1 = 73581, // heroic only, summons Spirit Bomb every 1 sec + SPELL_SUMMON_SPIRIT_BOMBS_2 = 74299, // 2 secs interval + SPELL_SUMMON_SPIRIT_BOMB = 74300, // aura doesnt work somehow, so we will use manual summoning + + // Spirit Bomb + SPELL_SPIRIT_BOMB_VISUAL = 73572, + SPELL_EXPLOSION = 73804, + + // NPCs + NPC_SHADOW_TRAP = 39137, + NPC_FROSTMOURNE = 38584, + NPC_ICE_SPHERE = 36633, + NPC_RAGING_SPIRIT = 36701, + NPC_DEFILE = 38757, + NPC_SPIRIT_WARDEN = 36824, + NPC_TERENAS_FM_NORMAL = 36823, + NPC_TERENAS_FM_HEROIC = 39217, + NPC_WICKED_SPIRIT = 39190, + NPC_SPIRIT_BOMB = 39189, +}; + +enum Phase +{ + PHASE_INTRO = 0, // intro + PHASE_ONE = 1, // phase one + PHASE_RUNNING_WINTER_ONE = 2, // running to center of platform to cast Remorseless Winter + PHASE_TRANSITION_ONE = 3, // Remorseless Winter aura and casting spells, summoning orbs and spirits + PHASE_QUAKE_ONE = 4, // casting Quake + PHASE_TWO = 5, // phase two with val'kyrs and some more spells + PHASE_RUNNING_WINTER_TWO = 6, // running to center of platform to cast Remorseless Winter again + PHASE_TRANSITION_TWO = 7, // second Remorseless Winter phase + PHASE_QUAKE_TWO = 8, // second Quake casting + PHASE_THREE = 9, // phase three, casting Soul Harvest (Frostmourne phase) + PHASE_IN_FROSTMOURNE = 10, // phase three, waiting untill whole raid leaves Frostmourne + PHASE_CUTSCENE = 11, // phase when LK kills raid, Terenas comes etc. + PHASE_DEATH_AWAITS = 12, // strangulating Lich King, raid group finishing him +}; + +enum Point +{ + POINT_CENTER_LAND = 1, + POINT_CENTER_LAND_TIRION = 2, + POINT_TELEPORTER_TIRION = 3, + POINT_VALKYR_THROW = 4, + POINT_VALKYR_CENTER = 5, + POINT_TP_TO_FM = 6, // point where strangulate vehicle moves, after reaching player is teleported into frostmourne + POINT_SPIRIT_BOMB = 7, // Spirit Bomb moving down +}; + +static const float fLichKingPosition[11][3] = +{ + {458.59f, -2122.71f, 1040.86f}, // 0 Lich King Intro + {503.16f, -2124.52f, 1040.86f}, // 1 Center of the platform + {500.16f, -2124.52f, 1040.86f}, // 2 Tirion strikes Lich King + {481.70f, -2124.64f, 1040.86f}, // 3 Tirion 2 + {498.00f, -2201.57f, 1046.09f}, // 4 Valkyrs? + {517.48f, -2124.91f, 1040.86f}, // 5 Tirion? + {529.85f, -2124.71f, 1040.86f}, // 6 Lich king final, o=3.1146 + {520.31f, -2124.71f, 1040.86f}, // 7 Frostmourne + {453.80f, -2088.20f, 1040.86f}, // 8 Val'kyr drop point right to Frozen Throne + {457.03f, -2155.08f, 1040.86f}, // 9 Val'kyr drop point left to Frozen Throne + {494.31f, -2523.08f, 1249.87f}, // 10 center of platform inside Frostmourne +}; + +struct boss_the_lich_king_iccAI : public ScriptedAI +{ + boss_the_lich_king_iccAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + uint32 m_uiPhase; + uint32 m_uiPhaseTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiGhoulsTimer; + uint32 m_uiHorrorTimer; + uint32 m_uiNecroticPlagueTimer; + uint32 m_uiInfestTimer; + uint32 m_uiShadowTrapTimer; + uint32 m_uiPainSufferingTimer; + uint32 m_uiRagingSpiritTimer; + uint32 m_uiIceSphereTimer; + uint32 m_uiValkyrTimer; + uint32 m_uiDefileTimer; + uint32 m_uiSoulReaperTimer; + uint32 m_uiHarvestSoulTimer; + uint32 m_uiFrostmournePhaseTimer; + uint32 m_uiVileSpiritsTimer; + + void Reset() override + { + // TODO: handling phases "intro" and "one" and aggroing depending on resetting encounter + m_uiPhase = PHASE_INTRO; + + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; + m_uiGhoulsTimer = 13000; + m_uiHorrorTimer = 21000; + m_uiInfestTimer = 20000; + m_uiNecroticPlagueTimer = 23000; + m_uiShadowTrapTimer = 15000; + m_uiPainSufferingTimer = 6000; + m_uiRagingSpiritTimer = 20000; + m_uiIceSphereTimer = 6000; + m_uiValkyrTimer = 10000; + m_uiDefileTimer = 30000; + m_uiSoulReaperTimer = 25000; + m_uiHarvestSoulTimer = 5000; + m_uiVileSpiritsTimer = 20000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LICH_KING, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + m_uiPhase = PHASE_ONE; + } + + void KilledUnit(Unit* pWho) override + { + if (pWho->GetTypeId() == TYPEID_PLAYER) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LICH_KING, DONE); + + DoScriptText(SAY_OUTRO_14, m_creature); + + // TODO: finish event, after around 8 seconds play cinematic + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LICH_KING, FAIL); + } + + void MovementInform(uint32 uiMovementType, uint32 uiData) override + { + if (uiMovementType != POINT_MOTION_TYPE) + return; + + switch (uiData) + { + case POINT_CENTER_LAND: + { + if (m_uiPhase == PHASE_RUNNING_WINTER_ONE) + { + DoScriptText(SAY_REMORSELESS_WINTER, m_creature); + + // TODO: not sure which spell in which phase + // DoCastSpellIfCan(m_creature, SPELL_REMORSELESS_WINTER_1); + + m_uiPhase = PHASE_TRANSITION_ONE; + m_uiPhaseTimer = 62000; + + // TODO: set phase initial timers + // TODO: on heroic despawn Shadow Traps + } + else if (m_uiPhase == PHASE_RUNNING_WINTER_TWO) + { + DoScriptText(SAY_REMORSELESS_WINTER, m_creature); + + // TODO: not sure which spell in which phase + // DoCastSpellIfCan(m_creature, SPELL_REMORSELESS_WINTER_2); + + m_uiPhase = PHASE_TRANSITION_TWO; + m_uiPhaseTimer = 62000; + + // TODO: set phase initial timers + } + else if (m_uiPhase == PHASE_DEATH_AWAITS) + { + DoCastSpellIfCan(m_creature, SPELL_RAISE_DEAD); + } + + break; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhase != PHASE_INTRO && m_uiPhase != PHASE_DEATH_AWAITS) + { + // check evade + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Berserk + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + } + + switch (m_uiPhase) + { + case PHASE_INTRO: + { + // wait until set in combat + return; + } + case PHASE_ONE: + { + // check HP + if (m_creature->GetHealthPercent() <= 70.0f) + { + // phase transition + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_LAND, fLichKingPosition[1][0], fLichKingPosition[1][1], fLichKingPosition[1][2]); + m_uiPhase = PHASE_RUNNING_WINTER_ONE; + return; + } + + // Necrotic Plague + if (m_uiNecroticPlagueTimer < uiDiff) + { + // shouldn't be targeting players who already have Necrotic Plague on them + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_NECROTIC_PLAGUE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_NECROTIC_PLAGUE) == CAST_OK) + m_uiNecroticPlagueTimer = 30000; + } + } + else + m_uiNecroticPlagueTimer -= uiDiff; + + // Infest + if (m_uiInfestTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INFEST) == CAST_OK) + m_uiInfestTimer = urand(20000, 25000); + } + else + m_uiInfestTimer -= uiDiff; + + // Summon Ghouls + if (m_uiGhoulsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_GHOULS) == CAST_OK) + m_uiGhoulsTimer = 32000; + } + else + m_uiGhoulsTimer -= uiDiff; + + // Summon Shambling Horror + if (m_uiHorrorTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_HORROR) == CAST_OK) + m_uiHorrorTimer = 60000; + } + else + m_uiHorrorTimer -= uiDiff; + + // Shadow Trap (heroic) + if (m_pInstance && m_pInstance->IsHeroicDifficulty()) + { + if (m_uiShadowTrapTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_SHADOW_TRAP, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_TRAP) == CAST_OK) + m_uiShadowTrapTimer = 15000; + } + } + else + m_uiShadowTrapTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + + break; + } + case PHASE_RUNNING_WINTER_ONE: + case PHASE_RUNNING_WINTER_TWO: + { + // wait for waypoint arrival + break; + } + case PHASE_TRANSITION_ONE: + case PHASE_TRANSITION_TWO: + { + // phase end timer + if (m_uiPhaseTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_QUAKE) == CAST_OK) + { + DoScriptText(SAY_SHATTER_ARENA, m_creature); + m_uiPhase = (m_uiPhase == PHASE_TRANSITION_ONE ? PHASE_QUAKE_ONE : PHASE_QUAKE_TWO); + m_uiPhaseTimer = 6500; + } + } + else + m_uiPhaseTimer -= uiDiff; + + // Pain and Suffering + if (m_uiPainSufferingTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_PAIN_AND_SUFFERING, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_PAIN_AND_SUFFERING) == CAST_OK) + m_uiPainSufferingTimer = urand(1500, 3000); + } + } + else + m_uiPainSufferingTimer -= uiDiff; + + // Summon Ice Sphere + if (m_uiIceSphereTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ICE_SPHERE) == CAST_OK) + m_uiIceSphereTimer = 6000; + } + else + m_uiIceSphereTimer -= uiDiff; + + // Summon Raging Spirit + if (m_uiRagingSpiritTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_RAGING_SPIRIT, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_RAGING_SPIRIT, CAST_TRIGGERED) == CAST_OK) + m_uiRagingSpiritTimer = (m_uiPhase == PHASE_TRANSITION_ONE ? 20000 : 15000); + } + } + else + m_uiRagingSpiritTimer -= uiDiff; + + break; + } + case PHASE_QUAKE_ONE: + case PHASE_QUAKE_TWO: + { + // Casting Quake spell - phase end timer + if (m_uiPhaseTimer < uiDiff) + { + // TODO: destroy platform + + m_uiPhase = (m_uiPhase == PHASE_QUAKE_ONE ? PHASE_TWO : PHASE_THREE); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + return; + } + else + m_uiPhaseTimer -= uiDiff; + + break; + } + case PHASE_TWO: + { + // check HP + if (m_creature->GetHealthPercent() <= 40.0f) + { + // phase transition + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_CENTER_LAND, fLichKingPosition[1][0], fLichKingPosition[1][1], fLichKingPosition[1][2]); + m_uiPhaseTimer = 60000; + m_uiPhase = PHASE_RUNNING_WINTER_TWO; + } + + // Soul Reaper + if (m_uiSoulReaperTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_REAPER) == CAST_OK) + m_uiSoulReaperTimer = 30000; + } + else + m_uiSoulReaperTimer -= uiDiff; + + // Infest + if (m_uiInfestTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INFEST) == CAST_OK) + m_uiInfestTimer = urand(20000, 25000); + } + else + m_uiInfestTimer -= uiDiff; + + // Defile + if (m_uiDefileTimer < uiDiff) + { + // shouldn't be targeting players in vehicles + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_DEFILE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEFILE) == CAST_OK) + m_uiDefileTimer = 30000; + } + } + else + m_uiDefileTimer -= uiDiff; + + // Summon Val'kyr + if (m_uiValkyrTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_VALKYR) == CAST_OK) + { + DoScriptText(SAY_SUMMON_VALKYR, m_creature); + m_uiValkyrTimer = 50000; + } + } + else + m_uiValkyrTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + } + case PHASE_THREE: + { + // check HP + if (m_creature->GetHealthPercent() <= 10.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_FURY_OF_FROSTMOURNE) == CAST_OK) + { + DoScriptText(SAY_LAST_PHASE, m_creature); + m_uiPhase = PHASE_DEATH_AWAITS; + + // TODO: start ending event + + return; + } + } + + // Soul Reaper + if (m_uiSoulReaperTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_REAPER) == CAST_OK) + m_uiSoulReaperTimer = 30000; + } + else + m_uiSoulReaperTimer -= uiDiff; + + // Defile + if (m_uiDefileTimer < uiDiff) + { + // shouldn't be targeting players in vehicles + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_DEFILE, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEFILE) == CAST_OK) + m_uiDefileTimer = 30000; + } + } + else + m_uiDefileTimer -= uiDiff; + + // Harvest Soul + if (m_uiHarvestSoulTimer < uiDiff) + { + Unit* pTarget = NULL; + bool m_bIsHeroic = m_pInstance && m_pInstance->IsHeroicDifficulty(); + if (m_bIsHeroic) + pTarget = m_creature; + else + pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_HARVEST_SOUL, SELECT_FLAG_PLAYER); + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, m_bIsHeroic ? SPELL_HARVEST_SOULS : SPELL_HARVEST_SOUL) == CAST_OK) + { + DoScriptText(SAY_HARVEST_SOUL, m_creature); + m_uiHarvestSoulTimer = m_bIsHeroic ? 120000 : 70000; + + // TODO: prepare Frostmourne room - summon bombs and Tirion, or Tirion and the "bad spirit-guy" + + if (m_bIsHeroic) + { + m_uiPhase = PHASE_IN_FROSTMOURNE; + SetCombatMovement(false); + m_creature->StopMoving(); + m_uiFrostmournePhaseTimer = 47000; + m_uiDefileTimer = 1000; + } + } + } + } + else + m_uiHarvestSoulTimer -= uiDiff; + + // Vile Spirits + if (m_uiVileSpiritsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VILE_SPIRITS) == CAST_OK) + m_uiVileSpiritsTimer = 30000; + } + else + m_uiVileSpiritsTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + } + case PHASE_IN_FROSTMOURNE: + { + // check if players are alive before entering evade mode? + // wait until they leave Frostmourne + if (m_uiFrostmournePhaseTimer < uiDiff) + { + m_uiPhase = PHASE_THREE; + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + return; + } + else + m_uiFrostmournePhaseTimer -= uiDiff; + + break; + } + case PHASE_DEATH_AWAITS: + { + // wait for swift death + break; + } + } + } +}; + +CreatureAI* GetAI_boss_the_lich_king_icc(Creature* pCreature) +{ + return new boss_the_lich_king_iccAI(pCreature); +} + void AddSC_boss_the_lich_king() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_the_lich_king_icc"; + pNewScript->GetAI = &GetAI_boss_the_lich_king_icc; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_valithria_dreamwalker.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_valithria_dreamwalker.cpp index e7f734625..ae6e10360 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_valithria_dreamwalker.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/boss_valithria_dreamwalker.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_valithria -SD%Complete: 0% +SD%Complete: 5% SDComment: SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" enum SvalnaTexts // TODO Maybe need own file? { @@ -49,6 +50,109 @@ enum SAY_VICTORY = -1631147, }; +// Valithria +enum +{ + SPELL_NIGHTMARE_PORTAL_PRE = 71977, + SPELL_NIGHTMARE_PORTAL = 71987, + SPELL_TWISTED_NIGHTMARES = 71941, + SPELL_TWISTED_NIGHTMARES_DOT = 71940, + SPELL_NIGHTMARE_CLOUD = 71970, // Nightmare Clouds cast this on dreaming Valithria - then she deals this dmg to Real Valithria(?) + SPELL_NIGHTMARE_CLOUD_VISUAL = 71939, + + SPELL_DREAM_PORTAL_PRE = 71301, + SPELL_DREAM_PORTAL = 71305, + SPELL_EMERALD_VIGOR = 70873, + SPELL_DREAM_CLOUD_VISUAL = 70876, + + SPELL_DREAM_STATE = 70766, + + SPELL_DREAMWALKER_RAGE = 71189, + SPELL_IMMUNITY = 72724, + SPELL_CORRUPTION = 70904, + SPELL_DREAM_SLIP = 71196, + SPELL_ICE_SPIKE = 70702, + + SPELL_CLEAR_DREAMS_NIGHTMARES = 75863, // script effect removes Emerald Vigor and Nightmare auras + + // summons + // TODO: + // these spells should be applied to dummy npcs in gates + // they should apply these auras once the encounter has started + // but how to apply this, which spell on which npc and when? + // how to handle summon timers speedup? + SPELL_SUMMON_TIMER_SUPPRESSER = 70912, + SPELL_SUMMON_TIMER_SKELETON = 70913, + SPELL_SUMMON_TIMER_ZOMBIE = 70914, + SPELL_SUMMON_TIMER_ABOMIN = 70915, + SPELL_SUMMON_TIMER_ARCHMAGE = 70916, + + // entries + NPC_NIGHTMARE_PORTAL_PRE = 38429, + NPC_NIGHTMARE_PORTAL = 38430, + NPC_NIGHTMARE_CLOUD = 38421, + NPC_DREAM_PORTAL_PRE = 38186, + NPC_DREAM_PORTAL = 37945, + NPC_DREAM_CLOUD = 37985, + + // Achievements + SPELL_ACHIEVEMENT_CREDIT = 72706, + + // other + SUMMON_TYPES_NUMBER = 4 +}; + +struct boss_valithria_dreamwalkerAI : public ScriptedAI +{ + boss_valithria_dreamwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_icecrown_citadel*)pCreature->GetInstanceData(); + Reset(); + } + + instance_icecrown_citadel* m_pInstance; + + void Reset() override + { + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VALITHRIA, FAIL); + } + + // actually, when summoned creature kills a player + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(SAY_PLAYER_DIES, m_creature, pVictim); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_0_HEALTH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VALITHRIA, FAIL); + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + } +}; + +CreatureAI* GetAI_boss_valithria_dreamwalker(Creature* pCreature) +{ + return new boss_valithria_dreamwalkerAI(pCreature); +}; + void AddSC_boss_valithria_dreamwalker() { + Script* pNewscript; + + pNewscript = new Script; + pNewscript->Name = "boss_valithria_dreamwalker"; + pNewscript->GetAI = &GetAI_boss_valithria_dreamwalker; + pNewscript->RegisterSelf(); } diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/gunship_battle.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/gunship_battle.cpp index 67a1ce34a..438046a0c 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/gunship_battle.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/gunship_battle.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h index 5871a49a1..834faa37e 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/icecrown_citadel.h @@ -1,3 +1,255 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_ICECROWN_CITADEL_H +#define DEF_ICECROWN_CITADEL_H + +enum +{ + MAX_ENCOUNTER = 12, + + TYPE_MARROWGAR = 0, + TYPE_LADY_DEATHWHISPER = 1, + TYPE_GUNSHIP_BATTLE = 2, + TYPE_DEATHBRINGER_SAURFANG = 3, + TYPE_FESTERGUT = 4, + TYPE_ROTFACE = 5, + TYPE_PROFESSOR_PUTRICIDE = 6, + TYPE_BLOOD_PRINCE_COUNCIL = 7, + TYPE_QUEEN_LANATHEL = 8, + TYPE_VALITHRIA = 9, + TYPE_SINDRAGOSA = 10, + TYPE_LICH_KING = 11, + + // NPC entries + NPC_LORD_MARROWGAR = 36612, + NPC_LADY_DEATHWHISPER = 36855, + NPC_DEATHBRINGER_SAURFANG = 37813, + NPC_FESTERGUT = 36626, + NPC_ROTFACE = 36627, + NPC_PROFESSOR_PUTRICIDE = 36678, + NPC_TALDARAM = 37973, + NPC_VALANAR = 37970, + NPC_KELESETH = 37972, + NPC_QUEEN_LANATHEL = 37955, + NPC_VALITHRIA = 36789, + NPC_SINDRAGOSA = 36853, + NPC_LICH_KING = 36597, + + // boss-related and other NPCs + NPC_DEATHWHISPER_SPAWN_STALKER = 37947, + NPC_DEATHWHISPER_CONTROLLER = 37948, + NPC_OVERLORD_SAURFANG = 37187, + NPC_KORKRON_REAVER = 37920, + NPC_MURADIN_BRONZEBEARD = 37200, // Saurfang's encounter and at the instance entrance + NPC_SKYBREAKER_MARINE = 37830, + NPC_ALLIANCE_MARINE = 37830, + NPC_BLOOD_ORB_CONTROL = 38008, + NPC_LANATHEL_INTRO = 38004, + NPC_VALITHRIA_QUEST = 38589, + NPC_VALITHRIA_COMBAT_TRIGGER = 38752, + NPC_MURADIN = 36948, // Gunship Battle's encounter(?) + NPC_TIRION = 38995, + NPC_MENETHIL = 38579, + NPC_FROSTMOURNE_TRIGGER = 38584, + NPC_FROSTMOURNE_HOLDER = 27880, + NPC_STINKY = 37025, + NPC_PRECIOUS = 37217, + NPC_PUDDLE_STALKER = 37013, // related to Festergut and Rotface + NPC_RIMEFANG = 37533, + NPC_SPINESTALKER = 37534, + + // GameObjects entries + GO_ICEWALL_1 = 201911, + GO_ICEWALL_2 = 201910, + GO_MARROWGAR_DOOR = 201857, // Marrowgar combat door + + GO_ORATORY_DOOR = 201563, + GO_DEATHWHISPER_ELEVATOR = 202220, + + GO_SAURFANG_DOOR = 201825, + + GO_GREEN_PLAGUE = 201370, // Rotface combat door + GO_ORANGE_PLAGUE = 201371, // Festergut combat door + GO_SCIENTIST_DOOR = 201372, // Putricide combat door + GO_SCIENTIST_DOOR_COLLISION = 201612, // Putricide pathway doors + GO_SCIENTIST_DOOR_ORANGE = 201613, + GO_SCIENTIST_DOOR_GREEN = 201614, + GO_GREEN_VALVE = 201615, // Valves used to release the Gas / Oozes in order to open the pathway to Putricide - triggers event 23426 + GO_ORANGE_VALVE = 201616, // triggers event 23438 + GO_ORANGE_TUBE = 201617, + GO_GREEN_TUBE = 201618, + + // GO_BLOODWING_DOOR = 201920, // not used + GO_CRIMSON_HALL_DOOR = 201376, // Council combat door + GO_COUNCIL_DOOR_1 = 201377, + GO_COUNCIL_DOOR_2 = 201378, + GO_BLOODPRINCE_DOOR = 201746, // Lanathel combat door + GO_ICECROWN_GRATE = 201755, // Lanathel trap door + + // GO_FROSTWING_DOOR = 201919, // not used + GO_GREEN_DRAGON_ENTRANCE = 201375, // Valithria combat door + GO_GREEN_DRAGON_EXIT = 201374, + GO_VALITHRIA_DOOR_1 = 201381, // Valithria event doors + GO_VALITHRIA_DOOR_2 = 201382, + GO_VALITHRIA_DOOR_3 = 201383, + GO_VALITHRIA_DOOR_4 = 201380, + GO_SINDRAGOSA_SHORTCUT_ENTRANCE = 201369, // Shortcut doors are opened only after the trash before Sindragosa is cleared + GO_SINDRAGOSA_SHORTCUT_EXIT = 201379, + GO_SINDRAGOSA_ENTRANCE = 201373, + + GO_FROZENTRONE_TRANSPORTER = 202223, + GO_ICESHARD_1 = 202142, + GO_ICESHARD_2 = 202141, + GO_ICESHARD_3 = 202143, + GO_ICESHARD_4 = 202144, + GO_FROSTY_WIND = 202188, + GO_FROSTY_EDGE = 202189, + GO_SNOW_EDGE = 202190, + GO_ARTHAS_PLATFORM = 202161, + GO_ARTHAS_PRECIPICE = 202078, + + GO_PLAGUE_SIGIL = 202182, // Possible used after each wing is cleared + GO_FROSTWING_SIGIL = 202181, + GO_BLOODWING_SIGIL = 202183, + + // Loot chests + GO_SAURFANG_CACHE = 202239, + GO_SAURFANG_CACHE_25 = 202240, + GO_SAURFANG_CACHE_10_H = 202238, + GO_SAURFANG_CACHE_25_H = 202241, + + GO_GUNSHIP_ARMORY_A = 201872, + GO_GUNSHIP_ARMORY_A_25 = 201873, + GO_GUNSHIP_ARMORY_A_10H = 201874, + GO_GUNSHIP_ARMORY_A_25H = 201875, + + GO_GUNSHIP_ARMORY_H = 202177, + GO_GUNSHIP_ARMORY_H_25 = 202178, + GO_GUNSHIP_ARMORY_H_10H = 202179, + GO_GUNSHIP_ARMORY_H_25H = 202180, + + GO_DREAMWALKER_CACHE = 201959, + GO_DREAMWALKER_CACHE_25 = 202339, + GO_DREAMWALKER_CACHE_10_H = 202338, + GO_DREAMWALKER_CACHE_25_H = 202340, + + // Area triggers + AREATRIGGER_MARROWGAR_INTRO = 5732, + AREATRIGGER_DEATHWHISPER_INTRO = 5709, + AREATRIGGER_SINDRAGOSA_PLATFORM = 5604, + + // Achievement criterias + ACHIEV_CRIT_BONED_10N = 12775, // Lord Marrowgar, achievs 4534, 4610 + ACHIEV_CRIT_BONED_25N = 12962, + ACHIEV_CRIT_BONED_10H = 13393, + ACHIEV_CRIT_BONED_25H = 13394, + + ACHIEV_CRIT_HOUSE_10N = 12776, // Lady Deathwhisper, achievs 4535, 4611 + ACHIEV_CRIT_HOUSE_25N = 12997, + ACHIEV_CRIT_HOUSE_10H = 12995, + ACHIEV_CRIT_HOUSE_25H = 12998, + + ACHIEV_CRIT_IM_ON_A_BOAT_10N = 12777, // Gunship Battle, achievs 4536, 4612 + ACHIEV_CRIT_IM_ON_A_BOAT_25N = 13080, + ACHIEV_CRIT_IM_ON_A_BOAT_10H = 13079, + ACHIEV_CRIT_IM_ON_A_BOAT_25H = 13081, + + ACHIEV_CRIT_MADE_A_MESS_10N = 12778, // Deathbringer Saurfang, achievs 4537, 4613 + ACHIEV_CRIT_MADE_A_MESS_25N = 13036, + ACHIEV_CRIT_MADE_A_MESS_10H = 13035, + ACHIEV_CRIT_MADE_A_MESS_25H = 13037, + + ACHIEV_CRIT_FLU_SHOT_SHORTAGE_10N = 12977, // Festergut, achievs 4615, 4577 + ACHIEV_CRIT_FLU_SHOT_SHORTAGE_25N = 12982, + ACHIEV_CRIT_FLU_SHOT_SHORTAGE_10H = 12986, + ACHIEV_CRIT_FLU_SHOT_SHORTAGE_25H = 12967, + + ACHIEV_CRIT_DANCES_WITH_OOZES_10N = 12984, // Rotface, achievs 4538, 4614 + ACHIEV_CRIT_DANCES_WITH_OOZES_25N = 12966, + ACHIEV_CRIT_DANCES_WITH_OOZES_10H = 12985, + ACHIEV_CRIT_DANCES_WITH_OOZES_25H = 12983, + + ACHIEV_CRIT_NAUSEA_10N = 12987, // Professor Putricide, achievs 4578, 4616 + ACHIEV_CRIT_NAUSEA_25N = 12968, + ACHIEV_CRIT_NAUSEA_10H = 12988, + ACHIEV_CRIT_NAUSEA_25H = 12981, + + ACHIEV_CRIT_ORB_WHISPERER_10N = 13033, // Blood Prince Council, achievs 4582, 4617 + ACHIEV_CRIT_ORB_WHISPERER_25N = 12969, + ACHIEV_CRIT_ORB_WHISPERER_10H = 13034, + ACHIEV_CRIT_ORB_WHISPERER_25H = 13032, + + ACHIEV_CRIT_ONCE_BITTEN_TWICE_SHY_10N = 12780, // Blood-Queen Lana'thel, achievs 4539, 4618 + ACHIEV_CRIT_ONCE_BITTEN_TWICE_SHY_25N = 13012, + ACHIEV_CRIT_ONCE_BITTEN_TWICE_SHY_10V = 13011, + ACHIEV_CRIT_ONCE_BITTEN_TWICE_SHY_25V = 13013, + + ACHIEV_CRIT_PORTAL_JOCKEY_10N = 12978, // Valithria, achievs 4579, 4619 + ACHIEV_CRIT_PORTAL_JOCKEY_25N = 12971, + ACHIEV_CRIT_PORTAL_JOCKEY_10H = 12979, + ACHIEV_CRIT_PORTAL_JOCKEY_25H = 12980, + + ACHIEV_CRIT_ALL_YOU_CAN_EAT_10N = 12822, // Sindragosa, achievs 4580, 4620 + ACHIEV_CRIT_ALL_YOU_CAN_EAT_25N = 12972, + ACHIEV_CRIT_ALL_YOU_CAN_EAT_10V = 12996, + ACHIEV_CRIT_ALL_YOU_CAN_EAT_25V = 12989, + + ACHIEV_CRIT_WAITING_A_LONG_TIME_10N = 13246, // Lich King, achievs 4601, 4621 + ACHIEV_CRIT_WAITING_A_LONG_TIME_25N = 13244, + ACHIEV_CRIT_WAITING_A_LONG_TIME_10H = 13247, + ACHIEV_CRIT_WAITING_A_LONG_TIME_25H = 13245, +}; + +class instance_icecrown_citadel : public ScriptedInstance, private DialogueHelper +{ + public: + instance_icecrown_citadel(Map* pMap); + + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* strIn) override; + + void DoHandleCitadelAreaTrigger(uint32 uiTriggerId, Player* pPlayer); + + // Difficulty wrappers + bool IsHeroicDifficulty() { return instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; } + bool Is25ManDifficulty() { return instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; } + + void GetDeathwhisperStalkersList(GuidList& lList) { lList = m_lDeathwhisperStalkersGuids; } + + // Open Putricide door in a few seconds + void DoPreparePutricideDoor() { m_uiPutricideValveTimer = 15000; } + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget = NULL, uint32 uiMiscvalue1 = 0) const override; + + void Update(uint32 uiDiff) override; + + private: + std::string m_strInstData; + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + uint32 m_uiTeam; // Team of first entered player, used on the Gunship event + uint32 m_uiPutricideValveTimer; + + bool m_bHasMarrowgarIntroYelled; + bool m_bHasDeathwhisperIntroYelled; + bool m_bHasRimefangLanded; + bool m_bHasSpinestalkerLanded; + + GuidList m_lDeathwhisperStalkersGuids; +}; + +#endif diff --git a/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp b/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp index a17aa1dc4..b50fb6125 100644 --- a/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp +++ b/scripts/northrend/icecrown_citadel/icecrown_citadel/instance_icecrown_citadel.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,551 @@ /* ScriptData SDName: instance_icecrown_citadel -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 20% +SDComment: Just basic stuff SDCategory: Icecrown Citadel EndScriptData */ #include "precompiled.h" +#include "icecrown_citadel.h" + +enum +{ + // Marrowgar + SAY_MARROWGAR_INTRO = -1631001, + + // Deathwhisper + SAY_DEATHWHISPER_SPEECH_1 = -1631011, + SAY_DEATHWHISPER_SPEECH_2 = -1631012, + SAY_DEATHWHISPER_SPEECH_3 = -1631013, + SAY_DEATHWHISPER_SPEECH_4 = -1631014, + SAY_DEATHWHISPER_SPEECH_5 = -1631015, + SAY_DEATHWHISPER_SPEECH_6 = -1631016, + SAY_DEATHWHISPER_SPEECH_7 = -1631017, + + // Festergut + SAY_STINKY_DIES = -1631081, + // Rotface + SAY_PRECIOUS_DIES = -1631070, +}; + +static const DialogueEntry aCitadelDialogue[] = +{ + {SAY_DEATHWHISPER_SPEECH_1, NPC_LADY_DEATHWHISPER, 12000}, + {SAY_DEATHWHISPER_SPEECH_2, NPC_LADY_DEATHWHISPER, 11000}, + {SAY_DEATHWHISPER_SPEECH_3, NPC_LADY_DEATHWHISPER, 10000}, + {SAY_DEATHWHISPER_SPEECH_4, NPC_LADY_DEATHWHISPER, 9000}, + {SAY_DEATHWHISPER_SPEECH_5, NPC_LADY_DEATHWHISPER, 10000}, + {SAY_DEATHWHISPER_SPEECH_6, NPC_LADY_DEATHWHISPER, 10000}, + {SAY_DEATHWHISPER_SPEECH_7, NPC_LADY_DEATHWHISPER, 0}, + {0, 0, 0}, +}; + +instance_icecrown_citadel::instance_icecrown_citadel(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aCitadelDialogue), + m_uiTeam(0), + m_uiPutricideValveTimer(0), + m_bHasMarrowgarIntroYelled(false), + m_bHasDeathwhisperIntroYelled(false), + m_bHasRimefangLanded(false), + m_bHasSpinestalkerLanded(false) +{ + Initialize(); +} + +void instance_icecrown_citadel::Initialize() +{ + InitializeDialogueHelper(this); + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +bool instance_icecrown_citadel::IsEncounterInProgress() const +{ + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + + return false; +} + +void instance_icecrown_citadel::DoHandleCitadelAreaTrigger(uint32 uiTriggerId, Player* pPlayer) +{ + if (uiTriggerId == AREATRIGGER_MARROWGAR_INTRO && !m_bHasMarrowgarIntroYelled) + { + if (Creature* pMarrowgar = GetSingleCreatureFromStorage(NPC_LORD_MARROWGAR)) + { + DoScriptText(SAY_MARROWGAR_INTRO, pMarrowgar); + m_bHasMarrowgarIntroYelled = true; + } + } + else if (uiTriggerId == AREATRIGGER_DEATHWHISPER_INTRO && !m_bHasDeathwhisperIntroYelled) + { + StartNextDialogueText(SAY_DEATHWHISPER_SPEECH_1); + m_bHasDeathwhisperIntroYelled = true; + } + else if (uiTriggerId == AREATRIGGER_SINDRAGOSA_PLATFORM) + { + if (Creature* pSindragosa = GetSingleCreatureFromStorage(NPC_SINDRAGOSA)) + { + if (pSindragosa->isAlive() && !pSindragosa->isInCombat()) + pSindragosa->SetInCombatWithZone(); + } + else + { + if (!m_bHasRimefangLanded) + { + if (Creature* pRimefang = GetSingleCreatureFromStorage(NPC_RIMEFANG)) + { + pRimefang->AI()->AttackStart(pPlayer); + m_bHasRimefangLanded = true; + } + } + + if (!m_bHasSpinestalkerLanded) + { + if (Creature* pSpinestalker = GetSingleCreatureFromStorage(NPC_SPINESTALKER)) + { + pSpinestalker->AI()->AttackStart(pPlayer); + m_bHasSpinestalkerLanded = true; + } + } + } + } +} + +void instance_icecrown_citadel::OnPlayerEnter(Player* pPlayer) +{ + if (!m_uiTeam) // very first player to enter + m_uiTeam = pPlayer->GetTeam(); +} + +void instance_icecrown_citadel::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_LORD_MARROWGAR: + case NPC_LADY_DEATHWHISPER: + case NPC_DEATHBRINGER_SAURFANG: + case NPC_FESTERGUT: + case NPC_ROTFACE: + case NPC_PROFESSOR_PUTRICIDE: + case NPC_TALDARAM: + case NPC_VALANAR: + case NPC_KELESETH: + case NPC_LANATHEL_INTRO: + case NPC_VALITHRIA: + case NPC_SINDRAGOSA: + case NPC_LICH_KING: + case NPC_TIRION: + case NPC_RIMEFANG: + case NPC_SPINESTALKER: + case NPC_VALITHRIA_COMBAT_TRIGGER: + case NPC_BLOOD_ORB_CONTROL: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_DEATHWHISPER_SPAWN_STALKER: + m_lDeathwhisperStalkersGuids.push_back(pCreature->GetObjectGuid()); + return; + } +} + +void instance_icecrown_citadel::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_ICEWALL_1: + case GO_ICEWALL_2: + case GO_ORATORY_DOOR: + if (m_auiEncounter[TYPE_MARROWGAR] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_DEATHWHISPER_ELEVATOR: + // ToDo: set in motion when TYPE_LADY_DEATHWHISPER == DONE + break; + case GO_SAURFANG_DOOR: + case GO_SCIENTIST_DOOR: + case GO_CRIMSON_HALL_DOOR: + case GO_GREEN_DRAGON_ENTRANCE: + if (m_auiEncounter[TYPE_DEATHBRINGER_SAURFANG] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_ORANGE_TUBE: + if (m_auiEncounter[TYPE_FESTERGUT] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GREEN_TUBE: + if (m_auiEncounter[TYPE_ROTFACE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SCIENTIST_DOOR_GREEN: + // If both Festergut and Rotface are DONE, set as ACTIVE_ALTERNATIVE + if (m_auiEncounter[TYPE_FESTERGUT] == DONE && m_auiEncounter[TYPE_ROTFACE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + else if (m_auiEncounter[TYPE_ROTFACE] == DONE) + pGo->SetGoState(GO_STATE_READY); + break; + case GO_SCIENTIST_DOOR_ORANGE: + // If both Festergut and Rotface are DONE, set as ACTIVE_ALTERNATIVE + if (m_auiEncounter[TYPE_FESTERGUT] == DONE && m_auiEncounter[TYPE_ROTFACE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + else if (m_auiEncounter[TYPE_FESTERGUT] == DONE) + pGo->SetGoState(GO_STATE_READY); + break; + case GO_SCIENTIST_DOOR_COLLISION: + if (m_auiEncounter[TYPE_FESTERGUT] == DONE && m_auiEncounter[TYPE_ROTFACE] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_COUNCIL_DOOR_1: + case GO_COUNCIL_DOOR_2: + if (m_auiEncounter[TYPE_BLOOD_PRINCE_COUNCIL] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_GREEN_DRAGON_EXIT: + if (m_auiEncounter[TYPE_VALITHRIA] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_SAURFANG_CACHE: + case GO_SAURFANG_CACHE_25: + case GO_SAURFANG_CACHE_10_H: + case GO_SAURFANG_CACHE_25_H: + m_mGoEntryGuidStore[GO_SAURFANG_CACHE] = pGo->GetObjectGuid(); + return; + case GO_GUNSHIP_ARMORY_A: + case GO_GUNSHIP_ARMORY_A_25: + case GO_GUNSHIP_ARMORY_A_10H: + case GO_GUNSHIP_ARMORY_A_25H: + m_mGoEntryGuidStore[GO_GUNSHIP_ARMORY_A] = pGo->GetObjectGuid(); + return; + case GO_GUNSHIP_ARMORY_H: + case GO_GUNSHIP_ARMORY_H_25: + case GO_GUNSHIP_ARMORY_H_10H: + case GO_GUNSHIP_ARMORY_H_25H: + m_mGoEntryGuidStore[GO_GUNSHIP_ARMORY_H] = pGo->GetObjectGuid(); + return; + case GO_DREAMWALKER_CACHE: + case GO_DREAMWALKER_CACHE_25: + case GO_DREAMWALKER_CACHE_10_H: + case GO_DREAMWALKER_CACHE_25_H: + m_mGoEntryGuidStore[GO_DREAMWALKER_CACHE] = pGo->GetObjectGuid(); + return; + case GO_ICESHARD_1: + case GO_ICESHARD_2: + case GO_ICESHARD_3: + case GO_ICESHARD_4: + case GO_FROSTY_WIND: + case GO_FROSTY_EDGE: + case GO_SNOW_EDGE: + case GO_ARTHAS_PLATFORM: + case GO_ARTHAS_PRECIPICE: + case GO_MARROWGAR_DOOR: + case GO_BLOODPRINCE_DOOR: + case GO_SINDRAGOSA_ENTRANCE: + case GO_VALITHRIA_DOOR_1: + case GO_VALITHRIA_DOOR_2: + case GO_VALITHRIA_DOOR_3: + case GO_VALITHRIA_DOOR_4: + case GO_ICECROWN_GRATE: + case GO_SINDRAGOSA_SHORTCUT_ENTRANCE: + case GO_SINDRAGOSA_SHORTCUT_EXIT: + case GO_ORANGE_PLAGUE: + case GO_GREEN_PLAGUE: + case GO_ORANGE_VALVE: + case GO_GREEN_VALVE: + break; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_icecrown_citadel::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_STINKY: + if (Creature* pFestergut = GetSingleCreatureFromStorage(NPC_FESTERGUT)) + { + if (pFestergut->isAlive()) + DoScriptText(SAY_STINKY_DIES, pFestergut); + } + break; + case NPC_PRECIOUS: + if (Creature* pRotface = GetSingleCreatureFromStorage(NPC_ROTFACE)) + { + if (pRotface->isAlive()) + DoScriptText(SAY_PRECIOUS_DIES, pRotface); + } + break; + } +} + +void instance_icecrown_citadel::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_MARROWGAR: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_MARROWGAR_DOOR); + if (uiData == DONE) + { + DoUseDoorOrButton(GO_ICEWALL_1); + DoUseDoorOrButton(GO_ICEWALL_2); + + // Note: this door use may not be correct. In theory the door should be already opened + DoUseDoorOrButton(GO_ORATORY_DOOR); + } + break; + case TYPE_LADY_DEATHWHISPER: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_ORATORY_DOOR); + // ToDo: set the elevateor in motion when TYPE_LADY_DEATHWHISPER == DONE + break; + case TYPE_GUNSHIP_BATTLE: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoRespawnGameObject(m_uiTeam == ALLIANCE ? GO_GUNSHIP_ARMORY_A : GO_GUNSHIP_ARMORY_H, 60 * MINUTE); + DoToggleGameObjectFlags(m_uiTeam == ALLIANCE ? GO_GUNSHIP_ARMORY_A : GO_GUNSHIP_ARMORY_H, GO_FLAG_NO_INTERACT, false); + } + break; + case TYPE_DEATHBRINGER_SAURFANG: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoUseDoorOrButton(GO_SAURFANG_DOOR); + DoRespawnGameObject(GO_SAURFANG_CACHE, 60 * MINUTE); + DoToggleGameObjectFlags(GO_SAURFANG_CACHE, GO_FLAG_NO_INTERACT, false); + + // Note: these doors may not be correct. In theory the doors should be already opened + DoUseDoorOrButton(GO_SCIENTIST_DOOR); + DoUseDoorOrButton(GO_CRIMSON_HALL_DOOR); + DoUseDoorOrButton(GO_GREEN_DRAGON_ENTRANCE); + } + break; + case TYPE_FESTERGUT: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_ORANGE_PLAGUE); + if (uiData == DONE) + DoToggleGameObjectFlags(GO_ORANGE_VALVE, GO_FLAG_NO_INTERACT, false); + break; + case TYPE_ROTFACE: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_GREEN_PLAGUE); + if (uiData == DONE) + DoToggleGameObjectFlags(GO_GREEN_VALVE, GO_FLAG_NO_INTERACT, false); + break; + case TYPE_PROFESSOR_PUTRICIDE: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_SCIENTIST_DOOR); + break; + case TYPE_BLOOD_PRINCE_COUNCIL: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_CRIMSON_HALL_DOOR); + if (uiData == DONE) + { + DoUseDoorOrButton(GO_COUNCIL_DOOR_1); + DoUseDoorOrButton(GO_COUNCIL_DOOR_2); + } + if (uiData == DONE || uiData == FAIL) + { + // remove encounter frames + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_VALANAR)) + SendEncounterFrame(ENCOUNTER_FRAME_DISENGAGE, pPrince->GetObjectGuid()); + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_KELESETH)) + SendEncounterFrame(ENCOUNTER_FRAME_DISENGAGE, pPrince->GetObjectGuid()); + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_TALDARAM)) + SendEncounterFrame(ENCOUNTER_FRAME_DISENGAGE, pPrince->GetObjectGuid()); + } + else if (uiData == IN_PROGRESS) + { + // add encounter frames + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_VALANAR)) + SendEncounterFrame(ENCOUNTER_FRAME_ENGAGE, pPrince->GetObjectGuid()); + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_KELESETH)) + SendEncounterFrame(ENCOUNTER_FRAME_ENGAGE, pPrince->GetObjectGuid()); + if (Creature* pPrince = GetSingleCreatureFromStorage(NPC_TALDARAM)) + SendEncounterFrame(ENCOUNTER_FRAME_ENGAGE, pPrince->GetObjectGuid()); + } + break; + case TYPE_QUEEN_LANATHEL: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_BLOODPRINCE_DOOR); + if (uiData == DONE) + DoUseDoorOrButton(GO_ICECROWN_GRATE); + break; + case TYPE_VALITHRIA: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_GREEN_DRAGON_ENTRANCE); + // Side doors + DoUseDoorOrButton(GO_VALITHRIA_DOOR_1); + DoUseDoorOrButton(GO_VALITHRIA_DOOR_2); + // Some doors are used only in 25 man mode + if (instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC) + { + DoUseDoorOrButton(GO_VALITHRIA_DOOR_3); + DoUseDoorOrButton(GO_VALITHRIA_DOOR_4); + } + if (uiData == DONE) + { + DoUseDoorOrButton(GO_GREEN_DRAGON_EXIT); + DoUseDoorOrButton(GO_SINDRAGOSA_ENTRANCE); + DoRespawnGameObject(GO_DREAMWALKER_CACHE, 60 * MINUTE); + DoToggleGameObjectFlags(GO_DREAMWALKER_CACHE, GO_FLAG_NO_INTERACT, false); + } + if (uiData == DONE || uiData == FAIL) + { + // remove encounter frames + if (Creature* pDragon = GetSingleCreatureFromStorage(NPC_VALITHRIA)) + SendEncounterFrame(ENCOUNTER_FRAME_DISENGAGE, pDragon->GetObjectGuid()); + } + else if (uiData == IN_PROGRESS) + { + // add encounter frames + if (Creature* pDragon = GetSingleCreatureFromStorage(NPC_VALITHRIA)) + SendEncounterFrame(ENCOUNTER_FRAME_ENGAGE, pDragon->GetObjectGuid()); + } + break; + case TYPE_SINDRAGOSA: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_SINDRAGOSA_ENTRANCE); + break; + case TYPE_LICH_KING: + m_auiEncounter[uiType] = uiData; + break; + default: + script_error_log("Instance Icecrown Citadel: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + return; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_icecrown_citadel::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +bool instance_icecrown_citadel::CheckAchievementCriteriaMeet(uint32 /*uiCriteriaId*/, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscvalue1*/) const +{ + // ToDo: + return false; +} + +void instance_icecrown_citadel::Load(const char* strIn) +{ + if (!strIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(strIn); + + std::istringstream loadStream(strIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8] + >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_icecrown_citadel::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (m_uiPutricideValveTimer) + { + if (m_uiPutricideValveTimer <= uiDiff) + { + // Open the pathway to Putricide when the timer expires + DoUseDoorOrButton(GO_SCIENTIST_DOOR_COLLISION); + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_SCIENTIST_DOOR_GREEN)) + pDoor->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_SCIENTIST_DOOR_ORANGE)) + pDoor->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + + m_uiPutricideValveTimer = 0; + } + else + m_uiPutricideValveTimer -= uiDiff; + } +} + +InstanceData* GetInstanceData_instance_icecrown_citadel(Map* pMap) +{ + return new instance_icecrown_citadel(pMap); +} + +bool AreaTrigger_at_icecrown_citadel(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pAt->id == AREATRIGGER_MARROWGAR_INTRO || pAt->id == AREATRIGGER_DEATHWHISPER_INTRO || + pAt->id == AREATRIGGER_SINDRAGOSA_PLATFORM) + { + if (pPlayer->isGameMaster() || pPlayer->isDead()) + return false; + + if (instance_icecrown_citadel* pInstance = (instance_icecrown_citadel*)pPlayer->GetInstanceData()) + pInstance->DoHandleCitadelAreaTrigger(pAt->id, pPlayer); + } + + return false; +} + +bool ProcessEventId_event_gameobject_citadel_valve(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + { + if (instance_icecrown_citadel* pInstance = (instance_icecrown_citadel*)((Player*)pSource)->GetInstanceData()) + { + // Note: the Tubes and doors are activated by DB script + if (pInstance->GetData(TYPE_FESTERGUT) == DONE && pInstance->GetData(TYPE_ROTFACE) == DONE) + pInstance->DoPreparePutricideDoor(); + + return false; + } + } + return false; +} void AddSC_instance_icecrown_citadel() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_icecrown_citadel"; + pNewScript->GetInstanceData = &GetInstanceData_instance_icecrown_citadel; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_icecrown_citadel"; + pNewScript->pAreaTrigger = &AreaTrigger_at_icecrown_citadel; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_gameobject_citadel_valve"; + pNewScript->pProcessEventId = &ProcessEventId_event_gameobject_citadel_valve; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_anubrekhan.cpp b/scripts/northrend/naxxramas/boss_anubrekhan.cpp index 552baf457..b7ed1106e 100644 --- a/scripts/northrend/naxxramas/boss_anubrekhan.cpp +++ b/scripts/northrend/naxxramas/boss_anubrekhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Anubrekhan -SD%Complete: 70 -SDComment: +SD%Complete: 95 +SDComment: Intro text usage is not very clear. Requires additional research. SDCategory: Naxxramas EndScriptData */ @@ -36,35 +36,50 @@ enum SAY_TAUNT4 = -1533007, SAY_SLAY = -1533008, - EMOTE_CRYPT_GUARD = -1533153, // NYI - EMOTE_INSECT_SWARM = -1533154, // NYI - EMOTE_CORPSE_SCARABS = -1533155, // NYI + EMOTE_CRYPT_GUARD = -1533153, + EMOTE_INSECT_SWARM = -1533154, + EMOTE_CORPSE_SCARABS = -1533155, - SPELL_IMPALE = 28783, //May be wrong spell id. Causes more dmg than I expect + SPELL_IMPALE = 28783, // May be wrong spell id. Causes more dmg than I expect SPELL_IMPALE_H = 56090, - SPELL_LOCUSTSWARM = 28785, //This is a self buff that triggers the dmg debuff + SPELL_LOCUSTSWARM = 28785, // This is a self buff that triggers the dmg debuff SPELL_LOCUSTSWARM_H = 54021, - //spellId invalid - SPELL_SUMMONGUARD = 29508, //Summons 1 crypt guard at targeted location + // spellId invalid + // SPELL_SUMMONGUARD = 29508, // Summons 1 crypt guard at targeted location - spell doesn't exist in 3.x.x - SPELL_SELF_SPAWN_5 = 29105, //This spawns 5 corpse scarabs ontop of us (most likely the pPlayer casts this on death) - SPELL_SELF_SPAWN_10 = 28864, //This is used by the crypt guards when they die + SPELL_SELF_SPAWN_5 = 29105, // This spawns 5 corpse scarabs ontop of us (most likely the pPlayer casts this on death) + SPELL_SELF_SPAWN_10 = 28864, // This is used by the crypt guards when they die NPC_CRYPT_GUARD = 16573 }; -struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI +static const DialogueEntry aIntroDialogue[] = { - boss_anubrekhanAI(Creature* pCreature) : ScriptedAI(pCreature) + {SAY_GREET, NPC_ANUB_REKHAN, 7000}, + {SAY_TAUNT1, NPC_ANUB_REKHAN, 13000}, + {SAY_TAUNT2, NPC_ANUB_REKHAN, 11000}, + {SAY_TAUNT3, NPC_ANUB_REKHAN, 10000}, + {SAY_TAUNT4, NPC_ANUB_REKHAN, 0}, + {0, 0, 0} +}; + +static const float aCryptGuardLoc[4] = {3333.5f, -3475.9f, 287.1f, 3.17f}; + +struct boss_anubrekhanAI : public ScriptedAI +{ + boss_anubrekhanAI(Creature* pCreature) : ScriptedAI(pCreature), + m_introDialogue(aIntroDialogue) { m_pInstance = (instance_naxxramas*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_introDialogue.InitializeDialogueHelper(m_pInstance); m_bHasTaunted = false; Reset(); } instance_naxxramas* m_pInstance; + DialogueHelper m_introDialogue; bool m_bIsRegularMode; uint32 m_uiImpaleTimer; @@ -72,18 +87,18 @@ struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI uint32 m_uiSummonTimer; bool m_bHasTaunted; - void Reset() + void Reset() override { - m_uiImpaleTimer = 15000; // 15 seconds - m_uiLocustSwarmTimer = urand(80000, 120000); // Random time between 80 seconds and 2 minutes for initial cast - m_uiSummonTimer = m_uiLocustSwarmTimer + 45000; // 45 seconds after initial locust swarm + m_uiImpaleTimer = 15000; + m_uiLocustSwarmTimer = 90000; + m_uiSummonTimer = m_bIsRegularMode ? 20000 : 0;// spawn a guardian only after 20 seconds in normal mode; in heroic there are already 2 Guards spawned } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { - //Force the player to spawn corpse scarabs via spell + // Force the player to spawn corpse scarabs via spell if (pVictim->GetTypeId() == TYPEID_PLAYER) - pVictim->CastSpell(pVictim, SPELL_SELF_SPAWN_5, true); + pVictim->CastSpell(pVictim, SPELL_SELF_SPAWN_5, true, NULL, NULL, m_creature->GetObjectGuid()); if (urand(0, 4)) return; @@ -91,9 +106,9 @@ struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI DoScriptText(SAY_SLAY, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -104,38 +119,55 @@ struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI m_pInstance->SetData(TYPE_ANUB_REKHAN, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_ANUB_REKHAN, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ANUB_REKHAN, FAIL); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 60.0f)) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 110.0f) && m_creature->IsWithinLOSInMap(pWho)) { - switch(urand(0, 4)) - { - case 0: DoScriptText(SAY_GREET, m_creature); break; - case 1: DoScriptText(SAY_TAUNT1, m_creature); break; - case 2: DoScriptText(SAY_TAUNT2, m_creature); break; - case 3: DoScriptText(SAY_TAUNT3, m_creature); break; - case 4: DoScriptText(SAY_TAUNT4, m_creature); break; - } + m_introDialogue.StartNextDialogueText(SAY_GREET); m_bHasTaunted = true; } ScriptedAI::MoveInLineOfSight(pWho); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override { + if (pSummoned->GetEntry() == NPC_CRYPT_GUARD) + DoScriptText(EMOTE_CRYPT_GUARD, pSummoned); + + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + + void SummonedCreatureDespawn(Creature* pSummoned) override + { + // If creature despawns on out of combat, skip this + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (pSummoned->GetEntry() == NPC_CRYPT_GUARD) + { + pSummoned->CastSpell(pSummoned, SPELL_SELF_SPAWN_10, true, NULL, NULL, m_creature->GetObjectGuid()); + DoScriptText(EMOTE_CORPSE_SCARABS, pSummoned); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + m_introDialogue.DialogueUpdate(uiDiff); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -158,20 +190,30 @@ struct MANGOS_DLL_DECL boss_anubrekhanAI : public ScriptedAI // Locust Swarm if (m_uiLocustSwarmTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LOCUSTSWARM :SPELL_LOCUSTSWARM_H); - m_uiLocustSwarmTimer = 90000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LOCUSTSWARM : SPELL_LOCUSTSWARM_H) == CAST_OK) + { + DoScriptText(EMOTE_INSECT_SWARM, m_creature); + + // Summon a crypt guard + m_uiSummonTimer = 3000; + m_uiLocustSwarmTimer = 100000; + } } else m_uiLocustSwarmTimer -= uiDiff; // Summon - /*if (m_uiSummonTimer < uiDiff) + if (m_uiSummonTimer) { - DoCastSpellIfCan(m_creature, SPELL_SUMMONGUARD); - Summon_Timer = 45000; + if (m_uiSummonTimer <= uiDiff) + { + // Workaround for the not existing spell + m_creature->SummonCreature(NPC_CRYPT_GUARD, aCryptGuardLoc[0], aCryptGuardLoc[1], aCryptGuardLoc[2], aCryptGuardLoc[3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_uiSummonTimer = 0; + } + else + m_uiSummonTimer -= uiDiff; } - else - m_uiSummonTimer -= uiDiff;*/ DoMeleeAttackIfReady(); } diff --git a/scripts/northrend/naxxramas/boss_faerlina.cpp b/scripts/northrend/naxxramas/boss_faerlina.cpp index e0ab9a6f2..c545882d4 100644 --- a/scripts/northrend/naxxramas/boss_faerlina.cpp +++ b/scripts/northrend/naxxramas/boss_faerlina.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -49,7 +49,7 @@ enum SPELL_WIDOWS_EMBRACE_H = 54097, }; -struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI +struct boss_faerlinaAI : public ScriptedAI { boss_faerlinaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -67,16 +67,16 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI uint32 m_uiEnrageTimer; bool m_bHasTaunted; - void Reset() + void Reset() override { m_uiPoisonBoltVolleyTimer = 8000; m_uiRainOfFireTimer = 16000; m_uiEnrageTimer = 60000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -88,9 +88,9 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI m_pInstance->SetData(TYPE_FAERLINA, IN_PROGRESS); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 60.0f)) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 80.0f) && m_creature->IsWithinLOSInMap(pWho)) { DoScriptText(SAY_GREET, m_creature); m_bHasTaunted = true; @@ -99,12 +99,12 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -112,7 +112,7 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI m_pInstance->SetData(TYPE_FAERLINA, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_FAERLINA, FAIL); @@ -120,7 +120,7 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI // Widow's Embrace prevents frenzy and poison bolt, if it removes frenzy, next frenzy is sceduled in 60s // It is likely that this _should_ be handled with some dummy aura(s) - but couldn't find any - void SpellHit(Unit* pCaster, const SpellEntry* pSpellEntry) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpellEntry) override { // Check if we hit with Widow's Embrave if (pSpellEntry->Id == SPELL_WIDOWS_EMBRACE || pSpellEntry->Id == SPELL_WIDOWS_EMBRACE_H) @@ -147,7 +147,7 @@ struct MANGOS_DLL_DECL boss_faerlinaAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/naxxramas/boss_four_horsemen.cpp b/scripts/northrend/naxxramas/boss_four_horsemen.cpp index e87301195..506c00149 100644 --- a/scripts/northrend/naxxramas/boss_four_horsemen.cpp +++ b/scripts/northrend/naxxramas/boss_four_horsemen.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Four_Horsemen -SD%Complete: 75 -SDComment: Lady Blaumeux, Thane Korthazz, Sir Zeliek, Baron Rivendare +SD%Complete: 90 +SDComment: Lady Blaumeux, Thane Korthazz, Sir Zeliek, Baron Rivendare; Berserk NYI. SDCategory: Naxxramas EndScriptData */ @@ -26,148 +26,196 @@ EndScriptData */ enum { - //all horsemen - SPELL_SHIELDWALL = 29061, - SPELL_BESERK = 26662, - - //lady blaumeux + // ***** Yells ***** + // lady blaumeux SAY_BLAU_AGGRO = -1533044, - SAY_BLAU_TAUNT1 = -1533045, - SAY_BLAU_TAUNT2 = -1533046, - SAY_BLAU_TAUNT3 = -1533047, SAY_BLAU_SPECIAL = -1533048, SAY_BLAU_SLAY = -1533049, SAY_BLAU_DEATH = -1533050, + EMOTE_UNYIELDING_PAIN = -1533156, - EMOTE_UNYIELDING_PAIN = -1533156, // NYI - - SPELL_MARK_OF_BLAUMEUX = 28833, - SPELL_UNYILDING_PAIN = 57381, - SPELL_VOIDZONE = 28863, - SPELL_VOIDZONE_H = 57463, - SPELL_SHADOW_BOLT = 57374, - SPELL_SHADOW_BOLT_H = 57464, - - //baron rivendare + // baron rivendare SAY_RIVE_AGGRO1 = -1533065, SAY_RIVE_AGGRO2 = -1533066, SAY_RIVE_AGGRO3 = -1533067, SAY_RIVE_SLAY1 = -1533068, SAY_RIVE_SLAY2 = -1533069, SAY_RIVE_SPECIAL = -1533070, - SAY_RIVE_TAUNT1 = -1533071, - SAY_RIVE_TAUNT2 = -1533072, - SAY_RIVE_TAUNT3 = -1533073, SAY_RIVE_DEATH = -1533074, - SPELL_MARK_OF_RIVENDARE = 28834, - SPELL_UNHOLY_SHADOW = 28882, - SPELL_UNHOLY_SHADOW_H = 57369, - - //thane korthazz + // thane korthazz SAY_KORT_AGGRO = -1533051, - SAY_KORT_TAUNT1 = -1533052, - SAY_KORT_TAUNT2 = -1533053, - SAY_KORT_TAUNT3 = -1533054, SAY_KORT_SPECIAL = -1533055, SAY_KORT_SLAY = -1533056, SAY_KORT_DEATH = -1533057, - SPELL_MARK_OF_KORTHAZZ = 28832, - SPELL_METEOR = 26558, // m_creature->getVictim() auto-area spell but with a core problem - - //sir zeliek + // sir zeliek SAY_ZELI_AGGRO = -1533058, - SAY_ZELI_TAUNT1 = -1533059, - SAY_ZELI_TAUNT2 = -1533060, - SAY_ZELI_TAUNT3 = -1533061, SAY_ZELI_SPECIAL = -1533062, SAY_ZELI_SLAY = -1533063, SAY_ZELI_DEATH = -1533064, + EMOTE_CONDEMATION = -1533157, - EMOTE_CONDEMATION = -1533157, // NYI + // ***** Spells ***** + // all horsemen + // SPELL_SHIELDWALL = 29061, // not used in 3.x.x + SPELL_BESERK = 26662, + SPELL_ACHIEV_CHECK = 59450, + // Note: Berserk should be applied once 100 marks are casted. + // lady blaumeux + SPELL_MARK_OF_BLAUMEUX = 28833, + SPELL_VOID_ZONE = 28863, + SPELL_VOID_ZONE_H = 57463, + SPELL_SHADOW_BOLT = 57374, + SPELL_SHADOW_BOLT_H = 57464, + SPELL_UNYILDING_PAIN = 57381, + + // baron rivendare + SPELL_MARK_OF_RIVENDARE = 28834, + SPELL_UNHOLY_SHADOW = 28882, + SPELL_UNHOLY_SHADOW_H = 57369, + + // thane korthazz + SPELL_MARK_OF_KORTHAZZ = 28832, + SPELL_METEOR = 28884, + SPELL_METEOR_H = 57467, + + // sir zeliek SPELL_MARK_OF_ZELIEK = 28835, SPELL_HOLY_WRATH = 28883, SPELL_HOLY_WRATH_H = 57466, SPELL_HOLY_BOLT = 57376, SPELL_HOLY_BOLT_H = 57465, + SPELL_CONDEMNATION = 57377, + + // horseman spirits (not used in 3.x.x) + // NPC_SPIRIT_OF_BLAUMEUX = 16776, + // NPC_SPIRIT_OF_MOGRAINE = 16775, + // NPC_SPIRIT_OF_KORTHAZZ = 16778, + // NPC_SPIRIT_OF_ZELIREK = 16777 +}; - // horseman spirits - NPC_SPIRIT_OF_BLAUMEUX = 16776, - NPC_SPIRIT_OF_RIVENDARE = 0, //creature entry not known yet - NPC_SPIRIT_OF_KORTHAZZ = 16778, - NPC_SPIRIT_OF_ZELIREK = 16777 +static const float aHorseMenMoveCoords[4][3] = +{ + {2469.4f, -2947.6f, 241.28f}, // lady blaumeux + {2583.9f, -2971.67f, 241.35f}, // baron rivendare + {2542.9f, -3015.0f, 241.35f}, // thane korthazz + {2517.8f, -2896.6f, 241.28f}, // sir zeliek }; -struct MANGOS_DLL_DECL boss_lady_blaumeuxAI : public ScriptedAI +struct boss_lady_blaumeuxAI : public ScriptedAI { - boss_lady_blaumeuxAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_lady_blaumeuxAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } - uint32 Mark_Timer; - uint32 VoidZone_Timer; - bool ShieldWall1; - bool ShieldWall2; + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - void Reset() + bool m_bIsCornerMovement; + uint32 m_uiMarkTimer; + uint32 m_uiVoidZoneTimer; + uint32 m_uiShadowBoltTimer; + + void Reset() override { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - VoidZone_Timer = 12000; // right - ShieldWall1 = true; - ShieldWall2 = true; + m_uiMarkTimer = 20000; + m_uiVoidZoneTimer = 15000; + m_uiShadowBoltTimer = 10000; + m_bIsCornerMovement = true; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_BLAU_AGGRO, m_creature); + + SetCombatMovement(false); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, aHorseMenMoveCoords[0][0], aHorseMenMoveCoords[0][1], aHorseMenMoveCoords[0][2]); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, IN_PROGRESS); } - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_BLAU_SLAY, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_BLAU_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, SPECIAL); + + // Cast achiev check for last boss killed + if (m_pInstance->GetData(TYPE_FOUR_HORSEMEN) == DONE) + m_creature->CastSpell(m_creature, SPELL_ACHIEV_CHECK, true); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, FAIL); } - void UpdateAI(const uint32 uiDiff) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Stop moving when it reaches the corner + m_bIsCornerMovement = false; + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // Mark of Blaumeux - if (Mark_Timer < uiDiff) + // Don't attack while moving + if (m_bIsCornerMovement) + return; + + if (m_uiMarkTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MARK_OF_BLAUMEUX); - Mark_Timer = 12000; - }else Mark_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_MARK_OF_BLAUMEUX) == CAST_OK) + m_uiMarkTimer = 12000; + } + else + m_uiMarkTimer -= uiDiff; - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if (ShieldWall1 && m_creature->GetHealthPercent() < 50.0f) + if (m_uiVoidZoneTimer < uiDiff) { - if (ShieldWall1) - { - DoCastSpellIfCan(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; - } + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_VOID_ZONE : SPELL_VOID_ZONE_H) == CAST_OK) + m_uiVoidZoneTimer = 15000; } - if (ShieldWall2 && m_creature->GetHealthPercent() < 20.0f) + else + m_uiVoidZoneTimer -= uiDiff; + + if (m_uiShadowBoltTimer < uiDiff) { - if (ShieldWall2) + // If we can find a target in range of 45.0f, then cast Shadowbolt + if (m_creature->IsWithinDist(m_creature->getVictim(), 45.0f)) + DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_BOLT : SPELL_SHADOW_BOLT_H); + else { - DoCastSpellIfCan(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; + DoCastSpellIfCan(m_creature, SPELL_UNYILDING_PAIN); + DoScriptText(EMOTE_UNYIELDING_PAIN, m_creature); } + m_uiShadowBoltTimer = urand(2000, 3000); } - - // Void Zone - if (VoidZone_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_VOIDZONE); - VoidZone_Timer = 12000; - }else VoidZone_Timer -= uiDiff; + else + m_uiShadowBoltTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -178,39 +226,109 @@ CreatureAI* GetAI_boss_lady_blaumeux(Creature* pCreature) return new boss_lady_blaumeuxAI(pCreature); } -struct MANGOS_DLL_DECL boss_rivendare_naxxAI : public ScriptedAI +struct boss_rivendare_naxxAI : public ScriptedAI { - boss_rivendare_naxxAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_rivendare_naxxAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - void Reset() + bool m_bIsCornerMovement; + uint32 m_uiMarkTimer; + uint32 m_uiUnholyShadowTimer; + + void Reset() override { + m_uiMarkTimer = 20000; + m_uiUnholyShadowTimer = 15000; + m_bIsCornerMovement = true; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_RIVE_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_RIVE_AGGRO2, m_creature); break; case 2: DoScriptText(SAY_RIVE_AGGRO3, m_creature); break; } + + SetCombatMovement(false); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, aHorseMenMoveCoords[1][0], aHorseMenMoveCoords[1][1], aHorseMenMoveCoords[1][2]); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, IN_PROGRESS); } - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_RIVE_SLAY1 : SAY_RIVE_SLAY2, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_RIVE_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, SPECIAL); + + // Cast achiev check for last boss killed + if (m_pInstance->GetData(TYPE_FOUR_HORSEMEN) == DONE) + m_creature->CastSpell(m_creature, SPELL_ACHIEV_CHECK, true); + } } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, FAIL); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Start moving when it reaches the corner + SetCombatMovement(true); + m_bIsCornerMovement = false; + m_creature->GetMotionMaster()->Clear(); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Don't attack while moving + if (m_bIsCornerMovement) + return; + + if (m_uiMarkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MARK_OF_RIVENDARE) == CAST_OK) + m_uiMarkTimer = 12000; + } + else + m_uiMarkTimer -= uiDiff; + + if (m_uiUnholyShadowTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_UNHOLY_SHADOW : SPELL_UNHOLY_SHADOW_H) == CAST_OK) + m_uiUnholyShadowTimer = 15000; + } + else + m_uiUnholyShadowTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -220,74 +338,103 @@ CreatureAI* GetAI_boss_rivendare_naxx(Creature* pCreature) return new boss_rivendare_naxxAI(pCreature); } -struct MANGOS_DLL_DECL boss_thane_korthazzAI : public ScriptedAI +struct boss_thane_korthazzAI : public ScriptedAI { - boss_thane_korthazzAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_thane_korthazzAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - uint32 Mark_Timer; - uint32 Meteor_Timer; - bool ShieldWall1; - bool ShieldWall2; + bool m_bIsCornerMovement; + uint32 m_uiMarkTimer; + uint32 m_uiMeteorTimer; - void Reset() + void Reset() override { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - Meteor_Timer = 30000; // wrong - ShieldWall1 = true; - ShieldWall2 = true; + m_uiMarkTimer = 20000; + m_uiMeteorTimer = 30000; + m_bIsCornerMovement = true; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_KORT_AGGRO, m_creature); + + SetCombatMovement(false); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, aHorseMenMoveCoords[2][0], aHorseMenMoveCoords[2][1], aHorseMenMoveCoords[2][2]); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, IN_PROGRESS); } - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_KORT_SLAY, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_KORT_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, SPECIAL); + + // Cast achiev check for last boss killed + if (m_pInstance->GetData(TYPE_FOUR_HORSEMEN) == DONE) + m_creature->CastSpell(m_creature, SPELL_ACHIEV_CHECK, true); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, FAIL); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Start moving when it reaches the corner + SetCombatMovement(true); + m_bIsCornerMovement = false; + m_creature->GetMotionMaster()->Clear(); + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // Mark of Korthazz - if (Mark_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MARK_OF_KORTHAZZ); - Mark_Timer = 12000; - }else Mark_Timer -= uiDiff; + // Don't attack while moving + if (m_bIsCornerMovement) + return; - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if (ShieldWall1 && m_creature->GetHealthPercent() < 50.0f) - { - if (ShieldWall1) - { - DoCastSpellIfCan(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; - } - } - if (ShieldWall2 && m_creature->GetHealthPercent() < 20.0f) + if (m_uiMarkTimer < uiDiff) { - if (ShieldWall2) - { - DoCastSpellIfCan(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; - } + if (DoCastSpellIfCan(m_creature, SPELL_MARK_OF_KORTHAZZ) == CAST_OK) + m_uiMarkTimer = 12000; } + else + m_uiMarkTimer -= uiDiff; - // Meteor - if (Meteor_Timer < uiDiff) + if (m_uiMeteorTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_METEOR); - Meteor_Timer = 20000; // wrong - }else Meteor_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_METEOR : SPELL_METEOR_H) == CAST_OK) + m_uiMeteorTimer = 20000; + } + else + m_uiMeteorTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -298,75 +445,121 @@ CreatureAI* GetAI_boss_thane_korthazz(Creature* pCreature) return new boss_thane_korthazzAI(pCreature); } -struct MANGOS_DLL_DECL boss_sir_zeliekAI : public ScriptedAI +struct boss_sir_zeliekAI : public ScriptedAI { - boss_sir_zeliekAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_sir_zeliekAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; - uint32 Mark_Timer; - uint32 HolyWrath_Timer; - bool ShieldWall1; - bool ShieldWall2; + bool m_bIsCornerMovement; + uint32 m_uiMarkTimer; + uint32 m_uiHolyWrathTimer; + uint32 m_uiHolyBoltTimer; - void Reset() + void Reset() override { - Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec. - HolyWrath_Timer = 12000; // right - ShieldWall1 = true; - ShieldWall2 = true; + m_uiMarkTimer = 20000; + m_uiHolyWrathTimer = 12000; + m_uiHolyBoltTimer = 10000; + m_bIsCornerMovement = true; } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_ZELI_AGGRO, m_creature); + + SetCombatMovement(false); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, aHorseMenMoveCoords[3][0], aHorseMenMoveCoords[3][1], aHorseMenMoveCoords[3][2]); + + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, IN_PROGRESS); } - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_ZELI_SLAY, m_creature); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_ZELI_DEATH, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, SPECIAL); + + // Cast achiev check for last boss killed + if (m_pInstance->GetData(TYPE_FOUR_HORSEMEN) == DONE) + m_creature->CastSpell(m_creature, SPELL_ACHIEV_CHECK, true); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_FOUR_HORSEMEN, FAIL); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Stop moving when it reaches the corner + m_bIsCornerMovement = false; + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // Mark of Zeliek - if (Mark_Timer < uiDiff) + // Don't attack while moving + if (m_bIsCornerMovement) + return; + + if (m_uiMarkTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MARK_OF_ZELIEK); - Mark_Timer = 12000; - }else Mark_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_MARK_OF_ZELIEK) == CAST_OK) + m_uiMarkTimer = 12000; + } + else + m_uiMarkTimer -= uiDiff; - // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds - if (ShieldWall1 && m_creature->GetHealthPercent() < 50.0f) + if (m_uiHolyWrathTimer < uiDiff) { - if (ShieldWall1) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(m_creature,SPELL_SHIELDWALL); - ShieldWall1 = false; + if (DoCastSpellIfCan(pTarget, SPELL_HOLY_WRATH) == CAST_OK) + m_uiHolyWrathTimer = 15000; } } - if (ShieldWall2 && m_creature->GetHealthPercent() < 20.0f) + else + m_uiHolyWrathTimer -= uiDiff; + + if (m_uiHolyBoltTimer < uiDiff) { - if (ShieldWall2) + // If we can find a target in range of 45.0f, then cast Holy Bolt + if (m_creature->IsWithinDist(m_creature->getVictim(), 45.0f)) + DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_HOLY_BOLT : SPELL_HOLY_BOLT_H); + else { - DoCastSpellIfCan(m_creature,SPELL_SHIELDWALL); - ShieldWall2 = false; + DoCastSpellIfCan(m_creature, SPELL_CONDEMNATION); + DoScriptText(EMOTE_CONDEMATION, m_creature); } + m_uiHolyBoltTimer = urand(2000, 3000); } - - // Holy Wrath - if (HolyWrath_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_HOLY_WRATH); - HolyWrath_Timer = 12000; - }else HolyWrath_Timer -= uiDiff; + else + m_uiHolyBoltTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/northrend/naxxramas/boss_gluth.cpp b/scripts/northrend/naxxramas/boss_gluth.cpp index 996867f71..83abeacde 100644 --- a/scripts/northrend/naxxramas/boss_gluth.cpp +++ b/scripts/northrend/naxxramas/boss_gluth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Gluth -SD%Complete: 70 -SDComment: +SD%Complete: 95 +SDComment: Gluth should turn around to face the victim when he devours a Zombie SDCategory: Naxxramas EndScriptData */ @@ -27,55 +27,33 @@ EndScriptData */ enum { EMOTE_ZOMBIE = -1533119, - EMOTE_BOSS_GENERIC_ENRAGED = -1000006, // NYI - EMOTE_DECIMATE = -1533152, // NYI + EMOTE_BOSS_GENERIC_ENRAGED = -1000006, + EMOTE_DECIMATE = -1533152, - SPELL_MORTALWOUND = 25646, + SPELL_MORTALWOUND = 54378, // old vanilla spell was 25646, SPELL_DECIMATE = 28374, + SPELL_DECIMATE_H = 54426, SPELL_ENRAGE = 28371, SPELL_ENRAGE_H = 54427, SPELL_BERSERK = 26662, + // SPELL_TERRIFYING_ROAR = 29685, // no longer used in 3.x.x + // SPELL_SUMMON_ZOMBIE_CHOW = 28216, // removed from dbc: triggers 28217 every 6 secs + // SPELL_CALL_ALL_ZOMBIE_CHOW = 29681, // removed from dbc: triggers 29682 + // SPELL_ZOMBIE_CHOW_SEARCH = 28235, // removed from dbc: triggers 28236 every 3 secs - NPC_ZOMBIE_CHOW = 16360 -}; - -#define ADD_1X 3269.590f -#define ADD_1Y -3161.287f -#define ADD_1Z 297.423f - -#define ADD_2X 3277.797f -#define ADD_2Y -3170.352f -#define ADD_2Z 297.423f - -#define ADD_3X 3267.049f -#define ADD_3Y -3172.820f -#define ADD_3Z 297.423f - -#define ADD_4X 3252.157f -#define ADD_4Y -3132.135f -#define ADD_4Z 297.423f - -#define ADD_5X 3259.990f -#define ADD_5Y -3126.590f -#define ADD_5Z 297.423f + NPC_ZOMBIE_CHOW = 16360, // old vanilla summoning spell 28217 -#define ADD_6X 3259.815f -#define ADD_6Y -3137.576f -#define ADD_6Z 297.423f - -#define ADD_7X 3308.030f -#define ADD_7Y -3132.135f -#define ADD_7Z 297.423f - -#define ADD_8X 3303.046f -#define ADD_8Y -3180.682f -#define ADD_8Z 297.423f + MAX_ZOMBIE_LOCATIONS = 3, +}; -#define ADD_9X 3313.283f -#define ADD_9Y -3180.766f -#define ADD_9Z 297.423f +static const float aZombieSummonLoc[MAX_ZOMBIE_LOCATIONS][3] = +{ + {3267.9f, -3172.1f, 297.42f}, + {3253.2f, -3132.3f, 297.42f}, + {3308.3f, -3185.8f, 297.42f}, +}; -struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI +struct boss_gluthAI : public ScriptedAI { boss_gluthAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -91,47 +69,107 @@ struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI uint32 m_uiDecimateTimer; uint32 m_uiEnrageTimer; uint32 m_uiSummonTimer; + uint32 m_uiZombieSearchTimer; uint32 m_uiBerserkTimer; - void Reset() + GuidList m_lZombieChowGuidList; + + void Reset() override { - m_uiMortalWoundTimer = 8000; - m_uiDecimateTimer = 100000; - m_uiEnrageTimer = 60000; - m_uiSummonTimer = 10000; + m_uiMortalWoundTimer = 10000; + m_uiDecimateTimer = 110000; + m_uiEnrageTimer = 25000; + m_uiSummonTimer = 15000; + m_uiZombieSearchTimer = 3000; - m_uiBerserkTimer = MINUTE*8*IN_MILLISECONDS; + m_uiBerserkTimer = MINUTE * 8 * IN_MILLISECONDS; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GLUTH, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GLUTH, IN_PROGRESS); } - void JustReachedHome() + void KilledUnit(Unit* pVictim) override + { + // Restore 5% hp when killing a zombie + if (pVictim->GetEntry() == NPC_ZOMBIE_CHOW) + { + DoScriptText(EMOTE_ZOMBIE, m_creature); + m_creature->SetHealth(m_creature->GetHealth() + m_creature->GetMaxHealth() * 0.05f); + } + } + + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GLUTH, FAIL); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override + { + pSummoned->GetMotionMaster()->MoveFollow(m_creature, ATTACK_DISTANCE, 0); + m_lZombieChowGuidList.push_back(pSummoned->GetObjectGuid()); + } + + void SummonedCreatureDespawn(Creature* pSummoned) override + { + m_lZombieChowGuidList.remove(pSummoned->GetObjectGuid()); + } + + // Replaces missing spell 29682 + void DoCallAllZombieChow() + { + for (GuidList::const_iterator itr = m_lZombieChowGuidList.begin(); itr != m_lZombieChowGuidList.end(); ++itr) + { + if (Creature* pZombie = m_creature->GetMap()->GetCreature(*itr)) + pZombie->GetMotionMaster()->MoveFollow(m_creature, ATTACK_DISTANCE, 0); + } + } + + // Replaces missing spell 28236 + void DoSearchZombieChow() + { + for (GuidList::const_iterator itr = m_lZombieChowGuidList.begin(); itr != m_lZombieChowGuidList.end(); ++itr) + { + if (Creature* pZombie = m_creature->GetMap()->GetCreature(*itr)) + { + if (!pZombie->isAlive()) + continue; + + // Devour a Zombie + if (pZombie->IsWithinDistInMap(m_creature, 15.0f)) + m_creature->DealDamage(pZombie, pZombie->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiZombieSearchTimer < uiDiff) + { + DoSearchZombieChow(); + m_uiZombieSearchTimer = 3000; + } + else + m_uiZombieSearchTimer -= uiDiff; + // Mortal Wound if (m_uiMortalWoundTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTALWOUND); - m_uiMortalWoundTimer = 10000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTALWOUND) == CAST_OK) + m_uiMortalWoundTimer = 10000; } else m_uiMortalWoundTimer -= uiDiff; @@ -139,8 +177,12 @@ struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI // Decimate if (m_uiDecimateTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DECIMATE); - m_uiDecimateTimer = 100000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DECIMATE : SPELL_DECIMATE_H) == CAST_OK) + { + DoScriptText(EMOTE_DECIMATE, m_creature); + DoCallAllZombieChow(); + m_uiDecimateTimer = 100000; + } } else m_uiDecimateTimer -= uiDiff; @@ -148,8 +190,11 @@ struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI // Enrage if (m_uiEnrageTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H); - m_uiEnrageTimer = 60000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ENRAGE : SPELL_ENRAGE_H) == CAST_OK) + { + DoScriptText(EMOTE_BOSS_GENERIC_ENRAGED, m_creature); + m_uiEnrageTimer = urand(20000, 30000); + } } else m_uiEnrageTimer -= uiDiff; @@ -157,19 +202,13 @@ struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI // Summon if (m_uiSummonTimer < uiDiff) { - if (Creature* pZombie = m_creature->SummonCreature(NPC_ZOMBIE_CHOW, ADD_1X, ADD_1Y, ADD_1Z, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 80000)) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pZombie->AddThreat(pTarget); - } + uint8 uiPos1 = urand(0, MAX_ZOMBIE_LOCATIONS - 1); + m_creature->SummonCreature(NPC_ZOMBIE_CHOW, aZombieSummonLoc[uiPos1][0], aZombieSummonLoc[uiPos1][1], aZombieSummonLoc[uiPos1][2], 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); if (!m_bIsRegularMode) { - if (Creature* pZombie = m_creature->SummonCreature(NPC_ZOMBIE_CHOW, ADD_1X, ADD_1Y, ADD_1Z, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 80000)) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pZombie->AddThreat(pTarget); - } + uint8 uiPos2 = (uiPos1 + urand(1, MAX_ZOMBIE_LOCATIONS - 1)) % MAX_ZOMBIE_LOCATIONS; + m_creature->SummonCreature(NPC_ZOMBIE_CHOW, aZombieSummonLoc[uiPos2][0], aZombieSummonLoc[uiPos2][1], aZombieSummonLoc[uiPos2][2], 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); } m_uiSummonTimer = 10000; @@ -180,8 +219,8 @@ struct MANGOS_DLL_DECL boss_gluthAI : public ScriptedAI // Berserk if (m_uiBerserkTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); - m_uiBerserkTimer = MINUTE*5*IN_MILLISECONDS; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = MINUTE * 5 * IN_MILLISECONDS; } else m_uiBerserkTimer -= uiDiff; diff --git a/scripts/northrend/naxxramas/boss_gothik.cpp b/scripts/northrend/naxxramas/boss_gothik.cpp index 16c723dde..7bc7b632a 100644 --- a/scripts/northrend/naxxramas/boss_gothik.cpp +++ b/scripts/northrend/naxxramas/boss_gothik.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -68,7 +68,7 @@ enum eSpellDummy SPELL_C_TO_SKULL = 27937 }; -struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI +struct boss_gothikAI : public ScriptedAI { boss_gothikAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -81,10 +81,10 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI instance_naxxramas* m_pInstance; bool m_bIsRegularMode; - GUIDList m_lSummonedAddGuids; - GUIDList m_lTraineeSummonPosGuids; - GUIDList m_lDeathKnightSummonPosGuids; - GUIDList m_lRiderSummonPosGuids; + GuidList m_lSummonedAddGuids; + GuidList m_lTraineeSummonPosGuids; + GuidList m_lDeathKnightSummonPosGuids; + GuidList m_lRiderSummonPosGuids; uint8 m_uiPhase; uint8 m_uiSpeech; @@ -99,7 +99,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI uint32 m_uiControlZoneTimer; uint32 m_uiSpeechTimer; - void Reset() + void Reset() override { // Remove immunity m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false); @@ -107,18 +107,18 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI m_uiPhase = PHASE_SPEECH; m_uiSpeech = 1; - m_uiTraineeTimer = 24*IN_MILLISECONDS; - m_uiDeathKnightTimer = 74*IN_MILLISECONDS; - m_uiRiderTimer = 134*IN_MILLISECONDS; - m_uiTeleportTimer = 20*IN_MILLISECONDS; - m_uiShadowboltTimer = 2*IN_MILLISECONDS; + m_uiTraineeTimer = 24 * IN_MILLISECONDS; + m_uiDeathKnightTimer = 74 * IN_MILLISECONDS; + m_uiRiderTimer = 134 * IN_MILLISECONDS; + m_uiTeleportTimer = 20 * IN_MILLISECONDS; + m_uiShadowboltTimer = 2 * IN_MILLISECONDS; m_uiHarvestSoulTimer = 2500; - m_uiPhaseTimer = 4*MINUTE*IN_MILLISECONDS + 7*IN_MILLISECONDS; // last summon at 4:04, next would be 4:09 - m_uiControlZoneTimer = urand(120*IN_MILLISECONDS,150*IN_MILLISECONDS); - m_uiSpeechTimer = 1*IN_MILLISECONDS; + m_uiPhaseTimer = 4 * MINUTE * IN_MILLISECONDS + 7 * IN_MILLISECONDS; // last summon at 4:04, next would be 4:09 + m_uiControlZoneTimer = urand(120 * IN_MILLISECONDS, 150 * IN_MILLISECONDS); + m_uiSpeechTimer = 1 * IN_MILLISECONDS; // Despawn Adds - for (GUIDList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); itr++) + for (GuidList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); itr++) { if (Creature* pCreature = m_creature->GetMap()->GetCreature(*itr)) pCreature->ForcedDespawn(); @@ -130,7 +130,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI m_lRiderSummonPosGuids.clear(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (!m_pInstance) return; @@ -165,7 +165,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI if (lPlayers.isEmpty()) return false; - for(Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) { if (Player* pPlayer = itr->getSource()) { @@ -177,13 +177,13 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI return false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) DoScriptText(SAY_KILL, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -191,7 +191,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI m_pInstance->SetData(TYPE_GOTHIK, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GOTHIK, FAIL); @@ -241,10 +241,10 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI } } - void SummonAdds(bool bRightSide, uint32 uiSummonEntry) + void SummonAdds(bool /*bRightSide*/, uint32 uiSummonEntry) { - GUIDList* plSummonPosGuids; - switch(uiSummonEntry) + GuidList* plSummonPosGuids; + switch (uiSummonEntry) { case NPC_UNREL_TRAINEE: plSummonPosGuids = &m_lTraineeSummonPosGuids; break; case NPC_UNREL_DEATH_KNIGHT: plSummonPosGuids = &m_lDeathKnightSummonPosGuids; break; @@ -255,21 +255,21 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI if (plSummonPosGuids->empty()) return; - for (GUIDList::iterator itr = plSummonPosGuids->begin(); itr != plSummonPosGuids->end(); ++itr) + for (GuidList::iterator itr = plSummonPosGuids->begin(); itr != plSummonPosGuids->end(); ++itr) { if (Creature* pPos = m_creature->GetMap()->GetCreature(*itr)) m_creature->SummonCreature(uiSummonEntry, pPos->GetPositionX(), pPos->GetPositionY(), pPos->GetPositionZ(), pPos->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { m_lSummonedAddGuids.push_back(pSummoned->GetObjectGuid()); if (!IsCentralDoorClosed()) pSummoned->SetInCombatWithZone(); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { m_lSummonedAddGuids.remove(pSummoned->GetObjectGuid()); @@ -280,9 +280,9 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI { switch (pSummoned->GetEntry()) { - // Wrong caster, it expected to be pSummoned. - // Mangos deletes the spell event at caster death, so for delayed spell like this - // it's just a workaround. Does not affect other than the visual though (+ spell takes longer to "travel") + // Wrong caster, it expected to be pSummoned. + // Mangos deletes the spell event at caster death, so for delayed spell like this + // it's just a workaround. Does not affect other than the visual though (+ spell takes longer to "travel") case NPC_UNREL_TRAINEE: m_creature->CastSpell(pAnchor, SPELL_A_TO_ANCHOR_1, true, NULL, NULL, pSummoned->GetObjectGuid()); break; case NPC_UNREL_DEATH_KNIGHT: m_creature->CastSpell(pAnchor, SPELL_B_TO_ANCHOR_1, true, NULL, NULL, pSummoned->GetObjectGuid()); break; case NPC_UNREL_RIDER: m_creature->CastSpell(pAnchor, SPELL_C_TO_ANCHOR_1, true, NULL, NULL, pSummoned->GetObjectGuid()); break; @@ -290,7 +290,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -300,11 +300,11 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI case PHASE_SPEECH: if (m_uiSpeechTimer < uiDiff) { - switch(m_uiSpeech) + switch (m_uiSpeech) { - case 1: DoScriptText(SAY_SPEECH_1, m_creature); m_uiSpeechTimer = 4*IN_MILLISECONDS; break; - case 2: DoScriptText(SAY_SPEECH_2, m_creature); m_uiSpeechTimer = 6*IN_MILLISECONDS; break; - case 3: DoScriptText(SAY_SPEECH_3, m_creature); m_uiSpeechTimer = 5*IN_MILLISECONDS; break; + case 1: DoScriptText(SAY_SPEECH_1, m_creature); m_uiSpeechTimer = 4 * IN_MILLISECONDS; break; + case 2: DoScriptText(SAY_SPEECH_2, m_creature); m_uiSpeechTimer = 6 * IN_MILLISECONDS; break; + case 3: DoScriptText(SAY_SPEECH_3, m_creature); m_uiSpeechTimer = 5 * IN_MILLISECONDS; break; case 4: DoScriptText(SAY_SPEECH_4, m_creature); m_uiPhase = PHASE_BALCONY; break; } m_uiSpeech++; @@ -318,21 +318,21 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI if (m_uiTraineeTimer < uiDiff) { SummonAdds(true, NPC_UNREL_TRAINEE); - m_uiTraineeTimer = 20*IN_MILLISECONDS; + m_uiTraineeTimer = 20 * IN_MILLISECONDS; } else m_uiTraineeTimer -= uiDiff; if (m_uiDeathKnightTimer < uiDiff) { SummonAdds(true, NPC_UNREL_DEATH_KNIGHT); - m_uiDeathKnightTimer = 25*IN_MILLISECONDS; + m_uiDeathKnightTimer = 25 * IN_MILLISECONDS; } else m_uiDeathKnightTimer -= uiDiff; if (m_uiRiderTimer < uiDiff) { SummonAdds(true, NPC_UNREL_RIDER); - m_uiRiderTimer = 30*IN_MILLISECONDS; + m_uiRiderTimer = 30 * IN_MILLISECONDS; } else m_uiRiderTimer -= uiDiff; @@ -340,7 +340,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI if (m_uiPhaseTimer < uiDiff) { m_uiPhase = PHASE_STOP_SUMMONING; - m_uiPhaseTimer = 27*IN_MILLISECONDS; + m_uiPhaseTimer = 27 * IN_MILLISECONDS; } else m_uiPhaseTimer -= uiDiff; @@ -375,8 +375,8 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI uint32 uiTeleportSpell = m_pInstance->IsInRightSideGothArea(m_creature) ? SPELL_TELEPORT_LEFT : SPELL_TELEPORT_RIGHT; if (DoCastSpellIfCan(m_creature, uiTeleportSpell) == CAST_OK) { - m_uiTeleportTimer = 20*IN_MILLISECONDS; - m_uiShadowboltTimer = 2*IN_MILLISECONDS; + m_uiTeleportTimer = 20 * IN_MILLISECONDS; + m_uiShadowboltTimer = 2 * IN_MILLISECONDS; } } else @@ -395,7 +395,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI if (m_uiHarvestSoulTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_HARVESTSOUL) == CAST_OK) - m_uiHarvestSoulTimer = 15*IN_MILLISECONDS; + m_uiHarvestSoulTimer = 15 * IN_MILLISECONDS; } else m_uiHarvestSoulTimer -= uiDiff; @@ -428,7 +428,7 @@ struct MANGOS_DLL_DECL boss_gothikAI : public ScriptedAI if (m_pInstance && !HasPlayersInLeftSide()) { ProcessCentralDoor(); - for (GUIDList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); itr++) + for (GuidList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); itr++) { if (Creature* pCreature = m_pInstance->instance->GetCreature(*itr)) { @@ -449,7 +449,7 @@ CreatureAI* GetAI_boss_gothik(Creature* pCreature) return new boss_gothikAI(pCreature); } -bool EffectDummyCreature_spell_anchor(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_spell_anchor(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiEffIndex != EFFECT_INDEX_0 || pCreatureTarget->GetEntry() != NPC_SUB_BOSS_TRIGGER) return true; @@ -459,7 +459,7 @@ bool EffectDummyCreature_spell_anchor(Unit* pCaster, uint32 uiSpellId, SpellEffe if (!pInstance) return true; - switch(uiSpellId) + switch (uiSpellId) { case SPELL_A_TO_ANCHOR_1: // trigger mobs at high right side case SPELL_B_TO_ANCHOR_1: @@ -489,7 +489,7 @@ bool EffectDummyCreature_spell_anchor(Unit* pCaster, uint32 uiSpellId, SpellEffe if (!lTargets.empty()) { std::list::iterator itr = lTargets.begin(); - uint32 uiPosition = urand(0, lTargets.size()-1); + uint32 uiPosition = urand(0, lTargets.size() - 1); advance(itr, uiPosition); if (Creature* pTarget = (*itr)) diff --git a/scripts/northrend/naxxramas/boss_grobbulus.cpp b/scripts/northrend/naxxramas/boss_grobbulus.cpp index 5a72245f3..64014eae6 100644 --- a/scripts/northrend/naxxramas/boss_grobbulus.cpp +++ b/scripts/northrend/naxxramas/boss_grobbulus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -45,7 +45,7 @@ enum NPC_FALLOUT_SLIME = 16290 }; -struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI +struct boss_grobbulusAI : public ScriptedAI { boss_grobbulusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -65,29 +65,29 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI uint32 m_uiBerserkTimer; uint32 m_uiSlimeStreamTimer; - void Reset() + void Reset() override { - m_uiInjectionTimer = 12*IN_MILLISECONDS; - m_uiPoisonCloudTimer = urand (20*IN_MILLISECONDS, 25*IN_MILLISECONDS); - m_uiSlimeSprayTimer = urand(20*IN_MILLISECONDS, 30*IN_MILLISECONDS); - m_uiBerserkTimeSecs = m_bIsRegularMode ? 12*MINUTE : 9*MINUTE; - m_uiBerserkTimer = m_uiBerserkTimeSecs*IN_MILLISECONDS; - m_uiSlimeStreamTimer = 5*IN_MILLISECONDS; // The first few secs it is ok to be out of range + m_uiInjectionTimer = 12 * IN_MILLISECONDS; + m_uiPoisonCloudTimer = urand(20 * IN_MILLISECONDS, 25 * IN_MILLISECONDS); + m_uiSlimeSprayTimer = urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS); + m_uiBerserkTimeSecs = m_bIsRegularMode ? 12 * MINUTE : 9 * MINUTE; + m_uiBerserkTimer = m_uiBerserkTimeSecs * IN_MILLISECONDS; + m_uiSlimeStreamTimer = 5 * IN_MILLISECONDS; // The first few secs it is ok to be out of range } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GROBBULUS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GROBBULUS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_GROBBULUS, FAIL); @@ -101,9 +101,8 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI std::vector suitableTargets; ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); - ThreatList::const_iterator itr = threatList.begin(); - for (itr; itr != threatList.end(); ++itr) + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) { if (Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) { @@ -125,13 +124,13 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI return false; } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { if ((pSpell->Id == SPELL_SLIME_SPRAY || pSpell->Id == SPELL_SLIME_SPRAY_H) && pTarget->GetTypeId() == TYPEID_PLAYER) - m_creature->SummonCreature(NPC_FALLOUT_SLIME, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10*IN_MILLISECONDS); + m_creature->SummonCreature(NPC_FALLOUT_SLIME, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 10 * IN_MILLISECONDS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -143,7 +142,7 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_SLIME_STREAM) == CAST_OK) // Give some time, to re-reach grobbulus - m_uiSlimeStreamTimer = 3*IN_MILLISECONDS; + m_uiSlimeStreamTimer = 3 * IN_MILLISECONDS; } } else @@ -171,7 +170,7 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SLIME_SPRAY : SPELL_SLIME_SPRAY_H) == CAST_OK) { - m_uiSlimeSprayTimer = urand(30*IN_MILLISECONDS, 60*IN_MILLISECONDS); + m_uiSlimeSprayTimer = urand(30 * IN_MILLISECONDS, 60 * IN_MILLISECONDS); DoScriptText(EMOTE_SPRAY_SLIME, m_creature); } } @@ -185,9 +184,9 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI { // Timer dependend on time of encounter - on enrage time between 5-8s, heroic 2-5s (TODO no reliable source for heroic) if (m_bIsRegularMode) - m_uiInjectionTimer = urand(10*IN_MILLISECONDS, 13*IN_MILLISECONDS) - 5 * (m_uiBerserkTimeSecs*IN_MILLISECONDS - m_uiBerserkTimer) / m_uiBerserkTimeSecs; + m_uiInjectionTimer = urand(10 * IN_MILLISECONDS, 13 * IN_MILLISECONDS) - 5 * (m_uiBerserkTimeSecs * IN_MILLISECONDS - m_uiBerserkTimer) / m_uiBerserkTimeSecs; else - m_uiInjectionTimer = urand(10*IN_MILLISECONDS, 13*IN_MILLISECONDS) - 8 * (m_uiBerserkTimeSecs*IN_MILLISECONDS - m_uiBerserkTimer) / m_uiBerserkTimeSecs; + m_uiInjectionTimer = urand(10 * IN_MILLISECONDS, 13 * IN_MILLISECONDS) - 8 * (m_uiBerserkTimeSecs * IN_MILLISECONDS - m_uiBerserkTimer) / m_uiBerserkTimeSecs; } } else @@ -197,7 +196,7 @@ struct MANGOS_DLL_DECL boss_grobbulusAI : public ScriptedAI if (m_uiPoisonCloudTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_POISON_CLOUD) == CAST_OK) - m_uiPoisonCloudTimer = 15*IN_MILLISECONDS; + m_uiPoisonCloudTimer = 15 * IN_MILLISECONDS; } else m_uiPoisonCloudTimer -= uiDiff; diff --git a/scripts/northrend/naxxramas/boss_heigan.cpp b/scripts/northrend/naxxramas/boss_heigan.cpp index 4c11fedea..dfbaec161 100644 --- a/scripts/northrend/naxxramas/boss_heigan.cpp +++ b/scripts/northrend/naxxramas/boss_heigan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum SPELL_PLAGUE_CLOUD = 29350 }; -struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI +struct boss_heiganAI : public ScriptedAI { boss_heiganAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -82,16 +82,16 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI m_uiPhaseTimer = m_uiPhase == PHASE_GROUND ? 90000 : 45000; } - void Reset() + void Reset() override { m_uiPhase = PHASE_GROUND; - m_uiTauntTimer = urand(20000,60000); // TODO, find information + m_uiTauntTimer = urand(20000, 60000); // TODO, find information ResetPhase(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -102,12 +102,12 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI m_pInstance->SetData(TYPE_HEIGAN, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -115,13 +115,13 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI m_pInstance->SetData(TYPE_HEIGAN, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_HEIGAN, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -193,7 +193,7 @@ struct MANGOS_DLL_DECL boss_heiganAI : public ScriptedAI // Taunt if (m_uiTauntTimer < uiDiff) { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_TAUNT1, m_creature); break; case 1: DoScriptText(SAY_TAUNT2, m_creature); break; diff --git a/scripts/northrend/naxxramas/boss_kelthuzad.cpp b/scripts/northrend/naxxramas/boss_kelthuzad.cpp index b12432357..ba7e0cbee 100644 --- a/scripts/northrend/naxxramas/boss_kelthuzad.cpp +++ b/scripts/northrend/naxxramas/boss_kelthuzad.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,9 +30,9 @@ EndScriptData */ enum { - SAY_SUMMON_MINIONS = -1533105, //start of phase 1 + SAY_SUMMON_MINIONS = -1533105, // start of phase 1 - EMOTE_PHASE2 = -1533135, //start of phase 2 + EMOTE_PHASE2 = -1533135, // start of phase 2 SAY_AGGRO1 = -1533094, SAY_AGGRO2 = -1533095, SAY_AGGRO3 = -1533096, @@ -46,8 +46,8 @@ enum SAY_CHAIN2 = -1533101, SAY_FROST_BLAST = -1533102, - SAY_REQUEST_AID = -1533103, //start of phase 3 - SAY_ANSWER_REQUEST = -1533104, //lich king answer + SAY_REQUEST_AID = -1533103, // start of phase 3 + SAY_ANSWER_REQUEST = -1533104, // lich king answer SAY_SPECIAL1_MANA_DET = -1533106, SAY_SPECIAL3_MANA_DET = -1533107, @@ -55,7 +55,7 @@ enum EMOTE_GUARDIAN = -1533134, // at each guardian summon - //spells to be casted + // spells to be casted SPELL_FROST_BOLT = 28478, SPELL_FROST_BOLT_H = 55802, SPELL_FROST_BOLT_NOVA = 28479, @@ -88,7 +88,7 @@ enum Phase PHASE_GUARDIANS, }; -struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI +struct boss_kelthuzadAI : public ScriptedAI { boss_kelthuzadAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -125,24 +125,24 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI uint32 m_uiIntroPackCount; uint32 m_uiKilledAbomination; - GUIDSet m_lIntroMobsSet; - GUIDSet m_lAddsSet; + GuidSet m_lIntroMobsSet; + GuidSet m_lAddsSet; - void Reset() + void Reset() override { - m_uiFrostBoltTimer = urand(1000, 60000); //It won't be more than a minute without cast it - m_uiFrostBoltNovaTimer = 15000; //Cast every 15 seconds - m_uiChainsTimer = urand(30000, 60000); //Cast no sooner than once every 30 seconds - m_uiManaDetonationTimer = 20000; //Seems to cast about every 20 seconds - m_uiShadowFissureTimer = 25000; //25 seconds - m_uiFrostBlastTimer = urand(30000, 60000); //Random time between 30-60 seconds - m_uiGuardiansTimer = 5000; //5 seconds for summoning each Guardian of Icecrown in phase 3 + m_uiFrostBoltTimer = urand(1000, 60000); // It won't be more than a minute without cast it + m_uiFrostBoltNovaTimer = 15000; // Cast every 15 seconds + m_uiChainsTimer = urand(30000, 60000); // Cast no sooner than once every 30 seconds + m_uiManaDetonationTimer = 20000; // Seems to cast about every 20 seconds + m_uiShadowFissureTimer = 25000; // 25 seconds + m_uiFrostBlastTimer = urand(30000, 60000); // Random time between 30-60 seconds + m_uiGuardiansTimer = 5000; // 5 seconds for summoning each Guardian of Icecrown in phase 3 m_uiLichKingAnswerTimer = 4000; m_uiGuardiansCount = 0; m_uiSummonIntroTimer = 0; m_uiIntroPackCount = 0; - m_uiPhase1Timer = 228000; //Phase 1 lasts "3 minutes and 48 seconds" + m_uiPhase1Timer = 228000; // Phase 1 lasts "3 minutes and 48 seconds" m_uiSoldierTimer = 5000; m_uiBansheeTimer = 5000; m_uiAbominationTimer = 5000; @@ -157,7 +157,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI SetCombatMovement(false); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -166,7 +166,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); DespawnAdds(); @@ -175,7 +175,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI m_pInstance->SetData(TYPE_KELTHUZAD, DONE); } - void JustReachedHome() + void JustReachedHome() override { DespawnIntroCreatures(); DespawnAdds(); @@ -184,7 +184,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI m_pInstance->SetData(TYPE_KELTHUZAD, NOT_STARTED); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (m_pInstance && m_pInstance->GetData(TYPE_KELTHUZAD) != IN_PROGRESS) return; @@ -196,7 +196,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI { if (m_pInstance) { - for(GUIDSet::const_iterator itr = m_lIntroMobsSet.begin(); itr != m_lIntroMobsSet.end(); ++itr) + for (GuidSet::const_iterator itr = m_lIntroMobsSet.begin(); itr != m_lIntroMobsSet.end(); ++itr) { if (Creature* pCreature = m_pInstance->instance->GetCreature(*itr)) pCreature->ForcedDespawn(); @@ -210,7 +210,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI { if (m_pInstance) { - for(GUIDSet::const_iterator itr = m_lAddsSet.begin(); itr != m_lAddsSet.end(); ++itr) + for (GuidSet::const_iterator itr = m_lAddsSet.begin(); itr != m_lAddsSet.end(); ++itr) { if (Creature* pCreature = m_pInstance->instance->GetCreature(*itr)) { @@ -228,7 +228,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI float GetLocationAngle(uint32 uiId) { - switch(uiId) + switch (uiId) { case 1: return M_PI_F - M_F_ANGLE; // south case 2: return M_PI_F / 2 * 3 - M_F_ANGLE; // east @@ -247,7 +247,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI if (!m_pInstance) return; - float fAngle = GetLocationAngle(packId+1); + float fAngle = GetLocationAngle(packId + 1); float fX, fY, fZ; m_pInstance->GetChamberCenterCoords(fX, fY, fZ); @@ -261,7 +261,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI uint32 uiNpcEntry = NPC_SOUL_WEAVER; - for(uint8 uiI = 0; uiI < 14; ++uiI) + for (uint8 uiI = 0; uiI < 14; ++uiI) { if (uiI > 0) { @@ -298,9 +298,9 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI m_creature->SummonCreature(uiType, fX, fY, fZ, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 5000); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_GUARDIAN: { @@ -335,9 +335,9 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_GUARDIAN: case NPC_SOLDIER_FROZEN: @@ -355,13 +355,13 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType == POINT_MOTION_TYPE && uiPointId == 0) pSummoned->SetInCombatWithZone(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -398,7 +398,7 @@ struct MANGOS_DLL_DECL boss_kelthuzadAI : public ScriptedAI DoScriptText(EMOTE_PHASE2, m_creature); - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; diff --git a/scripts/northrend/naxxramas/boss_loatheb.cpp b/scripts/northrend/naxxramas/boss_loatheb.cpp index 74aceb4fd..a4b178e07 100644 --- a/scripts/northrend/naxxramas/boss_loatheb.cpp +++ b/scripts/northrend/naxxramas/boss_loatheb.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,7 +41,7 @@ enum NPC_SPORE = 16286 }; -struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI +struct boss_loathebAI : public ScriptedAI { boss_loathebAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -60,35 +60,35 @@ struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI uint32 m_uiBerserkTimer; uint8 m_uiNecroticAuraCount; // Used for emotes, 5min check - void Reset() + void Reset() override { m_uiDeathbloomTimer = 5000; m_uiNecroticAuraTimer = 12000; - m_uiInevitableDoomTimer = MINUTE*2*IN_MILLISECONDS; + m_uiInevitableDoomTimer = MINUTE * 2 * IN_MILLISECONDS; m_uiSummonTimer = urand(10000, 15000); // first seen in vid after approx 12s - m_uiBerserkTimer = MINUTE*12*IN_MILLISECONDS; // only in heroic, after 12min + m_uiBerserkTimer = MINUTE * 12 * IN_MILLISECONDS; // only in heroic, after 12min m_uiNecroticAuraCount = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LOATHEB, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_LOATHEB, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_LOATHEB, NOT_STARTED); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() != NPC_SPORE) return; @@ -97,13 +97,13 @@ struct MANGOS_DLL_DECL boss_loathebAI : public ScriptedAI pSummoned->AddThreat(pTarget); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SPORE && m_pInstance) m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_SPORE_LOSER, false); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/naxxramas/boss_maexxna.cpp b/scripts/northrend/naxxramas/boss_maexxna.cpp index 3da2fc82b..5f4d6ced2 100644 --- a/scripts/northrend/naxxramas/boss_maexxna.cpp +++ b/scripts/northrend/naxxramas/boss_maexxna.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Maexxna -SD%Complete: 70 -SDComment: Need to correct web wrap ability +SD%Complete: 90 +SDComment: Web wrap effect still needs more love and research. SDCategory: Naxxramas EndScriptData */ @@ -46,44 +46,71 @@ enum SPELL_FRENZY = 54123, SPELL_FRENZY_H = 54124, - NPC_WEB_WRAP = 16486, - NPC_SPIDERLING = 17055 -}; + // SPELL_SUMMON_SPIDERLING_1 = 29434, // removed from dbc. Summons 10 spiderlings + // SPELL_SUMMON_SPIDERLING_2 = 30076, // removed from dbc. Summons 3 spiderlings + // SPELL_SUMMON_WEB_WRAP = 28627, // removed from dbc. Summons one web wrap and transforms it into creature 17286 -#define LOC_X1 3546.796f -#define LOC_Y1 -3869.082f -#define LOC_Z1 296.450f + NPC_WEB_WRAP = 16486, + NPC_SPIDERLING = 17055, -#define LOC_X2 3531.271f -#define LOC_Y2 -3847.424f -#define LOC_Z2 299.450f + MAX_SPIDERLINGS = 8, + MAX_WEB_WRAP_POSITIONS = 3, +}; -#define LOC_X3 3497.067f -#define LOC_Y3 -3843.384f -#define LOC_Z3 302.384f +static const float aWebWrapLoc[MAX_WEB_WRAP_POSITIONS][3] = +{ + {3546.796f, -3869.082f, 296.450f}, + {3531.271f, -3847.424f, 299.450f}, + {3497.067f, -3843.384f, 302.384f} +}; -struct MANGOS_DLL_DECL npc_web_wrapAI : public ScriptedAI +struct npc_web_wrapAI : public ScriptedAI { npc_web_wrapAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } ObjectGuid m_victimGuid; + uint32 m_uiWebWrapTimer; - void Reset() {} + void Reset() override + { + m_uiWebWrapTimer = 0; + } - void MoveInLineOfSight(Unit* pWho) {} - void AttackStart(Unit* pWho) {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void AttackStart(Unit* /*pWho*/) override {} void SetVictim(Unit* pVictim) { if (pVictim) { - DoTeleportPlayer(pVictim, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), pVictim->GetOrientation()); + // Vanilla spell 28618, 28619, 28620, 28621 had effect SPELL_EFFECT_PLAYER_PULL with EffectMiscValue = 200, 300, 400 and 500 + // All these spells trigger 28622 after 1 or 2 seconds + // the EffectMiscValue may have been based on the distance between the victim and the target + + // NOTE: This implementation may not be 100% correct, but it gets very close to the expected result + + float fDist = m_creature->GetDistance2d(pVictim); + // Switch the speed multiplier based on the distance from the web wrap + uint32 uiEffectMiscValue = 500; + if (fDist < 25.0f) + uiEffectMiscValue = 200; + else if (fDist < 50.0f) + uiEffectMiscValue = 300; + else if (fDist < 75.0f) + uiEffectMiscValue = 400; + + // Note: normally we should use the Knockback effect to handle this, but because this doesn't behave as expected we'll just use Jump Movement + // pVictim->KnockBackFrom(m_creature, -fDist, uiEffectMiscValue * 0.1f); + + float fSpeed = fDist * (uiEffectMiscValue * 0.01f); + pVictim->GetMotionMaster()->MoveJump(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), fSpeed, 0.0f); + m_victimGuid = pVictim->GetObjectGuid(); - pVictim->CastSpell(pVictim, SPELL_WEBWRAP, true); + m_uiWebWrapTimer = uiEffectMiscValue == 200 ? 1000 : 2000; } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_victimGuid) { @@ -94,9 +121,26 @@ struct MANGOS_DLL_DECL npc_web_wrapAI : public ScriptedAI } } } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiWebWrapTimer) + { + // Finally the player gets web wrapped and he should change the display id until the creature is killed + if (m_uiWebWrapTimer <= uiDiff) + { + if (Player* pVictim = m_creature->GetMap()->GetPlayer(m_victimGuid)) + pVictim->CastSpell(pVictim, SPELL_WEBWRAP, true, NULL, NULL, m_creature->GetObjectGuid()); + + m_uiWebWrapTimer = 0; + } + else + m_uiWebWrapTimer -= uiDiff; + } + } }; -struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI +struct boss_maexxnaAI : public ScriptedAI { boss_maexxnaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -115,107 +159,78 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI uint32 m_uiSummonSpiderlingTimer; bool m_bEnraged; - void Reset() + void Reset() override { - m_uiWebWrapTimer = 20000; // 20 sec init, 40 sec normal - m_uiWebSprayTimer = 40000; // 40 seconds - m_uiPoisonShockTimer = 20000; // 20 seconds - m_uiNecroticPoisonTimer = 30000; // 30 seconds - m_uiSummonSpiderlingTimer = 30000; // 30 sec init, 40 sec normal - m_bEnraged = false; + m_uiWebWrapTimer = 15000; + m_uiWebSprayTimer = 40000; + m_uiPoisonShockTimer = urand(10000, 20000); + m_uiNecroticPoisonTimer = urand(20000, 30000); + m_uiSummonSpiderlingTimer = 30000; + m_bEnraged = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_MAEXXNA, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_MAEXXNA, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_MAEXXNA, FAIL); } - bool DoCastWebWrap() + void JustSummoned(Creature* pSummoned) override { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - std::vector vTargets; - - // This spell doesn't work if we only have 1 player on threat list - if (tList.size() < 2) - return false; - - // begin + 1 , so we don't target the one with the highest threat - ThreatList::const_iterator itr = tList.begin(); - std::advance(itr, 1); - - // store the threat list in a different container - for (;itr != tList.end(); ++itr) + if (pSummoned->GetEntry() == NPC_WEB_WRAP) { - Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - // only on alive players - if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) - vTargets.push_back(pTarget); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_WEBWRAP, SELECT_FLAG_PLAYER)) + { + if (npc_web_wrapAI* pWebAI = dynamic_cast(pSummoned->AI())) + pWebAI->SetVictim(pTarget); + } } + else if (pSummoned->GetEntry() == NPC_SPIDERLING) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } - if (vTargets.empty()) + bool DoCastWebWrap() + { + // If we can't select a player for web wrap then skip the summoning + if (!m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_PLAYER)) return false; - // cut down to size if we have more than 1/2 targets (10m/25m) (was 3 in 40m) - uint8 uiMaxTargets = m_bIsRegularMode ? 1 : 2; - while(vTargets.size() > uiMaxTargets) - vTargets.erase(vTargets.begin() + urand(0, vTargets.size() - 1)); + uint8 uiPos1 = urand(0, MAX_WEB_WRAP_POSITIONS - 1); + m_creature->SummonCreature(NPC_WEB_WRAP, aWebWrapLoc[uiPos1][0], aWebWrapLoc[uiPos1][1], aWebWrapLoc[uiPos1][2], 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); - int i = 0; - - // TODO check locations for 10m/25m - for(std::vector::const_iterator iter = vTargets.begin(); iter != vTargets.end(); ++iter, ++i) + // Summon a second web wrap on heroic + if (!m_bIsRegularMode) { - // Teleport the targets to a location on the wall and summon a Web Wrap on them - switch(i) - { - case 0: - if (Creature* pWrap = m_creature->SummonCreature(NPC_WEB_WRAP, LOC_X1, LOC_Y1, LOC_Z1, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000)) - { - if (npc_web_wrapAI* pWebAI = dynamic_cast(pWrap->AI())) - pWebAI->SetVictim(*iter); - } - break; - case 1: - if (Creature* pWrap = m_creature->SummonCreature(NPC_WEB_WRAP, LOC_X2, LOC_Y2, LOC_Z2, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000)) - { - if (npc_web_wrapAI* pWebAI = dynamic_cast(pWrap->AI())) - pWebAI->SetVictim(*iter); - } - break; - case 2: - if (Creature* pWrap = m_creature->SummonCreature(NPC_WEB_WRAP, LOC_X3, LOC_Y3, LOC_Z3, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000)) - { - if (npc_web_wrapAI* pWebAI = dynamic_cast(pWrap->AI())) - pWebAI->SetVictim(*iter); - } - break; - } + uint8 uiPos2 = (uiPos1 + urand(1, MAX_WEB_WRAP_POSITIONS - 1)) % MAX_WEB_WRAP_POSITIONS; + m_creature->SummonCreature(NPC_WEB_WRAP, aWebWrapLoc[uiPos2][0], aWebWrapLoc[uiPos2][1], aWebWrapLoc[uiPos2][2], 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); } return true; } + // Summons spiderlings around the boss void SummonSpiderlings() { - for(uint8 i = 0; i < 8; ++i) - m_creature->SummonCreature(NPC_SPIDERLING, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + for (uint8 i = 0; i < MAX_SPIDERLINGS; ++i) + m_creature->SummonCreature(NPC_SPIDERLING, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -225,6 +240,7 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI { if (DoCastWebWrap()) DoScriptText(EMOTE_SPIN_WEB, m_creature); + m_uiWebWrapTimer = 40000; } else @@ -233,7 +249,7 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI // Web Spray if (m_uiWebSprayTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_WEBSPRAY : SPELL_WEBSPRAY_H) == CAST_OK) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WEBSPRAY : SPELL_WEBSPRAY_H) == CAST_OK) { DoScriptText(EMOTE_SPRAY, m_creature); m_uiWebSprayTimer = 40000; @@ -245,8 +261,8 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI // Poison Shock if (m_uiPoisonShockTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_POISONSHOCK : SPELL_POISONSHOCK_H); - m_uiPoisonShockTimer = 20000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_POISONSHOCK : SPELL_POISONSHOCK_H) == CAST_OK) + m_uiPoisonShockTimer = urand(10000, 20000); } else m_uiPoisonShockTimer -= uiDiff; @@ -254,8 +270,8 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI // Necrotic Poison if (m_uiNecroticPoisonTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_NECROTICPOISON : SPELL_NECROTICPOISON_H); - m_uiNecroticPoisonTimer = 30000; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_NECROTICPOISON : SPELL_NECROTICPOISON_H) == CAST_OK) + m_uiNecroticPoisonTimer = urand(20000, 30000); } else m_uiNecroticPoisonTimer -= uiDiff; @@ -265,7 +281,7 @@ struct MANGOS_DLL_DECL boss_maexxnaAI : public ScriptedAI { SummonSpiderlings(); DoScriptText(EMOTE_SPIDERLING, m_creature); - m_uiSummonSpiderlingTimer = 40000; + m_uiSummonSpiderlingTimer = 30000; } else m_uiSummonSpiderlingTimer -= uiDiff; diff --git a/scripts/northrend/naxxramas/boss_noth.cpp b/scripts/northrend/naxxramas/boss_noth.cpp index ceab11a0e..ca76b9d1a 100644 --- a/scripts/northrend/naxxramas/boss_noth.cpp +++ b/scripts/northrend/naxxramas/boss_noth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -84,7 +84,7 @@ enum PHASE_SKELETON_3 = 3 }; -struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI +struct boss_nothAI : public ScriptedAI { boss_nothAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -104,7 +104,7 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI uint32 m_uiCurseTimer; uint32 m_uiSummonTimer; - void Reset() + void Reset() override { m_uiPhase = PHASE_GROUND; m_uiPhaseSub = PHASE_GROUND; @@ -115,9 +115,9 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI m_uiSummonTimer = 12000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -128,17 +128,17 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI m_pInstance->SetData(TYPE_NOTH, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->SetInCombatWithZone(); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -146,19 +146,19 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI m_pInstance->SetData(TYPE_NOTH, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NOTH, FAIL); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pCaster == m_creature && pSpell->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_LEAP) DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CRIPPLE : SPELL_CRIPPLE_H); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -176,7 +176,7 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI m_uiPhase = PHASE_BALCONY; ++m_uiPhaseSub; - switch(m_uiPhaseSub) // Set Duration of Skeleton phase + switch (m_uiPhaseSub) // Set Duration of Skeleton phase { case PHASE_SKELETON_1: m_uiPhaseTimer = 70000; break; case PHASE_SKELETON_2: m_uiPhaseTimer = 97000; break; @@ -228,8 +228,8 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI SPELL_SUMMON_WARRIOR_1, SPELL_SUMMON_WARRIOR_2, SPELL_SUMMON_WARRIOR_3 }; - for(uint8 i = 0; i < 2; ++i) - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedWarrior[urand(0,2)], CAST_TRIGGERED); + for (uint8 i = 0; i < 2; ++i) + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedWarrior[urand(0, 2)], CAST_TRIGGERED); } else { @@ -284,12 +284,12 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI }; // A bit unclear how many in each sub phase - switch(m_uiPhaseSub) + switch (m_uiPhaseSub) { case PHASE_SKELETON_1: { for (uint8 i = 0; i < (m_bIsRegularMode ? 2 : 4); ++i) - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0,9)], CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0, 9)], CAST_TRIGGERED); break; } @@ -297,15 +297,15 @@ struct MANGOS_DLL_DECL boss_nothAI : public ScriptedAI { for (uint8 i = 0; i < (m_bIsRegularMode ? 1 : 2); ++i) { - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0,9)], CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0,3)], CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedChampion[urand(0, 9)], CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0, 3)], CAST_TRIGGERED); } break; } case PHASE_SKELETON_3: { for (uint8 i = 0; i < (m_bIsRegularMode ? 2 : 4); ++i) - DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0,3)], CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, auiSpellSummonPlaguedGuardian[urand(0, 3)], CAST_TRIGGERED); break; } diff --git a/scripts/northrend/naxxramas/boss_patchwerk.cpp b/scripts/northrend/naxxramas/boss_patchwerk.cpp index e9e84aa59..89a11dc5f 100644 --- a/scripts/northrend/naxxramas/boss_patchwerk.cpp +++ b/scripts/northrend/naxxramas/boss_patchwerk.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,7 +41,7 @@ enum SPELL_SLIMEBOLT = 32309 }; -struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI +struct boss_patchwerkAI : public ScriptedAI { boss_patchwerkAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -59,16 +59,16 @@ struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI bool m_bEnraged; bool m_bBerserk; - void Reset() + void Reset() override { - m_uiHatefulStrikeTimer = 1000; //1 second - m_uiBerserkTimer = MINUTE*6*IN_MILLISECONDS; //6 minutes + m_uiHatefulStrikeTimer = 1000; // 1 second + m_uiBerserkTimer = MINUTE * 6 * IN_MILLISECONDS; // 6 minutes m_uiSlimeboltTimer = 10000; m_bEnraged = false; m_bBerserk = false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 4)) return; @@ -76,7 +76,7 @@ struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI DoScriptText(SAY_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -84,15 +84,15 @@ struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI m_pInstance->SetData(TYPE_PATCHWERK, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - DoScriptText(urand(0, 1)?SAY_AGGRO1:SAY_AGGRO2, m_creature); + DoScriptText(urand(0, 1) ? SAY_AGGRO1 : SAY_AGGRO2, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_PATCHWERK, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_PATCHWERK, FAIL); @@ -136,7 +136,7 @@ struct MANGOS_DLL_DECL boss_patchwerkAI : public ScriptedAI DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_HATEFULSTRIKE : SPELL_HATEFULSTRIKE_H); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/naxxramas/boss_razuvious.cpp b/scripts/northrend/naxxramas/boss_razuvious.cpp index 1f22dad2f..3cdb94ebf 100644 --- a/scripts/northrend/naxxramas/boss_razuvious.cpp +++ b/scripts/northrend/naxxramas/boss_razuvious.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,7 +44,7 @@ enum SPELL_HOPELESS = 29125 }; -struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI +struct boss_razuviousAI : public ScriptedAI { boss_razuviousAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -61,7 +61,7 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI uint32 m_uiJaggedKnifeTimer; uint32 m_uiCommandSoundTimer; - void Reset() + void Reset() override { m_uiUnbalancingStrikeTimer = 30000; // 30 seconds m_uiDisruptingShoutTimer = 15000; // 15 seconds @@ -69,19 +69,19 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI m_uiCommandSoundTimer = 40000; // 40 seconds } - void KilledUnit(Unit* Victim) + void KilledUnit(Unit* /*Victim*/) override { if (urand(0, 3)) return; - switch(urand(0, 1)) + switch (urand(0, 1)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -91,9 +91,9 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI m_pInstance->SetData(TYPE_RAZUVIOUS, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -104,13 +104,13 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI m_pInstance->SetData(TYPE_RAZUVIOUS, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_RAZUVIOUS, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -148,7 +148,7 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI // Random say if (m_uiCommandSoundTimer < uiDiff) { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_COMMAND1, m_creature); break; case 1: DoScriptText(SAY_COMMAND2, m_creature); break; @@ -164,6 +164,7 @@ struct MANGOS_DLL_DECL boss_razuviousAI : public ScriptedAI DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_boss_razuvious(Creature* pCreature) { return new boss_razuviousAI(pCreature); diff --git a/scripts/northrend/naxxramas/boss_sapphiron.cpp b/scripts/northrend/naxxramas/boss_sapphiron.cpp index 502e17150..428cd0430 100644 --- a/scripts/northrend/naxxramas/boss_sapphiron.cpp +++ b/scripts/northrend/naxxramas/boss_sapphiron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -75,7 +75,7 @@ enum Phases PHASE_LANDING = 5, }; -struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI +struct boss_sapphironAI : public ScriptedAI { boss_sapphironAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -100,7 +100,7 @@ struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI uint32 m_uiIceboltCount; Phases m_Phase; - void Reset() + void Reset() override { m_uiCleaveTimer = 5000; m_uiTailSweepTimer = 12000; @@ -116,10 +116,10 @@ struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI SetCombatMovement(true); m_creature->SetLevitate(false); - //m_creature->ApplySpellMod(SPELL_FROST_AURA, SPELLMOD_DURATION, -1); + // m_creature->ApplySpellMod(SPELL_FROST_AURA, SPELLMOD_DURATION, -1); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FROST_AURA : SPELL_FROST_AURA_H); @@ -127,19 +127,19 @@ struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI m_pInstance->SetData(TYPE_SAPPHIRON, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SAPPHIRON, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SAPPHIRON, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_YOU_KNOW_WHO) { @@ -148,7 +148,7 @@ struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI } } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 /*uiPointId*/) override { if (uiType == POINT_MOTION_TYPE && m_Phase == PHASE_LIFT_OFF) { @@ -163,7 +163,7 @@ struct MANGOS_DLL_DECL boss_sapphironAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -322,6 +322,25 @@ CreatureAI* GetAI_boss_sapphiron(Creature* pCreature) return new boss_sapphironAI(pCreature); } +bool GOUse_go_sapphiron_birth(Player* pPlayer, GameObject* pGo) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_SAPPHIRON) != NOT_STARTED) + return true; + + // If already summoned return (safety check) + if (pInstance->GetSingleCreatureFromStorage(NPC_SAPPHIRON, true)) + return true; + + // Set data to special and allow the Go animation to proceed + pInstance->SetData(TYPE_SAPPHIRON, SPECIAL); + return false; +} + void AddSC_boss_sapphiron() { Script* pNewScript; @@ -330,4 +349,9 @@ void AddSC_boss_sapphiron() pNewScript->Name = "boss_sapphiron"; pNewScript->GetAI = &GetAI_boss_sapphiron; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_sapphiron_birth"; + pNewScript->pGOUse = &GOUse_go_sapphiron_birth; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/naxxramas/boss_thaddius.cpp b/scripts/northrend/naxxramas/boss_thaddius.cpp index 7e6cbeba6..612bab2cd 100644 --- a/scripts/northrend/naxxramas/boss_thaddius.cpp +++ b/scripts/northrend/naxxramas/boss_thaddius.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ enum SAY_STAL_SLAY = -1533024, SAY_STAL_DEATH = -1533025, - //Feugen + // Feugen SAY_FEUG_AGGRO = -1533026, SAY_FEUG_SLAY = -1533027, SAY_FEUG_DEATH = -1533028, @@ -47,7 +47,7 @@ enum EMOTE_LOSING_LINK = -1533149, EMOTE_TESLA_OVERLOAD = -1533150, - //Thaddus + // Thaddus SAY_AGGRO_1 = -1533030, SAY_AGGRO_2 = -1533031, SAY_AGGRO_3 = -1533032, @@ -72,7 +72,7 @@ enum SPELL_CLEAR_CHARGES = 63133, // TODO NYI, cast on death, most likely to remove remaining buffs // Stalagg & Feugen Spells - //SPELL_WARSTOMP = 28125, // Not used in Wotlk Version + // SPELL_WARSTOMP = 28125, // Not used in Wotlk Version SPELL_MAGNETIC_PULL_A = 28338, SPELL_MAGNETIC_PULL_B = 54517, // used by Feugen (wotlk) SPELL_STATIC_FIELD = 28135, @@ -87,14 +87,14 @@ enum SPELL_STALAGG_TESLA_PASSIVE = 28097, SPELL_SHOCK_OVERLOAD = 28159, SPELL_SHOCK = 28099, - }; +}; /************ ** boss_thaddius ************/ // Actually this boss behaves like a NoMovement Boss (SPELL_BALL_LIGHTNING) - but there are some movement packages used, unknown what this means! -struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI +struct boss_thaddiusAI : public Scripted_NoMovementAI { boss_thaddiusAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { @@ -112,19 +112,19 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI uint32 m_uiBallLightningTimer; uint32 m_uiBerserkTimer; - void Reset() + void Reset() override { - m_uiPolarityShiftTimer = 15*IN_MILLISECONDS; - m_uiChainLightningTimer = 8*IN_MILLISECONDS; - m_uiBallLightningTimer = 1*IN_MILLISECONDS; - m_uiBerserkTimer = 6*MINUTE*IN_MILLISECONDS; + m_uiPolarityShiftTimer = 15 * IN_MILLISECONDS; + m_uiChainLightningTimer = 8 * IN_MILLISECONDS; + m_uiBallLightningTimer = 1 * IN_MILLISECONDS; + m_uiBerserkTimer = 6 * MINUTE * IN_MILLISECONDS; m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch (urand(0,2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -135,7 +135,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) { @@ -157,7 +157,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -165,7 +165,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI DoScriptText(SAY_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -184,7 +184,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_pInstance) return; @@ -196,7 +196,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI if (m_uiBerserkTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_BESERK) == CAST_OK) // allow combat movement? - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; } else m_uiBerserkTimer -= uiDiff; @@ -208,7 +208,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI { DoScriptText(SAY_ELECT, m_creature); DoScriptText(EMOTE_POLARITY_SHIFT, m_creature); - m_uiPolarityShiftTimer = 30*IN_MILLISECONDS; + m_uiPolarityShiftTimer = 30 * IN_MILLISECONDS; } } else @@ -219,7 +219,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI { Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); if (pTarget && DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING_H) == CAST_OK) - m_uiChainLightningTimer = 15*IN_MILLISECONDS; + m_uiChainLightningTimer = 15 * IN_MILLISECONDS; } else m_uiChainLightningTimer -= uiDiff; @@ -231,7 +231,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAI : public Scripted_NoMovementAI if (m_uiBallLightningTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BALL_LIGHTNING) == CAST_OK) - m_uiBallLightningTimer = 1*IN_MILLISECONDS; + m_uiBallLightningTimer = 1 * IN_MILLISECONDS; } else m_uiBallLightningTimer -= uiDiff; @@ -246,7 +246,7 @@ CreatureAI* GetAI_boss_thaddius(Creature* pCreature) return new boss_thaddiusAI(pCreature); } -bool EffectDummyNPC_spell_thaddius_encounter(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyNPC_spell_thaddius_encounter(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { switch (uiSpellId) { @@ -279,12 +279,12 @@ bool EffectDummyNPC_spell_thaddius_encounter(Unit* pCaster, uint32 uiSpellId, Sp ** npc_tesla_coil ************/ -struct MANGOS_DLL_DECL npc_tesla_coilAI : public Scripted_NoMovementAI +struct npc_tesla_coilAI : public Scripted_NoMovementAI { npc_tesla_coilAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { m_pInstance = (instance_naxxramas*)pCreature->GetInstanceData(); - m_uiSetupTimer = 1*IN_MILLISECONDS; + m_uiSetupTimer = 1 * IN_MILLISECONDS; m_uiOverloadTimer = 0; m_bReapply = false; Reset(); @@ -297,10 +297,10 @@ struct MANGOS_DLL_DECL npc_tesla_coilAI : public Scripted_NoMovementAI uint32 m_uiSetupTimer; uint32 m_uiOverloadTimer; - void Reset() {} - void MoveInLineOfSight(Unit* pWho) {} + void Reset() override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(EMOTE_LOSING_LINK, m_creature); } @@ -308,7 +308,7 @@ struct MANGOS_DLL_DECL npc_tesla_coilAI : public Scripted_NoMovementAI // Overwrite this function here to // * Keep Chain spells casted when evading after useless EnterCombat caused by 'buffing' the add // * To not remove the Passive spells when evading after ie killed a player - void EnterEvadeMode() + void EnterEvadeMode() override { m_creature->DeleteThreatList(); m_creature->CombatStop(); @@ -360,10 +360,10 @@ struct MANGOS_DLL_DECL npc_tesla_coilAI : public Scripted_NoMovementAI void SetOverloading() { - m_uiOverloadTimer = 14*IN_MILLISECONDS; // it takes some time to overload and activate Thaddius + m_uiOverloadTimer = 14 * IN_MILLISECONDS; // it takes some time to overload and activate Thaddius } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { m_creature->SelectHostileTarget(); @@ -377,7 +377,7 @@ struct MANGOS_DLL_DECL npc_tesla_coilAI : public Scripted_NoMovementAI if (SetupChain()) m_uiSetupTimer = 0; else - m_uiSetupTimer = 5*IN_MILLISECONDS; + m_uiSetupTimer = 5 * IN_MILLISECONDS; } else m_uiSetupTimer -= uiDiff; @@ -411,7 +411,7 @@ CreatureAI* GetAI_npc_tesla_coil(Creature* pCreature) ** boss_thaddiusAddsAI - Superclass for Feugen & Stalagg ************/ -struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI +struct boss_thaddiusAddsAI : public ScriptedAI { boss_thaddiusAddsAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -428,17 +428,17 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI bool m_bBothDead; uint32 m_uiHoldTimer; - //uint32 m_uiWarStompTimer; + // uint32 m_uiWarStompTimer; uint32 m_uiReviveTimer; - void Reset() + void Reset() override { m_bFakeDeath = false; m_bBothDead = false; - m_uiReviveTimer = 5*IN_MILLISECONDS; - m_uiHoldTimer = 2*IN_MILLISECONDS; - //m_uiWarStompTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); + m_uiReviveTimer = 5 * IN_MILLISECONDS; + m_uiHoldTimer = 2 * IN_MILLISECONDS; + // m_uiWarStompTimer = urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS); // We might Reset while faking death, so undo this m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -457,7 +457,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (!m_pInstance) return; @@ -471,11 +471,11 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI } } - void JustRespawned() + void JustRespawned() override { Reset(); // Needed to reset the flags properly - GUIDList lTeslaGUIDList; + GuidList lTeslaGUIDList; if (!m_pInstance) return; @@ -483,24 +483,24 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI if (lTeslaGUIDList.empty()) return; - for (GUIDList::const_iterator itr = lTeslaGUIDList.begin(); itr != lTeslaGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = lTeslaGUIDList.begin(); itr != lTeslaGUIDList.end(); ++itr) { if (Creature* pTesla = m_pInstance->instance->GetCreature(*itr)) { - if (npc_tesla_coilAI* pTeslaAI = dynamic_cast (pTesla->AI())) + if (npc_tesla_coilAI* pTeslaAI = dynamic_cast(pTesla->AI())) pTeslaAI->ReApplyChain(m_creature->GetEntry()); } } } - void JustReachedHome() + void JustReachedHome() override { if (!m_pInstance) return; if (Creature* pOther = GetOtherAdd()) { - if (boss_thaddiusAddsAI* pOtherAI = dynamic_cast (pOther->AI())) + if (boss_thaddiusAddsAI* pOtherAI = dynamic_cast(pOther->AI())) { if (pOtherAI->IsCountingDead()) { @@ -535,9 +535,9 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI m_uiHoldTimer = 1500; } - virtual void UpdateAddAI(const uint32 uiDiff) {} // Used for Add-specific spells + virtual void UpdateAddAI(const uint32 /*uiDiff*/) {} // Used for Add-specific spells - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bBothDead) // This is the case while fighting Thaddius return; @@ -548,7 +548,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI { if (Creature* pOther = GetOtherAdd()) { - if (boss_thaddiusAddsAI* pOtherAI = dynamic_cast (pOther->AI())) + if (boss_thaddiusAddsAI* pOtherAI = dynamic_cast(pOther->AI())) { if (!pOtherAI->IsCountingDead()) // Raid was to slow to kill the second add Revive(); @@ -557,13 +557,13 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI m_bBothDead = true; // Now both adds are counting dead pOtherAI->m_bBothDead = true; // Set both Teslas to overload - GUIDList lTeslaGUIDList; + GuidList lTeslaGUIDList; m_pInstance->GetThadTeslaCreatures(lTeslaGUIDList); - for (GUIDList::const_iterator itr = lTeslaGUIDList.begin(); itr != lTeslaGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = lTeslaGUIDList.begin(); itr != lTeslaGUIDList.end(); ++itr) { if (Creature* pTesla = m_pInstance->instance->GetCreature(*itr)) { - if (npc_tesla_coilAI* pTeslaAI = dynamic_cast (pTesla->AI())) + if (npc_tesla_coilAI* pTeslaAI = dynamic_cast(pTesla->AI())) pTeslaAI->SetOverloading(); } } @@ -605,7 +605,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI DoMeleeAttackIfReady(); } - void DamageTaken(Unit* pKiller, uint32& uiDamage) + void DamageTaken(Unit* pKiller, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; @@ -642,7 +642,7 @@ struct MANGOS_DLL_DECL boss_thaddiusAddsAI : public ScriptedAI ** boss_stalagg ************/ -struct MANGOS_DLL_DECL boss_stalaggAI : public boss_thaddiusAddsAI +struct boss_stalaggAI : public boss_thaddiusAddsAI { boss_stalaggAI(Creature* pCreature) : boss_thaddiusAddsAI(pCreature) { @@ -650,24 +650,24 @@ struct MANGOS_DLL_DECL boss_stalaggAI : public boss_thaddiusAddsAI } uint32 m_uiPowerSurgeTimer; - void Reset() + void Reset() override { boss_thaddiusAddsAI::Reset(); - m_uiPowerSurgeTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiPowerSurgeTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoScriptText(SAY_STAL_AGGRO, m_creature); boss_thaddiusAddsAI::Aggro(pWho); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - DoScriptText(SAY_STAL_DEATH, m_creature); + DoScriptText(SAY_STAL_DEATH, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) DoScriptText(SAY_STAL_SLAY, m_creature); @@ -678,7 +678,7 @@ struct MANGOS_DLL_DECL boss_stalaggAI : public boss_thaddiusAddsAI if (m_uiPowerSurgeTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_POWERSURGE : SPELL_POWERSURGE_H) == CAST_OK) - m_uiPowerSurgeTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiPowerSurgeTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); } else m_uiPowerSurgeTimer -= uiDiff; @@ -694,34 +694,34 @@ CreatureAI* GetAI_boss_stalagg(Creature* pCreature) ** boss_feugen ************/ -struct MANGOS_DLL_DECL boss_feugenAI : public boss_thaddiusAddsAI +struct boss_feugenAI : public boss_thaddiusAddsAI { boss_feugenAI(Creature* pCreature) : boss_thaddiusAddsAI(pCreature) { Reset(); } uint32 m_uiStaticFieldTimer; - uint32 m_uiMagneticPullTimer; // TODO, missing + uint32 m_uiMagneticPullTimer; // TODO, missing - void Reset() + void Reset() override { boss_thaddiusAddsAI::Reset(); - m_uiStaticFieldTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); - m_uiMagneticPullTimer = 20*IN_MILLISECONDS; + m_uiStaticFieldTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); + m_uiMagneticPullTimer = 20 * IN_MILLISECONDS; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { DoScriptText(SAY_FEUG_AGGRO, m_creature); boss_thaddiusAddsAI::Aggro(pWho); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_FEUG_DEATH, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) DoScriptText(SAY_FEUG_SLAY, m_creature); @@ -732,7 +732,7 @@ struct MANGOS_DLL_DECL boss_feugenAI : public boss_thaddiusAddsAI if (m_uiStaticFieldTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STATIC_FIELD : SPELL_STATIC_FIELD_H) == CAST_OK) - m_uiStaticFieldTimer = urand(10*IN_MILLISECONDS, 15*IN_MILLISECONDS); + m_uiStaticFieldTimer = urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS); } else m_uiStaticFieldTimer -= uiDiff; diff --git a/scripts/northrend/naxxramas/instance_naxxramas.cpp b/scripts/northrend/naxxramas/instance_naxxramas.cpp index 784a53a32..b9fb7bc5f 100644 --- a/scripts/northrend/naxxramas/instance_naxxramas.cpp +++ b/scripts/northrend/naxxramas/instance_naxxramas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,20 +26,33 @@ EndScriptData */ static const DialogueEntry aNaxxDialogue[] = { - {SAY_SAPP_DIALOG1, NPC_KELTHUZAD, 6000}, - {SAY_SAPP_DIALOG2_LICH, NPC_THE_LICHKING, 6000}, + {NPC_KELTHUZAD, 0, 10000}, + {SAY_SAPP_DIALOG1, NPC_KELTHUZAD, 8000}, + {SAY_SAPP_DIALOG2_LICH, NPC_THE_LICHKING, 14000}, {SAY_SAPP_DIALOG3, NPC_KELTHUZAD, 10000}, {SAY_SAPP_DIALOG4_LICH, NPC_THE_LICHKING, 12000}, {SAY_SAPP_DIALOG5, NPC_KELTHUZAD, 0}, - {0,0,0} + {NPC_THANE, 0, 10000}, + {SAY_KORT_TAUNT1, NPC_THANE, 5000}, + {SAY_ZELI_TAUNT1, NPC_ZELIEK, 6000}, + {SAY_BLAU_TAUNT1, NPC_BLAUMEUX, 6000}, + {SAY_RIVE_TAUNT1, NPC_RIVENDARE, 6000}, + {SAY_BLAU_TAUNT2, NPC_BLAUMEUX, 6000}, + {SAY_ZELI_TAUNT2, NPC_ZELIEK, 5000}, + {SAY_KORT_TAUNT2, NPC_THANE, 7000}, + {SAY_RIVE_TAUNT2, NPC_RIVENDARE, 0}, + {0, 0, 0} }; instance_naxxramas::instance_naxxramas(Map* pMap) : ScriptedInstance(pMap), - m_uiTauntTimer(0), - m_dialogueHelper(aNaxxDialogue), m_fChamberCenterX(0.0f), m_fChamberCenterY(0.0f), - m_fChamberCenterZ(0.0f) + m_fChamberCenterZ(0.0f), + m_uiSapphSpawnTimer(0), + m_uiTauntTimer(0), + m_uiHorsemenAchievTimer(0), + m_uiHorseMenKilled(0), + m_dialogueHelper(aNaxxDialogue) { Initialize(); } @@ -54,9 +67,22 @@ void instance_naxxramas::Initialize() m_dialogueHelper.InitializeDialogueHelper(this, true); } +void instance_naxxramas::OnPlayerEnter(Player* pPlayer) +{ + // Function only used to summon Sapphiron in case of server reload + if (GetData(TYPE_SAPPHIRON) != SPECIAL) + return; + + // Check if already summoned + if (GetSingleCreatureFromStorage(NPC_SAPPHIRON, true)) + return; + + pPlayer->SummonCreature(NPC_SAPPHIRON, aSapphPositions[0], aSapphPositions[1], aSapphPositions[2], aSapphPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); +} + void instance_naxxramas::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_ANUB_REKHAN: case NPC_FAERLINA: @@ -68,6 +94,7 @@ void instance_naxxramas::OnCreatureCreate(Creature* pCreature) case NPC_BLAUMEUX: case NPC_RIVENDARE: case NPC_GOTHIK: + case NPC_SAPPHIRON: case NPC_KELTHUZAD: case NPC_THE_LICHKING: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); @@ -80,9 +107,9 @@ void instance_naxxramas::OnCreatureCreate(Creature* pCreature) void instance_naxxramas::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - // Arachnid Quarter + // Arachnid Quarter case GO_ARAC_ANUB_DOOR: break; case GO_ARAC_ANUB_GATE: @@ -102,7 +129,7 @@ void instance_naxxramas::OnObjectCreate(GameObject* pGo) pGo->SetGoState(GO_STATE_ACTIVE); break; - // Plague Quarter + // Plague Quarter case GO_PLAG_NOTH_ENTRY_DOOR: break; case GO_PLAG_NOTH_EXIT_DOOR: @@ -120,7 +147,7 @@ void instance_naxxramas::OnObjectCreate(GameObject* pGo) case GO_PLAG_LOAT_DOOR: break; - // Military Quarter + // Military Quarter case GO_MILI_GOTH_ENTRY_GATE: break; case GO_MILI_GOTH_EXIT_GATE: @@ -137,7 +164,7 @@ void instance_naxxramas::OnObjectCreate(GameObject* pGo) case GO_CHEST_HORSEMEN_HERO: break; - // Construct Quarter + // Construct Quarter case GO_CONS_PATH_EXIT_DOOR: if (m_auiEncounter[TYPE_PATCHWERK] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); @@ -159,7 +186,7 @@ void instance_naxxramas::OnObjectCreate(GameObject* pGo) pGo->SetGoState(GO_STATE_READY); break; - // Frostwyrm Lair + // Frostwyrm Lair case GO_KELTHUZAD_WATERFALL_DOOR: if (m_auiEncounter[TYPE_SAPPHIRON] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); @@ -167,29 +194,44 @@ void instance_naxxramas::OnObjectCreate(GameObject* pGo) case GO_KELTHUZAD_EXIT_DOOR: break; - // Eyes + // Eyes case GO_ARAC_EYE_RAMP: + case GO_ARAC_EYE_BOSS: if (m_auiEncounter[TYPE_MAEXXNA] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PLAG_EYE_RAMP: + case GO_PLAG_EYE_BOSS: if (m_auiEncounter[TYPE_LOATHEB] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_MILI_EYE_RAMP: + case GO_MILI_EYE_BOSS: if (m_auiEncounter[TYPE_FOUR_HORSEMEN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_CONS_EYE_RAMP: + case GO_CONS_EYE_BOSS: if (m_auiEncounter[TYPE_THADDIUS] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - // Portals + // Portals case GO_ARAC_PORTAL: + if (m_auiEncounter[TYPE_MAEXXNA] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; case GO_PLAG_PORTAL: + if (m_auiEncounter[TYPE_LOATHEB] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; case GO_MILI_PORTAL: + if (m_auiEncounter[TYPE_FOUR_HORSEMEN] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; case GO_CONS_PORTAL: + if (m_auiEncounter[TYPE_THADDIUS] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; default: @@ -213,7 +255,7 @@ void instance_naxxramas::OnObjectCreate(GameObject* pGo) m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } -void instance_naxxramas::OnPlayerDeath(Player* pPlayer) +void instance_naxxramas::OnPlayerDeath(Player* /*pPlayer*/) { if (IsEncounterInProgress()) SetData(TYPE_UNDYING_FAILED, DONE); @@ -245,7 +287,7 @@ bool instance_naxxramas::IsEncounterInProgress() const void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_ANUB_REKHAN: m_auiEncounter[uiType] = uiData; @@ -260,7 +302,7 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_ARAC_FAER_WEB); if (uiData == IN_PROGRESS) SetSpecialAchievementCriteria(TYPE_ACHIEV_KNOCK_YOU_OUT, true); - if (uiData == DONE) + else if (uiData == DONE) { DoUseDoorOrButton(GO_ARAC_FAER_DOOR); DoUseDoorOrButton(GO_ARAC_MAEX_OUTER_DOOR); @@ -273,7 +315,9 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) if (uiData == DONE) { DoUseDoorOrButton(GO_ARAC_EYE_RAMP); - DoRespawnGameObject(GO_ARAC_PORTAL, 30*MINUTE); + DoUseDoorOrButton(GO_ARAC_EYE_BOSS); + DoRespawnGameObject(GO_ARAC_PORTAL, 30 * MINUTE); + DoToggleGameObjectFlags(GO_ARAC_PORTAL, GO_FLAG_NO_INTERACT, false); m_uiTauntTimer = 5000; } break; @@ -291,7 +335,7 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_PLAG_HEIG_ENTRY_DOOR); if (uiData == IN_PROGRESS) SetSpecialAchievementCriteria(TYPE_ACHIEV_SAFETY_DANCE, true); - if (uiData == DONE) + else if (uiData == DONE) DoUseDoorOrButton(GO_PLAG_HEIG_EXIT_DOOR); break; case TYPE_LOATHEB: @@ -299,10 +343,12 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_PLAG_LOAT_DOOR); if (uiData == IN_PROGRESS) SetSpecialAchievementCriteria(TYPE_ACHIEV_SPORE_LOSER, true); - if (uiData == DONE) + else if (uiData == DONE) { DoUseDoorOrButton(GO_PLAG_EYE_RAMP); - DoRespawnGameObject(GO_PLAG_PORTAL, 30*MINUTE); + DoUseDoorOrButton(GO_PLAG_EYE_BOSS); + DoRespawnGameObject(GO_PLAG_PORTAL, 30 * MINUTE); + DoToggleGameObjectFlags(GO_PLAG_PORTAL, GO_FLAG_NO_INTERACT, false); m_uiTauntTimer = 5000; } break; @@ -310,7 +356,7 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; case TYPE_GOTHIK: - switch(uiData) + switch (uiData) { case IN_PROGRESS: DoUseDoorOrButton(GO_MILI_GOTH_ENTRY_GATE); @@ -329,26 +375,50 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_MILI_GOTH_ENTRY_GATE); DoUseDoorOrButton(GO_MILI_GOTH_EXIT_GATE); DoUseDoorOrButton(GO_MILI_HORSEMEN_DOOR); + + m_dialogueHelper.StartNextDialogueText(NPC_THANE); break; } m_auiEncounter[uiType] = uiData; break; case TYPE_FOUR_HORSEMEN: - m_auiEncounter[uiType] = uiData; - DoUseDoorOrButton(GO_MILI_HORSEMEN_DOOR); - if (uiData == DONE) + // Skip if already set + if (m_auiEncounter[uiType] == uiData) + return; + + if (uiData == SPECIAL) + { + // Start the achiev countdown + if (!m_uiHorseMenKilled) + m_uiHorsemenAchievTimer = 15000; + + ++m_uiHorseMenKilled; + + if (m_uiHorseMenKilled == 4) + SetData(TYPE_FOUR_HORSEMEN, DONE); + + // Don't store special data + return; + } + else if (uiData == FAIL) + m_uiHorseMenKilled = 0; + else if (uiData == DONE) { DoUseDoorOrButton(GO_MILI_EYE_RAMP); - DoRespawnGameObject(GO_MILI_PORTAL, 30*MINUTE); - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CHEST_HORSEMEN_NORM : GO_CHEST_HORSEMEN_HERO, 30*MINUTE); + DoUseDoorOrButton(GO_MILI_EYE_BOSS); + DoRespawnGameObject(GO_MILI_PORTAL, 30 * MINUTE); + DoToggleGameObjectFlags(GO_MILI_PORTAL, GO_FLAG_NO_INTERACT, false); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CHEST_HORSEMEN_NORM : GO_CHEST_HORSEMEN_HERO, 30 * MINUTE); m_uiTauntTimer = 5000; } + DoUseDoorOrButton(GO_MILI_HORSEMEN_DOOR); + m_auiEncounter[uiType] = uiData; break; case TYPE_PATCHWERK: m_auiEncounter[uiType] = uiData; if (uiData == IN_PROGRESS) DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_PATCHWERK_ID); - if (uiData == DONE) + else if (uiData == DONE) DoUseDoorOrButton(GO_CONS_PATH_EXIT_DOOR); break; case TYPE_GROBBULUS: @@ -371,25 +441,30 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) if (uiData != SPECIAL) DoUseDoorOrButton(GO_CONS_THAD_DOOR, uiData); // Uncomment when this achievement is implemented - //if (uiData == IN_PROGRESS) + // if (uiData == IN_PROGRESS) // SetSpecialAchievementCriteria(TYPE_ACHIEV_SHOCKING, true); if (uiData == DONE) { DoUseDoorOrButton(GO_CONS_EYE_RAMP); - DoRespawnGameObject(GO_CONS_PORTAL, 30*MINUTE); + DoUseDoorOrButton(GO_CONS_EYE_BOSS); + DoRespawnGameObject(GO_CONS_PORTAL, 30 * MINUTE); + DoToggleGameObjectFlags(GO_CONS_PORTAL, GO_FLAG_NO_INTERACT, false); m_uiTauntTimer = 5000; } break; case TYPE_SAPPHIRON: m_auiEncounter[uiType] = uiData; // Uncomment when achiev check implemented - //if (uiData == IN_PROGRESS) + // if (uiData == IN_PROGRESS) // SetSpecialAchievementCriteria(TYPE_ACHIEV_HUNDRED_CLUB, true); if (uiData == DONE) { DoUseDoorOrButton(GO_KELTHUZAD_WATERFALL_DOOR); - m_dialogueHelper.StartNextDialogueText(SAY_SAPP_DIALOG1); + m_dialogueHelper.StartNextDialogueText(NPC_KELTHUZAD); } + // Start Sapph summoning process + if (uiData == SPECIAL) + m_uiSapphSpawnTimer = 22000; break; case TYPE_KELTHUZAD: m_auiEncounter[uiType] = uiData; @@ -402,16 +477,16 @@ void instance_naxxramas::SetData(uint32 uiType, uint32 uiData) break; } - if (uiData == DONE) + if (uiData == DONE || (uiData == SPECIAL && uiType == TYPE_SAPPHIRON)) { OUT_SAVE_INST_DATA; std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] << " " - << m_auiEncounter[12] << " " << m_auiEncounter[13] << " " << m_auiEncounter[14] << " " << m_auiEncounter[15]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] << " " + << m_auiEncounter[12] << " " << m_auiEncounter[13] << " " << m_auiEncounter[14] << " " << m_auiEncounter[15]; m_strInstData = saveStream.str(); @@ -432,11 +507,11 @@ void instance_naxxramas::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11] - >> m_auiEncounter[12] >> m_auiEncounter[13] >> m_auiEncounter[14] >> m_auiEncounter[15]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11] + >> m_auiEncounter[12] >> m_auiEncounter[13] >> m_auiEncounter[14] >> m_auiEncounter[15]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -445,7 +520,7 @@ void instance_naxxramas::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_naxxramas::GetData(uint32 uiType) +uint32 instance_naxxramas::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -459,7 +534,7 @@ void instance_naxxramas::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMe m_abAchievCriteria[uiType] = bIsMet; } -bool instance_naxxramas::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_naxxramas::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { @@ -481,7 +556,10 @@ bool instance_naxxramas::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Playe case ACHIEV_CRIT_GET_ENOUGH_N: case ACHIEV_CRIT_GET_ENOUGH_H: return m_abAchievCriteria[TYPE_ACHIEV_GET_ENOUGH]; - // 'The Immortal'(25m) or 'Undying'(10m) - (achievs 2186, 2187) + case ACHIEV_CRIT_TOGETHER_N: + case ACHIEV_CRIT_TOGETHER_H: + return m_uiHorsemenAchievTimer > 0; + // 'The Immortal'(25m) or 'Undying'(10m) - (achievs 2186, 2187) case ACHIEV_CRIT_IMMORTAL_KEL: case ACHIEV_CRIT_IMMOORTAL_LOA: case ACHIEV_CRIT_IMMOORTAL_THAD: @@ -519,6 +597,27 @@ void instance_naxxramas::Update(uint32 uiDiff) m_uiTauntTimer -= uiDiff; } + if (m_uiHorsemenAchievTimer) + { + if (m_uiHorsemenAchievTimer <= uiDiff) + m_uiHorsemenAchievTimer = 0; + else + m_uiHorsemenAchievTimer -= uiDiff; + } + + if (m_uiSapphSpawnTimer) + { + if (m_uiSapphSpawnTimer <= uiDiff) + { + if (Player* pPlayer = GetPlayerInMap()) + pPlayer->SummonCreature(NPC_SAPPHIRON, aSapphPositions[0], aSapphPositions[1], aSapphPositions[2], aSapphPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); + + m_uiSapphSpawnTimer = 0; + } + else + m_uiSapphSpawnTimer -= uiDiff; + } + m_dialogueHelper.DialogueUpdate(uiDiff); } @@ -529,7 +628,7 @@ void instance_naxxramas::SetGothTriggers() if (!pGoth) return; - for(GUIDList::const_iterator itr = m_lGothTriggerList.begin(); itr != m_lGothTriggerList.end(); ++itr) + for (GuidList::const_iterator itr = m_lGothTriggerList.begin(); itr != m_lGothTriggerList.end(); ++itr) { if (Creature* pTrigger = instance->GetCreature(*itr)) { @@ -567,7 +666,7 @@ Creature* instance_naxxramas::GetClosestAnchorForGoth(Creature* pSource, bool bR return NULL; } -void instance_naxxramas::GetGothSummonPointCreatures(std::list &lList, bool bRightSide) +void instance_naxxramas::GetGothSummonPointCreatures(std::list& lList, bool bRightSide) { for (UNORDERED_MAP::iterator itr = m_mGothTriggerMap.begin(); itr != m_mGothTriggerMap.end(); ++itr) { @@ -588,7 +687,7 @@ bool instance_naxxramas::IsInRightSideGothArea(Unit* pUnit) if (GameObject* pCombatGate = GetSingleGameObjectFromStorage(GO_MILI_GOTH_COMBAT_GATE)) return (pCombatGate->GetPositionY() >= pUnit->GetPositionY()); - error_log("SD2: left/right side check, Gothik combat area failed."); + script_error_log("left/right side check, Gothik combat area failed."); return true; } @@ -597,7 +696,7 @@ void instance_naxxramas::DoTriggerHeiganTraps(Creature* pHeigan, uint32 uiAreaIn if (uiAreaIndex >= MAX_HEIGAN_TRAP_AREAS) return; - for (GUIDList::const_iterator itr = m_alHeiganTrapGuids[uiAreaIndex].begin(); itr != m_alHeiganTrapGuids[uiAreaIndex].end(); ++itr) + for (GuidList::const_iterator itr = m_alHeiganTrapGuids[uiAreaIndex].begin(); itr != m_alHeiganTrapGuids[uiAreaIndex].end(); ++itr) { if (GameObject* pTrap = instance->GetGameObject(*itr)) pTrap->Use(pHeigan); @@ -629,7 +728,7 @@ void instance_naxxramas::DoTaunt() if (m_auiEncounter[TYPE_THADDIUS] == DONE) ++uiWingsCleared; - switch(uiWingsCleared) + switch (uiWingsCleared) { case 1: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT1, NPC_KELTHUZAD); break; case 2: DoOrSimulateScriptTextForThisInstance(SAY_KELTHUZAD_TAUNT2, NPC_KELTHUZAD); break; @@ -648,7 +747,7 @@ bool AreaTrigger_at_naxxramas(Player* pPlayer, AreaTriggerEntry const* pAt) { if (pAt->id == AREATRIGGER_KELTHUZAD) { - if (pPlayer->isGameMaster() || pPlayer->isDead()) + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) return false; instance_naxxramas* pInstance = (instance_naxxramas*)pPlayer->GetInstanceData(); diff --git a/scripts/northrend/naxxramas/naxxramas.h b/scripts/northrend/naxxramas/naxxramas.h index 6f54581b4..3567fe1ed 100644 --- a/scripts/northrend/naxxramas/naxxramas.h +++ b/scripts/northrend/naxxramas/naxxramas.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -25,6 +25,19 @@ enum SAY_SAPP_DIALOG3 = -1533086, SAY_SAPP_DIALOG4_LICH = -1533087, SAY_SAPP_DIALOG5 = -1533088, + // Horsemen dialogue texts + SAY_BLAU_TAUNT1 = -1533045, + SAY_BLAU_TAUNT2 = -1533046, + SAY_BLAU_TAUNT3 = -1533047, // NYI - requires additiona research + SAY_RIVE_TAUNT1 = -1533071, + SAY_RIVE_TAUNT2 = -1533072, + SAY_RIVE_TAUNT3 = -1533073, // NYI - requires additiona research + SAY_KORT_TAUNT1 = -1533052, + SAY_KORT_TAUNT2 = -1533053, + SAY_KORT_TAUNT3 = -1533054, // NYI - requires additiona research + SAY_ZELI_TAUNT1 = -1533059, + SAY_ZELI_TAUNT2 = -1533060, + SAY_ZELI_TAUNT3 = -1533061, // NYI - requires additiona research TYPE_ANUB_REKHAN = 0, TYPE_FAERLINA = 1, @@ -72,13 +85,14 @@ enum NPC_BLAUMEUX = 16065, NPC_RIVENDARE = 30549, + NPC_SAPPHIRON = 15989, NPC_KELTHUZAD = 15990, NPC_THE_LICHKING = 16980, NPC_MR_BIGGLESWORTH = 16998, // Gothik NPC_GOTHIK = 16060, - NPC_SUB_BOSS_TRIGGER = 16137, //summon locations + NPC_SUB_BOSS_TRIGGER = 16137, // summon locations NPC_UNREL_TRAINEE = 16124, NPC_UNREL_DEATH_KNIGHT = 16125, NPC_UNREL_RIDER = 16126, @@ -94,29 +108,29 @@ enum NPC_GUARDIAN = 16441, // Arachnid Quarter - GO_ARAC_ANUB_DOOR = 181126, //encounter door - GO_ARAC_ANUB_GATE = 181195, //open after boss is dead - GO_ARAC_FAER_WEB = 181235, //encounter door - GO_ARAC_FAER_DOOR = 194022, //after faerlina, to outer ring - GO_ARAC_MAEX_INNER_DOOR = 181197, //encounter door - GO_ARAC_MAEX_OUTER_DOOR = 181209, //right before maex + GO_ARAC_ANUB_DOOR = 181126, // encounter door + GO_ARAC_ANUB_GATE = 181195, // open after boss is dead + GO_ARAC_FAER_WEB = 181235, // encounter door + GO_ARAC_FAER_DOOR = 194022, // after faerlina, to outer ring + GO_ARAC_MAEX_INNER_DOOR = 181197, // encounter door + GO_ARAC_MAEX_OUTER_DOOR = 181209, // right before maex // Plague Quarter - GO_PLAG_SLIME01_DOOR = 181198, //not used - GO_PLAG_SLIME02_DOOR = 181199, //not used - GO_PLAG_NOTH_ENTRY_DOOR = 181200, //encounter door - GO_PLAG_NOTH_EXIT_DOOR = 181201, //exit, open when boss dead + GO_PLAG_SLIME01_DOOR = 181198, // not used + GO_PLAG_SLIME02_DOOR = 181199, // not used + GO_PLAG_NOTH_ENTRY_DOOR = 181200, // encounter door + GO_PLAG_NOTH_EXIT_DOOR = 181201, // exit, open when boss dead GO_PLAG_HEIG_ENTRY_DOOR = 181202, - GO_PLAG_HEIG_EXIT_DOOR = 181203, //exit, open when boss dead - GO_PLAG_LOAT_DOOR = 181241, //encounter door + GO_PLAG_HEIG_EXIT_DOOR = 181203, // exit, open when boss dead + GO_PLAG_LOAT_DOOR = 181241, // encounter door // Military Quarter - GO_MILI_GOTH_ENTRY_GATE = 181124, //used while encounter is in progress - GO_MILI_GOTH_EXIT_GATE = 181125, //exit, open at boss dead - GO_MILI_GOTH_COMBAT_GATE = 181170, //used while encounter is in progress - GO_MILI_HORSEMEN_DOOR = 181119, //encounter door + GO_MILI_GOTH_ENTRY_GATE = 181124, // used while encounter is in progress + GO_MILI_GOTH_EXIT_GATE = 181125, // exit, open at boss dead + GO_MILI_GOTH_COMBAT_GATE = 181170, // used while encounter is in progress + GO_MILI_HORSEMEN_DOOR = 181119, // encounter door - GO_CHEST_HORSEMEN_NORM = 181366, //four horsemen event, DoRespawnGameObject() when event == DONE + GO_CHEST_HORSEMEN_NORM = 181366, // four horsemen event, DoRespawnGameObject() when event == DONE GO_CHEST_HORSEMEN_HERO = 193426, // Construct Quarter @@ -136,6 +150,11 @@ enum GO_MILI_EYE_RAMP = 181210, GO_CONS_EYE_RAMP = 181213, + GO_ARAC_EYE_BOSS = 181233, + GO_PLAG_EYE_BOSS = 181231, + GO_MILI_EYE_BOSS = 181230, + GO_CONS_EYE_BOSS = 181232, + // Portals GO_ARAC_PORTAL = 181575, GO_PLAG_PORTAL = 181577, @@ -154,6 +173,8 @@ enum ACHIEV_CRIT_KNOCK_YOU_OUT_H = 7549, ACHIEV_CRIT_HUNDRED_CLUB_N = 7567, // Sapphiron, achievs 2146, 2147 ACHIEV_CRIT_HUNDRED_CLUB_H = 7568, + ACHIEV_CRIT_TOGETHER_N = 7600, // Four Horsemen, achievs 2176, 2177 + ACHIEV_CRIT_TOGETHER_H = 7601, ACHIEV_CRIT_SHOCKING_N = 7604, // Thaddius, achievs 2178, 2179 ACHIEV_CRIT_SHOCKING_H = 7605, ACHIEV_CRIT_SPORE_LOSER_N = 7612, // Loatheb, achievs 2182, 2183 @@ -184,32 +205,35 @@ struct GothTrigger bool bIsAnchorHigh; }; -class MANGOS_DLL_DECL instance_naxxramas : public ScriptedInstance +static const float aSapphPositions[4] = {3521.48f, -5234.87f, 137.626f, 4.53329f}; + +class instance_naxxramas : public ScriptedInstance { public: instance_naxxramas(Map* pMap); ~instance_naxxramas() {} - void Initialize(); + void Initialize() override; - bool IsEncounterInProgress() const; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnPlayerDeath(Player* pPlayer); - void OnCreatureDeath(Creature* pCreature); + void OnPlayerDeath(Player* pPlayer) override; + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; // Heigan void DoTriggerHeiganTraps(Creature* pHeigan, uint32 uiAreaIndex); @@ -217,15 +241,15 @@ class MANGOS_DLL_DECL instance_naxxramas : public ScriptedInstance // goth void SetGothTriggers(); Creature* GetClosestAnchorForGoth(Creature* pSource, bool bRightSide); - void GetGothSummonPointCreatures(std::list &lList, bool bRightSide); + void GetGothSummonPointCreatures(std::list& lList, bool bRightSide); bool IsInRightSideGothArea(Unit* pUnit); // thaddius - void GetThadTeslaCreatures(GUIDList &lList){ lList = m_lThadTeslaCoilList; }; + void GetThadTeslaCreatures(GuidList& lList) { lList = m_lThadTeslaCoilList; }; // kel void SetChamberCenterCoords(float fX, float fY, float fZ); - void GetChamberCenterCoords(float &fX, float &fY, float &fZ) { fX = m_fChamberCenterX; fY = m_fChamberCenterY; fZ = m_fChamberCenterZ; } + void GetChamberCenterCoords(float& fX, float& fY, float& fZ) { fX = m_fChamberCenterX; fY = m_fChamberCenterY; fZ = m_fChamberCenterZ; } void DoTaunt(); protected: @@ -233,17 +257,20 @@ class MANGOS_DLL_DECL instance_naxxramas : public ScriptedInstance bool m_abAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; std::string m_strInstData; - GUIDList m_lThadTeslaCoilList; - GUIDList m_lGothTriggerList; + GuidList m_lThadTeslaCoilList; + GuidList m_lGothTriggerList; UNORDERED_MAP m_mGothTriggerMap; - GUIDList m_alHeiganTrapGuids[MAX_HEIGAN_TRAP_AREAS]; + GuidList m_alHeiganTrapGuids[MAX_HEIGAN_TRAP_AREAS]; float m_fChamberCenterX; float m_fChamberCenterY; float m_fChamberCenterZ; + uint32 m_uiSapphSpawnTimer; uint32 m_uiTauntTimer; + uint32 m_uiHorsemenAchievTimer; + uint8 m_uiHorseMenKilled; DialogueHelper m_dialogueHelper; }; diff --git a/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp b/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp index 3a11c4b41..a6f1e82d6 100644 --- a/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp +++ b/scripts/northrend/nexus/eye_of_eternity/boss_malygos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,14 @@ /* ScriptData SDName: boss_malygos -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 80 +SDComment: Timers need adjustments; Vortex event NYI; Npc movement in Phase 2 NYI. SDCategory: Eye of Eternity EndScriptData */ #include "precompiled.h" +#include "eye_of_eternity.h" +#include "TemporarySummon.h" enum { @@ -54,15 +56,668 @@ enum SAY_SPELL_2 = -1616026, SAY_SPELL_3 = -1616027, SAY_DEATH = -1616028, - SAY_OUTRO_1 = -1616029, - SAY_OUTRO_2 = -1616030, - SAY_OUTRO_3 = -1616031, - SAY_OUTRO_4 = -1616032, SAY_EMOTE_SPARK = -1616033, SAY_EMOTE_BREATH = -1616034, + + // phase 1 spells + SPELL_BERSERK = 26662, + SPELL_ARCANE_BREATH = 56272, + SPELL_ARCANE_BREATH_H = 60072, + SPELL_SUMMON_SPARK = 56140, + SPELL_VORTEX = 56105, + + // phase 2 spells + SPELL_ARCANE_STORM = 57459, // related to spell 61693 + SPELL_ARCANE_STORM_H = 61694, + SPELL_SUMMON_ARCANE_BOMB = 56429, // summons 30282 + SPELL_ARCANE_BOMB = 56430, // triggers 56432 and 56431 on target hit + SPELL_SURGE_OF_POWER_PULSE = 56505, // deep breath spell + // SPELL_ARCANE_PULSE = 57432, // purpose unk + + // transition spells + SPELL_DESTROY_PLATFORM_PRE = 58842, + SPELL_DESTROY_PLATFORM_BOOM = 59084, + SPELL_DESTROY_PLATFORM_EVENT = 59099, + SPELL_SUMMON_RED_DRAGON = 58846, + + // phase 3 spells + SPELL_STATIC_FIELD_SUMMON = 57430, // cast on 1 or 3 targets based on difficulty + SPELL_SURGE_OF_POWER = 57407, // related to 60936 and 60939 + + // power spark + SPELL_POWER_SPARK_MALYGOS = 56152, + SPELL_POWER_SPARK_PLAYERS = 55852, + SPELL_POWER_SPARK_VISUAL = 55845, + + // vortex - thse spells require additional research + // related auras: 55853, 55883, 56263, 56264, 56265, 56266, 59666, 61071, 61072, 61073, 61074, 61075 + SPELL_VORTEX_SPAWN = 59670, + SPELL_VORTEX_VISUAL = 55873, + SPELL_VORTEX_CHANNEL = 56237, + + // arcane overload - handled in core + // SPELL_ARCANE_OVERLOAD = 56432, + // SPELL_ARCANE_BOMB_KNOCKBACK = 56431, + + // static field + SPELL_STATIC_FIELD = 57428, + + // vehicle related + SPELL_SUMMON_DISC = 56378, // summons npc 30234 for players + SPELL_RIDE_RED_DRAGON = 56072, + SPELL_FLIGHT = 60534, // ToDo: check if id is correct! + + // summoned npcs + NPC_VORTEX = 30090, + NPC_POWER_SPARK = 30084, + + NPC_NEXUS_LORD = 30245, + NPC_HOVER_DISK = 30248, + NPC_SCION_OF_ETERNITY = 30249, + NPC_ARCANE_OVERLOAD = 30282, + + NPC_STATIC_FIELD = 30592, + + // phases + PHASE_FLOOR = 1, + PHASE_TRANSITION_1 = 2, + PHASE_DISCS = 3, + PHASE_TRANSITION_2 = 4, + PHASE_DRAGONS = 5, + + POINT_ID_COMBAT = 1, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + // Intro dialogue + {SAY_INTRO_1, NPC_MALYGOS, 11000}, + {SAY_INTRO_2, NPC_MALYGOS, 13000}, + {SAY_INTRO_3, NPC_MALYGOS, 14000}, + {SAY_INTRO_4, NPC_MALYGOS, 12000}, + {SAY_INTRO_5, NPC_MALYGOS, 0}, + + // Phase transitions + {SAY_END_PHASE_1, NPC_MALYGOS, 25000}, + {PHASE_DISCS, 0, 0}, + {SAY_END_PHASE_2, NPC_MALYGOS, 13000}, + {SPELL_DESTROY_PLATFORM_BOOM, 0, 2000}, + {SPELL_SUMMON_RED_DRAGON, 0, 5000}, + {SAY_INTRO_PHASE_3, NPC_MALYGOS, 0}, + {0, 0, 0}, +}; + +static const float aCenterMovePos[3] = {754.395f, 1301.270f, 266.253f}; +static const float aAlextraszaSpawnPos[4] = {700.354f, 1310.718f, 298.13f, 6.02f}; +static const float aAlextraszaMovePos[3] = {726.754f, 1307.259f, 282.679f}; + +/*###### +## boss_malygos +######*/ + +struct boss_malygosAI : public ScriptedAI, private DialogueHelper +{ + boss_malygosAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (instance_eye_of_eternity*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + + m_uiMaxStaticFieldTargets = m_bIsRegularMode ? 1 : 3; + m_uiMaxNexusLords = m_bIsRegularMode ? 2 : 4; + m_uiMaxScions = m_bIsRegularMode ? 4 : 8; + + m_bHasDoneIntro = false; + Reset(); + } + + instance_eye_of_eternity* m_pInstance; + bool m_bIsRegularMode; + + bool m_bHasDoneIntro; + + uint8 m_uiPhase; + uint8 m_uiMaxNexusLords; + uint8 m_uiMaxScions; + uint8 m_uiAddsDeadCount; + uint8 m_uiMaxStaticFieldTargets; + + uint32 m_uiBerserkTimer; + uint32 m_uiVortexTimer; + uint32 m_uiArcaneBreathTimer; + uint32 m_uiPowerSparkTimer; + + uint32 m_uiArcanePulseTimer; + uint32 m_uiOverloadTimer; + uint32 m_uiArcaneStormTimer; + + uint32 m_uiStaticFieldTimer; + uint32 m_uiSurgeOfPowerTimer; + + void Reset() override + { + m_uiPhase = PHASE_FLOOR; + + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiVortexTimer = 60000; + m_uiArcaneBreathTimer = 15000; + m_uiPowerSparkTimer = 30000; + + m_uiArcanePulseTimer = 60000; + m_uiOverloadTimer = 1000; + m_uiArcaneStormTimer = 15000; + m_uiAddsDeadCount = 0; + + m_uiStaticFieldTimer = 15000; + m_uiSurgeOfPowerTimer = 30000; + + // reset flags + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + SetCombatMovement(false); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MALYGOS, IN_PROGRESS); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasDoneIntro && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, 110.0f)) + { + StartNextDialogueText(SAY_INTRO_1); + m_bHasDoneIntro = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + uint8 uiTextId = 0; + switch (m_uiPhase) + { + case PHASE_FLOOR: uiTextId = urand(0, 2); break; + case PHASE_DISCS: uiTextId = urand(3, 5); break; + case PHASE_DRAGONS: uiTextId = urand(6, 8); break; + } + + switch (uiTextId) + { + case 0: DoScriptText(SAY_SLAY_1_A, m_creature); break; + case 1: DoScriptText(SAY_SLAY_1_B, m_creature); break; + case 2: DoScriptText(SAY_SLAY_1_C, m_creature); break; + + case 3: DoScriptText(SAY_SLAY_2_A, m_creature); break; + case 4: DoScriptText(SAY_SLAY_2_B, m_creature); break; + case 5: DoScriptText(SAY_SLAY_2_C, m_creature); break; + + case 6: DoScriptText(SAY_SLAY_3_A, m_creature); break; + case 7: DoScriptText(SAY_SLAY_3_B, m_creature); break; + case 8: DoScriptText(SAY_SLAY_3_C, m_creature); break; + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + m_creature->SummonCreature(NPC_ALEXSTRASZA, aAlextraszaSpawnPos[0], aAlextraszaSpawnPos[1], aAlextraszaSpawnPos[2], aAlextraszaSpawnPos[3], TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS); + + if (m_pInstance) + m_pInstance->SetData(TYPE_MALYGOS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MALYGOS, FAIL); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + if (uiPointId == POINT_ID_COMBAT) + { + m_creature->SetLevitate(false); + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_ALEXSTRASZA: + pSummoned->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + pSummoned->GetMotionMaster()->MovePoint(0, aAlextraszaMovePos[0], aAlextraszaMovePos[1], aAlextraszaMovePos[2]); + break; + case NPC_POWER_SPARK: + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + break; + case NPC_ARCANE_OVERLOAD: + DoCastSpellIfCan(pSummoned, SPELL_ARCANE_BOMB, CAST_TRIGGERED); + break; + case NPC_STATIC_FIELD: + pSummoned->CastSpell(pSummoned, SPELL_STATIC_FIELD, false); + break; + case NPC_NEXUS_LORD: + case NPC_SCION_OF_ETERNITY: + if (Creature* pDisk = GetClosestCreatureWithEntry(pSummoned, NPC_HOVER_DISK, 10.0f)) + pSummoned->CastSpell(pDisk, SPELL_RIDE_VEHICLE_HARDCODED, true); + pSummoned->SetInCombatWithZone(); + break; + case NPC_HOVER_DISK: + pSummoned->CastSpell(pSummoned, SPELL_FLIGHT, true); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_NEXUS_LORD || pSummoned->GetEntry() == NPC_SCION_OF_ETERNITY) + { + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_DISC, true); + ++m_uiAddsDeadCount; + + // When all adds are killed start phase 3 + if (m_uiAddsDeadCount == m_uiMaxScions + m_uiMaxNexusLords) + { + StartNextDialogueText(SAY_END_PHASE_2); + m_uiPhase = PHASE_TRANSITION_2; + + // Start platform animation - not sure if this is cast by the right npc + if (m_pInstance) + { + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_LARGE_TRIGGER)) + pTrigger->CastSpell(pTrigger, SPELL_DESTROY_PLATFORM_PRE, false); + } + } + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // Handle yell on Power Spark hit + if (pSpell->Id == SPELL_POWER_SPARK_MALYGOS && pCaster->GetEntry() == NPC_POWER_SPARK && m_uiPhase == PHASE_FLOOR) + DoScriptText(SAY_SPARK_BUFF, m_creature); + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case PHASE_DISCS: + // ToDo: start some movement over the platform + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiPhase = PHASE_DISCS; + DoSpawnAdds(); + break; + case SPELL_DESTROY_PLATFORM_BOOM: + if (m_pInstance) + { + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_LARGE_TRIGGER)) + pTrigger->CastSpell(pTrigger, SPELL_DESTROY_PLATFORM_BOOM, false); + } + break; + case SPELL_SUMMON_RED_DRAGON: + if (m_pInstance) + { + // Destroy the platform + if (GameObject* pPlatform = m_pInstance->GetSingleGameObjectFromStorage(GO_PLATFORM)) + pPlatform->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_11); + } + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_RED_DRAGON); + break; + case SAY_INTRO_PHASE_3: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiPhase = PHASE_DRAGONS; + break; + } + } + + // Wrapper to spawn the adds in phase 2 + void DoSpawnAdds() + { + float fX, fY, fZ; + for (uint8 i = 0; i < m_uiMaxNexusLords; ++i) + { + m_creature->GetRandomPoint(aCenterMovePos[0], aCenterMovePos[1], aCenterMovePos[2], 50.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_HOVER_DISK, fX, fY, fZ + 30.0f, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_NEXUS_LORD, fX, fY, fZ + 30.0f, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + for (uint8 i = 0; i < m_uiMaxScions; ++i) + { + m_creature->GetRandomPoint(aCenterMovePos[0], aCenterMovePos[1], aCenterMovePos[2], 50.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_HOVER_DISK, fX, fY, fZ + 30.0f, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->SummonCreature(NPC_SCION_OF_ETERNITY, fX, fY, fZ + 30.0f, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_FLOOR: + + /* ToDo: Enable this when the spells are properly supported in core + if (m_uiVortexTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VORTEX) == CAST_OK) + { + DoScriptText(SAY_VORTEX, m_creature); + m_uiVortexTimer = 60000; + } + } + else + m_uiVortexTimer -= uiDiff; + */ + + if (m_uiArcaneBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_BREATH : SPELL_ARCANE_BREATH_H) == CAST_OK) + m_uiArcaneBreathTimer = urand(13000, 16000); + } + else + m_uiArcaneBreathTimer -= uiDiff; + + if (m_uiPowerSparkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPARK) == CAST_OK) + { + DoScriptText(SAY_EMOTE_SPARK, m_creature); + m_uiPowerSparkTimer = 30000; + } + } + else + m_uiPowerSparkTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 50.0f) + { + SetCombatMovement(false); + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + // Move idle first, so we can avoid evading, because of the waypoint movement + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->GetMotionMaster()->MovePoint(0, aCenterMovePos[0], aCenterMovePos[1], aCenterMovePos[2] + 30.0f); + + StartNextDialogueText(SAY_END_PHASE_1); + m_uiPhase = PHASE_TRANSITION_1; + } + + DoMeleeAttackIfReady(); + + break; + case PHASE_DISCS: + + if (m_uiOverloadTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ARCANE_BOMB) == CAST_OK) + { + if (!urand(0, 3)) + DoScriptText(SAY_SHELL, m_creature); + + m_uiOverloadTimer = urand(16000, 19000); + } + } + else + m_uiOverloadTimer -= uiDiff; + + // Note: the boss should move in certain points before he does the breath ability + if (m_uiArcanePulseTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SURGE_OF_POWER_PULSE) == CAST_OK) + { + DoScriptText(SAY_DEEP_BREATH, m_creature); + DoScriptText(SAY_EMOTE_BREATH, m_creature); + m_uiArcanePulseTimer = 60000; + } + } + else + m_uiArcanePulseTimer -= uiDiff; + + if (m_uiArcaneStormTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_STORM : SPELL_ARCANE_STORM_H) == CAST_OK) + m_uiArcaneStormTimer = urand(15000, 17000); + } + else + m_uiArcaneStormTimer -= uiDiff; + + break; + case PHASE_DRAGONS: + + if (m_uiStaticFieldTimer < uiDiff) + { + // Cast Static Field spell on a number of targets, based on difficulty + for (uint8 i = 0; i < m_uiMaxStaticFieldTargets; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_STATIC_FIELD_SUMMON, CAST_TRIGGERED) == CAST_OK) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_SPELL_1, m_creature); break; + case 1: DoScriptText(SAY_SPELL_2, m_creature); break; + case 2: DoScriptText(SAY_SPELL_3, m_creature); break; + } + m_uiStaticFieldTimer = urand(10000, 17000); + } + } + } + } + else + m_uiStaticFieldTimer -= uiDiff; + + if (m_uiSurgeOfPowerTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SURGE_OF_POWER) == CAST_OK) + { + if (!urand(0, 3)) + DoScriptText(SAY_SURGE, m_creature); + + m_uiSurgeOfPowerTimer = urand(5000, 15000); + } + } + } + else + m_uiSurgeOfPowerTimer -= uiDiff; + + break; + case PHASE_TRANSITION_1: + case PHASE_TRANSITION_2: + // Nothing here - wait for transition to finish + break; + } + } }; +CreatureAI* GetAI_boss_malygos(Creature* pCreature) +{ + return new boss_malygosAI(pCreature); +} + +/*###### +## npc_power_spark +######*/ + +struct npc_power_sparkAI : public ScriptedAI +{ + npc_power_sparkAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_POWER_SPARK_VISUAL); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (pWho->GetEntry() == NPC_MALYGOS && m_creature->CanReachWithMeleeAttack(pWho)) + { + DoCastSpellIfCan(m_creature, SPELL_POWER_SPARK_MALYGOS, CAST_TRIGGERED); + m_creature->ForcedDespawn(); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_POWER_SPARK_PLAYERS, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_power_spark(Creature* pCreature) +{ + return new npc_power_sparkAI(pCreature); +} + +/*###### +## npc_wyrmrest_skytalon +######*/ + +struct npc_wyrmrest_skytalonAI : public ScriptedAI +{ + npc_wyrmrest_skytalonAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + m_bHasMounted = false; + Reset(); + } + + bool m_bHasMounted; + + void Reset() override { } + + // TODO: Temporary workaround - please remove when the boarding wrappers are implemented in core + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pCaster->GetTypeId() != TYPEID_PLAYER) + return; + + if (pSpell->Id == 56071) + DoCastSpellIfCan(m_creature, SPELL_FLIGHT, CAST_TRIGGERED); + } + + // TODO: Enable the wrappers below, when they will be properly supported by the core + /* + void PassengerBoarded(Unit* pPassenger, uint8 uiSeat) override + { + if (pPassenger->GetTypeId() != TYPEID_PLAYER) + return; + + // Set vehicle auras + DoCastSpellIfCan(m_creature, SPELL_FLIGHT, CAST_TRIGGERED); + } + */ + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_bHasMounted) + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + // Force player to mount + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + pSummoner->CastSpell(m_creature, SPELL_RIDE_RED_DRAGON, true); + } + + m_bHasMounted = true; + } + } +}; + +CreatureAI* GetAI_npc_wyrmrest_skytalon(Creature* pCreature) +{ + return new npc_wyrmrest_skytalonAI(pCreature); +} + +/*###### +## event_go_focusing_iris +######*/ + +bool ProcessEventId_event_go_focusing_iris(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (instance_eye_of_eternity* pInstance = (instance_eye_of_eternity*)((Creature*)pSource)->GetInstanceData()) + { + if (pSource->GetTypeId() != TYPEID_PLAYER) + return false; + + if (pInstance->GetData(TYPE_MALYGOS) == IN_PROGRESS || pInstance->GetData(TYPE_MALYGOS) == DONE) + return false; + + Creature* pMalygos = pInstance->GetSingleCreatureFromStorage(NPC_MALYGOS); + Creature* pTrigger = pInstance->GetSingleCreatureFromStorage(NPC_LARGE_TRIGGER); + if (!pMalygos || !pTrigger) + return false; + + // Enter combat area - Move to ground point first, then start chasing target + float fX, fY, fZ; + pTrigger->GetNearPoint(pTrigger, fX, fY, fZ, 0, 30.0f, pTrigger->GetAngle(pMalygos)); + pMalygos->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, fX, fY, fZ); + pMalygos->AI()->AttackStart((Player*)pSource); + + return true; + } + return false; +} + void AddSC_boss_malygos() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_malygos"; + pNewScript->GetAI = &GetAI_boss_malygos; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_power_spark"; + pNewScript->GetAI = &GetAI_npc_power_spark; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_wyrmrest_skytalon"; + pNewScript->GetAI = &GetAI_npc_wyrmrest_skytalon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_go_focusing_iris"; + pNewScript->pProcessEventId = &ProcessEventId_event_go_focusing_iris; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h b/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h new file mode 100644 index 000000000..9b1b012d1 --- /dev/null +++ b/scripts/northrend/nexus/eye_of_eternity/eye_of_eternity.h @@ -0,0 +1,62 @@ +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_EYE_ETERNITY_H +#define DEF_EYE_ETERNITY_H + +enum +{ + TYPE_MALYGOS = 0, + + NPC_MALYGOS = 28859, + NPC_ALEXSTRASZA = 32295, + NPC_LARGE_TRIGGER = 22517, + NPC_ALEXSTRASZAS_GIFT = 32448, + + GO_EXIT_PORTAL = 193908, + GO_PLATFORM = 193070, + GO_FOCUSING_IRIS = 193958, + GO_FOCUSING_IRIS_H = 193960, + + GO_HEART_OF_MAGIC = 194158, + GO_HEART_OF_MAGIC_H = 194159, + GO_ALEXSTRASZAS_GIFT = 193905, + GO_ALEXSTRASZAS_GIFT_H = 193967, + + ACHIEV_START_MALYGOS_ID = 20387, + + // epilogue related + SAY_OUTRO_1 = -1616029, + SAY_OUTRO_2 = -1616030, + SAY_OUTRO_3 = -1616031, + SAY_OUTRO_4 = -1616032, + + SPELL_ALEXSTRASZAS_GIFT_BEAM = 61028, + SPELL_ALEXSTRASZAS_GIFT_VISUAL = 61023, +}; + +class instance_eye_of_eternity : public ScriptedInstance, private DialogueHelper +{ + public: + instance_eye_of_eternity(Map* pMap); + ~instance_eye_of_eternity() {} + + void Initialize() override; + + bool IsEncounterInProgress() const override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + + void Update(uint32 uiDiff) { DialogueUpdate(uiDiff); } + + protected: + void JustDidDialogueStep(int32 iEntry) override; + + uint32 m_uiEncounter; +}; + +#endif diff --git a/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp b/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp new file mode 100644 index 000000000..4599ed502 --- /dev/null +++ b/scripts/northrend/nexus/eye_of_eternity/instance_eye_of_eternity.cpp @@ -0,0 +1,148 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: instance_eye_of_eternity +SD%Complete: 50 +SDComment: +SDCategory: Eye of Eternity +EndScriptData */ + +#include "precompiled.h" +#include "eye_of_eternity.h" + +static const DialogueEntry aEpilogueDialogue[] = +{ + {NPC_ALEXSTRASZA, 0, 10000}, + {SPELL_ALEXSTRASZAS_GIFT_BEAM, 0, 3000}, + {NPC_ALEXSTRASZAS_GIFT, 0, 2000}, + {SAY_OUTRO_1, NPC_ALEXSTRASZA, 6000}, + {SAY_OUTRO_2, NPC_ALEXSTRASZA, 4000}, + {SAY_OUTRO_3, NPC_ALEXSTRASZA, 23000}, + {SAY_OUTRO_4, NPC_ALEXSTRASZA, 20000}, + {GO_PLATFORM, 0, 0}, + {0, 0, 0}, +}; + +instance_eye_of_eternity::instance_eye_of_eternity(Map* pMap) : ScriptedInstance(pMap), + DialogueHelper(aEpilogueDialogue) +{ + Initialize(); +} + +void instance_eye_of_eternity::Initialize() +{ + m_uiEncounter = NOT_STARTED; + InitializeDialogueHelper(this); +} + +bool instance_eye_of_eternity::IsEncounterInProgress() const +{ + return m_uiEncounter == IN_PROGRESS; +} + +void instance_eye_of_eternity::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_MALYGOS: + case NPC_ALEXSTRASZA: + case NPC_LARGE_TRIGGER: + case NPC_ALEXSTRASZAS_GIFT: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} + +void instance_eye_of_eternity::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_EXIT_PORTAL: + case GO_PLATFORM: + case GO_FOCUSING_IRIS: + case GO_FOCUSING_IRIS_H: + case GO_HEART_OF_MAGIC: + case GO_HEART_OF_MAGIC_H: + case GO_ALEXSTRASZAS_GIFT: + case GO_ALEXSTRASZAS_GIFT_H: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + } +} + +void instance_eye_of_eternity::SetData(uint32 uiType, uint32 uiData) +{ + if (uiType != TYPE_MALYGOS) + return; + + m_uiEncounter = uiData; + if (uiData == IN_PROGRESS) + { + // ToDo: Despawn the exit portal + + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_MALYGOS_ID); + } + else if (uiData == FAIL) + { + // ToDo: respawn the focus iris and the portal + + if (GameObject* pPlatform = GetSingleGameObjectFromStorage(GO_PLATFORM)) + pPlatform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_11); + } + else if (uiData == DONE) + StartNextDialogueText(NPC_ALEXSTRASZA); + + // Currently no reason to save anything +} + +void instance_eye_of_eternity::JustDidDialogueStep(int32 iEntry) +{ + switch (iEntry) + { + case SPELL_ALEXSTRASZAS_GIFT_BEAM: + if (Creature* pAlextrasza = GetSingleCreatureFromStorage(NPC_ALEXSTRASZA)) + pAlextrasza->CastSpell(pAlextrasza, SPELL_ALEXSTRASZAS_GIFT_BEAM, false); + break; + case NPC_ALEXSTRASZAS_GIFT: + if (Creature* pGift = GetSingleCreatureFromStorage(NPC_ALEXSTRASZAS_GIFT)) + pGift->CastSpell(pGift, SPELL_ALEXSTRASZAS_GIFT_VISUAL, false); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_ALEXSTRASZAS_GIFT : GO_ALEXSTRASZAS_GIFT_H, 30 * MINUTE); + break; + case GO_PLATFORM: + // ToDo: respawn the portal + if (GameObject* pPlatform = GetSingleGameObjectFromStorage(GO_PLATFORM)) + pPlatform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_UNK_11); + // Spawn the Heart of Malygos + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_HEART_OF_MAGIC : GO_HEART_OF_MAGIC_H, 30 * MINUTE); + break; + } +} + +InstanceData* GetInstanceData_instance_eye_of_eternity(Map* pMap) +{ + return new instance_eye_of_eternity(pMap); +} + +void AddSC_instance_eye_of_eternity() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_eye_of_eternity"; + pNewScript->GetInstanceData = &GetInstanceData_instance_eye_of_eternity; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/nexus/boss_anomalus.cpp b/scripts/northrend/nexus/nexus/boss_anomalus.cpp index 2f431be28..281a61e78 100644 --- a/scripts/northrend/nexus/nexus/boss_anomalus.cpp +++ b/scripts/northrend/nexus/nexus/boss_anomalus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -58,7 +58,7 @@ enum ## boss_anomalus ######*/ -struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI +struct boss_anomalusAI : public ScriptedAI { boss_anomalusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -75,7 +75,7 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI uint32 m_uiCreateRiftTimer; uint8 m_uiChaoticRiftCount; - void Reset() + void Reset() override { m_bChaoticRift = false; m_uiSparkTimer = 5000; @@ -83,7 +83,7 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI m_uiChaoticRiftCount = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -91,7 +91,7 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI m_pInstance->SetData(TYPE_ANOMALUS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -99,13 +99,13 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI m_pInstance->SetData(TYPE_ANOMALUS, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) DoScriptText(SAY_KILL, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_CHAOTIC_RIFT) { @@ -118,7 +118,7 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_CHAOTIC_RIFT) { @@ -136,10 +136,10 @@ struct MANGOS_DLL_DECL boss_anomalusAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || m_creature->HasAura(SPELL_RIFT_SHIELD)) - return; + return; // Create additional Chaotic Rift at 50% HP if (!m_bChaoticRift && m_creature->GetHealthPercent() < 50.0f) @@ -190,25 +190,25 @@ CreatureAI* GetAI_boss_anomalus(Creature* pCreature) return new boss_anomalusAI(pCreature); } -struct MANGOS_DLL_DECL mob_chaotic_riftAI : public Scripted_NoMovementAI +struct mob_chaotic_riftAI : public Scripted_NoMovementAI { mob_chaotic_riftAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } uint32 m_uiChargedRemoveTimer; - void Reset() + void Reset() override { m_uiChargedRemoveTimer = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { // Auras are applied on aggro because there are many npcs with this entry in the instance DoCastSpellIfCan(m_creature, SPELL_RIFT_AURA, CAST_TRIGGERED); DoCastSpellIfCan(m_creature, SPELL_RIFT_SUMMON_AURA, CAST_TRIGGERED); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_CRAZED_MANA_WRAITH) { @@ -217,7 +217,7 @@ struct MANGOS_DLL_DECL mob_chaotic_riftAI : public Scripted_NoMovementAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { // When hit with Charge Rift cast the Charged Rift spells if (pSpell->Id == SPELL_CHARGE_RIFT) @@ -228,7 +228,7 @@ struct MANGOS_DLL_DECL mob_chaotic_riftAI : public Scripted_NoMovementAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/nexus/nexus/boss_keristrasza.cpp b/scripts/northrend/nexus/nexus/boss_keristrasza.cpp index 50e201fd1..f5e74655e 100644 --- a/scripts/northrend/nexus/nexus/boss_keristrasza.cpp +++ b/scripts/northrend/nexus/nexus/boss_keristrasza.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Keristrasza -SD%Complete: 65% -SDComment: timers tuning, add achievement +SD%Complete: 95% +SDComment: timers tuning SDCategory: Nexus EndScriptData */ @@ -53,7 +53,7 @@ enum ## boss_keristrasza ######*/ -struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI +struct boss_keristraszaAI : public ScriptedAI { boss_keristraszaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -73,7 +73,7 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI bool m_bIsEnraged; - void Reset() + void Reset() override { uiCrystalChainTimer = 30000; uiTailSweepTimer = urand(5000, 7500); @@ -93,7 +93,7 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -103,7 +103,7 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI m_pInstance->SetData(TYPE_KERISTRASZA, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -111,40 +111,44 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI m_pInstance->SetData(TYPE_KERISTRASZA, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) DoScriptText(SAY_KILL, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (uiCheckIntenseColdTimer < uiDiff) + // This needs to be checked only on heroic + if (!m_bIsRegularMode) { - ThreatList playerList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) + if (uiCheckIntenseColdTimer < uiDiff) { - if (Player* pTarget = m_creature->GetMap()->GetPlayer((*itr)->getUnitGuid())) + ThreatList playerList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) { - Aura* pAuraIntenseCold = pTarget->GetAura(SPELL_INTENSE_COLD_AURA, EFFECT_INDEX_0); - - if (pAuraIntenseCold) + if (Player* pTarget = m_creature->GetMap()->GetPlayer((*itr)->getUnitGuid())) { - if (pAuraIntenseCold->GetStackAmount() > MAX_INTENSE_COLD_STACK) + Aura* pAuraIntenseCold = pTarget->GetAura(SPELL_INTENSE_COLD_AURA, EFFECT_INDEX_0); + + if (pAuraIntenseCold) { - if (m_pInstance) - m_pInstance->SetData(TYPE_INTENSE_COLD_FAILED, pTarget->GetGUIDLow()); + if (pAuraIntenseCold->GetStackAmount() > MAX_INTENSE_COLD_STACK) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_INTENSE_COLD_FAILED, pTarget->GetGUIDLow()); + } } } } + uiCheckIntenseColdTimer = 1000; } - uiCheckIntenseColdTimer = 1000; + else + uiCheckIntenseColdTimer -= uiDiff; } - else - uiCheckIntenseColdTimer -= uiDiff; if (!m_bIsEnraged && m_creature->GetHealthPercent() < 25.0f) { @@ -183,7 +187,7 @@ struct MANGOS_DLL_DECL boss_keristraszaAI : public ScriptedAI if (Group* pGroup = pPlayer->GetGroup()) { - for(GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { if (Player* pMember = pRef->getSource()) { diff --git a/scripts/northrend/nexus/nexus/boss_ormorok.cpp b/scripts/northrend/nexus/nexus/boss_ormorok.cpp index bd7e5bb21..091413fc9 100644 --- a/scripts/northrend/nexus/nexus/boss_ormorok.cpp +++ b/scripts/northrend/nexus/nexus/boss_ormorok.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Ormorok -SD%Complete: 50% -SDComment: TODO: Correct timers. Research how spikes work, and attempt code it properly from mangos side. +SD%Complete: 90% +SDComment: Crystal spikes may need small adjustments. SDCategory: Nexus EndScriptData */ @@ -34,25 +34,41 @@ enum EMOTE_BOSS_GENERIC_FRENZY = -1000005, SPELL_REFLECTION = 47981, - SPELL_CRYSTAL_SPIKES = 47958, SPELL_CRYSTAL_SPIKES_H1 = 57082, SPELL_CRYSTAL_SPIKES_H2 = 57083, - SPELL_FRENZY = 48017, SPELL_FRENZY_H = 57086, - SPELL_TRAMPLE = 48016, SPELL_TRAMPLE_H = 57066, + SPELL_SUMMON_TANGLER_H = 61564, + + // crystal spike spells + SPELL_CRYSTAL_SPIKE_BACK = 47936, + SPELL_CRYSTAL_SPIKE_LEFT = 47942, + SPELL_CRYSTAL_SPIKE_RIGHT = 47943, + SPELL_CRYSTAL_SPIKE_AURA = 47941, + SPELL_CRYSTAL_SPIKE_PRE = 50442, + + //SPELL_CRYSTAL_SPIKE_DMG = 47944, + //SPELL_CRYSTAL_SPIKE_DMG_H = 57067, - SPELL_SUMMON_TANGLER_H = 61564 + // summons + NPC_CRYSTAL_SPIKE_INITIAL = 27101, + NPC_CRYSTAL_SPIKE_TRIGGER = 27079, + //NPC_CRYSTAL_SPIKE = 27099, // summoned by 47947 - handled in eventAI + NPC_CRYSTALLINE_TANGLER = 32665, + + GO_CRYSTAL_SPIKE = 188537, + + MAX_ALLOWED_SPIKES = 28, // this defines the maximum number of spikes summoned per turn }; /*###### ## boss_ormorok ######*/ -struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI +struct boss_ormorokAI : public ScriptedAI { boss_ormorokAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -70,23 +86,25 @@ struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI uint32 m_uiSpellReflectTimer; uint32 m_uiCrystalSpikeTimer; uint32 m_uiTanglerTimer; + uint8 m_uiSpikeCount; - void Reset() + void Reset() override { m_bIsEnraged = false; - m_uiTrampleTimer = urand(10000, 35000); - m_uiSpellReflectTimer = urand(5000, 10000); - m_uiCrystalSpikeTimer = urand(15000, 30000); - m_uiTanglerTimer = 20000; + m_uiTrampleTimer = urand(10000, 15000); + m_uiSpellReflectTimer = urand(20000, 23000); + m_uiCrystalSpikeTimer = urand(10000, 15000); + m_uiTanglerTimer = urand(17000, 20000); + m_uiSpikeCount = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -94,54 +112,77 @@ struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI m_pInstance->SetData(TYPE_ORMOROK, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) DoScriptText(SAY_KILL, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - pSummoned->AI()->AttackStart(pTarget); + switch (pSummoned->GetEntry()) + { + case NPC_CRYSTALLINE_TANGLER: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + pSummoned->AI()->AttackStart(pTarget); + break; + case NPC_CRYSTAL_SPIKE_TRIGGER: + pSummoned->CastSpell(pSummoned, SPELL_CRYSTAL_SPIKE_PRE, true); + ++m_uiSpikeCount; + // no break; + case NPC_CRYSTAL_SPIKE_INITIAL: + // Update orientation so we can always face the boss + pSummoned->SetFacingToObject(m_creature); + + // allow continuous summoning only until we reach the limit + if (m_uiSpikeCount < MAX_ALLOWED_SPIKES) + pSummoned->CastSpell(pSummoned, SPELL_CRYSTAL_SPIKE_AURA, true); + break; + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!m_bIsEnraged && m_creature->GetHealthPercent() < 25.0f) { - if (!m_creature->IsNonMeleeSpellCasted(false)) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FRENZY : SPELL_FRENZY_H) == CAST_OK) { - m_bIsEnraged = true; DoScriptText(EMOTE_BOSS_GENERIC_FRENZY, m_creature); - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FRENZY : SPELL_FRENZY_H); + m_bIsEnraged = true; } } if (m_uiTrampleTimer < uiDiff) { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TRAMPLE : SPELL_TRAMPLE_H); - m_uiTrampleTimer = urand(10000, 35000); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TRAMPLE : SPELL_TRAMPLE_H) == CAST_OK) + m_uiTrampleTimer = urand(20000, 25000); } else m_uiTrampleTimer -= uiDiff; if (m_uiSpellReflectTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_REFLECTION); - m_uiSpellReflectTimer = urand(25000, 40000); + if (DoCastSpellIfCan(m_creature, SPELL_REFLECTION) == CAST_OK) + m_uiSpellReflectTimer = urand(26000, 30000); } else m_uiSpellReflectTimer -= uiDiff; if (m_uiCrystalSpikeTimer < uiDiff) { - DoScriptText(SAY_ICESPIKE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_CRYSTAL_SPIKES); - m_uiCrystalSpikeTimer = urand(15000, 30000); + uint32 uiSpikeSpell = SPELL_CRYSTAL_SPIKES; + if (!m_bIsRegularMode) + uiSpikeSpell = urand(0, 1) ? SPELL_CRYSTAL_SPIKES_H1 : SPELL_CRYSTAL_SPIKES_H2; + + if (DoCastSpellIfCan(m_creature, uiSpikeSpell) == CAST_OK) + { + DoScriptText(SAY_ICESPIKE, m_creature); + m_uiCrystalSpikeTimer = urand(13000, 15000); + m_uiSpikeCount = 0; + } } else m_uiCrystalSpikeTimer -= uiDiff; @@ -150,8 +191,8 @@ struct MANGOS_DLL_DECL boss_ormorokAI : public ScriptedAI { if (m_uiTanglerTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_TANGLER_H); - m_uiTanglerTimer = urand(15000, 25000); + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_TANGLER_H) == CAST_OK) + m_uiTanglerTimer = urand(15000, 25000); } else m_uiTanglerTimer -= uiDiff; @@ -166,6 +207,60 @@ CreatureAI* GetAI_boss_ormorok(Creature* pCreature) return new boss_ormorokAI(pCreature); } +bool EffectDummyCreature_npc_crystal_spike_trigger(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_CRYSTAL_SPIKE_AURA && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_CRYSTAL_SPIKE_INITIAL || pCreatureTarget->GetEntry() == NPC_CRYSTAL_SPIKE_TRIGGER) + { + ScriptedInstance* pInstance = (ScriptedInstance*)pCreatureTarget->GetInstanceData(); + if (!pInstance) + return true; + + Creature* pOrmorok = pInstance->GetSingleCreatureFromStorage(NPC_ORMOROK); + if (!pOrmorok) + return true; + + // The following spells define the direction of the spike line + // All of the spells are targeting the back of the caster, but some take a small turn to left or right + // The exact algorithm is unk but we know that the chances of getting a straight line are about 75%. The other two directions are about 12.5% each + uint32 uiSpellId = 0; + if (roll_chance_i(75)) + uiSpellId = SPELL_CRYSTAL_SPIKE_BACK; + else + uiSpellId = urand(0, 1) ? SPELL_CRYSTAL_SPIKE_LEFT : SPELL_CRYSTAL_SPIKE_RIGHT; + + pCreatureTarget->CastSpell(pCreatureTarget, uiSpellId, true, NULL, NULL, pOrmorok->GetObjectGuid()); + // always return true when we are handling this spell and effect + return true; + } + } + + return false; +} + +bool EffectAuraDummy_spell_aura_dummy_crystal_spike_visual(const Aura* pAura, bool bApply) +{ + if (pAura->GetId() == SPELL_CRYSTAL_SPIKE_PRE && pAura->GetEffIndex() == EFFECT_INDEX_0 && !bApply) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + if (pTarget->GetEntry() != NPC_CRYSTAL_SPIKE_TRIGGER) + return true; + + // Use the Spike gameobject so we can summon the npc which actual does the damage + if (GameObject* pSpike = GetClosestGameObjectWithEntry(pTarget, GO_CRYSTAL_SPIKE, 10.0f)) + { + pSpike->Use(pTarget); + // Note: the following command should be handled in core by the trap GO code + pSpike->SetLootState(GO_JUST_DEACTIVATED); + } + } + } + return true; +} + void AddSC_boss_ormorok() { Script* pNewScript; @@ -174,4 +269,10 @@ void AddSC_boss_ormorok() pNewScript->Name = "boss_ormorok"; pNewScript->GetAI = &GetAI_boss_ormorok; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_crystal_spike_trigger"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_crystal_spike_trigger; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_crystal_spike_visual; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/nexus/boss_telestra.cpp b/scripts/northrend/nexus/nexus/boss_telestra.cpp index 267575359..d891dc75f 100644 --- a/scripts/northrend/nexus/nexus/boss_telestra.cpp +++ b/scripts/northrend/nexus/nexus/boss_telestra.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -71,7 +71,7 @@ enum ## boss_telestra ######*/ -struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI +struct boss_telestraAI : public ScriptedAI { boss_telestraAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -93,7 +93,7 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI bool m_bCanCheckAchiev; - void Reset() + void Reset() override { m_uiPhase = PHASE_1; m_uiCloneDeadCount = 0; @@ -106,12 +106,12 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI m_bCanCheckAchiev = false; } - void JustReachedHome() + void JustReachedHome() override { m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, true)) { @@ -123,7 +123,7 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -131,7 +131,7 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI m_pInstance->SetData(TYPE_TELESTRA, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -139,17 +139,17 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI m_pInstance->SetData(TYPE_TELESTRA, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) DoScriptText(SAY_KILL, m_creature); } - void SpellHit(Unit* pCaster, const SpellEntry *pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - switch(pSpell->Id) + switch (pSpell->Id) { - // eventAi must make sure clones cast spells when each of them die + // eventAi must make sure clones cast spells when each of them die case SPELL_FIRE_DIES: case SPELL_ARCANE_DIES: case SPELL_FROST_DIES: @@ -190,9 +190,9 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_TELEST_FIRE: pSummoned->CastSpell(pSummoned, SPELL_FIRE_VISUAL, true); break; case NPC_TELEST_ARCANE: pSummoned->CastSpell(pSummoned, SPELL_ARCANE_VISUAL, true); break; @@ -200,7 +200,7 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -208,7 +208,7 @@ struct MANGOS_DLL_DECL boss_telestraAI : public ScriptedAI if (m_bCanCheckAchiev) m_uiPersonalityTimer += uiDiff; - switch(m_uiPhase) + switch (m_uiPhase) { case PHASE_1: case PHASE_3: diff --git a/scripts/northrend/nexus/nexus/instance_nexus.cpp b/scripts/northrend/nexus/nexus/instance_nexus.cpp index 7a11840a4..6049384ca 100644 --- a/scripts/northrend/nexus/nexus/instance_nexus.cpp +++ b/scripts/northrend/nexus/nexus/instance_nexus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,14 +24,14 @@ EndScriptData */ #include "precompiled.h" #include "nexus.h" -bool GOUse_go_containment_sphere(Player* pPlayer, GameObject* pGo) +bool GOUse_go_containment_sphere(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); if (!pInstance) return false; - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_CONTAINMENT_SPHERE_TELESTRA: pInstance->SetData(TYPE_TELESTRA, SPECIAL); break; case GO_CONTAINMENT_SPHERE_ANOMALUS: pInstance->SetData(TYPE_ANOMALUS, SPECIAL); break; @@ -80,11 +80,16 @@ void instance_nexus::OnObjectCreate(GameObject* pGo) void instance_nexus::OnCreatureCreate(Creature* pCreature) { - if (pCreature->GetEntry() == NPC_KERISTRASZA) - m_mNpcEntryGuidStore[NPC_KERISTRASZA] = pCreature->GetObjectGuid(); + switch (pCreature->GetEntry()) + { + case NPC_ORMOROK: + case NPC_KERISTRASZA: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } } -uint32 instance_nexus::GetData(uint32 uiType) +uint32 instance_nexus::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -126,7 +131,7 @@ void instance_nexus::SetData(uint32 uiType, uint32 uiData) m_sIntenseColdFailPlayers.insert(uiData); break; default: - error_log("SD2: Instance Nexus: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Nexus: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); return; } @@ -163,7 +168,7 @@ void instance_nexus::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) m_abAchievCriteria[uiType] = bIsMet; } -bool instance_nexus::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_nexus::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { @@ -193,7 +198,7 @@ void instance_nexus::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/northrend/nexus/nexus/nexus.h b/scripts/northrend/nexus/nexus/nexus.h index 431de8acf..e2459f2a9 100644 --- a/scripts/northrend/nexus/nexus/nexus.h +++ b/scripts/northrend/nexus/nexus/nexus.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -35,25 +35,25 @@ enum ACHIEV_CRIT_SPLIT_PERSONALITY = 7577, // Telestra, achiev 2150 }; -class MANGOS_DLL_DECL instance_nexus : public ScriptedInstance +class instance_nexus : public ScriptedInstance { public: instance_nexus(Map* pMap); - void Initialize(); + void Initialize() override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; - uint32 GetData(uint32 uiType); - void SetData(uint32 uiType, uint32 uiData); + uint32 GetData(uint32 uiType) const override; + void SetData(uint32 uiType, uint32 uiData) override; void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return m_strInstData.c_str(); } + const char* Save() const override { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/northrend/nexus/oculus/boss_eregos.cpp b/scripts/northrend/nexus/oculus/boss_eregos.cpp index 0c28532c3..503f8aa66 100644 --- a/scripts/northrend/nexus/oculus/boss_eregos.cpp +++ b/scripts/northrend/nexus/oculus/boss_eregos.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_eregos -SD%Complete: 30 -SDComment: only yells and instance data support +SD%Complete: 90 +SDComment: Small adjustments may be required. SDCategory: Oculus EndScriptData */ @@ -26,7 +26,6 @@ EndScriptData */ enum { - SAY_SPAWN = -1578010, SAY_AGGRO = -1578011, SAY_ARCANE_SHIELD = -1578012, SAY_FIRE_SHIELD = -1578013, @@ -36,9 +35,29 @@ enum SAY_KILL_2 = -1578017, SAY_KILL_3 = -1578018, SAY_DEATH = -1578019, + EMOTE_ASTRAL_PLANE = -1578024, + + SPELL_ARCANE_BARRAGE = 50804, + SPELL_ARCANE_BARRAGE_H = 59381, + SPELL_ARCANE_VOLLEY = 51153, + SPELL_ARCANE_VOLLEY_H = 59382, + SPELL_ENRAGED_ASSAULT = 51170, + SPELL_PLANAR_ANOMALIES = 57959, + SPELL_SUMMON_LEY_WHELP = 51175, + SPELL_PLANAR_SHIFT = 51162, + + SPELL_PLANAR_ANOMALY_AGGRO = 57971, + SPELL_PLANAR_BLAST = 57976, + + NPC_PLANAR_ANOMALY = 30879, + NPC_GREATER_LEY_WHELP = 28276, }; -struct MANGOS_DLL_DECL boss_eregosAI : public ScriptedAI +/*###### +## boss_eregos +######*/ + +struct boss_eregosAI : public ScriptedAI { boss_eregosAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -50,11 +69,26 @@ struct MANGOS_DLL_DECL boss_eregosAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiArcaneBarrageTimer; + uint32 m_uiArcaneVolleyTimer; + uint32 m_uiEnrageTimer; + uint32 m_uiSummonWhelpsTimer; + float m_fHpPercent; + + uint8 m_uiAnomalyTargetIndex; + GuidVector m_vAnomalyTargets; + + void Reset() override { + m_uiArcaneBarrageTimer = 0; + m_uiArcaneVolleyTimer = 20000; + m_uiEnrageTimer = 35000; + m_uiSummonWhelpsTimer = urand(15000, 20000); + m_fHpPercent = 60.0f; + m_uiAnomalyTargetIndex = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -62,9 +96,20 @@ struct MANGOS_DLL_DECL boss_eregosAI : public ScriptedAI m_pInstance->SetData(TYPE_EREGOS, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } + } + + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -72,7 +117,7 @@ struct MANGOS_DLL_DECL boss_eregosAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -80,18 +125,118 @@ struct MANGOS_DLL_DECL boss_eregosAI : public ScriptedAI m_pInstance->SetData(TYPE_EREGOS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_EREGOS, FAIL); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_PLANAR_ANOMALY) + { + pSummoned->CastSpell(pSummoned, SPELL_PLANAR_ANOMALY_AGGRO, true); + + // If this happens then something is really wrong + if (m_vAnomalyTargets.empty()) + return; + + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_vAnomalyTargets[m_uiAnomalyTargetIndex])) + pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0, 0); + + if (m_uiAnomalyTargetIndex < m_vAnomalyTargets.size() - 1) + ++m_uiAnomalyTargetIndex; + } + else if (pSummoned->GetEntry() == NPC_GREATER_LEY_WHELP) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - DoMeleeAttackIfReady(); + if (m_creature->HasAura(SPELL_PLANAR_SHIFT)) + return; + + if (m_creature->GetHealthPercent() < m_fHpPercent) + { + if (DoCastSpellIfCan(m_creature, SPELL_PLANAR_SHIFT) == CAST_OK) + { + // Get all the vehicle entries which are in combat with the boss + m_vAnomalyTargets.clear(); + m_uiAnomalyTargetIndex = 0; + + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pTarget->GetEntry() == NPC_RUBY_DRAKE || pTarget->GetEntry() == NPC_AMBER_DRAKE || pTarget->GetEntry() == NPC_EMERALD_DRAKE) + m_vAnomalyTargets.push_back(pTarget->GetObjectGuid()); + } + } + + // This will summon an anomaly for each player (vehicle) + DoCastSpellIfCan(m_creature, SPELL_PLANAR_ANOMALIES, CAST_TRIGGERED); + + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_ARCANE_SHIELD, m_creature); break; + case 1: DoScriptText(SAY_FIRE_SHIELD, m_creature); break; + case 2: DoScriptText(SAY_NATURE_SHIELD, m_creature); break; + } + DoScriptText(EMOTE_ASTRAL_PLANE, m_creature); + + // set next phase to 20% + m_fHpPercent -= 40; + } + } + + if (m_uiArcaneBarrageTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ARCANE_BARRAGE : SPELL_ARCANE_BARRAGE_H) == CAST_OK) + m_uiArcaneBarrageTimer = urand(2000, 3000); + } + } + else + m_uiArcaneBarrageTimer -= uiDiff; + + if (m_uiSummonWhelpsTimer < uiDiff) + { + // ToDo: the number of whelps summoned may be different based on difficulty. Needs research! + for (uint8 i = 0; i < 4; ++i) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_LEY_WHELP, CAST_TRIGGERED) == CAST_OK) + m_uiSummonWhelpsTimer = 20000; + } + } + else + m_uiSummonWhelpsTimer -= uiDiff; + + if (m_uiArcaneVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY_H) == CAST_OK) + m_uiArcaneVolleyTimer = urand(10000, 15000); + } + else + m_uiArcaneVolleyTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGED_ASSAULT) == CAST_OK) + { + DoScriptText(SAY_FRENZY, m_creature); + m_uiEnrageTimer = urand(40000, 50000); + } + } + else + m_uiEnrageTimer -= uiDiff; } }; @@ -100,6 +245,67 @@ CreatureAI* GetAI_boss_eregos(Creature* pCreature) return new boss_eregosAI(pCreature); } +/*###### +## npc_planar_anomaly +######*/ + +struct npc_planar_anomalyAI : public ScriptedAI +{ + npc_planar_anomalyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiPlanarBlastTimer; + bool m_bHasBlastCasted; + + void Reset() override + { + m_uiPlanarBlastTimer = 15000; + m_bHasBlastCasted = false; + } + + void AttackStart(Unit* /*pWho*/) override { } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bHasBlastCasted) + return; + + // Check for the players mounted on the vehicles + if (pWho->GetTypeId() == TYPEID_PLAYER) + { + if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_PLANAR_BLAST) == CAST_OK) + { + m_bHasBlastCasted = true; + m_creature->ForcedDespawn(1000); + } + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_bHasBlastCasted) + return; + + if (m_uiPlanarBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PLANAR_BLAST) == CAST_OK) + { + m_bHasBlastCasted = true; + m_creature->ForcedDespawn(1000); + } + } + else + m_uiPlanarBlastTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_planar_anomaly(Creature* pCreature) +{ + return new npc_planar_anomalyAI(pCreature); +} + void AddSC_boss_eregos() { Script* pNewScript; @@ -108,4 +314,9 @@ void AddSC_boss_eregos() pNewScript->Name = "boss_eregos"; pNewScript->GetAI = &GetAI_boss_eregos; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_planar_anomaly"; + pNewScript->GetAI = &GetAI_npc_planar_anomaly; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/nexus/oculus/boss_urom.cpp b/scripts/northrend/nexus/oculus/boss_urom.cpp index dec478926..98ebe40f2 100644 --- a/scripts/northrend/nexus/oculus/boss_urom.cpp +++ b/scripts/northrend/nexus/oculus/boss_urom.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_urom -SD%Complete: 30 -SDComment: only yells and instance data support +SD%Complete: 90 +SDComment: Small adjustments may be required. SDCategory: Oculus EndScriptData */ @@ -36,35 +36,147 @@ enum SAY_KILL_2 = -1578007, SAY_KILL_3 = -1578008, SAY_DEATH = -1578009, + EMOTE_EXPLOSION = -1578025, + + // spells + SPELL_ARCANE_SHIELD = 53813, // This spell id may be wrong. Needs research! + SPELL_ARCANE_EXPLOSION = 51110, + SPELL_ARCANE_EXPLOSION_H = 59377, + SPELL_FROSTBOMB = 51103, + SPELL_TIME_BOMB = 51121, + SPELL_TIME_BOMB_H = 59376, + SPELL_SUMMON_MENAGERIE_1 = 50476, + SPELL_SUMMON_MENAGERIE_2 = 50495, + SPELL_SUMMON_MENAGERIE_3 = 50496, + SPELL_TELEPORT = 51112, + + // npcs + NPC_PHANTASMAL_CLOUDSCRAPER = 27645, + NPC_PHANTASMAL_MAMMOTH = 27642, + NPC_PHANTASMAL_WOLF = 27644, + + NPC_PHANTASMAL_AIR = 27650, + NPC_PHANTASMAL_FIRE = 27651, + NPC_PHANTASMAL_WATER = 27653, + + NPC_PHANTASMAL_MURLOC = 27649, + NPC_PHANTASMAL_NAGAL = 27648, + NPC_PHANTASMAL_OGRE = 27647, + + MAX_PLATFORMS = 3, }; -struct MANGOS_DLL_DECL boss_uromAI : public ScriptedAI +static uint32 uiTrashPacks[MAX_PLATFORMS][MAX_PLATFORMS] = +{ + {NPC_PHANTASMAL_CLOUDSCRAPER, NPC_PHANTASMAL_MAMMOTH, NPC_PHANTASMAL_WOLF}, + {NPC_PHANTASMAL_AIR, NPC_PHANTASMAL_FIRE, NPC_PHANTASMAL_WATER}, + {NPC_PHANTASMAL_MURLOC, NPC_PHANTASMAL_NAGAL, NPC_PHANTASMAL_OGRE}, +}; + +struct boss_uromAI : public ScriptedAI { boss_uromAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + // Randomize the trash mobs packs + for (uint8 i = 0; i < MAX_PLATFORMS; ++i) + m_vuiTrashPacksIds.push_back(i); + Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + bool m_bIsTeleporting; + bool m_bIsPlatformPhase; + uint8 m_uiPlatformPhase; + uint32 m_uiExplosionExpireTimer; + uint32 m_uiArcaneShieldTimer; + uint32 m_uiExplosionTimer; + uint32 m_uiTeleportTimer; + uint32 m_uiFrostBombTimer; + uint32 m_uiTimeBombTimer; + + float m_fX, m_fY, m_fZ; + + ObjectGuid m_attackTarget; + + std::vector m_vuiTrashPacksIds; + + void Reset() override { + m_bIsPlatformPhase = true; + m_uiPlatformPhase = 0; + m_uiExplosionTimer = 0; + m_uiExplosionExpireTimer = 0; + m_uiTeleportTimer = 20000; + m_uiFrostBombTimer = 5000; + m_uiTimeBombTimer = urand(10000, 15000); + + ResetPlatformVariables(); + + std::random_shuffle(m_vuiTrashPacksIds.begin(), m_vuiTrashPacksIds.end()); } - void Aggro(Unit* pWho) + void ResetPlatformVariables() { - DoScriptText(SAY_AGGRO, m_creature); + m_bIsTeleporting = false; + m_uiArcaneShieldTimer = 1000; + } + void Aggro(Unit* /*pWho*/) override + { if (m_pInstance) m_pInstance->SetData(TYPE_UROM, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void AttackStart(Unit* pWho) override + { + if (m_uiPlatformPhase < MAX_PLATFORMS) + { + if (m_bIsTeleporting) + return; + + // Summon the trash mobs pack + m_bIsTeleporting = true; + m_attackTarget = pWho->GetObjectGuid(); + m_creature->InterruptNonMeleeSpells(false); + DoSpawnTrashPack(); + + // teleport to next platform and spawn adds + switch (m_uiPlatformPhase) + { + case 0: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_MENAGERIE_1) == CAST_OK) + DoScriptText(SAY_SUMMON_1, m_creature); + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_MENAGERIE_2) == CAST_OK) + DoScriptText(SAY_SUMMON_2, m_creature); + break; + case 2: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_MENAGERIE_3) == CAST_OK) + DoScriptText(SAY_SUMMON_3, m_creature); + break; + } + } + // Boss has teleported in the central ring - start normal combat + else if (m_bIsPlatformPhase) + { + DoScriptText(SAY_AGGRO, m_creature); + m_creature->InterruptNonMeleeSpells(false); + m_bIsPlatformPhase = false; + + ScriptedAI::AttackStart(pWho); + } + } + + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -72,25 +184,176 @@ struct MANGOS_DLL_DECL boss_uromAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_DEATH_SPELL, CAST_TRIGGERED); if (m_pInstance) m_pInstance->SetData(TYPE_UROM, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_UROM, FAIL); } - void UpdateAI(const uint32 uiDiff) + void EnterEvadeMode() override + { + // Don't evade while casting explosion + if (m_uiExplosionExpireTimer) + return; + + if (m_bIsPlatformPhase) + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + m_creature->SetLootRecipient(NULL); + + ResetPlatformVariables(); + } + else + { + // Teleport to home position, in order to override the movemaps + m_creature->NearTeleportTo(aOculusBossSpawnLocs[0][0], aOculusBossSpawnLocs[0][1], aOculusBossSpawnLocs[0][2], aOculusBossSpawnLocs[0][3]); + + ScriptedAI::EnterEvadeMode(); + } + } + + void JustSummoned(Creature* pSummon) override { + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_attackTarget)) + pSummon->AI()->AttackStart(pTarget); + } + + void DoSpawnTrashPack() + { + float fX, fY, fZ; + + // Summon the 3 mobs contained in the pack + for (uint8 i = 0; i < MAX_PLATFORMS; ++i) + { + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 10.0f, M_PI_F / 2 * i); + m_creature->SummonCreature(uiTrashPacks[m_vuiTrashPacksIds[m_uiPlatformPhase]][i], fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + } + + // Summon a fourth mob, which can be random + uint32 uiEntry = uiTrashPacks[m_vuiTrashPacksIds[m_uiPlatformPhase]][urand(0, 2)]; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 10.0f, M_PI_F / 2 * 3); + m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + switch (pSpell->Id) + { + case SPELL_SUMMON_MENAGERIE_3: + case SPELL_SUMMON_MENAGERIE_2: + case SPELL_SUMMON_MENAGERIE_1: + EnterEvadeMode(); + ++m_uiPlatformPhase; + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Set the Arcane Shield on out of combat timer + if (m_uiArcaneShieldTimer) + { + if (m_uiArcaneShieldTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_SHIELD) == CAST_OK) + m_uiArcaneShieldTimer = 0; + } + else + m_uiArcaneShieldTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + // Don't use any combat abilities during the platform transition + if (m_bIsPlatformPhase) + return; + + if (m_uiExplosionTimer) + { + if (m_uiExplosionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_EXPLOSION : SPELL_ARCANE_EXPLOSION_H) == CAST_OK) + { + DoScriptText(EMOTE_EXPLOSION, m_creature); + m_uiExplosionTimer = 0; + } + } + else + m_uiExplosionTimer -= uiDiff; + } + + if (m_uiExplosionExpireTimer) + { + if (m_uiExplosionExpireTimer <= uiDiff) + { + // Teleport to the original location + m_creature->NearTeleportTo(m_fX, m_fY, m_fZ, 0); + + // Resume combat movement + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiExplosionExpireTimer = 0; + } + else + m_uiExplosionExpireTimer -= uiDiff; + + // Don't decrease timers during the explosion event + return; + } + + if (m_uiTeleportTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_EXPLOSION_1 : SAY_EXPLOSION_2, m_creature); + + // Store the original position - boss needs to be teleported back + m_creature->GetPosition(m_fX, m_fY, m_fZ); + + // Stop movement until he casts the arcane explosion + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_uiTeleportTimer = 20000; + m_uiExplosionExpireTimer = m_bIsRegularMode ? 9500 : 7500; + m_uiExplosionTimer = 1000; + } + } + else + m_uiTeleportTimer -= uiDiff; + + if (m_uiFrostBombTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROSTBOMB) == CAST_OK) + m_uiFrostBombTimer = urand(4000, 6000); + } + else + m_uiFrostBombTimer -= uiDiff; + + if (m_uiTimeBombTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_TIME_BOMB : SPELL_TIME_BOMB_H) == CAST_OK) + m_uiTimeBombTimer = urand(10000, 15000); + } + } + else + m_uiTimeBombTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; diff --git a/scripts/northrend/nexus/oculus/boss_varos.cpp b/scripts/northrend/nexus/oculus/boss_varos.cpp new file mode 100644 index 000000000..c8d304611 --- /dev/null +++ b/scripts/northrend/nexus/oculus/boss_varos.cpp @@ -0,0 +1,389 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: boss_varos +SD%Complete: 90 +SDComment: Energize Cores spells requires additional research. +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" +#include "TemporarySummon.h" + +enum +{ + SAY_AGGRO = -1578020, + SAY_CALL_CAPTAIN_1 = -1578021, + SAY_CALL_CAPTAIN_2 = -1578022, + SAY_CALL_CAPTAIN_3 = -1578023, + SAY_KILL_1 = -1578026, + SAY_KILL_2 = -1578027, + SAY_DEATH = -1578028, + EMOTE_CAPTAIN = -1578029, + + // spells + SPELL_CENTRIFUGE_SHIELD = 50053, + SPELL_AMPLIFY_MAGIC = 51054, + SPELL_AMPLIFY_MAGIC_H = 59371, + SPELL_ENERGIZE_CORES = 50785, + SPELL_ENERGIZE_CORES_H = 59372, + SPELL_CALL_CAPTAIN_1 = 51008, // sends event 18455 + SPELL_CALL_CAPTAIN_2 = 51002, // sends event 12229 + SPELL_CALL_CAPTAIN_3 = 51006, // sends event 10665 + SPELL_CALL_CAPTAIN_4 = 51007, // sends event 18454 + + // events + EVENT_ID_CALL_CAPTAIN_1 = 18455, + EVENT_ID_CALL_CAPTAIN_2 = 12229, + EVENT_ID_CALL_CAPTAIN_3 = 10665, + EVENT_ID_CALL_CAPTAIN_4 = 18454, + + MAX_CAPTAIN_EVENTS = 4, + + // other spells + SPELL_SUMMON_ARCANE_BEAM = 51014, + SPELL_ARCANE_BEAM_PERIODIC = 51019, + SPELL_ARCANE_BEAM_SPAWN = 51022, + + NPC_AZURE_RING_CAPTAIN = 28236, + NPC_ARCANE_BEAM = 28239, +}; + +struct CaptainData +{ + uint32 uiEventId; + float fX, fY, fZ, fO, fDestX, fDestY, fDestZ; +}; + +static const CaptainData aVarosCaptainData[4] = +{ + {EVENT_ID_CALL_CAPTAIN_1, 1205.74f, 1060.24f, 480.083f, 1.15f, 1239.198f, 1064.537f, 455.587f}, + {EVENT_ID_CALL_CAPTAIN_2, 1273.78f, 1159.366f, 480.083f, 4.79f, 1278.488f, 1119.482f, 455.634f}, // this one is guesswork + {EVENT_ID_CALL_CAPTAIN_3, 1356.845f, 1077.118f, 480.083f, 3.28f, 1331.333f, 1076.381f, 455.69f}, + {EVENT_ID_CALL_CAPTAIN_4, 1296.89f, 1002.76f, 480.083f, 1.71f, 1291.95f, 1024.354f, 455.739f}, +}; + +/*###### +## boss_varos +######*/ + +struct boss_varosAI : public ScriptedAI +{ + boss_varosAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_oculus*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_oculus* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiShieldTimer; + uint32 m_uiAmplifyMagicTimer; + uint32 m_uiEnergizeCoresTimer; + uint32 m_uiCallCaptainTimer; + + void Reset() override + { + m_uiShieldTimer = 2000; + m_uiAmplifyMagicTimer = urand(8000, 15000); + m_uiEnergizeCoresTimer = urand(5000, 7000); + m_uiCallCaptainTimer = urand(10000, 15000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VAROS, IN_PROGRESS); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_DEATH_SPELL, CAST_TRIGGERED); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VAROS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VAROS, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiShieldTimer) + { + if (m_uiShieldTimer <= uiDiff) + { + if (!m_pInstance) + return; + + // Check for shield first + if (m_pInstance->IsShieldBroken()) + { + m_uiShieldTimer = 0; + return; + } + + if (DoCastSpellIfCan(m_creature, SPELL_CENTRIFUGE_SHIELD) == CAST_OK) + { + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, true); + m_uiShieldTimer = 0; + } + } + else + m_uiShieldTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiAmplifyMagicTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_AMPLIFY_MAGIC : SPELL_AMPLIFY_MAGIC_H) == CAST_OK) + m_uiAmplifyMagicTimer = urand(15000, 20000); + } + } + else + m_uiAmplifyMagicTimer -= uiDiff; + + if (m_uiEnergizeCoresTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ENERGIZE_CORES : SPELL_ENERGIZE_CORES_H) == CAST_OK) + m_uiEnergizeCoresTimer = urand(5000, 7000); + } + else + m_uiEnergizeCoresTimer -= uiDiff; + + if (m_uiCallCaptainTimer < uiDiff) + { + // choose a random captain spell + uint32 uiSpellId = 0; + switch (urand(0, 3)) + { + case 0: uiSpellId = SPELL_CALL_CAPTAIN_1; break; + case 1: uiSpellId = SPELL_CALL_CAPTAIN_2; break; + case 2: uiSpellId = SPELL_CALL_CAPTAIN_3; break; + case 3: uiSpellId = SPELL_CALL_CAPTAIN_4; break; + } + + if (DoCastSpellIfCan(m_creature, uiSpellId) == CAST_OK) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_CALL_CAPTAIN_1, m_creature); break; + case 1: DoScriptText(SAY_CALL_CAPTAIN_2, m_creature); break; + case 2: DoScriptText(SAY_CALL_CAPTAIN_3, m_creature); break; + } + + DoScriptText(EMOTE_CAPTAIN, m_creature); + m_uiCallCaptainTimer = urand(13000, 23000); + } + } + else + m_uiCallCaptainTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_varos(Creature* pCreature) +{ + return new boss_varosAI(pCreature); +} + +/*###### +## event_spell_call_captain +######*/ + +bool ProcessEventId_event_spell_call_captain(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_UNIT) + { + Creature* pVaros = (Creature*)pSource; + if (!pVaros) + return false; + + // each guardian has it's own spawn position + for (uint8 i = 0; i < MAX_CAPTAIN_EVENTS; ++i) + { + if (uiEventId == aVarosCaptainData[i].uiEventId) + { + if (Creature* pGuardian = pVaros->SummonCreature(NPC_AZURE_RING_CAPTAIN, aVarosCaptainData[i].fX, aVarosCaptainData[i].fY, aVarosCaptainData[i].fZ, aVarosCaptainData[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pGuardian->SetWalk(false); + pGuardian->GetMotionMaster()->MovePoint(1, aVarosCaptainData[i].fDestX, aVarosCaptainData[i].fDestY, aVarosCaptainData[i].fDestZ); + } + + return true; + } + } + } + + return false; +} + +/*###### +## npc_azure_ring_captain +######*/ + +struct npc_azure_ring_captainAI : public ScriptedAI +{ + npc_azure_ring_captainAI(Creature* pCreature) : ScriptedAI(pCreature) + { + SetCombatMovement(false); + Reset(); + } + + ObjectGuid m_arcaneBeamGuid; + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ARCANE_BEAM) + { + pSummoned->CastSpell(pSummoned, SPELL_ARCANE_BEAM_PERIODIC, true); + pSummoned->CastSpell(pSummoned, SPELL_ARCANE_BEAM_SPAWN, true); + m_arcaneBeamGuid = pSummoned->GetObjectGuid(); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + // Despawn the arcane beam in case of getting killed + if (Creature* pTemp = m_creature->GetMap()->GetCreature(m_arcaneBeamGuid)) + pTemp->ForcedDespawn(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Spawn arcane beam when the position is reached. Also prepare to despawn after the beam event is finished + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ARCANE_BEAM) == CAST_OK) + m_creature->ForcedDespawn(11000); + } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_azure_ring_captain(Creature* pCreature) +{ + return new npc_azure_ring_captainAI(pCreature); +} + +/*###### +## npc_arcane_beam +######*/ + +struct npc_arcane_beamAI : public ScriptedAI +{ + npc_arcane_beamAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override + { + // Start following the summoner (player) + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + m_creature->GetMotionMaster()->MoveFollow(pSummoner, 0, 0); + } + + // despawn manually because of combat bug + m_creature->ForcedDespawn(10000); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_arcane_beam(Creature* pCreature) +{ + return new npc_arcane_beamAI(pCreature); +} + +/*###### +## npc_centrifuge_core +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_centrifuge_coreAI : public Scripted_NoMovementAI +{ + npc_centrifuge_coreAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + // Note: visual already handled in creature_template_addon + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_centrifuge_core(Creature* pCreature) +{ + return new npc_centrifuge_coreAI(pCreature); +} + +void AddSC_boss_varos() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_varos"; + pNewScript->GetAI = &GetAI_boss_varos; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_call_captain"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_call_captain; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_azure_ring_captain"; + pNewScript->GetAI = &GetAI_npc_azure_ring_captain; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_arcane_beam"; + pNewScript->GetAI = &GetAI_npc_arcane_beam; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_centrifuge_core"; + pNewScript->GetAI = &GetAI_npc_centrifuge_core; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/instance_oculus.cpp b/scripts/northrend/nexus/oculus/instance_oculus.cpp index 6574e31c3..a1d831279 100644 --- a/scripts/northrend/nexus/oculus/instance_oculus.cpp +++ b/scripts/northrend/nexus/oculus/instance_oculus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: instance_oculus -SD%Complete: 30 -SDComment: Only basic support +SD%Complete: 50 +SDComment: Spawn instance bosses and handle Varos pre event; Dialogue handled by DBScripts SDCategory: Oculus EndScriptData */ @@ -34,6 +34,20 @@ void instance_oculus::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_oculus::OnPlayerEnter(Player* pPlayer) +{ + if (GetData(TYPE_EREGOS) == DONE) + return; + + DoSpawnNextBossIfCan(); + + if (GetData(TYPE_DRAKOS) == DONE && GetData(TYPE_VAROS) == NOT_STARTED) + { + pPlayer->SendUpdateWorldState(WORLD_STATE_CONSTRUCTS, 1); + pPlayer->SendUpdateWorldState(WORLD_STATE_CONSTRUCTS_COUNT, m_sConstructsAliveGUIDSet.size()); + } +} + void instance_oculus::OnCreatureCreate(Creature* pCreature) { switch (pCreature->GetEntry()) @@ -48,32 +62,66 @@ void instance_oculus::OnCreatureCreate(Creature* pCreature) void instance_oculus::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_CACHE_EREGOS: case GO_CACHE_EREGOS_H: m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); break; + case GO_DRAGON_CAGE_DOOR: + m_lCageDoorGUIDs.push_back(pGo->GetObjectGuid()); + if (m_auiEncounter[TYPE_DRAKOS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; } } void instance_oculus::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_DRAKOS: m_auiEncounter[TYPE_DRAKOS] = uiData; + if (uiData == DONE) + { + // Open all cages + for (GuidList::const_iterator itr = m_lCageDoorGUIDs.begin(); itr != m_lCageDoorGUIDs.end(); ++itr) + DoUseDoorOrButton(*itr); + + // Notes: The dialogue is handled by DB script + // Also the Centrifuge Constructs and the related npcs should be summoned - requires additional research + + // Activate the world state - the Centrifuge contructs should be loaded by now + DoUpdateWorldState(WORLD_STATE_CONSTRUCTS, 1); + DoUpdateWorldState(WORLD_STATE_CONSTRUCTS_COUNT, m_sConstructsAliveGUIDSet.size()); + + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_EREGOS_ID); + } break; case TYPE_VAROS: m_auiEncounter[TYPE_VAROS] = uiData; + if (uiData == DONE) + { + // Note: Image of Belgaristrasz dialogue is handled by DB script + DoSpawnNextBossIfCan(); + DoUpdateWorldState(WORLD_STATE_CONSTRUCTS, 0); + } break; case TYPE_UROM: m_auiEncounter[TYPE_UROM] = uiData; + // Note: Image of Belgaristrasz dialogue is handled by DB script + if (uiData == DONE) + DoSpawnNextBossIfCan(); break; case TYPE_EREGOS: m_auiEncounter[TYPE_EREGOS] = uiData; + // Note: Image of Belgaristrasz teleports to the Cache location and does more dialogue - requires additional research if (uiData == DONE) + { + // The data about the cache isn't consistent, so it's better to handle both cases DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_CACHE_EREGOS : GO_CACHE_EREGOS_H, GO_FLAG_NO_INTERACT, false); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_EREGOS : GO_CACHE_EREGOS_H, 30 * MINUTE); + } break; } @@ -91,7 +139,7 @@ void instance_oculus::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_oculus::GetData(uint32 uiType) +uint32 instance_oculus::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -99,22 +147,34 @@ uint32 instance_oculus::GetData(uint32 uiType) return 0; } -void instance_oculus::OnCreatureEnterCombat(Creature* pCreature) +void instance_oculus::SetData64(uint32 uiData, uint64 uiGuid) { - switch (pCreature->GetEntry()) + // If Varos already completed, just ignore + if (GetData(TYPE_VAROS) == DONE) + return; + + // Note: this is handled in Acid. The purpose is check which Centrifuge Construct is alive, in case of server reset + // The function is triggered by eventAI on generic timer + if (uiData == DATA_CONSTRUCTS_EVENT) { - case NPC_DRAKOS: SetData(TYPE_DRAKOS, IN_PROGRESS); break; - case NPC_VAROS: SetData(TYPE_VAROS, IN_PROGRESS); break; + m_sConstructsAliveGUIDSet.insert(ObjectGuid(uiGuid)); + + // Update world state in case of server reset + if (GetData(TYPE_DRAKOS) == DONE) + DoUpdateWorldState(WORLD_STATE_CONSTRUCTS_COUNT, m_sConstructsAliveGUIDSet.size()); } } +void instance_oculus::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_DRAKOS) + SetData(TYPE_DRAKOS, IN_PROGRESS); +} + void instance_oculus::OnCreatureEvade(Creature* pCreature) { - switch (pCreature->GetEntry()) - { - case NPC_DRAKOS: SetData(TYPE_DRAKOS, FAIL); break; - case NPC_VAROS: SetData(TYPE_VAROS, FAIL); break; - } + if (pCreature->GetEntry() == NPC_DRAKOS) + SetData(TYPE_DRAKOS, FAIL); } void instance_oculus::OnCreatureDeath(Creature* pCreature) @@ -122,7 +182,43 @@ void instance_oculus::OnCreatureDeath(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_DRAKOS: SetData(TYPE_DRAKOS, DONE); break; - case NPC_VAROS: SetData(TYPE_VAROS, DONE); break; + case NPC_CENTRIFUGE_CONSTRUCT: + m_sConstructsAliveGUIDSet.erase(pCreature->GetObjectGuid()); + DoUpdateWorldState(WORLD_STATE_CONSTRUCTS_COUNT, m_sConstructsAliveGUIDSet.size()); + + if (m_sConstructsAliveGUIDSet.empty()) + { + if (Creature* pVaros = GetSingleCreatureFromStorage(NPC_VAROS)) + { + pVaros->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false); + pVaros->InterruptNonMeleeSpells(false); + } + } + break; + } +} + +void instance_oculus::DoSpawnNextBossIfCan() +{ + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + if (GetData(TYPE_UROM) == DONE) + { + // return if already summoned + if (GetSingleCreatureFromStorage(NPC_EREGOS, true)) + return; + + pPlayer->SummonCreature(NPC_EREGOS, aOculusBossSpawnLocs[1][0], aOculusBossSpawnLocs[1][1], aOculusBossSpawnLocs[1][2], aOculusBossSpawnLocs[1][3], TEMPSUMMON_DEAD_DESPAWN, 0); + } + else if (GetData(TYPE_VAROS) == DONE) + { + // return if already summoned + if (GetSingleCreatureFromStorage(NPC_UROM, true)) + return; + + pPlayer->SummonCreature(NPC_UROM, aOculusBossSpawnLocs[0][0], aOculusBossSpawnLocs[0][1], aOculusBossSpawnLocs[0][2], aOculusBossSpawnLocs[0][3], TEMPSUMMON_DEAD_DESPAWN, 0); } } @@ -139,7 +235,7 @@ void instance_oculus::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[TYPE_DRAKOS] >> m_auiEncounter[TYPE_VAROS] >> m_auiEncounter[TYPE_UROM] >> m_auiEncounter[TYPE_EREGOS]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/northrend/nexus/oculus/oculus.cpp b/scripts/northrend/nexus/oculus/oculus.cpp new file mode 100644 index 000000000..352bfb2e1 --- /dev/null +++ b/scripts/northrend/nexus/oculus/oculus.cpp @@ -0,0 +1,155 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: Oculus +SD%Complete: 80 +SDComment: Make use of the passenger boarding wrappers when supported by the core. +SDCategory: Oculus +EndScriptData */ + +#include "precompiled.h" +#include "oculus.h" +#include "TemporarySummon.h" + +enum +{ + EMOTE_FLY_AWAY = -1578030, + + SPELL_RIDE_RUBY_DRAKE_QUE = 49463, + SPELL_RIDE_EMERAL_DRAKE_QUE = 49427, + SPELL_RIDE_AMBER_DRAKE_QUE = 49459, + + SPELL_DRAKE_FLAG_VISUAL = 53797, + SPELL_PARACHUTE = 50550, // triggers 50553 + SPELL_FLIGHT = 50296, + SPELL_SOAR = 50325, + SPELL_EVASIVE_AURA = 50248, +}; + +/*###### +## npc_oculus_drake +######*/ + +struct npc_oculus_drakeAI : public ScriptedAI +{ + npc_oculus_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + uint32 uiMountSpell = 0; + switch (m_creature->GetEntry()) + { + case NPC_RUBY_DRAKE: uiMountSpell = SPELL_RIDE_RUBY_DRAKE_QUE; break; + case NPC_AMBER_DRAKE: uiMountSpell = SPELL_RIDE_AMBER_DRAKE_QUE; break; + case NPC_EMERALD_DRAKE: uiMountSpell = SPELL_RIDE_EMERAL_DRAKE_QUE; break; + } + + // Force player to mount + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + { + pSummoner->CastSpell(pSummoner, uiMountSpell, true); + + // The dragon moves near the player after spawn + float fX, fY, fZ; + pSummoner->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + + SetCombatMovement(false); + Reset(); + } + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_SOAR, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + // Another aura for the Ruby drake + if (m_creature->GetEntry() == NPC_RUBY_DRAKE) + DoCastSpellIfCan(m_creature, SPELL_EVASIVE_AURA, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + + void JustDied(Unit* /*pKiller*/) override + { + // Handle player parachute + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + { + pSummoner->RemoveAurasDueToSpell(SPELL_DRAKE_FLAG_VISUAL); + pSummoner->CastSpell(pSummoner, SPELL_PARACHUTE, true); + } + } + } + + // TODO: Temporary workaround - please remove when the boarding wrappers are implemented in core + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pCaster->GetTypeId() != TYPEID_PLAYER) + return; + + if (pSpell->Id == 49464 || pSpell->Id == 49346 || pSpell->Id == 49460) + DoCastSpellIfCan(m_creature, SPELL_FLIGHT, CAST_TRIGGERED); + } + + // TODO: Enable the wrappers below, when they will be properly supported by the core + /* + void PassengerBoarded(Unit* pPassenger, uint8 uiSeat) override + { + if (pPassenger->GetTypeId() != TYPEID_PLAYER) + return; + + // Set vehicle auras + DoCastSpellIfCan(m_creature, SPELL_FLIGHT, CAST_TRIGGERED); + + // Set passenger auras + pPassenger->CastSpell(pPassenger, SPELL_DRAKE_FLAG_VISUAL, true); + } + + void PassengerUnBoarded(Unit* pPassenger) override + { + pPassenger->RemoveAurasDueToSpell(SPELL_DRAKE_FLAG_VISUAL); + pPassenger->CastSpell(pPassenger, SPELL_PARACHUTE, true); + + DoScriptText(EMOTE_FLY_AWAY, m_creature); + + // The dragon runs away and despawns + float fX, fY, fZ; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 20, frand(0, 2 * M_PI_F)); + m_creature->GetMotionMaster()->MovePoint(0, fX, fY, fZ + 20.0f); + m_creature->ForcedDespawn(5000); + } + */ +}; + +CreatureAI* GetAI_npc_oculus_drake(Creature* pCreature) +{ + return new npc_oculus_drakeAI(pCreature); +} + +void AddSC_oculus() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_oculus_drake"; + pNewScript->GetAI = &GetAI_npc_oculus_drake; + pNewScript->RegisterSelf(); +} diff --git a/scripts/northrend/nexus/oculus/oculus.h b/scripts/northrend/nexus/oculus/oculus.h index 41b036ec9..3440d4bf1 100644 --- a/scripts/northrend/nexus/oculus/oculus.h +++ b/scripts/northrend/nexus/oculus/oculus.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -21,14 +21,23 @@ enum TYPE_UROM = 2, TYPE_EREGOS = 3, + DATA_CONSTRUCTS_EVENT = 1, // DO NOT CHANGE! Used by Acid. - used to check the Centrifuge Constructs alive + NPC_DRAKOS = 27654, NPC_VAROS = 27447, NPC_UROM = 27655, NPC_EREGOS = 27656, + NPC_CENTRIFUGE_CONSTRUCT = 27641, + + NPC_ETERNOS = 27659, // bronze + NPC_VERDISA = 27657, // emerald + NPC_BELGARISTRASZ = 27658, // ruby + NPC_IMAGE_OF_BELGARISTRASZ = 28012, - NPC_ETERNOS = 27659, // bronze - NPC_VERDISA = 27657, // emerald - NPC_BELGARISTRASZ = 27658, // ruby + // Vehicle entries + NPC_EMERALD_DRAKE = 27692, + NPC_AMBER_DRAKE = 27755, + NPC_RUBY_DRAKE = 27756, // Cages in which the friendly dragons are hold GO_DRAGON_CAGE_DOOR = 193995, @@ -37,9 +46,10 @@ enum GO_CACHE_EREGOS = 191349, GO_CACHE_EREGOS_H = 193603, - // Yells after Drakos dies - SAY_VAROS_INTRO = -1578020, - SAY_BELGARISTRASZ_GREET = -1578021, + SPELL_DEATH_SPELL = 50415, // summons 28012 + + // Instance event yells + SAY_EREGOS_SPAWN = -1578010, // world states to show how many constructs are still alive WORLD_STATE_CONSTRUCTS = 3524, @@ -48,29 +58,46 @@ enum ACHIEV_START_EREGOS_ID = 18153, // eregos timed kill achiev }; -class MANGOS_DLL_DECL instance_oculus : public ScriptedInstance +static const float aOculusBossSpawnLocs[2][4] = +{ + {1177.47f, 937.722f, 527.405f, 2.21657f}, // Urom + {1077.04f, 1086.21f, 655.497f, 4.18879f} // Eregos +}; + +class instance_oculus : public ScriptedInstance { public: instance_oculus(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void SetData64(uint32 uiType, uint64 uiGuid) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + const char* Save() const override { return strInstData.c_str(); } + void Load(const char* chrIn) override; - const char* Save() { return strInstData.c_str(); } - void Load(const char* chrIn); + // Check Varos' shield + bool IsShieldBroken() { return m_sConstructsAliveGUIDSet.empty(); } protected: + void DoSpawnNextBossIfCan(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string strInstData; + + GuidList m_lCageDoorGUIDs; + GuidSet m_sConstructsAliveGUIDSet; }; #endif diff --git a/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp b/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp index 3e1d14e53..6f4a3b7f7 100644 --- a/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp +++ b/scripts/northrend/obsidian_sanctum/boss_sartharion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss Sartharion -SD%Complete: 70% -SDComment: Flame wave, achievement and portal events need to be implemented +SD%Complete: 95% +SDComment: Portal event may be incomplete - additional reseach required. SDCategory: Obsidian Sanctum EndScriptData */ @@ -26,7 +26,7 @@ EndScriptData */ enum { - //Sartharion Yell + // Sartharion Yell SAY_SARTHARION_AGGRO = -1615018, SAY_SARTHARION_BERSERK = -1615019, SAY_SARTHARION_BREATH = -1615020, @@ -42,14 +42,13 @@ enum SAY_SARTHARION_SLAY_2 = -1615030, SAY_SARTHARION_SLAY_3 = -1615031, - WHISPER_LAVA_CHURN = -1615032, + EMOTE_LAVA_CHURN = -1615032, + EMOTE_SHADRON_DICIPLE = -1615008, + EMOTE_VESPERON_DICIPLE = -1615041, + EMOTE_HATCH_EGGS = -1615017, + EMOTE_OPEN_PORTAL = -1615042, // emote shared by two dragons - WHISPER_SHADRON_DICIPLE = -1615008, - WHISPER_VESPERON_DICIPLE = -1615041, - WHISPER_HATCH_EGGS = -1615017, - WHISPER_OPEN_PORTAL = -1615042, // whisper, shared by two dragons - - //Sartharion Spells + // Sartharion Spells SPELL_BERSERK = 61632, // Increases the caster's attack speed by 150% and all damage it deals by 500% for 5 min. SPELL_CLEAVE = 56909, // Inflicts 35% weapon damage to an enemy and its nearest allies, affecting up to 10 targets. SPELL_FLAME_BREATH = 56908, // Inflicts 8750 to 11250 Fire damage to enemies in a cone in front of the caster. @@ -57,96 +56,121 @@ enum SPELL_TAIL_LASH = 56910, // A sweeping tail strike hits all enemies behind the caster, inflicting 3063 to 3937 damage and stunning them for 2 sec. SPELL_TAIL_LASH_H = 58957, // A sweeping tail strike hits all enemies behind the caster, inflicting 4375 to 5625 damage and stunning them for 2 sec. SPELL_WILL_OF_SARTHARION = 61254, // Sartharion's presence bolsters the resolve of the Twilight Drakes, increasing their total health by 25%. This effect also increases Sartharion's health by 25%. - SPELL_LAVA_STRIKE = 57571, // (Real spell casted should be 57578) 57571 then trigger visual missile, then summon Lava Blaze on impact(spell 57572) SPELL_TWILIGHT_REVENGE = 60639, SPELL_PYROBUFFET = 56916, // currently used for hard enrage after 15 minutes SPELL_PYROBUFFET_RANGE = 58907, // possibly used when player get too far away from dummy creatures (2x creature entry 30494) - SPELL_TWILIGHT_SHIFT_ENTER = 57620, // enter phase. Player get this when click GO + // phase spells + // SPELL_TWILIGHT_SHIFT_ENTER = 57620, // enter phase. Player get this when click GO SPELL_TWILIGHT_SHIFT_REMOVAL = 61187, // leave phase SPELL_TWILIGHT_SHIFT_REMOVAL_ALL = 61190, // leave phase (probably version to make all leave) - //Mini bosses common spells - SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase + // Mini bosses common spells + // SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase (handled in core) - //Miniboses (Vesperon, Shadron, Tenebron) + // Miniboses (Vesperon, Shadron, Tenebron) SPELL_SHADOW_BREATH_H = 59126, // Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. SPELL_SHADOW_BREATH = 57570, // Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. - SPELL_SHADOW_FISSURE_H = 59127, // Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. SPELL_SHADOW_FISSURE = 57579, // Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. - //Vesperon - //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times - NPC_ACOLYTE_OF_VESPERON = 31219, // Acolyte of Vesperon + // Vesperon + // In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times SPELL_POWER_OF_VESPERON = 61251, // Vesperon's presence decreases the maximum health of all enemies by 25%. SPELL_TWILIGHT_TORMENT_VESP = 57948, // (Shadow only) trigger 57935 then 57988 SPELL_TWILIGHT_TORMENT_VESP_ACO = 58853, // (Fire and Shadow) trigger 58835 then 57988 - //Shadron - //In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times - NPC_ACOLYTE_OF_SHADRON = 31218, // Acolyte of Shadron + // Vesperon related npcs + NPC_DISCIPLE_OF_VESPERON = 30858, // Disciple of Vesperon + NPC_ACOLYTE_OF_VESPERON = 31219, // Acolyte of Vesperon - summoned during Sartharion event + // NPC_VESPERON_CONTROLLER = 30878, // not clear how to use this; used only to cast 61190 to eject players to normal realm + // NPC_VESPERON_CONTROLLER_DEBUFF_CLEAR = 32694, // not used + + // Shadron + // In portal is a disciple, when disciple killed remove Power_of_vesperon, portal open multiple times SPELL_POWER_OF_SHADRON = 58105, // Shadron's presence increases Fire damage taken by all enemies by 100%. SPELL_GIFT_OF_TWILIGTH_SHA = 57835, // TARGET_SCRIPT shadron SPELL_GIFT_OF_TWILIGTH_SAR = 58766, // TARGET_SCRIPT sartharion - //Tenebron - //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 + // Shadron related npcs + NPC_DISCIPLE_OF_SHADRON = 30688, // Disciple of Shadron + NPC_ACOLYTE_OF_SHADRON = 31218, // Acolyte of Shadron - summoned during Sartharion event + // NPC_SHADRON_PORTAL = 30741, // not used + // NPC_SHADRON_PORTAL_VISUAL = 30650, // not used + + // Tenebron + // in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 SPELL_POWER_OF_TENEBRON = 61248, // Tenebron's presence increases Shadow damage taken by all enemies by 100%. - //Tenebron, dummy spell - SPELL_SUMMON_TWILIGHT_WHELP = 58035, // doesn't work, will spawn NPC_TWILIGHT_WHELP - SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP = 58826, // doesn't work, will spawn NPC_SHARTHARION_TWILIGHT_WHELP + SPELL_HATCH_EGGS_MAIN = 58793, // Tenebron's hatch eggs spell - not used because core can't target other phase creatures + // other hatch eggs spells - currently it's unknown how to use them SPELL_HATCH_EGGS_H = 59189, SPELL_HATCH_EGGS = 58542, SPELL_HATCH_EGGS_EFFECT_H = 59190, SPELL_HATCH_EGGS_EFFECT = 58685, - //Whelps + // Tenebron related npcs + NPC_TWILIGHT_EGG = 30882, // Twilight Egg - summoned during Tenebron event + NPC_SARTHARION_TWILIGHT_EGG = 31204, // Twilight Egg - summoned during Sartharion event + NPC_TWILIGHT_EGG_CONTROLLER = 31138, // not clear how to use this; used only to eject players to normal realm + + // Twilight eggs spells + SPELL_SUMMON_TWILIGHT_WHELP = 58035, // will spawn 30890 + SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP = 58826, // will spawn 31214 + NPC_TWILIGHT_WHELP = 30890, NPC_SHARTHARION_TWILIGHT_WHELP = 31214, - SPELL_FADE_ARMOR = 60708, // Reduces the armor of an enemy by 1500 for 15s - //flame tsunami + // Flame tsunami SPELL_FLAME_TSUNAMI = 57494, // the visual dummy - SPELL_FLAME_TSUNAMI_LEAP = 60241, // SPELL_EFFECT_138 some leap effect, causing caster to move in direction + // SPELL_FLAME_TSUNAMI_LEAP = 60241, // SPELL_EFFECT_138 some leap effect, causing caster to move in direction SPELL_FLAME_TSUNAMI_DMG_AURA = 57492, // periodic damage, npc has this aura + // Fire cyclone + // SPELL_LAVA_STRIKE = 57578, // triggers 57571 then trigger visual missile, then summon Lava Blaze on impact(spell 57572) + SPELL_LAVA_STRIKE_IMPACT = 57591, + // SPELL_CYCLONE_AURA = 57560, // in creature_template_addon + SPELL_CYCLONE_AURA_STRIKE = 57598, // triggers 57578 + NPC_FLAME_TSUNAMI = 30616, // for the flame waves NPC_LAVA_BLAZE = 30643, // adds spawning from flame strike - //using these custom points for dragons start and end + // other + MAX_TWILIGHT_EGGS = 6, + PHASEMASK_TWILIGHT_REALM = 16, + + // using these custom points for dragons start and end POINT_ID_INIT = 100, POINT_ID_LAND = 200 }; struct Waypoint { - float m_fX, m_fY, m_fZ; + float m_fX, m_fY, m_fZ, m_fO; }; -//each dragons special points. First where fly to before connect to connon, second where land point is. -Waypoint m_aTene[]= +// each dragons special points. First where fly to before connect to connon, second where land point is. +Waypoint m_aTene[] = { - {3212.854f, 575.597f, 109.856f}, //init - {3246.425f, 565.367f, 61.249f} //end + {3212.854f, 575.597f, 109.856f}, // init + {3246.425f, 565.367f, 61.249f} // end }; -Waypoint m_aShad[]= +Waypoint m_aShad[] = { {3293.238f, 472.223f, 106.968f}, {3271.669f, 526.907f, 61.931f} }; -Waypoint m_aVesp[]= +Waypoint m_aVesp[] = { {3193.310f, 472.861f, 102.697f}, {3227.268f, 533.238f, 59.995f} }; -//points around raid "isle", counter clockwise. should probably be adjusted to be more alike -Waypoint m_aDragonCommon[]= +// points around raid "isle", counter clockwise. should probably be adjusted to be more alike +Waypoint m_aDragonCommon[] = { {3214.012f, 468.932f, 98.652f}, {3244.950f, 468.427f, 98.652f}, @@ -156,20 +180,30 @@ Waypoint m_aDragonCommon[]= {3209.969f, 566.523f, 98.652f} }; +Waypoint m_aTsunamiLoc[] = +{ + // Note: this coords are guesswork, they might need to be updated. + {3201.0f, 481.82f, 58.6f, 6.23f}, // left to right + {3201.0f, 524.50f, 58.6f, 6.23f}, + {3201.0f, 566.64f, 58.6f, 6.23f}, + {3287.5f, 545.50f, 58.6f, 3.19f}, // right to left + {3287.5f, 503.00f, 58.6f, 3.19f}, +}; + /*###### ## Boss Sartharion ######*/ -struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI +struct boss_sartharionAI : public ScriptedAI { boss_sartharionAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_obsidian_sanctum*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_obsidian_sanctum* m_pInstance; bool m_bIsRegularMode; bool m_bIsBerserk; @@ -192,41 +226,32 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI bool m_bHasCalledShadron; bool m_bHasCalledVesperon; - void Reset() + void Reset() override { - m_bIsBerserk = false; - m_bIsSoftEnraged = false; - - m_uiEnrageTimer = MINUTE*15*IN_MILLISECONDS; - m_bIsHardEnraged = false; - - m_uiTenebronTimer = 30000; - m_uiShadronTimer = 75000; - m_uiVesperonTimer = 120000; + m_bIsBerserk = false; + m_bIsSoftEnraged = false; - m_uiFlameTsunamiTimer = 30000; - m_uiFlameBreathTimer = 20000; - m_uiTailSweepTimer = 20000; - m_uiCleaveTimer = 7000; - m_uiLavaStrikeTimer = 5000; + m_uiEnrageTimer = 15 * MINUTE * IN_MILLISECONDS; + m_bIsHardEnraged = false; - m_bHasCalledTenebron = false; - m_bHasCalledShadron = false; - m_bHasCalledVesperon = false; + m_uiTenebronTimer = 30000; + m_uiShadronTimer = 75000; + m_uiVesperonTimer = 120000; - if (m_creature->HasAura(SPELL_TWILIGHT_REVENGE)) - m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_REVENGE); - } + m_uiFlameTsunamiTimer = 30000; + m_uiFlameBreathTimer = 20000; + m_uiTailSweepTimer = 20000; + m_uiCleaveTimer = 7000; + m_uiLavaStrikeTimer = urand(20000, 30000); - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_SARTHARION_EVENT, NOT_STARTED); + m_bHasCalledTenebron = false; + m_bHasCalledShadron = false; + m_bHasCalledVesperon = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - DoScriptText(SAY_SARTHARION_AGGRO,m_creature); + DoScriptText(SAY_SARTHARION_AGGRO, m_creature); if (m_pInstance) { @@ -235,17 +260,17 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - DoScriptText(SAY_SARTHARION_DEATH,m_creature); + DoScriptText(SAY_SARTHARION_DEATH, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_SARTHARION_EVENT, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SARTHARION_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SARTHARION_SLAY_2, m_creature); break; @@ -253,13 +278,23 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI } } + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SARTHARION_EVENT, FAIL); + + // Despawn portal + if (GameObject* pPortal = GetClosestGameObjectWithEntry(m_creature, GO_TWILIGHT_PORTAL, 50.0f)) + pPortal->SetLootState(GO_JUST_DEACTIVATED); + } + void FetchDragons() { Creature* pTene = m_pInstance->GetSingleCreatureFromStorage(NPC_TENEBRON); Creature* pShad = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADRON); Creature* pVesp = m_pInstance->GetSingleCreatureFromStorage(NPC_VESPERON); - //if at least one of the dragons are alive and are being called + // if at least one of the dragons are alive and are being called uint8 uiCountFetchableDragons = 0; if (pTene && pTene->isAlive() && !pTene->getVictim()) @@ -300,17 +335,19 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI if (m_pInstance) { Creature* pTemp = m_pInstance->GetSingleCreatureFromStorage(uiEntry); - - if (pTemp && pTemp->isAlive() && !pTemp->getVictim()) + if (pTemp && pTemp->isAlive()) { - pTemp->SetWalk(false); - if (pTemp->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) pTemp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (pTemp->getVictim()) + return; + + pTemp->SetWalk(false); + int32 iTextId = 0; - switch(uiEntry) + switch (uiEntry) { case NPC_TENEBRON: iTextId = SAY_SARTHARION_CALL_TENEBRON; @@ -333,38 +370,37 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI void SendFlameTsunami() { - Map* pMap = m_creature->GetMap(); + DoScriptText(EMOTE_LAVA_CHURN, m_creature); - if (pMap && pMap->IsDungeon()) + uint8 uiTsunamiStartLoc = 0; + uint8 uiTsunamiEndLoc = 3; + if (urand(0, 1)) { - Map::PlayerList const &PlayerList = pMap->GetPlayers(); - - if (!PlayerList.isEmpty()) - { - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (i->getSource()->isAlive()) - DoScriptText(WHISPER_LAVA_CHURN, m_creature,i->getSource()); - } - } + uiTsunamiStartLoc = 3; + uiTsunamiEndLoc = 5; } + + for (uint8 i = uiTsunamiStartLoc; i < uiTsunamiEndLoc; ++i) + m_creature->SummonCreature(NPC_FLAME_TSUNAMI, m_aTsunamiLoc[i].m_fX, m_aTsunamiLoc[i].m_fY, m_aTsunamiLoc[i].m_fZ, m_aTsunamiLoc[i].m_fO, TEMPSUMMON_TIMED_DESPAWN, 15000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //spell will target dragons, if they are still alive at 35% + // spell will target dragons, if they are still alive at 35% if (!m_bIsBerserk && m_creature->GetHealthPercent() < 35.0f) { - DoScriptText(SAY_SARTHARION_BERSERK, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - m_bIsBerserk = true; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_SARTHARION_BERSERK, m_creature); + m_bIsBerserk = true; + } } - //soft enrage + // soft enrage if (!m_bIsSoftEnraged && m_creature->GetHealthPercent() <= 10.0f) { // TODO @@ -376,8 +412,8 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI { if (m_uiEnrageTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_PYROBUFFET, CAST_TRIGGERED); - m_bIsHardEnraged = true; + if (DoCastSpellIfCan(m_creature, SPELL_PYROBUFFET, CAST_TRIGGERED) == CAST_OK) + m_bIsHardEnraged = true; } else m_uiEnrageTimer -= uiDiff; @@ -395,9 +431,11 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI // flame breath if (m_uiFlameBreathTimer < uiDiff) { - DoScriptText(SAY_SARTHARION_BREATH, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FLAME_BREATH : SPELL_FLAME_BREATH_H); - m_uiFlameBreathTimer = urand(25000, 35000); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FLAME_BREATH : SPELL_FLAME_BREATH_H) == CAST_OK) + { + DoScriptText(SAY_SARTHARION_BREATH, m_creature); + m_uiFlameBreathTimer = urand(25000, 35000); + } } else m_uiFlameBreathTimer -= uiDiff; @@ -405,8 +443,8 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI // Tail Sweep if (m_uiTailSweepTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_TAIL_LASH : SPELL_TAIL_LASH_H); - m_uiTailSweepTimer = urand(15000, 20000); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TAIL_LASH : SPELL_TAIL_LASH_H) == CAST_OK) + m_uiTailSweepTimer = urand(15000, 20000); } else m_uiTailSweepTimer -= uiDiff; @@ -414,8 +452,8 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI // Cleave if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleaveTimer = urand(7000, 10000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(7000, 10000); } else m_uiCleaveTimer -= uiDiff; @@ -423,48 +461,59 @@ struct MANGOS_DLL_DECL boss_sartharionAI : public ScriptedAI // Lavas Strike if (m_uiLavaStrikeTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (m_pInstance) { - DoCastSpellIfCan(pTarget, SPELL_LAVA_STRIKE); + if (Creature* pCyclone = m_creature->GetMap()->GetCreature(m_pInstance->SelectRandomFireCycloneGuid())) + pCyclone->CastSpell(pCyclone, SPELL_CYCLONE_AURA_STRIKE, true); - switch(urand(0, 15)) + switch (urand(0, 5)) { case 0: DoScriptText(SAY_SARTHARION_SPECIAL_1, m_creature); break; case 1: DoScriptText(SAY_SARTHARION_SPECIAL_2, m_creature); break; case 2: DoScriptText(SAY_SARTHARION_SPECIAL_3, m_creature); break; + case 3: DoScriptText(SAY_SARTHARION_SPECIAL_4, m_creature); break; } } - m_uiLavaStrikeTimer = urand(5000, 20000); + m_uiLavaStrikeTimer = 30000; } else m_uiLavaStrikeTimer -= uiDiff; // call tenebron - if (!m_bHasCalledTenebron && m_uiTenebronTimer < uiDiff) + if (!m_bHasCalledTenebron) { - CallDragon(NPC_TENEBRON); - m_bHasCalledTenebron = true; + if (m_uiTenebronTimer < uiDiff) + { + CallDragon(NPC_TENEBRON); + m_bHasCalledTenebron = true; + } + else + m_uiTenebronTimer -= uiDiff; } - else - m_uiTenebronTimer -= uiDiff; // call shadron - if (!m_bHasCalledShadron && m_uiShadronTimer < uiDiff) + if (!m_bHasCalledShadron) { - CallDragon(NPC_SHADRON); - m_bHasCalledShadron = true; + if (m_uiShadronTimer < uiDiff) + { + CallDragon(NPC_SHADRON); + m_bHasCalledShadron = true; + } + else + m_uiShadronTimer -= uiDiff; } - else - m_uiShadronTimer -= uiDiff; // call vesperon - if (!m_bHasCalledVesperon && m_uiVesperonTimer < uiDiff) + if (!m_bHasCalledVesperon) { - CallDragon(NPC_VESPERON); - m_bHasCalledVesperon = true; + if (m_uiVesperonTimer < uiDiff) + { + CallDragon(NPC_VESPERON); + m_bHasCalledVesperon = true; + } + else + m_uiVesperonTimer -= uiDiff; } - else - m_uiVesperonTimer -= uiDiff; DoMeleeAttackIfReady(); @@ -513,50 +562,84 @@ enum VespText SAY_VESPERON_SPECIAL_2 = -1615040 }; -//to control each dragons common abilities -struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI +// to control each dragons common abilities +struct dummy_dragonAI : public ScriptedAI { dummy_dragonAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_obsidian_sanctum*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_obsidian_sanctum* m_pInstance; bool m_bIsRegularMode; + uint8 m_uiPortalId; uint32 m_uiWaypointId; uint32 m_uiMoveNextTimer; - int32 m_iPortalRespawnTime; bool m_bCanMoveFree; - void Reset() + uint32 m_uiPortalRespawnTimer; + uint32 m_uiShadowBreathTimer; + uint32 m_uiShadowFissureTimer; + + ObjectGuid m_portalOwnerGuid; + + void Reset() override + { + m_uiWaypointId = 0; + m_uiMoveNextTimer = 500; + m_bCanMoveFree = false; + + m_uiPortalRespawnTimer = 20000; + m_uiShadowBreathTimer = 20000; + m_uiShadowFissureTimer = 5000; + } + + void JustReachedHome() override { if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_uiWaypointId = 0; - m_uiMoveNextTimer = 500; - m_iPortalRespawnTime = 30000; - m_bCanMoveFree = false; + // Despawn portal + if (GameObject* pPortal = GetClosestGameObjectWithEntry(m_creature, GO_TWILIGHT_PORTAL, 50.0f)) + pPortal->SetLootState(GO_JUST_DEACTIVATED); + + // reset portal events (in case some remain active); summons cleanup handled by creature linking + if (m_pInstance) + m_pInstance->SetPortalStatus(m_uiPortalId, false); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void JustDied(Unit* /*pKiller*/) override + { + // despawn portal if Sartharion is not in combat + if (GameObject* pPortal = GetClosestGameObjectWithEntry(m_creature, GO_TWILIGHT_PORTAL, 50.0f)) + pPortal->SetLootState(GO_JUST_DEACTIVATED); + + // eject players and despawn portal owner + if (Creature* pTemp = m_creature->GetMap()->GetCreature(m_portalOwnerGuid)) + { + pTemp->CastSpell(pTemp, SPELL_TWILIGHT_SHIFT_REMOVAL_ALL, true); + pTemp->ForcedDespawn(1000); + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (!m_pInstance || uiType != POINT_MOTION_TYPE) return; debug_log("dummy_dragonAI: %s reached point %u", m_creature->GetName(), uiPointId); - //if healers messed up the raid and we was already initialized + // if healers messed up the raid and we was already initialized if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) { EnterEvadeMode(); return; } - //this is the end (!) + // this is the end (!) if (uiPointId == POINT_ID_LAND) { m_creature->GetMotionMaster()->Clear(); @@ -565,14 +648,11 @@ struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI return; } - //get amount of common points - uint32 uiCommonWPCount = sizeof(m_aDragonCommon)/sizeof(Waypoint); + // increase + m_uiWaypointId = uiPointId + 1; - //increase - m_uiWaypointId = uiPointId+1; - - //if we have reached a point bigger or equal to count, it mean we must reset to point 0 - if (m_uiWaypointId >= uiCommonWPCount) + // if we have reached a point bigger or equal to count, it mean we must reset to point 0 + if (m_uiWaypointId >= countof(m_aDragonCommon)) { if (!m_bCanMoveFree) m_bCanMoveFree = true; @@ -583,67 +663,40 @@ struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI m_uiMoveNextTimer = 500; } - //used when open portal and spawn mobs in phase - void DoRaidWhisper(int32 iTextId) - { - Map* pMap = m_creature->GetMap(); - - if (pMap && pMap->IsDungeon()) - { - Map::PlayerList const &PlayerList = pMap->GetPlayers(); - - if (!PlayerList.isEmpty()) - { - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - DoScriptText(iTextId, m_creature, i->getSource()); - } - } - } - //"opens" the portal and does the "opening" whisper - void OpenPortal() + void DoOpenPortal() { - int32 iTextId = 0; - - //there are 4 portal spawn locations, each are expected to be spawned with negative spawntimesecs in database - - //using a grid search here seem to be more efficient than caching all four guids - //in instance script and calculate range to each. - GameObject* pPortal = GetClosestGameObjectWithEntry(m_creature,GO_TWILIGHT_PORTAL,50.0f); - - switch(m_creature->GetEntry()) - { - case NPC_TENEBRON: - iTextId = WHISPER_HATCH_EGGS; - break; - case NPC_SHADRON: - case NPC_VESPERON: - iTextId = WHISPER_OPEN_PORTAL; - break; - } + // there are 4 portal spawn locations, each are expected to be spawned with negative spawntimesecs in database - DoRaidWhisper(iTextId); + // using a grid search here seem to be more efficient than caching all four guids + // in instance script and calculate range to each. + GameObject* pPortal = GetClosestGameObjectWithEntry(m_creature, GO_TWILIGHT_PORTAL, 50.0f); + DoScriptText(EMOTE_OPEN_PORTAL, m_creature); - //By using SetRespawnTime() we will actually "spawn" the object with our defined time. - //Once time is up, portal will disappear again. + // By using SetRespawnTime() we will actually "spawn" the object with our defined time. + // Once time is up, portal will disappear again. if (pPortal && !pPortal->isSpawned()) { - pPortal->SetRespawnTime(m_iPortalRespawnTime); + pPortal->SetRespawnTime(HOUR * IN_MILLISECONDS); pPortal->Refresh(); } - //Unclear what are expected to happen if one drake has a portal open already - //Refresh respawnTime so time again are set to 30secs? + // set portal status as active when Sartharion is in progress + if (m_pInstance && m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + m_pInstance->SetPortalStatus(m_uiPortalId, true); + + // Unclear what are expected to happen if one drake has a portal open already + // Refresh respawnTime so time again are set to 30secs? } - //Removes each drakes unique debuff from players + // Removes each drakes unique debuff from players void RemoveDebuff(uint32 uiSpellId) { Map* pMap = m_creature->GetMap(); if (pMap && pMap->IsDungeon()) { - Map::PlayerList const &PlayerList = pMap->GetPlayers(); + Map::PlayerList const& PlayerList = pMap->GetPlayers(); if (PlayerList.isEmpty()) return; @@ -656,54 +709,35 @@ struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + // Eject players from Twilight realm if no other portal event is active + void DoEjectTwilightPlayersIfCan(Creature* pCreature) { - int32 iTextId = 0; - uint32 uiSpellId = 0; - - switch(m_creature->GetEntry()) - { - case NPC_TENEBRON: - iTextId = SAY_TENEBRON_DEATH; - uiSpellId = SPELL_POWER_OF_TENEBRON; - break; - case NPC_SHADRON: - iTextId = SAY_SHADRON_DEATH; - uiSpellId = SPELL_POWER_OF_SHADRON; - break; - case NPC_VESPERON: - iTextId = SAY_VESPERON_DEATH; - uiSpellId = SPELL_POWER_OF_VESPERON; - break; - } - - DoScriptText(iTextId, m_creature); - - RemoveDebuff(uiSpellId); + if (!m_pInstance || !pCreature) + return; - if (m_pInstance) + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS || !m_pInstance->IsActivePortal()) { - // not if solo mini-boss fight - if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) != IN_PROGRESS) - return; + pCreature->CastSpell(pCreature, SPELL_TWILIGHT_SHIFT_REMOVAL_ALL, true); - // Twilight Revenge to main boss - if (Creature* pSartharion = m_pInstance->GetSingleCreatureFromStorage(NPC_SARTHARION)) - { - if (pSartharion->isAlive()) - m_creature->CastSpell(pSartharion, SPELL_TWILIGHT_REVENGE, true); - } + if (GameObject* pPortal = GetClosestGameObjectWithEntry(m_creature, GO_TWILIGHT_PORTAL, 50.0f)) + pPortal->SetLootState(GO_JUST_DEACTIVATED); } } - void UpdateAI(const uint32 uiDiff) + // Handle breath yell + virtual void DoHandleBreathYell() { } + + // Handle special events for each dragon + virtual void UpdateDragonAI(const uint32 /*uiDiff*/) { } + + void UpdateAI(const uint32 uiDiff) override { if (m_bCanMoveFree && m_uiMoveNextTimer) { if (m_uiMoveNextTimer <= uiDiff) { m_creature->GetMotionMaster()->MovePoint(m_uiWaypointId, - m_aDragonCommon[m_uiWaypointId].m_fX, m_aDragonCommon[m_uiWaypointId].m_fY, m_aDragonCommon[m_uiWaypointId].m_fZ); + m_aDragonCommon[m_uiWaypointId].m_fX, m_aDragonCommon[m_uiWaypointId].m_fY, m_aDragonCommon[m_uiWaypointId].m_fZ); debug_log("dummy_dragonAI: %s moving to point %u", m_creature->GetName(), m_uiWaypointId); m_uiMoveNextTimer = 0; @@ -711,6 +745,53 @@ struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI else m_uiMoveNextTimer -= uiDiff; } + + // if no target return + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Call dragon specific virtual function + UpdateDragonAI(uiDiff); + + // respawn portal + if (m_uiPortalRespawnTimer < uiDiff) + { + if (m_pInstance && m_pInstance->IsActivePortal()) + m_uiPortalRespawnTimer = 10000; + else + { + m_uiPortalRespawnTimer = 60000; + DoOpenPortal(); + } + } + else + m_uiPortalRespawnTimer -= uiDiff; + + // shadow fissure + if (m_uiShadowFissureTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_FISSURE : SPELL_SHADOW_FISSURE_H) == CAST_OK) + m_uiShadowFissureTimer = urand(15000, 20000); + } + } + else + m_uiShadowFissureTimer -= uiDiff; + + // shadow breath + if (m_uiShadowBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_BREATH : SPELL_SHADOW_BREATH_H) == CAST_OK) + { + DoHandleBreathYell(); + m_uiShadowBreathTimer = urand(20000, 25000); + } + } + else + m_uiShadowBreathTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; @@ -718,63 +799,107 @@ struct MANGOS_DLL_DECL dummy_dragonAI : public ScriptedAI ## Mob Tenebron ######*/ -struct MANGOS_DLL_DECL mob_tenebronAI : public dummy_dragonAI +struct mob_tenebronAI : public dummy_dragonAI { - mob_tenebronAI(Creature* pCreature) : dummy_dragonAI(pCreature) { Reset(); } + mob_tenebronAI(Creature* pCreature) : dummy_dragonAI(pCreature) + { + m_uiPortalId = TYPE_PORTAL_TENEBRON; + Reset(); + } - uint32 m_uiShadowBreathTimer; - uint32 m_uiShadowFissureTimer; - uint32 m_uiHatchEggTimer; + uint32 m_uiSpawnEggsTimer; - void Reset() + void Reset() override { - m_uiShadowBreathTimer = 20000; - m_uiShadowFissureTimer = 5000; - m_uiHatchEggTimer = 30000; + m_uiSpawnEggsTimer = 20000; + + dummy_dragonAI::Reset(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_TENEBRON_AGGRO, m_creature); DoCastSpellIfCan(m_creature, SPELL_POWER_OF_TENEBRON); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_TENEBRON_SLAY_1 : SAY_TENEBRON_SLAY_2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* pKiller) override { - //if no target, update dummy and return - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + DoScriptText(SAY_TENEBRON_DEATH, m_creature); + + if (m_pInstance) { - dummy_dragonAI::UpdateAI(uiDiff); - return; + // Cast Twilight Revent - script target on Sartharion + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_REVENGE, CAST_TRIGGERED); + else + dummy_dragonAI::JustDied(pKiller); } + } - // shadow fissure - if (m_uiShadowFissureTimer < uiDiff) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_TWILIGHT_EGG_CONTROLLER) + m_portalOwnerGuid = pSummoned->GetObjectGuid(); + + // update phasemask manually + pSummoned->SetPhaseMask(PHASEMASK_TWILIGHT_REALM, true); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_TWILIGHT_EGG_CONTROLLER) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_FISSURE : SPELL_SHADOW_FISSURE_H); + if (m_pInstance) + m_pInstance->SetPortalStatus(m_uiPortalId, false); - m_uiShadowFissureTimer = urand(15000, 20000); + DoEjectTwilightPlayersIfCan((Creature*)pInvoker); } - else - m_uiShadowFissureTimer -= uiDiff; + } - // shadow breath - if (m_uiShadowBreathTimer < uiDiff) + void DoHandleBreathYell() + { + DoScriptText(SAY_TENEBRON_BREATH, m_creature); + } + + void UpdateDragonAI(const uint32 uiDiff) + { + if (m_uiSpawnEggsTimer < uiDiff) { - DoScriptText(SAY_TENEBRON_BREATH, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_BREATH : SPELL_SHADOW_BREATH_H); - m_uiShadowBreathTimer = urand(20000, 25000); + uint32 uiSpawnEntry = NPC_TWILIGHT_EGG; + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + uiSpawnEntry = NPC_SARTHARION_TWILIGHT_EGG; + } + + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_TWILIGHT_EGGS; ++i) + { + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); + m_creature->SummonCreature(uiSpawnEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + // spawn the controller as well in order to eject players from twilight realm + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_TWILIGHT_EGG_CONTROLLER, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + // used only for visual - the result is handled by the Twilight eggs script + if (DoCastSpellIfCan(m_creature, SPELL_HATCH_EGGS_MAIN) == CAST_OK) + { + DoScriptText(EMOTE_HATCH_EGGS, m_creature); + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_TENEBRON_SPECIAL_1 : SAY_TENEBRON_SPECIAL_2, m_creature); + } + + m_uiSpawnEggsTimer = 60000; } else - m_uiShadowBreathTimer -= uiDiff; - - DoMeleeAttackIfReady(); + m_uiSpawnEggsTimer -= uiDiff; } }; @@ -787,69 +912,112 @@ CreatureAI* GetAI_mob_tenebron(Creature* pCreature) ## Mob Shadron ######*/ -struct MANGOS_DLL_DECL mob_shadronAI : public dummy_dragonAI +struct mob_shadronAI : public dummy_dragonAI { - mob_shadronAI(Creature* pCreature) : dummy_dragonAI(pCreature) { Reset(); } + mob_shadronAI(Creature* pCreature) : dummy_dragonAI(pCreature) + { + m_uiPortalId = TYPE_PORTAL_SHADRON; + Reset(); + } - uint32 m_uiShadowBreathTimer; - uint32 m_uiShadowFissureTimer; uint32 m_uiAcolyteShadronTimer; - void Reset() + void Reset() override { - m_uiShadowBreathTimer = 20000; - m_uiShadowFissureTimer = 5000; - m_uiAcolyteShadronTimer = 60000; - - if (m_creature->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) - m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + m_uiAcolyteShadronTimer = 25000; - if (m_creature->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) - m_creature->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); + dummy_dragonAI::Reset(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - DoScriptText(SAY_SHADRON_AGGRO,m_creature); + DoScriptText(SAY_SHADRON_AGGRO, m_creature); DoCastSpellIfCan(m_creature, SPELL_POWER_OF_SHADRON); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SHADRON_SLAY_1 : SAY_SHADRON_SLAY_2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* pKiller) override { - //if no target, update dummy and return - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + DoScriptText(SAY_SHADRON_DEATH, m_creature); + + if (m_pInstance) { - dummy_dragonAI::UpdateAI(uiDiff); - return; + // Cast Twilight Revent - script target on Sartharion + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_REVENGE, CAST_TRIGGERED); + else + dummy_dragonAI::JustDied(pKiller); } + } - // shadow fissure - if (m_uiShadowFissureTimer < uiDiff) + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DISCIPLE_OF_SHADRON) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_FISSURE : SPELL_SHADOW_FISSURE_H); - - m_uiShadowFissureTimer = urand(15000, 20000); + pSummoned->CastSpell(pSummoned, SPELL_GIFT_OF_TWILIGTH_SHA, true); + m_portalOwnerGuid = pSummoned->GetObjectGuid(); } - else - m_uiShadowFissureTimer -= uiDiff; + else if (pSummoned->GetEntry() == NPC_ACOLYTE_OF_SHADRON) + pSummoned->CastSpell(pSummoned, SPELL_GIFT_OF_TWILIGTH_SAR, true); - // shadow breath - if (m_uiShadowBreathTimer < uiDiff) + // update phasemask manually + pSummoned->SetPhaseMask(PHASEMASK_TWILIGHT_REALM, true); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (m_pInstance) { - DoScriptText(SAY_SHADRON_BREATH, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_BREATH : SPELL_SHADOW_BREATH_H); - m_uiShadowBreathTimer = urand(20000, 25000); + m_pInstance->SetPortalStatus(m_uiPortalId, false); + + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + { + if (Creature* pSartharion = m_pInstance->GetSingleCreatureFromStorage(NPC_SARTHARION)) + pSartharion->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SAR); + } + else + m_creature->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); } - else - m_uiShadowBreathTimer -= uiDiff; - DoMeleeAttackIfReady(); + DoEjectTwilightPlayersIfCan(pSummoned); + m_uiAcolyteShadronTimer = m_uiPortalRespawnTimer + 5000; + } + + void DoHandleBreathYell() + { + DoScriptText(SAY_SHADRON_BREATH, m_creature); + } + + void UpdateDragonAI(const uint32 uiDiff) + { + if (m_uiAcolyteShadronTimer) + { + if (m_uiAcolyteShadronTimer <= uiDiff) + { + DoScriptText(EMOTE_SHADRON_DICIPLE, m_creature); + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SHADRON_SPECIAL_1 : SAY_SHADRON_SPECIAL_2, m_creature); + + uint32 uiSpawnEntry = NPC_DISCIPLE_OF_SHADRON; + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + uiSpawnEntry = NPC_ACOLYTE_OF_SHADRON; + } + + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); + m_creature->SummonCreature(uiSpawnEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + m_uiAcolyteShadronTimer = 0; + } + else + m_uiAcolyteShadronTimer -= uiDiff; + } } }; @@ -862,63 +1030,104 @@ CreatureAI* GetAI_mob_shadron(Creature* pCreature) ## Mob Vesperon ######*/ -struct MANGOS_DLL_DECL mob_vesperonAI : public dummy_dragonAI +struct mob_vesperonAI : public dummy_dragonAI { - mob_vesperonAI(Creature* pCreature) : dummy_dragonAI(pCreature) { Reset(); } + mob_vesperonAI(Creature* pCreature) : dummy_dragonAI(pCreature) + { + m_uiPortalId = TYPE_PORTAL_VESPERON; + Reset(); + } - uint32 m_uiShadowBreathTimer; - uint32 m_uiShadowFissureTimer; uint32 m_uiAcolyteVesperonTimer; - void Reset() + void Reset() override { - m_uiShadowBreathTimer = 20000; - m_uiShadowFissureTimer = 5000; - m_uiAcolyteVesperonTimer = 60000; + m_uiAcolyteVesperonTimer = 25000; + + dummy_dragonAI::Reset(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - DoScriptText(SAY_VESPERON_AGGRO,m_creature); + DoScriptText(SAY_VESPERON_AGGRO, m_creature); DoCastSpellIfCan(m_creature, SPELL_POWER_OF_VESPERON); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_VESPERON_SLAY_1 : SAY_VESPERON_SLAY_2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* pKiller) override { - //if no target, update dummy and return - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + DoScriptText(SAY_VESPERON_DEATH, m_creature); + + if (m_pInstance) { - dummy_dragonAI::UpdateAI(uiDiff); - return; + // Cast Twilight Revent - script target on Sartharion + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_REVENGE, CAST_TRIGGERED); + else + dummy_dragonAI::JustDied(pKiller); } + } - // shadow fissure - if (m_uiShadowFissureTimer < uiDiff) + void JustSummoned(Creature* pSummoned) override + { + // ToDo: these spells may break the encounter and make it unplayable. More research is required!!! + if (pSummoned->GetEntry() == NPC_DISCIPLE_OF_VESPERON) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_FISSURE : SPELL_SHADOW_FISSURE_H); - - m_uiShadowFissureTimer = urand(15000, 20000); + //pSummoned->CastSpell(pSummoned, SPELL_TWILIGHT_TORMENT_VESP, true); + m_portalOwnerGuid = pSummoned->GetObjectGuid(); } - else - m_uiShadowFissureTimer -= uiDiff; + //else if (pSummoned->GetEntry() == NPC_ACOLYTE_OF_VESPERON) + // pSummoned->CastSpell(pSummoned, SPELL_TWILIGHT_TORMENT_VESP_ACO, true); - // shadow breath - if (m_uiShadowBreathTimer < uiDiff) + // update phasemask manually + pSummoned->SetPhaseMask(PHASEMASK_TWILIGHT_REALM, true); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // ToDo: remove Twilight Torment debuff + if (m_pInstance) + m_pInstance->SetPortalStatus(m_uiPortalId, false); + + DoEjectTwilightPlayersIfCan(pSummoned); + m_uiAcolyteVesperonTimer = m_uiPortalRespawnTimer + 5000; + } + + void DoHandleBreathYell() + { + DoScriptText(SAY_VESPERON_BREATH, m_creature); + } + + void UpdateDragonAI(const uint32 uiDiff) + { + if (m_uiAcolyteVesperonTimer) { - DoScriptText(SAY_VESPERON_BREATH, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SHADOW_BREATH : SPELL_SHADOW_BREATH_H); - m_uiShadowBreathTimer = urand(20000, 25000); - } - else - m_uiShadowBreathTimer -= uiDiff; + if (m_uiAcolyteVesperonTimer <= uiDiff) + { + DoScriptText(EMOTE_VESPERON_DICIPLE, m_creature); + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_VESPERON_SPECIAL_1 : SAY_VESPERON_SPECIAL_2, m_creature); - DoMeleeAttackIfReady(); + uint32 uiSpawnEntry = NPC_DISCIPLE_OF_VESPERON; + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + uiSpawnEntry = NPC_ACOLYTE_OF_VESPERON; + } + + float fX, fY, fZ; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); + m_creature->SummonCreature(uiSpawnEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + + m_uiAcolyteVesperonTimer = 0; + } + else + m_uiAcolyteVesperonTimer -= uiDiff; + } } }; @@ -928,77 +1137,63 @@ CreatureAI* GetAI_mob_vesperon(Creature* pCreature) } /*###### -## Mob Acolyte of Shadron +## Mob Twilight Eggs ######*/ -struct MANGOS_DLL_DECL mob_acolyte_of_shadronAI : public ScriptedAI +struct mob_twilight_eggsAI : public Scripted_NoMovementAI { - mob_acolyte_of_shadronAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_twilight_eggsAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiHatchTimer; + + void Reset() override { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); + m_uiHatchTimer = 20000; } - ScriptedInstance* m_pInstance; + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + void JustSummoned(Creature* pSummoned) override { - if (m_pInstance) - { - //if not solo figth, buff main boss, else place debuff on mini-boss. both spells TARGET_SCRIPT - if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) - DoCastSpellIfCan(m_creature, SPELL_GIFT_OF_TWILIGTH_SAR); - else - DoCastSpellIfCan(m_creature, SPELL_GIFT_OF_TWILIGTH_SHA); - } + if (pSummoned->GetEntry() == NPC_TWILIGHT_WHELP || pSummoned->GetEntry() == NPC_SHARTHARION_TWILIGHT_WHELP) + pSummoned->SetInCombatWithZone(); } - void JustDied(Unit* killer) + void UpdateAI(const uint32 uiDiff) override { - if (m_pInstance) + if (m_uiHatchTimer < uiDiff) { - Creature* pDebuffTarget = NULL; - - if (m_pInstance->GetData(TYPE_SARTHARION_EVENT) == IN_PROGRESS) + uint32 uiSpellEntry = 0; + switch (m_creature->GetEntry()) { - //not solo fight, so main boss has deduff - pDebuffTarget = m_pInstance->GetSingleCreatureFromStorage(NPC_SARTHARION); - - if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SAR)) - pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SAR); + case NPC_TWILIGHT_EGG: uiSpellEntry = SPELL_SUMMON_TWILIGHT_WHELP; break; + case NPC_SARTHARION_TWILIGHT_EGG: uiSpellEntry = SPELL_SUMMON_SARTHARION_TWILIGHT_WHELP; break; } - else - { - //event not in progress, then solo fight and must remove debuff mini-boss - pDebuffTarget = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADRON); - if (pDebuffTarget && pDebuffTarget->isAlive() && pDebuffTarget->HasAura(SPELL_GIFT_OF_TWILIGTH_SHA)) - pDebuffTarget->RemoveAurasDueToSpell(SPELL_GIFT_OF_TWILIGTH_SHA); - } - } - } + m_creature->SetPhaseMask(PHASEMASK_NORMAL, true); + DoCastSpellIfCan(m_creature, uiSpellEntry, CAST_TRIGGERED); - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + m_uiHatchTimer = 0; + } + else + m_uiHatchTimer -= uiDiff; } }; -CreatureAI* GetAI_mob_acolyte_of_shadron(Creature* pCreature) +CreatureAI* GetAI_mob_twilight_eggs(Creature* pCreature) { - return new mob_acolyte_of_shadronAI(pCreature); + return new mob_twilight_eggsAI(pCreature); } /*###### -## Mob Acolyte of Vesperon +## npc_tenebron_egg_controller ######*/ -struct MANGOS_DLL_DECL mob_acolyte_of_vesperonAI : public ScriptedAI +struct npc_tenebron_egg_controllerAI : public Scripted_NoMovementAI { - mob_acolyte_of_vesperonAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_tenebron_egg_controllerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -1006,95 +1201,131 @@ struct MANGOS_DLL_DECL mob_acolyte_of_vesperonAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() + uint32 m_uiHatchTimer; + + void Reset() override { - DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_TORMENT_VESP_ACO); + m_uiHatchTimer = 20000; } - void JustDied(Unit* pKiller) + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override { - // remove twilight torment on Vesperon - if (m_pInstance) + if (m_uiHatchTimer) { - Creature* pVesperon = m_pInstance->GetSingleCreatureFromStorage(NPC_VESPERON); - - if (pVesperon && pVesperon->isAlive() && pVesperon->HasAura(SPELL_TWILIGHT_TORMENT_VESP)) - pVesperon->RemoveAurasDueToSpell(SPELL_TWILIGHT_TORMENT_VESP); + if (m_uiHatchTimer < uiDiff) + { + if (m_pInstance) + { + // Inform Tenebron to hatch the eggs + if (Creature* pTenebron = m_pInstance->GetSingleCreatureFromStorage(NPC_TENEBRON)) + m_creature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pTenebron); + } + m_creature->ForcedDespawn(1000); + m_uiHatchTimer = 0; + } + else + m_uiHatchTimer -= uiDiff; } } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } }; -CreatureAI* GetAI_mob_acolyte_of_vesperon(Creature* pCreature) +CreatureAI* GetAI_npc_tenebron_egg_controller(Creature* pCreature) { - return new mob_acolyte_of_vesperonAI(pCreature); + return new npc_tenebron_egg_controllerAI(pCreature); } /*###### -## Mob Twilight Eggs +## npc_flame_tsunami ######*/ -struct MANGOS_DLL_DECL mob_twilight_eggsAI : public ScriptedAI +struct npc_flame_tsunamiAI : public ScriptedAI { - mob_twilight_eggsAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_flame_tsunamiAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiTsunamiTimer; + + void Reset() override + { + m_uiTsunamiTimer = 2000; + + DoCastSpellIfCan(m_creature, SPELL_FLAME_TSUNAMI, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FLAME_TSUNAMI_DMG_AURA, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + void MovementInform(uint32 uiType, uint32 uiPointId) override { + if (uiType != POINT_MOTION_TYPE || !uiPointId) + return; + + m_creature->RemoveAllAurasOnEvade(); } - void AttackStart(Unit* pWho) { } - void MoveInLineOfSight(Unit* pWho) { } + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiTsunamiTimer) + { + if (m_uiTsunamiTimer <= uiDiff) + { + // Note: currently the way in which spell 60241 works is unk, so for the moment we'll use simple movement + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX() < 3250.0f ? m_creature->GetPositionX() + 86.5f : m_creature->GetPositionX() - 86.5f, + m_creature->GetPositionY(), m_creature->GetPositionZ()); + + m_uiTsunamiTimer = 0; + } + else + m_uiTsunamiTimer -= uiDiff; + } + } }; -CreatureAI* GetAI_mob_twilight_eggs(Creature* pCreature) +CreatureAI* GetAI_npc_flame_tsunami(Creature* pCreature) { - return new mob_twilight_eggsAI(pCreature); + return new npc_flame_tsunamiAI(pCreature); } /*###### -## Mob Twilight Whelps +## npc_fire_cyclone ######*/ -struct MANGOS_DLL_DECL mob_twilight_whelpAI : public ScriptedAI +struct npc_fire_cycloneAI : public ScriptedAI { - mob_twilight_whelpAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_fire_cycloneAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; - uint32 m_uiFadeArmorTimer; + void Reset() override { } - void Reset() + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - m_uiFadeArmorTimer = 1000; + // Mark the achiev failed for the hit target + if (pSpell->Id == SPELL_LAVA_STRIKE_IMPACT && pTarget->GetTypeId() == TYPEID_PLAYER && m_pInstance) + m_pInstance->SetData(TYPE_VOLCANO_BLOW_FAILED, pTarget->GetGUIDLow()); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // twilight torment - if (m_uiFadeArmorTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FADE_ARMOR); - m_uiFadeArmorTimer = urand(5000, 10000); - } - else - m_uiFadeArmorTimer -= uiDiff; - - DoMeleeAttackIfReady(); + if (pSummoned->GetEntry() == NPC_LAVA_BLAZE) + pSummoned->SetInCombatWithZone(); } }; -CreatureAI* GetAI_mob_twilight_whelp(Creature* pCreature) +CreatureAI* GetAI_npc_fire_cyclone(Creature* pCreature) { - return new mob_twilight_whelpAI(pCreature); + return new npc_fire_cycloneAI(pCreature); } void AddSC_boss_sartharion() @@ -1122,22 +1353,22 @@ void AddSC_boss_sartharion() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_acolyte_of_shadron"; - pNewScript->GetAI = &GetAI_mob_acolyte_of_shadron; + pNewScript->Name = "mob_twilight_eggs"; + pNewScript->GetAI = &GetAI_mob_twilight_eggs; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_acolyte_of_vesperon"; - pNewScript->GetAI = &GetAI_mob_acolyte_of_vesperon; + pNewScript->Name = "npc_tenebron_egg_controller"; + pNewScript->GetAI = &GetAI_npc_tenebron_egg_controller; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_twilight_eggs"; - pNewScript->GetAI = &GetAI_mob_twilight_eggs; + pNewScript->Name = "npc_flame_tsunami"; + pNewScript->GetAI = &GetAI_npc_flame_tsunami; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_twilight_whelp"; - pNewScript->GetAI = &GetAI_mob_twilight_whelp; + pNewScript->Name = "npc_fire_cyclone"; + pNewScript->GetAI = &GetAI_npc_fire_cyclone; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp b/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp index 1138bbe8d..3fb433e21 100644 --- a/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp +++ b/scripts/northrend/obsidian_sanctum/instance_obsidian_sanctum.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,21 +30,24 @@ EndScriptData */ instance_obsidian_sanctum::instance_obsidian_sanctum(Map* pMap) : ScriptedInstance(pMap), m_uiAliveDragons(0) - { - Initialize(); - } +{ + Initialize(); +} void instance_obsidian_sanctum::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + for (uint8 i = 0; i < MAX_TWILIGHT_DRAGONS; ++i) + m_bPortalActive[i] = false; } void instance_obsidian_sanctum::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - // The three dragons below set to active state once created. - // We must expect bigger raid to encounter main boss, and then three dragons must be active due to grid differences + // The three dragons below set to active state once created. + // We must expect bigger raid to encounter main boss, and then three dragons must be active due to grid differences case NPC_TENEBRON: case NPC_SHADRON: case NPC_VESPERON: @@ -52,20 +55,33 @@ void instance_obsidian_sanctum::OnCreatureCreate(Creature* pCreature) case NPC_SARTHARION: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_FIRE_CYCLONE: + m_lFireCycloneGuidList.push_back(pCreature->GetObjectGuid()); + break; } } void instance_obsidian_sanctum::SetData(uint32 uiType, uint32 uiData) { if (uiType == TYPE_SARTHARION_EVENT) + { m_auiEncounter[0] = uiData; + if (uiData == IN_PROGRESS) + m_sVolcanoBlowFailPlayers.clear(); + } else if (uiType == TYPE_ALIVE_DRAGONS) m_uiAliveDragons = uiData; + else if (uiType == TYPE_VOLCANO_BLOW_FAILED) + { + // Insert the players who fail the achiev and haven't been already inserted in the set + if (m_sVolcanoBlowFailPlayers.find(uiData) == m_sVolcanoBlowFailPlayers.end()) + m_sVolcanoBlowFailPlayers.insert(uiData); + } // No need to save anything here } -uint32 instance_obsidian_sanctum::GetData(uint32 uiType) +uint32 instance_obsidian_sanctum::GetData(uint32 uiType) const { if (uiType == TYPE_SARTHARION_EVENT) return m_auiEncounter[0]; @@ -73,7 +89,18 @@ uint32 instance_obsidian_sanctum::GetData(uint32 uiType) return 0; } -bool instance_obsidian_sanctum::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +ObjectGuid instance_obsidian_sanctum::SelectRandomFireCycloneGuid() +{ + if (m_lFireCycloneGuidList.empty()) + return ObjectGuid(); + + GuidList::iterator iter = m_lFireCycloneGuidList.begin(); + advance(iter, urand(0, m_lFireCycloneGuidList.size() - 1)); + + return *iter; +} + +bool instance_obsidian_sanctum::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { @@ -86,11 +113,30 @@ bool instance_obsidian_sanctum::CheckAchievementCriteriaMeet(uint32 uiCriteriaId case ACHIEV_DRAGONS_ALIVE_3_N: case ACHIEV_DRAGONS_ALIVE_3_H: return m_uiAliveDragons >= 3; + case ACHIEV_CRIT_VOLCANO_BLOW_N: + case ACHIEV_CRIT_VOLCANO_BLOW_H: + // Return true if not found in the set + return m_sVolcanoBlowFailPlayers.find(pSource->GetGUIDLow()) == m_sVolcanoBlowFailPlayers.end(); default: return false; } } +bool instance_obsidian_sanctum::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const +{ + switch (uiInstanceConditionId) + { + case INSTANCE_CONDITION_ID_HARD_MODE: // Exactly one dragon alive on event start + case INSTANCE_CONDITION_ID_HARD_MODE_2: // Exactly two dragons alive on event start + case INSTANCE_CONDITION_ID_HARD_MODE_3: // All three dragons alive on event start + return m_uiAliveDragons == uiInstanceConditionId; + } + + script_error_log("instance_obsidian_sanctum::CheckConditionCriteriaMeet called with unsupported Id %u. Called with param plr %s, src %s, condition source type %u", + uiInstanceConditionId, pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", pConditionSource ? pConditionSource->GetGuidStr().c_str() : "NULL", conditionSourceType); + return false; +} + InstanceData* GetInstanceData_instance_obsidian_sanctum(Map* pMap) { return new instance_obsidian_sanctum(pMap); diff --git a/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h b/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h index 1c740bfe1..d7faa7ee8 100644 --- a/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h +++ b/scripts/northrend/obsidian_sanctum/obsidian_sanctum.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -12,12 +12,21 @@ enum TYPE_SARTHARION_EVENT = 1, // internal used types for achievement TYPE_ALIVE_DRAGONS = 2, + TYPE_VOLCANO_BLOW_FAILED = 3, + + MAX_TWILIGHT_DRAGONS = 3, + + TYPE_PORTAL_TENEBRON = 0, + TYPE_PORTAL_SHADRON = 1, + TYPE_PORTAL_VESPERON = 2, NPC_SARTHARION = 28860, NPC_TENEBRON = 30452, NPC_SHADRON = 30451, NPC_VESPERON = 30449, + NPC_FIRE_CYCLONE = 30648, + GO_TWILIGHT_PORTAL = 193988, // Achievement related @@ -31,24 +40,46 @@ enum ACHIEV_DRAGONS_ALIVE_3_H = 7333, }; -class MANGOS_DLL_DECL instance_obsidian_sanctum : public ScriptedInstance +class instance_obsidian_sanctum : public ScriptedInstance { public: instance_obsidian_sanctum(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnCreatureCreate(Creature* pCreature); + ObjectGuid SelectRandomFireCycloneGuid(); - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + bool IsActivePortal() + { + for (uint8 i = 0; i < MAX_TWILIGHT_DRAGONS; ++i) + { + if (m_bPortalActive[i]) + return true; + } - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + return false; + } + + void SetPortalStatus(uint8 uiType, bool bStatus) { m_bPortalActive[uiType] = bStatus; } + bool GetPortaStatus(uint8 uiType) { return m_bPortalActive[uiType]; } + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; + bool m_bPortalActive[MAX_TWILIGHT_DRAGONS]; uint8 m_uiAliveDragons; + + std::set m_sVolcanoBlowFailPlayers; + + GuidList m_lFireCycloneGuidList; }; #endif diff --git a/scripts/northrend/ruby_sanctum/boss_baltharus.cpp b/scripts/northrend/ruby_sanctum/boss_baltharus.cpp index eb3b2d85c..a652da65a 100644 --- a/scripts/northrend/ruby_sanctum/boss_baltharus.cpp +++ b/scripts/northrend/ruby_sanctum/boss_baltharus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,17 +16,20 @@ /* ScriptData SDName: boss_baltharus -SD%Complete: 20 -SDComment: only yells +SD%Complete: 90 +SDComment: intro channeled spell NYI. SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" enum { // Xerestrasza intro and outro texts SAY_HELP = -1724000, + SAY_INTRO = -1724001, + SAY_THANKS = -1724002, SAY_OUTRO_1 = -1724003, SAY_OUTRO_2 = -1724004, @@ -37,14 +40,279 @@ enum SAY_OUTRO_7 = -1724009, // Baltharus texts - SAY_INTRO = -1724001, SAY_AGGRO = -1724010, SAY_SLAY_1 = -1724011, SAY_SLAY_2 = -1724012, SAY_DEATH = -1724013, SAY_SPLIT = -1724014, + + SPELL_BARRIER_CHANNEL = 76221, // channeled on the tree + SPELL_BLADE_TEMPEST = 75125, + SPELL_CLEAVE = 40504, + SPELL_ENERVATING_BRAND = 74502, + SPELL_REPELLING_WAVE = 74509, + SPELL_ENERVATING_BRAND_PL = 74505, // spell triggerd on players by 74502 + SPELL_SIPHONED_MIGHT = 74507, // spell triggered on boss by 74505 + SPELL_SUMMON_CLONE = 74511, // summons 39899 + SPELL_SIMPLE_TELEPORT = 64195, // spell id not confirmed + + NPC_BALTHARUS_CLONE = 39899, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_HELP, NPC_XERESTRASZA, 7000}, + {SAY_INTRO, NPC_BALTHARUS, 0}, + {0, 0, 0}, }; +/*###### +## boss_baltharus +######*/ + +struct boss_baltharusAI : public ScriptedAI +{ + boss_baltharusAI(Creature* pCreature) : ScriptedAI(pCreature), + m_introDialogue(aIntroDialogue) + { + m_pInstance = (instance_ruby_sanctum*)pCreature->GetInstanceData(); + m_introDialogue.InitializeDialogueHelper(m_pInstance); + + // Health check percent depends on difficulty + if (m_pInstance) + m_fHealthPercentCheck = m_pInstance->Is25ManDifficulty() ? 33.3f : 50; + else + script_error_log("Instance Ruby Sanctum: ERROR Failed to load instance data for this instace."); + + m_bHasDoneIntro = false; + Reset(); + } + + instance_ruby_sanctum* m_pInstance; + DialogueHelper m_introDialogue; + + bool m_bHasDoneIntro; + + uint8 m_uiPhase; + float m_fHealthPercentCheck; + + uint32 m_uiBladeTempestTimer; + uint32 m_uiEnervatingBrandTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiSummonCloneTimer; + + void Reset() override + { + m_uiPhase = 1; + m_uiSummonCloneTimer = 0; + m_uiBladeTempestTimer = 15000; + m_uiEnervatingBrandTimer = 14000; + m_uiCleaveTimer = urand(10000, 12000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BALTHARUS, IN_PROGRESS); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasDoneIntro && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster()) + { + m_introDialogue.StartNextDialogueText(SAY_HELP); + m_bHasDoneIntro = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_BALTHARUS, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_BALTHARUS, FAIL); + } + + void JustSummoned(Creature* pSummoned) + { + if (pSummoned->GetEntry() == NPC_BALTHARUS_CLONE) + { + pSummoned->CastSpell(pSummoned, SPELL_SIMPLE_TELEPORT, true); + pSummoned->SetInCombatWithZone(); + } + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpellEntry->Id == SPELL_ENERVATING_BRAND_PL) + pTarget->CastSpell(m_creature, SPELL_SIPHONED_MIGHT, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + m_introDialogue.DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_creature->GetHealthPercent() < 100 - m_fHealthPercentCheck * m_uiPhase) + { + if (DoCastSpellIfCan(m_creature, SPELL_REPELLING_WAVE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + m_uiSummonCloneTimer = 3000; + ++m_uiPhase; + } + } + + if (m_uiSummonCloneTimer) + { + if (m_uiSummonCloneTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_CLONE) == CAST_OK) + { + DoScriptText(SAY_SPLIT, m_creature); + m_uiSummonCloneTimer = 0; + } + } + else + m_uiSummonCloneTimer -= uiDiff; + + // no other actions + return; + } + + if (m_uiBladeTempestTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLADE_TEMPEST) == CAST_OK) + m_uiBladeTempestTimer = 22000; + } + else + m_uiBladeTempestTimer -= uiDiff; + + if (m_uiEnervatingBrandTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ENERVATING_BRAND) == CAST_OK) + m_uiEnervatingBrandTimer = 25000; + } + } + else + m_uiEnervatingBrandTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(17000, 20000); + } + else + m_uiCleaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_baltharus_clone +######*/ + +struct npc_baltharus_cloneAI : public ScriptedAI +{ + npc_baltharus_cloneAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiBladeTempestTimer; + uint32 m_uiEnervatingBrandTimer; + uint32 m_uiCleaveTimer; + + void Reset() override + { + m_uiBladeTempestTimer = 15000; + m_uiEnervatingBrandTimer = 14000; + m_uiCleaveTimer = urand(10000, 12000); + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpellEntry->Id == SPELL_ENERVATING_BRAND_PL) + pTarget->CastSpell(m_creature, SPELL_SIPHONED_MIGHT, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBladeTempestTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLADE_TEMPEST) == CAST_OK) + m_uiBladeTempestTimer = 22000; + } + else + m_uiBladeTempestTimer -= uiDiff; + + if (m_uiEnervatingBrandTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_ENERVATING_BRAND) == CAST_OK) + m_uiEnervatingBrandTimer = 25000; + } + } + else + m_uiEnervatingBrandTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(17000, 20000); + } + else + m_uiCleaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_baltharus(Creature* pCreature) +{ + return new boss_baltharusAI(pCreature); +} + +CreatureAI* GetAI_npc_baltharus_clone(Creature* pCreature) +{ + return new npc_baltharus_cloneAI(pCreature); +} + void AddSC_boss_baltharus() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_baltharus"; + pNewScript->GetAI = &GetAI_boss_baltharus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_baltharus_clone"; + pNewScript->GetAI = &GetAI_npc_baltharus_clone; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ruby_sanctum/boss_halion.cpp b/scripts/northrend/ruby_sanctum/boss_halion.cpp index 878d9e211..4967b0a61 100644 --- a/scripts/northrend/ruby_sanctum/boss_halion.cpp +++ b/scripts/northrend/ruby_sanctum/boss_halion.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,18 +16,19 @@ /* ScriptData SDName: boss_halion -SD%Complete: 20 -SDComment: only yells +SD%Complete: 50 +SDComment: Phase 3 and related transition NYI; Twilight portals NYI; Shadow Orbs NYI; Meteor Strikes NYI; Heroic abilities NYI. SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" enum { - SAY_SPAWN = -1724024, SAY_AGGRO = -1724025, - SAY_SLAY = -1724026, // There is an additonal sound entry related to SLAY: 17502 + SAY_SLAY_1 = -1724026, + SOUND_SLAY_2 = 17502, // not sure if this one has a text SAY_DEATH = -1724027, SAY_BERSERK = -1724028, SAY_FIREBALL = -1724029, @@ -41,8 +42,508 @@ enum EMOTE_INTO_TWILLIGHT = -1724036, EMOTE_INTO_PHYSICAL = -1724037, EMOTE_REGENERATE = -1724038, + + // *** Spells *** + // General + SPELL_TWILIGHT_PRECISION = 78243, + SPELL_CLEAVE = 74524, + SPELL_TAIL_LASH = 74531, + SPELL_BERSERK = 26662, + + // Transitions + SPELL_TWILIGHT_PHASING = 74808, // Start phase 2 + SPELL_SUMMON_PORTAL = 74809, + SPELL_TWILIGHT_DIVISION = 75063, + SPELL_TWILIGHT_REALM = 74807, + SPELL_TWILIGHT_MENDING = 75509, + SPELL_LEAVE_TWILIGHT_REALM = 74812, // handled by GO 202796 + //share damage spell: 74810 - serverside spell + + // Real + SPELL_FLAME_BREATH = 74525, + SPELL_METEOR_SUMMON = 74637, // summons 40029 + SPELL_FIERY_COMBUSTION = 74562, // curse - triggers 74567 on self (player); on dispell triggers 74607 and 74610 + + // Twilight + SPELL_DARK_BREATH = 74806, + SPELL_DUSK_SHROUD = 75476, + SPELL_SOUL_CONSUMPTION = 74792, // curse - triggers 74795 on self (player); on dispell triggers 74799 and 74800 + + // Corporeality + SPELL_CORPOREALITY_EVEN = 74826, // Deals & receives normal damage + SPELL_CORPOREALITY_20I = 74827, // Damage dealt increased by 10% - Damage taken increased by 15% + SPELL_CORPOREALITY_40I = 74828, // Damage dealt increased by 30% - Damage taken increased by 50% + SPELL_CORPOREALITY_60I = 74829, // Damage dealt increased by 60% - Damage taken increased by 100% + SPELL_CORPOREALITY_80I = 74830, // Damage dealt increased by 100% - Damage taken increased by 200% + SPELL_CORPOREALITY_100I = 74831, // Damage dealt increased by 200% - Damage taken increased by 400% + SPELL_CORPOREALITY_20D = 74832, // Damage dealt reduced by 10% - Damage taken reduced by 15% + SPELL_CORPOREALITY_40D = 74833, // Damage dealt reduced by 30% - Damage taken reduced by 50% + SPELL_CORPOREALITY_60D = 74834, // Damage dealt reduced by 60% - Damage taken reduced by 100% + SPELL_CORPOREALITY_80D = 74835, // Damage dealt reduced by 100% - Damage taken reduced by 200% + SPELL_CORPOREALITY_100D = 74836, // Damage dealt reduced by 200% - Damage taken reduced by 400% + + // *** Other spells *** + //Combustion + SPELL_COMBUSTION_PERIODIC = 74629, // cast by npc 40001 + + // Consumption + SPELL_CONSUMPTION_PERIODIC = 74803, // cast by npc 40135 + + // Meteor + SPELL_METEOR_VISUAL = 74641, // cast by npc 40029 (all meteor spells) + SPELL_METEOR_IMPACT = 74648, // cast on visual aura expire + SPELL_METEOR_FLAME = 74713, + SPELL_METEOR_FLAME2 = 74718, // cast by the secondary strike npcs + SPELL_BIRTH = 40031, // cast by the meteor strike npcs + + // Cutter + SPELL_TWILIGHT_CUTTER = 74768, + SEPLL_TWILIGHT_PULSE = 78861, + SPELL_TRACK_ROTATION = 74758, // cast by 40081 on 40091 + + // Living Inferno + SPELL_BLAZING_AURA = 75885, // cast by 40681 + + // Living Ember + SPELL_AWAKEN_FLAMES = 75889, // cast by 40683 + + // Npcs + NPC_COMBUSTION = 40001, + NPC_METEOR_STRIKE_MAIN = 40029, // summons the other meteor strikes using serverside spells like 74680, 74681, 74682, 74683 + NPC_CONSUMPTION = 40135, + NPC_ORB_CARRIER = 40081, // vehicle for shadow orbs + NPC_ORB_ROTATION_FOCUS = 40091, + + NPC_METEOR_STRIKE_1 = 40041, // Npc 40029 summons the first 4 secondary meteor strike npcs, then each of them summons one 40055 npc using serverside spells 74687, 74688 + NPC_METEOR_STRIKE_2 = 40042, + NPC_METEOR_STRIKE_3 = 40043, + NPC_METEOR_STRIKE_4 = 40044, + NPC_METEOR_STRIKE_FLAME = 40055, // Each npc 40055 summons other 10 40055 npcs resulting in a total spawns of 40 40055 npcs. + + // Heroic npcs + NPC_LIVING_INFERNO = 40681, // summoned by 75879 (heroic version spell) + NPC_LIVING_EMBER = 40683, + + // *** Phases *** + PHASE_PHISYCAL_REALM = 1, + PHASE_TWILIGHT_REALM = 2, + PHASE_BOTH_REALMS = 3, +}; + +static const uint32 aShadowOrbs[4] = { NPC_SHADOW_ORB_1, NPC_SHADOW_ORB_2, NPC_SHADOW_ORB_3, NPC_SHADOW_ORB_4 }; +static const uint32 aMeteorStrikes[4] = { NPC_METEOR_STRIKE_1, NPC_METEOR_STRIKE_2, NPC_METEOR_STRIKE_3, NPC_METEOR_STRIKE_4 }; + +static const float aRotationFocusPosition[4] = {3113.711f, 533.5382f, 72.96f, 1.93f}; +static const float aOrbCarrierPosition1[3] = {3153.75f, 579.1875f, 70.47f}; +static const float aOrbCarrierPosition2[3] = {3153.75f, 487.1875f, 70.47f}; + +/*###### +## boss_halion_real +######*/ + +struct boss_halion_realAI : public ScriptedAI +{ + boss_halion_realAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ruby_sanctum*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ruby_sanctum* m_pInstance; + + uint8 m_uiPhase; + + uint32 m_uiTailLashTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiFieryCombustionTimer; + uint32 m_uiMeteorTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiBerserkTimer; + + void Reset() override + { + m_uiPhase = PHASE_PHISYCAL_REALM; + + m_uiTailLashTimer = 10000; + m_uiCleaveTimer = urand(5000, 10000); + m_uiFieryCombustionTimer = 15000; + m_uiMeteorTimer = 20000; + m_uiBerserkTimer = 8 * MINUTE * IN_MILLISECONDS; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_HALION, IN_PROGRESS); + m_pInstance->SendEncounterFrame(ENCOUNTER_FRAME_ENGAGE, m_creature->GetObjectGuid(), 1); + } + + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_PRECISION, CAST_TRIGGERED); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + switch (urand(0, 1)) + { + case 0: DoScriptText(SAY_SLAY_1, m_creature); break; + case 1: DoPlaySoundToSet(m_creature, SOUND_SLAY_2); break; + } + } + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HALION, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HALION, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_COMBUSTION: + pSummoned->CastSpell(pSummoned, SPELL_COMBUSTION_PERIODIC, true); + break; + case NPC_METEOR_STRIKE_MAIN: + // ToDo: summon the other meteor strikes around this one + pSummoned->CastSpell(pSummoned, SPELL_BIRTH, true); + pSummoned->CastSpell(pSummoned, SPELL_METEOR_VISUAL, true); + break; + } + } + + void DoPrepareTwilightPhase() + { + if (!m_pInstance) + return; + + // Spawn the orbs and the carriers. Use the twilight Halion version to preserve the phase + if (Creature* pHalion = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + { + // Set current Halion hp + pHalion->SetHealth(m_creature->GetHealth()); + + // NOTE: the spawn coords seem to be totally off, compared to the actual map layout - requires additional research!!! + + // Spawn the rotation focus first + // pHalion->SummonCreature(NPC_ORB_ROTATION_FOCUS, aRotationFocusPosition[0], aRotationFocusPosition[1], aRotationFocusPosition[2], aRotationFocusPosition[3], TEMPSUMMON_DEAD_DESPAWN, 0); + + // Then spawn the orb carriers and the shadow orbs. ToDo: research if it's possible to make this dynamic + // pHalion->SummonCreature(NPC_ORB_CARRIER, aOrbCarrierPosition1[0], aOrbCarrierPosition1[1], aOrbCarrierPosition1[2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + // pHalion->SummonCreature(NPC_ORB_CARRIER, aOrbCarrierPosition2[0], aOrbCarrierPosition2[1], aOrbCarrierPosition2[2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + // pHalion->SummonCreature(NPC_SHADOW_ORB_1, aOrbCarrierPosition1[0], aOrbCarrierPosition1[1], aOrbCarrierPosition1[2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + // pHalion->SummonCreature(NPC_SHADOW_ORB_2, aOrbCarrierPosition2[0], aOrbCarrierPosition2[1], aOrbCarrierPosition2[2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + // Do the same for the Twilight halion + if (m_pInstance) + { + if (Creature* pHalion = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT, true)) + pHalion->CastSpell(pHalion, SPELL_BERSERK, true); + } + + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_BOTH_REALMS: + // ToDo: handle corporeality + // no break; + case PHASE_PHISYCAL_REALM: + + if (m_uiTailLashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(15000, 25000); + } + else + m_uiTailLashTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 15000); + } + else + m_uiCleaveTimer -= uiDiff; + + if (m_uiFlameBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BREATH) == CAST_OK) + m_uiFlameBreathTimer = urand(15000, 20000); + } + else + m_uiFlameBreathTimer -= uiDiff; + + if (m_uiFieryCombustionTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_FIERY_COMBUSTION, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIERY_COMBUSTION) == CAST_OK) + m_uiFieryCombustionTimer = 25000; + } + } + else + m_uiFieryCombustionTimer -= uiDiff; + + if (m_uiMeteorTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_METEOR_SUMMON) == CAST_OK) + { + DoScriptText(SAY_FIREBALL, m_creature); + m_uiMeteorTimer = 40000; + } + } + } + else + m_uiMeteorTimer -= uiDiff; + + // Switch to phase 2 + if (m_creature->GetHealthPercent() < 75.0f && m_uiPhase == PHASE_PHISYCAL_REALM) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_PHASING, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_PORTAL, CAST_TRIGGERED); + DoScriptText(SAY_PHASE_2, m_creature); + DoPrepareTwilightPhase(); + m_uiPhase = PHASE_TWILIGHT_REALM; + } + } + + break; + case PHASE_TWILIGHT_REALM: + + // Switch to phase 3 + if (m_creature->GetHealthPercent() < 50.0f) + { + m_creature->RemoveAurasDueToSpell(SPELL_TWILIGHT_PHASING); + DoScriptText(SAY_PHASE_3, m_creature); + m_uiPhase = PHASE_BOTH_REALMS; + } + + break; + } + + DoMeleeAttackIfReady(); + } +}; + +/*###### +## boss_halion_twilight +######*/ + +struct boss_halion_twilightAI : public ScriptedAI +{ + boss_halion_twilightAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ruby_sanctum*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ruby_sanctum* m_pInstance; + + uint8 m_uiPhase; + uint32 m_uiTailLashTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiDarkBreathTimer; + uint32 m_uiSoulConsumptionTimer; + + void Reset() override + { + m_uiPhase = PHASE_TWILIGHT_REALM; + m_uiTailLashTimer = 10000; + m_uiCleaveTimer = urand(5000, 10000); + m_uiDarkBreathTimer = 15000; + m_uiSoulConsumptionTimer = 20000; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SendEncounterFrame(ENCOUNTER_FRAME_ENGAGE, m_creature->GetObjectGuid(), 2); + + DoCastSpellIfCan(m_creature, SPELL_DUSK_SHROUD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_PRECISION, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + // Allow real Halion to evade + if (m_pInstance) + { + if (Creature* pHalion = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + pHalion->AI()->EnterEvadeMode(); + } + } + + void JustDied(Unit* /*pKiller*/) override + { + // ToDo: handle the damage sharing! + + DoScriptText(SAY_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() == TYPEID_PLAYER) + { + switch (urand(0, 1)) + { + case 0: DoScriptText(SAY_SLAY_1, m_creature); break; + case 1: DoPlaySoundToSet(m_creature, SOUND_SLAY_2); break; + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_CONSUMPTION: + pSummoned->CastSpell(pSummoned, SPELL_CONSUMPTION_PERIODIC, true); + break; + case NPC_SHADOW_ORB_1: + case NPC_SHADOW_ORB_2: + case NPC_SHADOW_ORB_3: + case NPC_SHADOW_ORB_4: + if (Creature* pCarrier = GetClosestCreatureWithEntry(pSummoned, NPC_ORB_CARRIER, 5.0f)) + pSummoned->CastSpell(pCarrier, SPELL_RIDE_VEHICLE_HARDCODED, true); + break; + case NPC_ORB_CARRIER: + pSummoned->CastSpell(pSummoned, SPELL_TRACK_ROTATION, true); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_PHISYCAL_REALM: + // nothing here - phase not handled by this npc + break; + case PHASE_BOTH_REALMS: + // ToDo: handle corporeality + // no break; + case PHASE_TWILIGHT_REALM: + + if (m_uiTailLashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TAIL_LASH) == CAST_OK) + m_uiTailLashTimer = urand(15000, 25000); + } + else + m_uiTailLashTimer -= uiDiff; + + if (m_uiCleaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(10000, 15000); + } + else + m_uiCleaveTimer -= uiDiff; + + if (m_uiDarkBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_BREATH) == CAST_OK) + m_uiDarkBreathTimer = urand(15000, 20000); + } + else + m_uiDarkBreathTimer -= uiDiff; + + if (m_uiSoulConsumptionTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SOUL_CONSUMPTION, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SOUL_CONSUMPTION) == CAST_OK) + m_uiSoulConsumptionTimer = 25000; + } + } + else + m_uiSoulConsumptionTimer -= uiDiff; + + // Switch to phase 3 + if (m_creature->GetHealthPercent() < 50.0f && m_uiPhase == PHASE_TWILIGHT_REALM) + { + if (DoCastSpellIfCan(m_creature, SPELL_TWILIGHT_DIVISION, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + if (m_pInstance) + { + // ToDo: Update world states and spawn the exit portals + + // Set the real Halion health, so it can also begin phase 3 + if (Creature* pHalion = m_pInstance->GetSingleCreatureFromStorage(NPC_HALION_REAL)) + pHalion->SetHealth(m_creature->GetHealth()); + } + + DoScriptText(SAY_PHASE_3, m_creature); + m_uiPhase = PHASE_BOTH_REALMS; + } + } + + break; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_halion_real(Creature* pCreature) +{ + return new boss_halion_realAI(pCreature); +}; + +CreatureAI* GetAI_boss_halion_twilight(Creature* pCreature) +{ + return new boss_halion_twilightAI(pCreature); }; void AddSC_boss_halion() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_halion_real"; + pNewScript->GetAI = &GetAI_boss_halion_real; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_halion_twilight"; + pNewScript->GetAI = &GetAI_boss_halion_twilight; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ruby_sanctum/boss_saviana.cpp b/scripts/northrend/ruby_sanctum/boss_saviana.cpp index fad2b283d..0efca0949 100644 --- a/scripts/northrend/ruby_sanctum/boss_saviana.cpp +++ b/scripts/northrend/ruby_sanctum/boss_saviana.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_saviana -SD%Complete: 20 -SDComment: only yells +SD%Complete: 100 +SDComment: SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" enum { @@ -30,8 +31,192 @@ enum SAY_SLAY_2 = -1724017, SAY_SPECIAL = -1724018, SOUND_DEATH = 17531, // On death it has only a screaming sound + EMOTE_ENRAGE = -1000003, + + SPELL_ENRAGE = 78722, + SPELL_FLAME_BREATH = 74403, + SPELL_CONFLAGRATION = 74452, // dummy targeting spell - effect handled in core + + PHASE_GROUND = 1, + PHASE_AIR = 2, + PHASE_TRANSITION = 3, + + POINT_AIR = 1, + POINT_GROUND = 2 +}; + +static const float aAirPositions[3] = {3155.51f, 683.844f, 90.50f}; + +struct boss_savianaAI : public ScriptedAI +{ + boss_savianaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ruby_sanctum*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ruby_sanctum* m_pInstance; + + uint8 m_uiPhase; + uint32 m_uiPhaseSwitchTimer; + uint32 m_uiFlameBreathTimer; + uint32 m_uiEnrageTimer; + + void Reset() override + { + m_uiPhase = PHASE_GROUND; + m_uiPhaseSwitchTimer = 28000; + m_uiEnrageTimer = urand(10000, 15000); + m_uiFlameBreathTimer = 10000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SAVIANA, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoPlaySoundToSet(m_creature, SOUND_DEATH); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SAVIANA, DONE); + } + + void JustReachedHome() override + { + SetCombatMovement(true); + m_creature->SetLevitate(false); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SAVIANA, FAIL); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case POINT_AIR: + if (DoCastSpellIfCan(m_creature, SPELL_CONFLAGRATION) == CAST_OK) + { + DoScriptText(SAY_SPECIAL, m_creature); + m_uiPhaseSwitchTimer = 6000; + m_uiPhase = PHASE_AIR; + } + + break; + case POINT_GROUND: + m_uiPhase = PHASE_GROUND; + m_uiPhaseSwitchTimer = 38000; + + SetCombatMovement(true); + m_creature->SetLevitate(false); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0); + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + case PHASE_GROUND: + + if (m_uiFlameBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BREATH) == CAST_OK) + m_uiFlameBreathTimer = urand(20000, 25000); + } + else + m_uiFlameBreathTimer -= uiDiff; + + if (m_uiEnrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + { + DoScriptText(EMOTE_ENRAGE, m_creature); + m_uiEnrageTimer = urand(20000, 25000); + } + } + else + m_uiEnrageTimer -= uiDiff; + + if (m_uiPhaseSwitchTimer < uiDiff) + { + m_uiPhaseSwitchTimer = 0; + m_uiPhase = PHASE_TRANSITION; + + SetCombatMovement(false); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + m_creature->SetLevitate(true); + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_AIR, aAirPositions[0], aAirPositions[1], aAirPositions[2]); + } + else + m_uiPhaseSwitchTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + break; + case PHASE_AIR: + if (m_uiPhaseSwitchTimer) + { + if (m_uiPhaseSwitchTimer <= uiDiff) + { + m_uiPhase = PHASE_TRANSITION; + m_uiPhaseSwitchTimer = 0; + + float fX, fY, fZ; + m_creature->GetRespawnCoord(fX, fY, fZ); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_GROUND, fX, fY, fZ); + } + else + m_uiPhaseSwitchTimer -= uiDiff; + } + break; + case PHASE_TRANSITION: + // nothing here + break; + } + } }; +CreatureAI* GetAI_boss_saviana(Creature* pCreature) +{ + return new boss_savianaAI(pCreature); +} + void AddSC_boss_saviana() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_saviana"; + pNewScript->GetAI = &GetAI_boss_saviana; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp b/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp index ab1156362..ee94b73af 100644 --- a/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp +++ b/scripts/northrend/ruby_sanctum/boss_zarithrian.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: boss_zarithrian -SD%Complete: 20 -SDComment: only texts +SD%Complete: 100 +SDComment: SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" enum { @@ -30,8 +31,133 @@ enum SAY_SLAY_2 = -1724021, SAY_DEATH = -1724022, SAY_SUMMON = -1724023, + + SPELL_SUMMON_FLAMECALLER = 74398, + SPELL_CLEAVE_ARMOR = 74367, + SPELL_INTIMIDATING_ROAR = 74384, + + NPC_ONYX_FLAMECALLER = 39814, // handled in ACID }; +struct boss_zarithrianAI : public ScriptedAI +{ + boss_zarithrianAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ruby_sanctum*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ruby_sanctum* m_pInstance; + + uint32 m_uiCleaveArmorTimer; + uint32 m_uiIntimidatingRoarTimer; + uint32 m_uiCallFlamecallerTimer; + + void Reset() override + { + m_uiCleaveArmorTimer = 15000; + m_uiIntimidatingRoarTimer = 14000; + m_uiCallFlamecallerTimer = 15000; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ZARITHRIAN, IN_PROGRESS); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ZARITHRIAN, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ZARITHRIAN, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ONYX_FLAMECALLER) + pSummoned->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCleaveArmorTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE_ARMOR) == CAST_OK) + m_uiCleaveArmorTimer = 15000; + } + else + m_uiCleaveArmorTimer -= uiDiff; + + if (m_uiIntimidatingRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INTIMIDATING_ROAR) == CAST_OK) + m_uiIntimidatingRoarTimer = 32000; + } + else + m_uiIntimidatingRoarTimer -= uiDiff; + + if (m_uiCallFlamecallerTimer < uiDiff) + { + if (!m_pInstance) + { + script_error_log("Instance Ruby Sanctum: ERROR Failed to load instance data for this instace."); + return; + } + + GuidList m_lStalkersGuidList; + m_pInstance->GetSpawnStalkersGuidList(m_lStalkersGuidList); + + for (GuidList::const_iterator itr = m_lStalkersGuidList.begin(); itr != m_lStalkersGuidList.end(); ++itr) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(*itr)) + pStalker->CastSpell(pStalker, SPELL_SUMMON_FLAMECALLER, true, NULL, NULL, m_creature->GetObjectGuid()); + } + + DoScriptText(SAY_SUMMON, m_creature); + m_uiCallFlamecallerTimer = 45000; + } + else + m_uiCallFlamecallerTimer -= uiDiff; + + DoMeleeAttackIfReady(); + + EnterEvadeIfOutOfCombatArea(uiDiff); + } +}; + +CreatureAI* GetAI_boss_zarithrian(Creature* pCreature) +{ + return new boss_zarithrianAI(pCreature); +} + void AddSC_boss_zarithrian() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_zarithrian"; + pNewScript->GetAI = &GetAI_boss_zarithrian; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp b/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp index 4b9274f55..204ed268c 100644 --- a/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp +++ b/scripts/northrend/ruby_sanctum/instance_ruby_sanctum.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,315 @@ /* ScriptData SDName: instance_ruby_sanctum -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 30% +SDComment: Basic instance script SDCategory: Ruby Sanctum EndScriptData */ #include "precompiled.h" +#include "ruby_sanctum.h" + +instance_ruby_sanctum::instance_ruby_sanctum(Map* pMap) : ScriptedInstance(pMap), + m_uiHalionSummonTimer(0), + m_uiHalionSummonStage(0), + m_uiHalionResetTimer(0) +{ + Initialize(); +} + +void instance_ruby_sanctum::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); +} + +bool instance_ruby_sanctum::IsEncounterInProgress() const +{ + for (uint8 i = 1; i < MAX_ENCOUNTER ; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } + + return false; +} + +void instance_ruby_sanctum::OnPlayerEnter(Player* /*pPlayer*/) +{ + // Return if Halion already dead, or Zarithrian alive + if (m_auiEncounter[TYPE_ZARITHRIAN] != DONE || m_auiEncounter[TYPE_HALION] == DONE) + return; + + // Return if already summoned + if (GetSingleCreatureFromStorage(NPC_HALION_REAL, true)) + return; + + if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_HALION_CONTROLLER)) + pSummoner->SummonCreature(NPC_HALION_REAL, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ(), 3.159f, TEMPSUMMON_DEAD_DESPAWN, 0); +} + +void instance_ruby_sanctum::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_XERESTRASZA: + // Special case for Xerestrasza: she only needs to have questgiver flag if Baltharus is killed + if (m_auiEncounter[TYPE_BALTHARUS] != DONE) + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_ZARITHRIAN: + if (m_auiEncounter[TYPE_SAVIANA] == DONE && m_auiEncounter[TYPE_BALTHARUS] == DONE) + pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // no break; + case NPC_BALTHARUS: + case NPC_HALION_REAL: + case NPC_HALION_TWILIGHT: + case NPC_HALION_CONTROLLER: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_ZARITHRIAN_SPAWN_STALKER: + m_lSpawnStalkersGuidList.push_back(pCreature->GetObjectGuid()); + break; + } +} + +void instance_ruby_sanctum::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_FLAME_WALLS: + if (m_auiEncounter[TYPE_SAVIANA] == DONE && m_auiEncounter[TYPE_BALTHARUS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FIRE_FIELD: + if (m_auiEncounter[TYPE_BALTHARUS] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FLAME_RING: + break; + case GO_BURNING_TREE_1: + case GO_BURNING_TREE_2: + case GO_BURNING_TREE_3: + case GO_BURNING_TREE_4: + if (m_auiEncounter[TYPE_ZARITHRIAN] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_TWILIGHT_PORTAL_ENTER_1: + case GO_TWILIGHT_PORTAL_ENTER_2: + case GO_TWILIGHT_PORTAL_LEAVE: + break; + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +// Wrapper to unlock the flame wall in from of Zarithrian +void instance_ruby_sanctum::DoHandleZarithrianDoor() +{ + if (m_auiEncounter[TYPE_SAVIANA] == DONE && m_auiEncounter[TYPE_BALTHARUS] == DONE) + { + DoUseDoorOrButton(GO_FLAME_WALLS); + + // Also remove not_selectable unit flag + if (Creature* pZarithrian = GetSingleCreatureFromStorage(NPC_ZARITHRIAN)) + pZarithrian->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } +} + +void instance_ruby_sanctum::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_SAVIANA: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoHandleZarithrianDoor(); + break; + case TYPE_BALTHARUS: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoHandleZarithrianDoor(); + DoUseDoorOrButton(GO_FIRE_FIELD); + + // Start outro event by DB script + if (Creature* pXerestrasza = GetSingleCreatureFromStorage(NPC_XERESTRASZA)) + pXerestrasza->GetMotionMaster()->MoveWaypoint(); + } + break; + case TYPE_ZARITHRIAN: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_FLAME_WALLS); + if (uiData == DONE) + { + // Start Halion summoning process + if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_HALION_CONTROLLER)) + { + pSummoner->CastSpell(pSummoner, SPELL_FIRE_PILLAR, false); + m_uiHalionSummonTimer = 5000; + } + } + break; + case TYPE_HALION: + // Don't set the same data twice + if (m_auiEncounter[uiType] == uiData) + return; + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_FLAME_RING); + + // encounter unit frame + if (uiData == DONE || uiData == FAIL) + { + // remove encounter frames + if (Creature* pDragon = GetSingleCreatureFromStorage(NPC_HALION_REAL)) + SendEncounterFrame(ENCOUNTER_FRAME_DISENGAGE, pDragon->GetObjectGuid()); + if (Creature* pDragon = GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + SendEncounterFrame(ENCOUNTER_FRAME_DISENGAGE, pDragon->GetObjectGuid()); + } + + // cleanup + switch (uiData) + { + case FAIL: + // Despawn the boss + if (Creature* pHalion = GetSingleCreatureFromStorage(NPC_HALION_REAL)) + pHalion->ForcedDespawn(); + if (Creature* pHalion = GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + pHalion->ForcedDespawn(); + // Note: rest of the cleanup is handled by creature_linking + + m_uiHalionResetTimer = 30000; + // no break; + case DONE: + // clear debuffs + if (Creature* pController = GetSingleCreatureFromStorage(NPC_HALION_CONTROLLER)) + pController->CastSpell(pController, SPELL_CLEAR_DEBUFFS, true); + + // Despawn the portals + if (GameObject* pPortal = GetSingleGameObjectFromStorage(GO_TWILIGHT_PORTAL_ENTER_1)) + pPortal->SetLootState(GO_JUST_DEACTIVATED); + + // ToDo: despawn the other portals as well, and disable world state + break; + } + break; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " << m_auiEncounter[3]; + + strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_ruby_sanctum::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_ruby_sanctum::Update(uint32 uiDiff) +{ + if (m_uiHalionSummonTimer) + { + if (m_uiHalionSummonTimer <= uiDiff) + { + switch (m_uiHalionSummonStage) + { + case 0: + // Burn the first line of trees + DoUseDoorOrButton(GO_BURNING_TREE_1); + DoUseDoorOrButton(GO_BURNING_TREE_2); + m_uiHalionSummonTimer = 5000; + break; + case 1: + // Burn the second line of trees + DoUseDoorOrButton(GO_BURNING_TREE_3); + DoUseDoorOrButton(GO_BURNING_TREE_4); + m_uiHalionSummonTimer = 4000; + break; + case 2: + // Cast Fiery explosion + if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_HALION_CONTROLLER)) + pSummoner->CastSpell(pSummoner, SPELL_FIERY_EXPLOSION, true); + m_uiHalionSummonTimer = 2000; + case 3: + // Spawn Halion + if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_HALION_CONTROLLER)) + { + if (Creature* pHalion = pSummoner->SummonCreature(NPC_HALION_REAL, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ(), 3.159f, TEMPSUMMON_DEAD_DESPAWN, 0)) + DoScriptText(SAY_HALION_SPAWN, pHalion); + } + m_uiHalionSummonTimer = 0; + break; + } + ++m_uiHalionSummonStage; + } + else + m_uiHalionSummonTimer -= uiDiff; + } + + // Resummon Halion if the encounter resets + if (m_uiHalionResetTimer) + { + if (m_uiHalionResetTimer <= uiDiff) + { + if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_HALION_CONTROLLER)) + pSummoner->SummonCreature(NPC_HALION_REAL, pSummoner->GetPositionX(), pSummoner->GetPositionY(), pSummoner->GetPositionZ(), 3.159f, TEMPSUMMON_DEAD_DESPAWN, 0); + + if (Creature* pHalion = GetSingleCreatureFromStorage(NPC_HALION_TWILIGHT)) + pHalion->Respawn(); + + m_uiHalionResetTimer = 0; + } + else + m_uiHalionResetTimer -= uiDiff; + } +} + +void instance_ruby_sanctum::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +InstanceData* GetInstanceData_instance_ruby_sanctum(Map* pMap) +{ + return new instance_ruby_sanctum(pMap); +} void AddSC_instance_ruby_sanctum() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "instance_ruby_sanctum"; + pNewScript->GetInstanceData = &GetInstanceData_instance_ruby_sanctum; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ruby_sanctum/ruby_sanctum.h b/scripts/northrend/ruby_sanctum/ruby_sanctum.h index 5871a49a1..53e9f29e2 100644 --- a/scripts/northrend/ruby_sanctum/ruby_sanctum.h +++ b/scripts/northrend/ruby_sanctum/ruby_sanctum.h @@ -1,3 +1,99 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_RUBY_SANCTUM_H +#define DEF_RUBY_SANCTUM_H + +enum +{ + MAX_ENCOUNTER = 4, + + TYPE_SAVIANA = 0, + TYPE_BALTHARUS = 1, + TYPE_ZARITHRIAN = 2, + TYPE_HALION = 3, + + NPC_HALION_REAL = 39863, // Halion - Physical Realm NPC + NPC_HALION_TWILIGHT = 40142, // Halion - Twilight Realm NPC + NPC_HALION_CONTROLLER = 40146, + + NPC_SHADOW_ORB_1 = 40083, // shadow orbs for Halion encounter + NPC_SHADOW_ORB_2 = 40100, + NPC_SHADOW_ORB_3 = 40468, // heroic only + NPC_SHADOW_ORB_4 = 40469, // heroic only + + NPC_SAVIANA = 39747, // minibosses + NPC_BALTHARUS = 39751, + NPC_ZARITHRIAN = 39746, + + NPC_XERESTRASZA = 40429, // friendly npc, used for some cinematic and quest + NPC_ZARITHRIAN_SPAWN_STALKER = 39794, + + GO_TWILIGHT_PORTAL_ENTER_1 = 202794, // Portals used in the Halion encounter + GO_TWILIGHT_PORTAL_ENTER_2 = 202795, + GO_TWILIGHT_PORTAL_LEAVE = 202796, + + GO_FIRE_FIELD = 203005, // Xerestrasza flame door + GO_FLAME_WALLS = 203006, // Zarithrian flame walls + GO_FLAME_RING = 203007, // Halion flame ring + GO_TWILIGHT_FLAME_RING = 203624, // Halion flame ring - twilight version + + GO_BURNING_TREE_1 = 203036, // Trees which burn when Halion appears + GO_BURNING_TREE_2 = 203037, + GO_BURNING_TREE_3 = 203035, + GO_BURNING_TREE_4 = 203034, + + // Spells used to summon Halion + SPELL_FIRE_PILLAR = 76006, + SPELL_FIERY_EXPLOSION = 76010, + SPELL_CLEAR_DEBUFFS = 75396, // cast by the controller on encounter reset + + SAY_HALION_SPAWN = -1724024, + + // world state to show corporeality in Halion encounter - phase 3 + WORLD_STATE_CORP_PHYSICAL = 5049, + WORLD_STATE_CORP_TWILIGHT = 5050, + WORLD_STATE_CORPOREALITY = 5051, +}; + +class instance_ruby_sanctum : public ScriptedInstance +{ + public: + instance_ruby_sanctum(Map* pMap); + + void Initialize() override; + bool IsEncounterInProgress() const override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + void Update(uint32 uiDiff) override; + + void GetSpawnStalkersGuidList(GuidList& lList) { lList = m_lSpawnStalkersGuidList; } + + const char* Save() const override { return strInstData.c_str(); } + void Load(const char* chrIn) override; + + // Difficulty wrappers + bool IsHeroicDifficulty() { return instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; } + bool Is25ManDifficulty() { return instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL || instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_HEROIC; } + + protected: + void DoHandleZarithrianDoor(); + + std::string strInstData; + uint32 m_auiEncounter[MAX_ENCOUNTER]; + + uint32 m_uiHalionSummonTimer; + uint32 m_uiHalionSummonStage; + uint32 m_uiHalionResetTimer; + + GuidList m_lSpawnStalkersGuidList; +}; + +#endif diff --git a/scripts/northrend/sholazar_basin.cpp b/scripts/northrend/sholazar_basin.cpp index 493b9cf3b..532670976 100644 --- a/scripts/northrend/sholazar_basin.cpp +++ b/scripts/northrend/sholazar_basin.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Sholazar_Basin SD%Complete: 100 -SDComment: Quest support: 12570, 12580, 12688 +SDComment: Quest support: 12570, 12580, 12644, 12688 SDCategory: Sholazar Basin EndScriptData */ @@ -25,6 +25,9 @@ EndScriptData */ npc_helice npc_injured_rainspeaker npc_mosswalker_victim +npc_tipsy_mcmanus +npc_wants_fruit_credit +go_quest_still_at_it_credit EndContentData */ #include "precompiled.h" @@ -50,7 +53,7 @@ enum SPELL_DETONATE_EXPLOSIVES_2 = 52371, // second "barrel" }; -struct MANGOS_DLL_DECL npc_heliceAI : public npc_escortAI +struct npc_heliceAI : public npc_escortAI { npc_heliceAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -64,13 +67,13 @@ struct MANGOS_DLL_DECL npc_heliceAI : public npc_escortAI uint32 m_uiExplodePhase; bool m_bFirstBarrel; - void Reset() + void Reset() override { } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 2: { @@ -102,7 +105,7 @@ struct MANGOS_DLL_DECL npc_heliceAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -115,7 +118,7 @@ struct MANGOS_DLL_DECL npc_heliceAI : public npc_escortAI { if (m_bFirstBarrel) { - switch(m_uiExplodePhase) + switch (m_uiExplodePhase) { case 0: DoCastSpellIfCan(m_creature, SPELL_DETONATE_EXPLOSIVES_1); @@ -143,7 +146,7 @@ struct MANGOS_DLL_DECL npc_heliceAI : public npc_escortAI } else { - switch(m_uiExplodePhase) + switch (m_uiExplodePhase) { case 0: DoCastSpellIfCan(m_creature, SPELL_DETONATE_EXPLOSIVES_2); @@ -218,13 +221,13 @@ enum SPELL_ORACLE_INTRO = 51448, }; -struct MANGOS_DLL_DECL npc_injured_rainspeakerAI : public npc_escortAI +struct npc_injured_rainspeakerAI : public npc_escortAI { npc_injured_rainspeakerAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void JustStartedEscort() + void JustStartedEscort() override { if (Player* pPlayer = GetPlayerForEscort()) { @@ -233,9 +236,9 @@ struct MANGOS_DLL_DECL npc_injured_rainspeakerAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 22: { @@ -263,7 +266,7 @@ struct MANGOS_DLL_DECL npc_injured_rainspeakerAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 /*uiDiff*/) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -355,7 +358,7 @@ bool GossipHello_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature) if (pPlayer->GetQuestStatus(QUEST_MOSSWALKER_SAVIOR) == QUEST_STATUS_INCOMPLETE) { // doesn't appear they always emote - if (urand(0,3) == 0) + if (urand(0, 3) == 0) DoScriptText(EMOTE_PAIN, pCreature); pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_PULSE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); @@ -365,7 +368,7 @@ bool GossipHello_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF) { @@ -377,9 +380,9 @@ bool GossipSelect_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature, ui else pCreature->SetLootRecipient(pPlayer); - if (urand(0,2)) // die + if (urand(0, 2)) // die { - switch(urand(0,5)) + switch (urand(0, 5)) { case 0: DoScriptText(SAY_DIE_1, pCreature, pPlayer); break; case 1: DoScriptText(SAY_DIE_2, pCreature, pPlayer); break; @@ -391,7 +394,7 @@ bool GossipSelect_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature, ui } else // survive { - switch(urand(0,3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_RESCUE_1, pCreature, pPlayer); break; case 1: DoScriptText(SAY_RESCUE_2, pCreature, pPlayer); break; @@ -408,6 +411,277 @@ bool GossipSelect_npc_mosswalker_victim(Player* pPlayer, Creature* pCreature, ui return true; } +/*###### +## npc_tipsy_mcmanus +######*/ + +enum +{ + SAY_DISTILLATION_START = -1001125, + SAY_ADD_ORANGE = -1001126, + SAY_ADD_BANANAS = -1001127, + SAY_ADD_PAPAYA = -1001128, + SAY_LIGHT_BRAZIER = -1001129, + SAY_OPEN_VALVE = -1001130, + SAY_ACTION_COMPLETE_1 = -1001131, + SAY_ACTION_COMPLETE_2 = -1001132, + SAY_ACTION_COMPLETE_3 = -1001133, + SAY_ACTION_COMPLETE_4 = -1001134, + SAY_DISTILLATION_FAIL = -1001135, + SAY_DISTILLATION_COMPLETE = -1001136, + + GOSSIP_ITEM_TIPSY_MCMANUS = -3000114, + TEXT_ID_READY = 13288, + QUEST_ID_STILL_AT_IT = 12644, + + SPELL_TOSS_ORANGE = 51931, + SPELL_TOSS_BANANA = 51932, + SPELL_TOSS_PAPAYA = 51933, + + NPC_WANTS_ORANGE_TRIGGER = 28535, + NPC_WANTS_PAPAYA_TRIGGER = 28536, + NPC_WANTS_BANANA_TRIGGER = 28537, + // NPC_STEAMING_VALVE_TRIGGER = 28539, + // NPC_WANTS_FIRE_TRIGGER = 28540, + NPC_TIPSY_MCMANUS = 28566, + + GO_THUNDERBREW_JUNGLE_PUNCH = 190643, + GO_PRESSURE_VALVE = 190635, + GO_BRAZIER = 190636, +}; + +struct StillAtItData +{ + int32 iText; + uint32 uiOwnerEntry; +}; + +static const StillAtItData aStillAtItFruits[3] = +{ + {SAY_ADD_ORANGE, NPC_WANTS_ORANGE_TRIGGER}, + {SAY_ADD_BANANAS, NPC_WANTS_BANANA_TRIGGER}, + {SAY_ADD_PAPAYA, NPC_WANTS_PAPAYA_TRIGGER}, +}; + +static const StillAtItData aStillAtItMachines[2] = +{ + {SAY_LIGHT_BRAZIER, GO_BRAZIER}, + {SAY_OPEN_VALVE, GO_PRESSURE_VALVE}, +}; + +struct npc_tipsy_mcmanusAI : public ScriptedAI +{ + npc_tipsy_mcmanusAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint8 m_uiTaskIndex; + uint32 m_uiTaskOwnerEntry; + uint32 m_uiTaskTimer; + uint32 m_uiActionTimer; + + void Reset() override + { + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + m_uiTaskIndex = 0; + m_uiTaskOwnerEntry = 0; + m_uiTaskTimer = 0; + m_uiActionTimer = 0; + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (pInvoker->GetTypeId() != TYPEID_PLAYER) + return; + + // start event + if (eventType == AI_EVENT_START_EVENT) + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + DoScriptText(SAY_DISTILLATION_START, m_creature); + m_uiTaskTimer = 5000; + } + // check fruit tasks + else if (eventType == AI_EVENT_CUSTOM_A) + { + for (uint8 i = 0; i < 3; ++i) + { + if (aStillAtItFruits[i].uiOwnerEntry == uiMiscValue) + DoCheckDistillationTask(uiMiscValue); + } + } + // check machine tasks + else if (eventType == AI_EVENT_CUSTOM_B) + { + for (uint8 i = 0; i < 2; ++i) + { + if (aStillAtItMachines[i].uiOwnerEntry == uiMiscValue) + DoCheckDistillationTask(uiMiscValue); + } + } + } + + // wrapper to complete a distillation task + void DoCheckDistillationTask(uint32 uiOwnerEntry) + { + // check if the given entry matches the expected one + if (uiOwnerEntry == m_uiTaskOwnerEntry) + { + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_ACTION_COMPLETE_1, m_creature); break; + case 1: DoScriptText(SAY_ACTION_COMPLETE_2, m_creature); break; + case 2: DoScriptText(SAY_ACTION_COMPLETE_3, m_creature); break; + case 3: DoScriptText(SAY_ACTION_COMPLETE_4, m_creature); break; + } + + m_uiTaskTimer = 6000; + m_uiActionTimer = 0; + } + // reset if failed + else + { + DoScriptText(SAY_DISTILLATION_FAIL, m_creature); + EnterEvadeMode(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiTaskTimer) + { + if (m_uiTaskTimer <= uiDiff) + { + switch (m_uiTaskIndex) + { + // fruit tasks + case 0: + case 1: + case 3: + case 6: + case 7: + { + uint8 uiIndex = urand(0, 2); + DoScriptText(aStillAtItFruits[uiIndex].iText, m_creature); + m_uiTaskOwnerEntry = aStillAtItFruits[uiIndex].uiOwnerEntry; + + m_uiTaskTimer = 0; + m_uiActionTimer = 5000; + break; + } + // valve or fire task + case 2: + case 4: + case 5: + case 8: + { + uint8 uiIndex = urand(0, 1); + DoScriptText(aStillAtItMachines[uiIndex].iText, m_creature); + m_uiTaskOwnerEntry = aStillAtItMachines[uiIndex].uiOwnerEntry; + + m_uiTaskTimer = 0; + m_uiActionTimer = 5000; + break; + } + // complete event + case 9: + DoScriptText(SAY_DISTILLATION_COMPLETE, m_creature); + if (GameObject* pPunch = GetClosestGameObjectWithEntry(m_creature, GO_THUNDERBREW_JUNGLE_PUNCH, 10.0f)) + { + pPunch->SetRespawnTime(30); + pPunch->Refresh(); + } + m_uiTaskTimer = 20000; + break; + case 10: + EnterEvadeMode(); + m_uiTaskTimer = 0; + break; + } + ++m_uiTaskIndex; + } + else + m_uiTaskTimer -= uiDiff; + } + + // timer delay to allow player to complete the task + if (m_uiActionTimer) + { + if (m_uiActionTimer <= uiDiff) + { + DoScriptText(SAY_DISTILLATION_FAIL, m_creature); + EnterEvadeMode(); + m_uiActionTimer = 0; + } + else + m_uiActionTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_tipsy_mcmanus(Creature* pCreature) +{ + return new npc_tipsy_mcmanusAI(pCreature); +} + +bool GossipHello_npc_tipsy_mcmanus(Player* pPlayer, Creature* pCreature) +{ + if (pPlayer->GetQuestStatus(QUEST_ID_STILL_AT_IT) == QUEST_STATUS_INCOMPLETE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TIPSY_MCMANUS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_READY, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_tipsy_mcmanus(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction != GOSSIP_ACTION_INFO_DEF + 1) + return false; + + pPlayer->CLOSE_GOSSIP_MENU(); + pCreature->AI()->SendAIEvent(AI_EVENT_START_EVENT, pPlayer, pCreature); + return true; +} + +/*###### +## npc_wants_fruit_credit +######*/ + +bool EffectDummyCreature_npc_wants_fruit_credit(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if ((uiSpellId == SPELL_TOSS_ORANGE || uiSpellId == SPELL_TOSS_BANANA || uiSpellId == SPELL_TOSS_PAPAYA) && uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() == TYPEID_PLAYER && ((Player*)pCaster)->GetQuestStatus(QUEST_ID_STILL_AT_IT) == QUEST_STATUS_INCOMPLETE) + { + if (Creature* pTipsyMcmanus = GetClosestCreatureWithEntry(pCaster, NPC_TIPSY_MCMANUS, 2 * INTERACTION_DISTANCE)) + { + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pTipsyMcmanus, pCreatureTarget->GetEntry()); + return true; + } + } + } + return false; +} + +/*###### +## go_quest_still_at_it_credit +######*/ + +bool GOUse_go_quest_still_at_it_credit(Player* pPlayer, GameObject* pGo) +{ + if (pPlayer->GetQuestStatus(QUEST_ID_STILL_AT_IT) != QUEST_STATUS_INCOMPLETE) + return true; + + if (Creature* pTipsyMcmanus = GetClosestCreatureWithEntry(pPlayer, NPC_TIPSY_MCMANUS, 2 * INTERACTION_DISTANCE)) + pTipsyMcmanus->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, pPlayer, pTipsyMcmanus, pGo->GetEntry()); + + return false; +} + void AddSC_sholazar_basin() { Script* pNewScript; @@ -422,8 +696,8 @@ void AddSC_sholazar_basin() pNewScript->Name = "npc_injured_rainspeaker"; pNewScript->GetAI = &GetAI_npc_injured_rainspeaker; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_injured_rainspeaker; - //pNewScript->pGossipHello = &GossipHello_npc_injured_rainspeaker; - //pNewScript->pGossipSelect = &GossipSelect_npc_injured_rainspeaker; + // pNewScript->pGossipHello = &GossipHello_npc_injured_rainspeaker; + // pNewScript->pGossipSelect = &GossipSelect_npc_injured_rainspeaker; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -431,4 +705,21 @@ void AddSC_sholazar_basin() pNewScript->pGossipHello = &GossipHello_npc_mosswalker_victim; pNewScript->pGossipSelect = &GossipSelect_npc_mosswalker_victim; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_tipsy_mcmanus"; + pNewScript->GetAI = &GetAI_npc_tipsy_mcmanus; + pNewScript->pGossipHello = &GossipHello_npc_tipsy_mcmanus; + pNewScript->pGossipSelect = &GossipSelect_npc_tipsy_mcmanus; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_wants_fruit_credit"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_wants_fruit_credit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "go_quest_still_at_it_credit"; + pNewScript->pGOUse = &GOUse_go_quest_still_at_it_credit; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/storm_peaks.cpp b/scripts/northrend/storm_peaks.cpp index 6689a0ce2..009598fa5 100644 --- a/scripts/northrend/storm_peaks.cpp +++ b/scripts/northrend/storm_peaks.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,16 +16,232 @@ /* ScriptData SDName: Storm_Peaks -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 100 +SDComment: Quest support: 12832, 12977. SDCategory: Storm Peaks EndScriptData */ /* ContentData +npc_floating_spirit +npc_restless_frostborn +npc_injured_miner EndContentData */ #include "precompiled.h" +#include "escort_ai.h" + +/*###### +## npc_floating_spirit +######*/ + +enum +{ + SPELL_BLOW_HODIRS_HORN = 55983, + SPELL_SUMMON_FROST_GIANG_SPIRIT = 55986, + SPELL_SUMMON_FROST_WARRIOR_SPIRIT = 55991, + SPELL_SUMMON_FROST_GHOST_SPIRIT = 55992, + + NPC_FROST_GIANT_GHOST_KC = 30138, + NPC_FROST_DWARF_GHOST_KC = 30139, + + NPC_NIFFELEM_FOREFATHER = 29974, + NPC_FROSTBORN_WARRIOR = 30135, + NPC_FROSTBORN_GHOST = 30144, +}; + +struct npc_floating_spiritAI : public ScriptedAI +{ + npc_floating_spiritAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override + { + // Simple animation for the floating spirit + m_creature->SetLevitate(true); + m_creature->ForcedDespawn(5000); + + m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 50.0f); + } +}; + +CreatureAI* GetAI_npc_floating_spirit(Creature* pCreature) +{ + return new npc_floating_spiritAI(pCreature); +} + +/*###### +## npc_restless_frostborn +######*/ + +bool EffectDummyCreature_npc_restless_frostborn(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_BLOW_HODIRS_HORN && uiEffIndex == EFFECT_INDEX_0 && !pCreatureTarget->isAlive() && pCaster->GetTypeId() == TYPEID_PLAYER) + { + uint32 uiCredit = 0; + uint32 uiSpawnSpell = 0; + switch (pCreatureTarget->GetEntry()) + { + case NPC_NIFFELEM_FOREFATHER: + uiCredit = NPC_FROST_GIANT_GHOST_KC; + uiSpawnSpell = SPELL_SUMMON_FROST_GIANG_SPIRIT; + break; + case NPC_FROSTBORN_WARRIOR: + uiCredit = NPC_FROST_DWARF_GHOST_KC; + uiSpawnSpell = SPELL_SUMMON_FROST_WARRIOR_SPIRIT; + break; + case NPC_FROSTBORN_GHOST: + uiCredit = NPC_FROST_DWARF_GHOST_KC; + uiSpawnSpell = SPELL_SUMMON_FROST_GHOST_SPIRIT; + break; + } + + // spawn the spirit and give the credit; spirit animation is handled by the script above + pCaster->CastSpell(pCaster, uiSpawnSpell, true); + ((Player*)pCaster)->KilledMonsterCredit(uiCredit); + return true; + } + + return false; +} + +/*###### +## npc_injured_miner +######*/ + +enum +{ + // yells + SAY_MINER_READY = -1001051, + SAY_MINER_COMPLETE = -1001052, + + // gossip + GOSSIP_ITEM_ID_READY = -3000112, + TEXT_ID_POISONED = 13650, + TEXT_ID_READY = 13651, + + // misc + SPELL_FEIGN_DEATH = 51329, + QUEST_ID_BITTER_DEPARTURE = 12832, +}; + +struct npc_injured_minerAI : public npc_escortAI +{ + npc_injured_minerAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + void Reset() override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + Start(true, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + SetEscortPaused(true); + + // set alternative waypoints if required + if (m_creature->GetPositionX() > 6650.0f) + SetCurrentWaypoint(7); + else if (m_creature->GetPositionX() > 6635.0f) + SetCurrentWaypoint(35); + + DoScriptText(SAY_MINER_READY, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_FRIEND_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + } + else if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + SetEscortPaused(false); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 33: + DoScriptText(SAY_MINER_COMPLETE, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + { + pPlayer->GroupEventHappens(QUEST_ID_BITTER_DEPARTURE, m_creature); + m_creature->SetFacingToObject(pPlayer); + } + break; + case 34: + m_creature->ForcedDespawn(); + break; + case 46: + // merge with the other wp path + SetEscortPaused(true); + SetCurrentWaypoint(13); + SetEscortPaused(false); + break; + } + } +}; + +CreatureAI* GetAI_npc_injured_miner(Creature* pCreature) +{ + return new npc_injured_minerAI(pCreature); +} + +bool GossipHello_npc_injured_miner(Player* pPlayer, Creature* pCreature) +{ + if (pCreature->isQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + if (!pCreature->HasAura(SPELL_FEIGN_DEATH)) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ID_READY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_READY, pCreature->GetObjectGuid()); + return true; + } + + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_POISONED, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_injured_miner(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + pPlayer->CLOSE_GOSSIP_MENU(); + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pCreature); + } + + return true; +} + +bool QuestAccept_npc_injured_miner(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_BITTER_DEPARTURE) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} void AddSC_storm_peaks() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "npc_floating_spirit"; + pNewScript->GetAI = &GetAI_npc_floating_spirit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_restless_frostborn"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_restless_frostborn; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_injured_miner"; + pNewScript->GetAI = &GetAI_npc_injured_miner; + pNewScript->pGossipHello = &GossipHello_npc_injured_miner; + pNewScript->pGossipSelect = &GossipSelect_npc_injured_miner; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_injured_miner; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp index 355ee8c5d..82e8ce07e 100644 --- a/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp +++ b/scripts/northrend/ulduar/halls_of_lightning/boss_bjarngrim.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Boss General Bjarngrim -SD%Complete: 70% +SD%Complete: 90% SDComment: Waypoint needed, we expect boss to always have 2x Stormforged Lieutenant following SDCategory: Halls of Lightning EndScriptData */ @@ -26,7 +26,7 @@ EndScriptData */ enum { - //Yell + // Yell SAY_AGGRO = -1602000, SAY_SLAY_1 = -1602001, SAY_SLAY_2 = -1602002, @@ -54,9 +54,9 @@ enum SPELL_MORTAL_STRIKE = 16856, SPELL_SLAM = 52026, - //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 + // Other spells - handled by DB wp movement script + // SPELL_CHARGE_UP = 52098, // only used when starting walk from one platform to the other + SPELL_TEMPORARY_ELECTRICAL_CHARGE = 52092, // triggered part of above NPC_STORMFORGED_LIEUTENANT = 29240, SPELL_ARC_WELD = 59085, @@ -72,9 +72,9 @@ enum ## boss_bjarngrim ######*/ -struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI +struct boss_bjarngrimAI : public ScriptedAI { - boss_bjarngrimAI(Creature *pCreature) : ScriptedAI(pCreature) + boss_bjarngrimAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -90,74 +90,66 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI uint8 m_uiChargingStatus; uint8 m_uiStance; - uint32 m_uiCharge_Timer; - uint32 m_uiChangeStance_Timer; + uint32 m_uiChargeTimer; + uint32 m_uiChangeStanceTimer; - uint32 m_uiReflection_Timer; - uint32 m_uiKnockAway_Timer; - uint32 m_uiPummel_Timer; - uint32 m_uiIronform_Timer; + uint32 m_uiReflectionTimer; + uint32 m_uiKnockAwayTimer; + uint32 m_uiPummelTimer; + uint32 m_uiIronformTimer; - uint32 m_uiIntercept_Timer; - uint32 m_uiWhirlwind_Timer; - uint32 m_uiCleave_Timer; + uint32 m_uiInterceptTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiCleaveTimer; - uint32 m_uiMortalStrike_Timer; - uint32 m_uiSlam_Timer; + uint32 m_uiMortalStrikeTimer; + uint32 m_uiSlamTimer; - ObjectGuid m_aStormforgedLieutenantGuid[2]; // TODO - not filled yet. - - void Reset() + void Reset() override { - m_bIsChangingStance = false; - - m_uiChargingStatus = 0; - m_uiCharge_Timer = 1000; + m_bIsChangingStance = false; - m_uiChangeStance_Timer = urand(20000, 25000); + m_uiChargingStatus = 0; + m_uiChargeTimer = 1000; - m_uiReflection_Timer = 8000; - m_uiKnockAway_Timer = 20000; - m_uiPummel_Timer = 10000; - m_uiIronform_Timer = 25000; + m_uiChangeStanceTimer = urand(20000, 25000); - m_uiIntercept_Timer = 5000; - m_uiWhirlwind_Timer = 10000; - m_uiCleave_Timer = 8000; + m_uiReflectionTimer = 8000; + m_uiKnockAwayTimer = 20000; + m_uiPummelTimer = 10000; + m_uiIronformTimer = 25000; - m_uiMortalStrike_Timer = 8000; - m_uiSlam_Timer = 10000; + m_uiInterceptTimer = 5000; + m_uiWhirlwindTimer = 10000; + m_uiCleaveTimer = 8000; - for(uint8 i = 0; i < 2; ++i) - { - if (Creature* pStormforgedLieutenant = m_creature->GetMap()->GetCreature(m_aStormforgedLieutenantGuid[i])) - { - if (!pStormforgedLieutenant->isAlive()) - pStormforgedLieutenant->Respawn(); - } - } + m_uiMortalStrikeTimer = 8000; + m_uiSlamTimer = 10000; if (m_uiStance != STANCE_DEFENSIVE) { DoCastSpellIfCan(m_creature, SPELL_DEFENSIVE_STANCE); m_uiStance = STANCE_DEFENSIVE; } - - if (m_pInstance) - m_pInstance->SetData(TYPE_BJARNGRIM, NOT_STARTED); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) + { + // Set the achiev in progress + if (m_creature->HasAura(SPELL_TEMPORARY_ELECTRICAL_CHARGE)) + m_pInstance->SetData(TYPE_BJARNGRIM, SPECIAL); + m_pInstance->SetData(TYPE_BJARNGRIM, IN_PROGRESS); + } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -165,7 +157,7 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -173,27 +165,33 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI m_pInstance->SetData(TYPE_BJARNGRIM, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override { - //Return since we have no target + if (m_pInstance) + m_pInstance->SetData(TYPE_BJARNGRIM, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Change stance - if (m_uiChangeStance_Timer < uiDiff) + if (m_uiChangeStanceTimer < uiDiff) { - //wait for current spell to finish before change stance + // wait for current spell to finish before change stance if (m_creature->IsNonMeleeSpellCasted(false)) return; - int uiTempStance = rand()%(3-1); + int uiTempStance = rand() % (3 - 1); if (uiTempStance >= m_uiStance) ++uiTempStance; m_uiStance = uiTempStance; - switch(m_uiStance) + switch (m_uiStance) { case STANCE_DEFENSIVE: DoScriptText(SAY_DEFENSIVE_STANCE, m_creature); @@ -212,96 +210,96 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI break; } - m_uiChangeStance_Timer = urand(20000, 25000); + m_uiChangeStanceTimer = urand(20000, 25000); return; } else - m_uiChangeStance_Timer -= uiDiff; + m_uiChangeStanceTimer -= uiDiff; - switch(m_uiStance) + switch (m_uiStance) { case STANCE_DEFENSIVE: { - if (m_uiReflection_Timer < uiDiff) + if (m_uiReflectionTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SPELL_REFLECTION); - m_uiReflection_Timer = urand(8000, 9000); + if (DoCastSpellIfCan(m_creature, SPELL_SPELL_REFLECTION) == CAST_OK) + m_uiReflectionTimer = urand(8000, 9000); } else - m_uiReflection_Timer -= uiDiff; + m_uiReflectionTimer -= uiDiff; - if (m_uiKnockAway_Timer < uiDiff) + if (m_uiKnockAwayTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_KNOCK_AWAY); - m_uiKnockAway_Timer = urand(20000, 21000); + if (DoCastSpellIfCan(m_creature, SPELL_KNOCK_AWAY) == CAST_OK) + m_uiKnockAwayTimer = urand(20000, 21000); } else - m_uiKnockAway_Timer -= uiDiff; + m_uiKnockAwayTimer -= uiDiff; - if (m_uiPummel_Timer < uiDiff) + if (m_uiPummelTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PUMMEL); - m_uiPummel_Timer = urand(10000, 11000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PUMMEL) == CAST_OK) + m_uiPummelTimer = urand(10000, 11000); } else - m_uiPummel_Timer -= uiDiff; + m_uiPummelTimer -= uiDiff; - if (m_uiIronform_Timer < uiDiff) + if (m_uiIronformTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_IRONFORM); - m_uiIronform_Timer = urand(25000, 26000); + if (DoCastSpellIfCan(m_creature, SPELL_IRONFORM) == CAST_OK) + m_uiIronformTimer = urand(25000, 26000); } else - m_uiIronform_Timer -= uiDiff; + m_uiIronformTimer -= uiDiff; break; } case STANCE_BERSERKER: { - if (m_uiIntercept_Timer < uiDiff) + if (m_uiInterceptTimer < uiDiff) { - //not much point is this, better random target and more often? - DoCastSpellIfCan(m_creature->getVictim(), SPELL_INTERCEPT); - m_uiIntercept_Timer = urand(45000, 46000); + // not much point is this, better random target and more often? + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_INTERCEPT) == CAST_OK) + m_uiInterceptTimer = urand(45000, 46000); } else - m_uiIntercept_Timer -= uiDiff; + m_uiInterceptTimer -= uiDiff; - if (m_uiWhirlwind_Timer < uiDiff) + if (m_uiWhirlwindTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlwind_Timer = urand(10000, 11000); + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = urand(10000, 11000); } else - m_uiWhirlwind_Timer -= uiDiff; + m_uiWhirlwindTimer -= uiDiff; - if (m_uiCleave_Timer < uiDiff) + if (m_uiCleaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleave_Timer = urand(8000, 9000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = urand(8000, 9000); } else - m_uiCleave_Timer -= uiDiff; + m_uiCleaveTimer -= uiDiff; break; } case STANCE_BATTLE: { - if (m_uiMortalStrike_Timer < uiDiff) + if (m_uiMortalStrikeTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE); - m_uiMortalStrike_Timer = urand(20000, 21000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_STRIKE) == CAST_OK) + m_uiMortalStrikeTimer = urand(20000, 21000); } else - m_uiMortalStrike_Timer -= uiDiff; + m_uiMortalStrikeTimer -= uiDiff; - if (m_uiSlam_Timer < uiDiff) + if (m_uiSlamTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SLAM); - m_uiSlam_Timer = urand(15000, 16000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SLAM) == CAST_OK) + m_uiSlamTimer = urand(15000, 16000); } else - m_uiSlam_Timer -= uiDiff; + m_uiSlamTimer -= uiDiff; break; } @@ -315,9 +313,9 @@ struct MANGOS_DLL_DECL boss_bjarngrimAI : public ScriptedAI ## mob_stormforged_lieutenant ######*/ -struct MANGOS_DLL_DECL mob_stormforged_lieutenantAI : public ScriptedAI +struct mob_stormforged_lieutenantAI : public ScriptedAI { - mob_stormforged_lieutenantAI(Creature *pCreature) : ScriptedAI(pCreature) + mob_stormforged_lieutenantAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -327,42 +325,30 @@ struct MANGOS_DLL_DECL mob_stormforged_lieutenantAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 m_uiArcWeld_Timer; - uint32 m_uiRenewSteel_Timer; - - void Reset() - { - m_uiArcWeld_Timer = urand(20000, 21000); - m_uiRenewSteel_Timer = urand(10000, 11000); - } + uint32 m_uiArcWeldTimer; + uint32 m_uiRenewSteelTimer; - void Aggro(Unit* pWho) + void Reset() override { - if (m_pInstance) - { - if (Creature* pBjarngrim = m_pInstance->GetSingleCreatureFromStorage(NPC_BJARNGRIM)) - { - if (pBjarngrim->isAlive() && !pBjarngrim->getVictim()) - pBjarngrim->AI()->AttackStart(pWho); - } - } + m_uiArcWeldTimer = urand(20000, 21000); + m_uiRenewSteelTimer = urand(10000, 11000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiArcWeld_Timer < uiDiff) + if (m_uiArcWeldTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARC_WELD); - m_uiArcWeld_Timer = urand(20000, 21000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARC_WELD) == CAST_OK) + m_uiArcWeldTimer = urand(20000, 21000); } else - m_uiArcWeld_Timer -= uiDiff; + m_uiArcWeldTimer -= uiDiff; - if (m_uiRenewSteel_Timer < uiDiff) + if (m_uiRenewSteelTimer < uiDiff) { if (m_pInstance) { @@ -372,10 +358,10 @@ struct MANGOS_DLL_DECL mob_stormforged_lieutenantAI : public ScriptedAI DoCastSpellIfCan(pBjarngrim, m_bIsRegularMode ? SPELL_RENEW_STEEL_N : SPELL_RENEW_STEEL_H); } } - m_uiRenewSteel_Timer = urand(10000, 14000); + m_uiRenewSteelTimer = urand(10000, 14000); } else - m_uiRenewSteel_Timer -= uiDiff; + m_uiRenewSteelTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp index 0855d3f9f..266e83a9e 100644 --- a/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp +++ b/scripts/northrend/ulduar/halls_of_lightning/boss_ionar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,7 +43,7 @@ enum SPELL_SUMMON_SPARK = 52746, SPELL_SPARK_DESPAWN = 52776, - //Spark of Ionar + // Spark of Ionar SPELL_SPARK_VISUAL_TRIGGER_N = 52667, SPELL_SPARK_VISUAL_TRIGGER_H = 59833, @@ -57,9 +57,9 @@ enum ## Boss Ionar ######*/ -struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI +struct boss_ionarAI : public ScriptedAI { - boss_ionarAI(Creature *pCreature) : ScriptedAI(pCreature) + boss_ionarAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -68,7 +68,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI ScriptedInstance* m_pInstance; - GUIDList m_lSparkGUIDList; + GuidList m_lSparkGUIDList; bool m_bIsRegularMode; @@ -82,7 +82,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI uint32 m_uiHealthAmountModifier; - void Reset() + void Reset() override { m_bIsSplitPhase = true; m_bIsDesperseCasting = false; @@ -98,7 +98,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI m_creature->SetVisibility(VISIBILITY_ON); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -109,7 +109,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI AttackStart(pAttacker); } - void Aggro(Unit* who) + void Aggro(Unit* /*who*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -117,7 +117,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI m_pInstance->SetData(TYPE_IONAR, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_IONAR, FAIL); @@ -125,7 +125,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI DespawnSpark(); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, true)) { @@ -138,7 +138,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI } } - void JustDied(Unit* killer) + void JustDied(Unit* /*killer*/) override { DoScriptText(SAY_DEATH, m_creature); DespawnSpark(); @@ -147,9 +147,9 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI m_pInstance->SetData(TYPE_IONAR, DONE); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*victim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -159,7 +159,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI void DespawnSpark() { - for (GUIDList::const_iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) { @@ -174,7 +174,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI // make sparks come back void CallBackSparks() { - for (GUIDList::const_iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lSparkGUIDList.begin(); itr != m_lSparkGUIDList.end(); ++itr) { if (Creature* pSpark = m_creature->GetMap()->GetCreature(*itr)) { @@ -195,7 +195,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI ++m_uiSparkAtHomeCount; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SPARK_OF_IONAR) { @@ -208,7 +208,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -273,7 +273,7 @@ struct MANGOS_DLL_DECL boss_ionarAI : public ScriptedAI m_uiBallLightningTimer -= uiDiff; // Health check - if (m_creature->GetHealthPercent() < float(100 - 20*m_uiHealthAmountModifier)) + if (m_creature->GetHealthPercent() < float(100 - 20 * m_uiHealthAmountModifier)) { ++m_uiHealthAmountModifier; @@ -293,9 +293,9 @@ CreatureAI* GetAI_boss_ionar(Creature* pCreature) return new boss_ionarAI(pCreature); } -bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_boss_ionar(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_DISPERSE && uiEffIndex == EFFECT_INDEX_0) { if (pCreatureTarget->GetEntry() != NPC_IONAR) @@ -310,7 +310,7 @@ bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, SpellEffect if (pCreatureTarget->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) pCreatureTarget->GetMotionMaster()->MovementExpired(); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } else if (uiSpellId == SPELL_SPARK_DESPAWN && uiEffIndex == EFFECT_INDEX_0) @@ -318,7 +318,7 @@ bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, SpellEffect if (pCreatureTarget->GetEntry() != NPC_IONAR) return true; - if (boss_ionarAI* pIonarAI = dynamic_cast (pCreatureTarget->AI())) + if (boss_ionarAI* pIonarAI = dynamic_cast(pCreatureTarget->AI())) pIonarAI->DespawnSpark(); return true; @@ -330,9 +330,9 @@ bool EffectDummyCreature_boss_ionar(Unit* pCaster, uint32 uiSpellId, SpellEffect ## mob_spark_of_ionar ######*/ -struct MANGOS_DLL_DECL mob_spark_of_ionarAI : public ScriptedAI +struct mob_spark_of_ionarAI : public ScriptedAI { - mob_spark_of_ionarAI(Creature *pCreature) : ScriptedAI(pCreature) + mob_spark_of_ionarAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -340,9 +340,9 @@ struct MANGOS_DLL_DECL mob_spark_of_ionarAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() { } + void Reset() override { } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE || !m_pInstance) return; diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp index 6f1ec2077..870d201d4 100644 --- a/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp +++ b/scripts/northrend/ulduar/halls_of_lightning/boss_loken.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss Loken -SD%Complete: 60% -SDComment: Missing intro. Remove hack of Pulsing Shockwave when core supports. Aura is not working (59414) +SD%Complete: 80% +SDComment: Missing intro. SDCategory: Halls of Lightning EndScriptData */ @@ -42,10 +42,10 @@ enum EMOTE_NOVA = -1602031, SPELL_ARC_LIGHTNING = 52921, - SPELL_LIGHTNING_NOVA_N = 52960, + SPELL_LIGHTNING_NOVA = 52960, SPELL_LIGHTNING_NOVA_H = 59835, - SPELL_PULSING_SHOCKWAVE_N = 52961, + SPELL_PULSING_SHOCKWAVE = 52961, SPELL_PULSING_SHOCKWAVE_H = 59836, SPELL_PULSING_SHOCKWAVE_AURA = 59414 }; @@ -54,9 +54,9 @@ enum ## Boss Loken ######*/ -struct MANGOS_DLL_DECL boss_lokenAI : public ScriptedAI +struct boss_lokenAI : public ScriptedAI { - boss_lokenAI(Creature *pCreature) : ScriptedAI(pCreature) + boss_lokenAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -66,39 +66,33 @@ struct MANGOS_DLL_DECL boss_lokenAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - bool m_bIsAura; - uint32 m_uiArcLightning_Timer; - uint32 m_uiLightningNova_Timer; - uint32 m_uiPulsingShockwave_Timer; - uint32 m_uiResumePulsingShockwave_Timer; + uint32 m_uiArcLightningTimer; + uint32 m_uiLightningNovaTimer; uint32 m_uiHealthAmountModifier; - void Reset() + void Reset() override { - m_bIsAura = false; - - m_uiArcLightning_Timer = 15000; - m_uiLightningNova_Timer = 20000; - m_uiPulsingShockwave_Timer = 2000; - m_uiResumePulsingShockwave_Timer = 15000; + m_uiArcLightningTimer = 15000; + m_uiLightningNovaTimer = 20000; m_uiHealthAmountModifier = 1; - - if (m_pInstance) - m_pInstance->SetData(TYPE_LOKEN, NOT_STARTED); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_LOKEN, IN_PROGRESS); + + // Cast Pulsing Shockwave at aggro - ToDo: enable this when the core will properly support this spell + // DoCastSpellIfCan(m_creature, SPELL_PULSING_SHOCKWAVE_AURA, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + // DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_PULSING_SHOCKWAVE : SPELL_PULSING_SHOCKWAVE_H, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -106,99 +100,59 @@ struct MANGOS_DLL_DECL boss_lokenAI : public ScriptedAI m_pInstance->SetData(TYPE_LOKEN, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { - case 0: DoScriptText(SAY_SLAY_1, m_creature);break; - case 1: DoScriptText(SAY_SLAY_2, m_creature);break; - case 2: DoScriptText(SAY_SLAY_3, m_creature);break; + case 0: DoScriptText(SAY_SLAY_1, m_creature); break; + case 1: DoScriptText(SAY_SLAY_2, m_creature); break; + case 2: DoScriptText(SAY_SLAY_3, m_creature); break; } } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LOKEN, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_bIsAura) + if (m_uiArcLightningTimer < uiDiff) { - // workaround for PULSING_SHOCKWAVE - /*if (m_uiPulsingShockwave_Timer < uiDiff) - { - Map *map = m_creature->GetMap(); - if (map->IsDungeon()) - { - Map::PlayerList const &PlayerList = map->GetPlayers(); - - if (PlayerList.isEmpty()) - return; - - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - if (i->getSource()->isAlive() && i->getSource()->isTargetableForAttack()) - { - int32 dmg; - float m_fDist = m_creature->GetDistance(i->getSource()); - - if (m_fDist <= 1.0f) // Less than 1 yard - dmg = (m_bIsRegularMode ? 800 : 850); // need to correct damage - else // Further from 1 yard - dmg = round((m_bIsRegularMode ? 200 : 250) * m_fDist) + (m_bIsRegularMode ? 800 : 850); // need to correct damage - - m_creature->CastCustomSpell(i->getSource(), (m_bIsRegularMode ? 52942 : 59837), &dmg, 0, 0, false); - } - } - m_uiPulsingShockwave_Timer = 2000; - }else m_uiPulsingShockwave_Timer -= uiDiff;*/ - } - else - { - if (m_uiResumePulsingShockwave_Timer < uiDiff) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - //breaks at movement, can we assume when it's time, this spell is casted and also must stop movement? - //m_creature->CastSpell(m_creature, SPELL_PULSING_SHOCKWAVE_AURA, true); - - //DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_PULSING_SHOCKWAVE_N : SPELL_PULSING_SHOCKWAVE_H); // need core support - m_bIsAura = true; - m_uiResumePulsingShockwave_Timer = 0; + if (DoCastSpellIfCan(pTarget, SPELL_ARC_LIGHTNING) == CAST_OK) + m_uiArcLightningTimer = urand(15000, 16000); } - else - m_uiResumePulsingShockwave_Timer -= uiDiff; - } - - if (m_uiArcLightning_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_ARC_LIGHTNING); - - m_uiArcLightning_Timer = urand(15000, 16000); } else - m_uiArcLightning_Timer -= uiDiff; + m_uiArcLightningTimer -= uiDiff; - if (m_uiLightningNova_Timer < uiDiff) + if (m_uiLightningNovaTimer < uiDiff) { - switch(urand(0, 2)) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_NOVA : SPELL_LIGHTNING_NOVA_H) == CAST_OK) { - case 0: DoScriptText(SAY_NOVA_1, m_creature);break; - case 1: DoScriptText(SAY_NOVA_2, m_creature);break; - case 2: DoScriptText(SAY_NOVA_3, m_creature);break; + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_NOVA_1, m_creature); break; + case 1: DoScriptText(SAY_NOVA_2, m_creature); break; + case 2: DoScriptText(SAY_NOVA_3, m_creature); break; + } + m_uiLightningNovaTimer = urand(20000, 21000); } - - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_NOVA_N : SPELL_LIGHTNING_NOVA_H); - - m_bIsAura = false; - m_uiResumePulsingShockwave_Timer = (m_bIsRegularMode ? 5000 : 4000); // Pause Pulsing Shockwave aura - m_uiLightningNova_Timer = urand(20000, 21000); } else - m_uiLightningNova_Timer -= uiDiff; + m_uiLightningNovaTimer -= uiDiff; // Health check - if (m_creature->GetHealthPercent() < float(100 - 25*m_uiHealthAmountModifier)) + if (m_creature->GetHealthPercent() < float(100 - 25 * m_uiHealthAmountModifier)) { - switch(m_uiHealthAmountModifier) + switch (m_uiHealthAmountModifier) { case 1: DoScriptText(SAY_75HEALTH, m_creature); break; case 2: DoScriptText(SAY_50HEALTH, m_creature); break; diff --git a/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp b/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp index bbb49d197..6ea0a4b88 100644 --- a/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp +++ b/scripts/northrend/ulduar/halls_of_lightning/boss_volkhan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,14 +43,14 @@ enum SPELL_SHATTERING_STOMP = 52237, SPELL_SHATTERING_STOMP_H = 59529, - //unclear how "directions" of spells must be. Last, summoning GO, what is it for? Script depend on: - SPELL_TEMPER = 52238, //TARGET_SCRIPT boss->anvil - SPELL_TEMPER_DUMMY = 52654, //TARGET_SCRIPT anvil->boss - //SPELL_TEMPER_VISUAL = 52661, //summons GO + // unclear how "directions" of spells must be. Last, summoning GO, what is it for? Script depend on: + SPELL_TEMPER = 52238, // TARGET_SCRIPT boss->anvil + SPELL_TEMPER_DUMMY = 52654, // TARGET_SCRIPT anvil->boss + // SPELL_TEMPER_VISUAL = 52661, // summons GO SPELL_SUMMON_MOLTEN_GOLEM = 52405, - //Molten Golem + // Molten Golem SPELL_BLAST_WAVE = 23113, SPELL_IMMOLATION_STRIKE = 52433, SPELL_IMMOLATION_STRIKE_H = 59530, @@ -68,9 +68,9 @@ enum ## Boss Volkhan ######*/ -struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI +struct boss_volkhanAI : public ScriptedAI { - boss_volkhanAI(Creature *pCreature) : ScriptedAI(pCreature) + boss_volkhanAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -79,7 +79,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI ScriptedInstance* m_pInstance; - GUIDList m_lGolemGUIDList; + GuidList m_lGolemGUIDList; bool m_bIsRegularMode; bool m_bHasShattered; @@ -88,7 +88,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI uint32 m_uiHeatTimer; uint32 m_uiTemperTimer; - void Reset() + void Reset() override { m_bHasShattered = false; @@ -97,7 +97,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI m_uiTemperTimer = 10000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -105,7 +105,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI m_pInstance->SetData(TYPE_VOLKHAN, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); DespawnGolems(); @@ -114,7 +114,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI m_pInstance->SetData(TYPE_VOLKHAN, DONE); } - void JustReachedHome() + void JustReachedHome() override { DespawnGolems(); @@ -122,9 +122,9 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI m_pInstance->SetData(TYPE_VOLKHAN, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -137,7 +137,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI if (m_lGolemGUIDList.empty()) return; - for(GUIDList::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) { @@ -154,11 +154,11 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI uint8 m_uiBrittleGolemsCount = 0; - for(GUIDList::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) + for (GuidList::const_iterator itr = m_lGolemGUIDList.begin(); itr != m_lGolemGUIDList.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) { - // only shatter brittle golems + // only shatter brittle golems if (pTemp->GetEntry() == NPC_BRITTLE_GOLEM) { pTemp->CastSpell(pTemp, m_bIsRegularMode ? SPELL_SHATTER : SPELL_SHATTER_H, true); @@ -175,7 +175,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_MOLTEN_GOLEM) { @@ -186,7 +186,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI } } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) return; @@ -195,9 +195,9 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI SetCombatMovement(true); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -244,7 +244,7 @@ struct MANGOS_DLL_DECL boss_volkhanAI : public ScriptedAI m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else - error_log("SD2: Npc %u couldn't be found or something really bad happened.", NPC_VOLKHAN_ANVIL); + script_error_log("Npc %u couldn't be found or something really bad happened.", NPC_VOLKHAN_ANVIL); } m_uiTemperTimer = 30000; } @@ -269,9 +269,9 @@ CreatureAI* GetAI_boss_volkhan(Creature* pCreature) return new boss_volkhanAI(pCreature); } -bool EffectDummyCreature_boss_volkhan(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_boss_volkhan(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_TEMPER_DUMMY && uiEffIndex == EFFECT_INDEX_0) { if (pCaster->GetEntry() != NPC_VOLKHAN_ANVIL || pCreatureTarget->GetEntry() != NPC_VOLKHAN) @@ -280,7 +280,7 @@ bool EffectDummyCreature_boss_volkhan(Unit* pCaster, uint32 uiSpellId, SpellEffe for (uint8 i = 0; i < MAX_GOLEM; ++i) pCreatureTarget->CastSpell(pCaster, SPELL_SUMMON_MOLTEN_GOLEM, true); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } @@ -291,9 +291,9 @@ bool EffectDummyCreature_boss_volkhan(Unit* pCaster, uint32 uiSpellId, SpellEffe ## npc_volkhan_anvil ######*/ -bool EffectDummyCreature_npc_volkhan_anvil(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_volkhan_anvil(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_TEMPER && uiEffIndex == EFFECT_INDEX_0) { if (pCaster->GetEntry() != NPC_VOLKHAN || pCreatureTarget->GetEntry() != NPC_VOLKHAN_ANVIL) @@ -308,7 +308,7 @@ bool EffectDummyCreature_npc_volkhan_anvil(Unit* pCaster, uint32 uiSpellId, Spel pCaster->GetMotionMaster()->MoveChase(pCaster->getVictim()); } - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } @@ -319,9 +319,9 @@ bool EffectDummyCreature_npc_volkhan_anvil(Unit* pCaster, uint32 uiSpellId, Spel ## mob_molten_golem ######*/ -struct MANGOS_DLL_DECL mob_molten_golemAI : public ScriptedAI +struct mob_molten_golemAI : public ScriptedAI { - mob_molten_golemAI(Creature *pCreature) : ScriptedAI(pCreature) + mob_molten_golemAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); @@ -335,16 +335,16 @@ struct MANGOS_DLL_DECL mob_molten_golemAI : public ScriptedAI uint32 m_uiBlastTimer; uint32 m_uiImmolationTimer; - void Reset() + void Reset() override { m_uiBlastTimer = 20000; m_uiImmolationTimer = 5000; } - void EnterEvadeMode() + void EnterEvadeMode() override { // Evade but keep the current location - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->LoadCreatureAddon(true); @@ -356,7 +356,7 @@ struct MANGOS_DLL_DECL mob_molten_golemAI : public ScriptedAI m_creature->UpdateEntry(NPC_BRITTLE_GOLEM); } - void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { // Transform intro Brittle when damaged to 0 HP if (uiDamage >= m_creature->GetHealth()) @@ -370,7 +370,7 @@ struct MANGOS_DLL_DECL mob_molten_golemAI : public ScriptedAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { // This is the dummy effect of the spells - Note: should be handled as a dummy effect in core if (pSpell->Id == SPELL_SHATTER || pSpell->Id == SPELL_SHATTER_H) @@ -380,24 +380,24 @@ struct MANGOS_DLL_DECL mob_molten_golemAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target or if we are frozen + // Return since we have no target or if we are frozen if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE); - m_uiBlastTimer = 20000; + if (DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE) == CAST_OK) + m_uiBlastTimer = 20000; } else m_uiBlastTimer -= uiDiff; if (m_uiImmolationTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_IMMOLATION_STRIKE : SPELL_IMMOLATION_STRIKE_H); - m_uiImmolationTimer = 5000; + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_IMMOLATION_STRIKE : SPELL_IMMOLATION_STRIKE_H) == CAST_OK) + m_uiImmolationTimer = 5000; } else m_uiImmolationTimer -= uiDiff; diff --git a/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h b/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h index 09b806d11..39f73d3af 100644 --- a/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h +++ b/scripts/northrend/ulduar/halls_of_lightning/halls_of_lightning.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -22,36 +22,38 @@ enum GO_VOLKHAN_DOOR = 191325, //_doors07 GO_IONAR_DOOR = 191326, //_doors05 - //GO_LOKEN_DOOR = 191324, //_doors02 + // GO_LOKEN_DOOR = 191324, //_doors02 GO_LOKEN_THRONE = 192654, ACHIEV_START_LOKEN_ID = 20384, + ACHIEV_CRIT_LIGHTNING = 6835, // Bjarngrim, achiev 1834 ACHIEV_CRIT_RESISTANT = 7321, // Volkhan, achiev 2042 }; -class MANGOS_DLL_DECL instance_halls_of_lightning : public ScriptedInstance +class instance_halls_of_lightning : public ScriptedInstance { public: instance_halls_of_lightning(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; + bool m_bLightningStruck; bool m_bIsShatterResistant; }; diff --git a/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp b/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp index ff84f1c48..74c0a9e35 100644 --- a/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp +++ b/scripts/northrend/ulduar/halls_of_lightning/instance_halls_of_lightning.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -32,6 +32,7 @@ EndScriptData */ */ instance_halls_of_lightning::instance_halls_of_lightning(Map* pMap) : ScriptedInstance(pMap), + m_bLightningStruck(false), m_bIsShatterResistant(false) { Initialize(); @@ -44,7 +45,7 @@ void instance_halls_of_lightning::Initialize() void instance_halls_of_lightning::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_BJARNGRIM: case NPC_IONAR: @@ -56,7 +57,7 @@ void instance_halls_of_lightning::OnCreatureCreate(Creature* pCreature) void instance_halls_of_lightning::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_VOLKHAN_DOOR: if (m_auiEncounter[TYPE_VOLKHAN] == DONE) @@ -77,17 +78,21 @@ void instance_halls_of_lightning::OnObjectCreate(GameObject* pGo) void instance_halls_of_lightning::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_BJARNGRIM: + if (uiData == SPECIAL) + m_bLightningStruck = true; + else if (uiData == FAIL) + m_bLightningStruck = false; m_auiEncounter[uiType] = uiData; break; case TYPE_VOLKHAN: if (uiData == DONE) DoUseDoorOrButton(GO_VOLKHAN_DOOR); - if (uiData == IN_PROGRESS) + else if (uiData == IN_PROGRESS) m_bIsShatterResistant = true; - if (uiData == SPECIAL) + else if (uiData == SPECIAL) m_bIsShatterResistant = false; m_auiEncounter[uiType] = uiData; break; @@ -99,11 +104,10 @@ void instance_halls_of_lightning::SetData(uint32 uiType, uint32 uiData) case TYPE_LOKEN: if (uiData == IN_PROGRESS) DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_LOKEN_ID); - if (uiData == DONE) + else if (uiData == DONE) { - //Appears to be type 5 GO with animation. Need to figure out how this work, code below only placeholder if (GameObject* pGlobe = GetSingleGameObjectFromStorage(GO_LOKEN_THRONE)) - pGlobe->SetGoState(GO_STATE_ACTIVE); + pGlobe->SendGameObjectCustomAnim(pGlobe->GetObjectGuid()); } m_auiEncounter[uiType] = uiData; break; @@ -123,7 +127,7 @@ void instance_halls_of_lightning::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_halls_of_lightning::GetData(uint32 uiType) +uint32 instance_halls_of_lightning::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -131,10 +135,15 @@ uint32 instance_halls_of_lightning::GetData(uint32 uiType) return 0; } -bool instance_halls_of_lightning::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_halls_of_lightning::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { - if (uiCriteriaId == ACHIEV_CRIT_RESISTANT) - return m_bIsShatterResistant; + switch (uiCriteriaId) + { + case ACHIEV_CRIT_LIGHTNING: + return m_bLightningStruck; + case ACHIEV_CRIT_RESISTANT: + return m_bIsShatterResistant; + } return false; } @@ -152,7 +161,7 @@ void instance_halls_of_lightning::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp b/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp index 80c6f86d5..36dea1f77 100644 --- a/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp +++ b/scripts/northrend/ulduar/halls_of_stone/boss_maiden_of_grief.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum ## boss_maiden_of_grief ######*/ -struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI +struct boss_maiden_of_griefAI : public ScriptedAI { boss_maiden_of_griefAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -67,7 +67,7 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI uint32 m_uiPillarTimer; uint32 m_uiPartingSorrowTimer; - void Reset() + void Reset() override { m_uiStormTimer = 5000; m_uiShockTimer = 10000; @@ -75,23 +75,23 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI m_uiPartingSorrowTimer = 12000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - if(m_pInstance) + if (m_pInstance) m_pInstance->SetData(TYPE_MAIDEN, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { - if(m_pInstance) + if (m_pInstance) m_pInstance->SetData(TYPE_MAIDEN, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -100,7 +100,7 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -108,7 +108,7 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI m_pInstance->SetData(TYPE_MAIDEN, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -118,13 +118,12 @@ struct MANGOS_DLL_DECL boss_maiden_of_griefAI : public ScriptedAI if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_PARTING_SORROW, SELECT_FLAG_PLAYER | SELECT_FLAG_POWER_MANA)) { if (DoCastSpellIfCan(pTarget, SPELL_PARTING_SORROW) == CAST_OK) - m_uiPartingSorrowTimer = 12000 + rand()%5000; + m_uiPartingSorrowTimer = 12000 + rand() % 5000; } } else m_uiPartingSorrowTimer -= uiDiff; - if (m_uiStormTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STORM_OF_GRIEF : SPELL_STORM_OF_GRIEF_H) == CAST_OK) diff --git a/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp b/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp index 1e0938085..219ff9245 100644 --- a/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp +++ b/scripts/northrend/ulduar/halls_of_stone/boss_sjonnir.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -62,13 +62,14 @@ enum // Cast at 15% hp when Bran repairs the machine SPELL_SUMMON_EARTHEN_DWARF = 50824, // left/right 50825, 50826 - SPELL_SUMMON_IRON_SLUDGE = 50747, // instakill TARGET_SCRIPT - SPELL_IRON_SLUDGE_SPAWN_VISUAL = 50777, + // Ooze and Sludge spells + SPELL_OOZE_COMBINE = 50741, // periodic aura - cast by 27981 + // SPELL_SUMMON_IRON_SLUDGE = 50747, // instakill TARGET_SCRIPT + // SPELL_IRON_SLUDGE_SPAWN_VISUAL = 50777, NPC_IRON_TROGG = 27979, NPC_IRON_DWARF = 27982, NPC_MALFORMED_OOZE = 27981, - NPC_IRON_SLUDGE = 28165, NPC_EARTHEN_DWARF = 27980, }; @@ -76,7 +77,7 @@ enum ## boss_sjonnir ######*/ -struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI +struct boss_sjonnirAI : public ScriptedAI { boss_sjonnirAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -96,18 +97,18 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI uint8 m_uiHpCheck; - void Reset() + void Reset() override { - m_uiChainLightningTimer = urand(3000, 8000); // TODO timers weak + m_uiChainLightningTimer = urand(3000, 8000); // TODO timers weak m_uiLightningShieldTimer = urand(20000, 25000); m_uiStaticChargeTimer = urand(20000, 25000); m_uiLightningRingTimer = urand(30000, 35000); - m_uiFrenzyTimer = 4*MINUTE*IN_MILLISECONDS; // TODO no proper source for this "long" + m_uiFrenzyTimer = 4 * MINUTE * IN_MILLISECONDS; // TODO no proper source for this "long" m_uiHpCheck = 75; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -118,7 +119,7 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI m_pInstance->SetData(TYPE_SJONNIR, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -126,29 +127,56 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI m_pInstance->SetData(TYPE_SJONNIR, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SJONNIR, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (pSummoned->GetEntry() == NPC_IRON_TROGG || pSummoned->GetEntry() == NPC_IRON_DWARF || pSummoned->GetEntry() == NPC_MALFORMED_OOZE) + switch (pSummoned->GetEntry()) { - float fX, fY, fZ; - pSummoned->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, fX, fY, fZ); + case NPC_EARTHEN_DWARF: + pSummoned->AI()->AttackStart(m_creature); + break; + case NPC_MALFORMED_OOZE: + { + pSummoned->CastSpell(pSummoned, SPELL_OOZE_COMBINE, true); + + // Always move to the center of the room + float fX, fY, fZ; + m_creature->GetRespawnCoord(fX, fY, fZ); + + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + break; + } + case NPC_IRON_TROGG: + case NPC_IRON_DWARF: + { + // Move to a random point around the room in order to start the attack + float fX, fY, fZ; + pSummoned->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, fX, fY, fZ); - pSummoned->SetWalk(false); - pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + break; + } } - else if (pSummoned->GetEntry() == NPC_EARTHEN_DWARF) - pSummoned->AI()->AttackStart(m_creature); } - void KilledUnit(Unit* pVictim) + void SummonedMovementInform(Creature* pSummoned, uint32 uiType, uint32 uiPointId) override { - switch(urand(0, 2)) + if (uiType != POINT_MOTION_TYPE || pSummoned->GetEntry() != NPC_MALFORMED_OOZE || !uiPointId) + return; + + pSummoned->GetMotionMaster()->MoveRandomAroundPoint(pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 10.0f); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -172,14 +200,14 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_creature->GetHealthPercent() <= (float)m_uiHpCheck) { - switch(m_uiHpCheck) + switch (m_uiHpCheck) { case 75: if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_IRON_TROGG : SPELL_SUMMON_IRON_TROGG_H, CAST_TRIGGERED) == CAST_OK) @@ -188,6 +216,7 @@ struct MANGOS_DLL_DECL boss_sjonnirAI : public ScriptedAI case 50: if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_MALFORMED_OOZE : SPELL_SUMMON_MALFORMED_OOZE_H, CAST_TRIGGERED) == CAST_OK) m_uiHpCheck = 15; + break; case 15: if (DoFrenzyIfCan()) m_uiHpCheck = 0; diff --git a/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp b/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp index 37408b405..baa75a3a2 100644 --- a/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp +++ b/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -95,39 +95,30 @@ enum SAY_ENTRANCE_MEET = -1599064, + GOSSIP_ITEM_ID_START = -3599000, + GOSSIP_ITEM_ID_PROGRESS = -3599001, + TEXT_ID_START = 13100, TEXT_ID_PROGRESS = 13101, - SPELL_STEALTH = 58506, + SPELL_SUMMON_PROTECTOR = 51780, // all spells are casted by stalker npcs 28130 + SPELL_SUMMON_STORMCALLER = 51050, + SPELL_SUMMON_CUSTODIAN = 51051, - SPELL_ACHIEVEMENT_CHECK = 59046, // Doesn't exist in client dbc + SPELL_STEALTH = 58506, - NPC_DARK_RUNE_PROTECTOR = 27983, - NPC_DARK_RUNE_STORMCALLER = 27984, - NPC_IRON_GOLEM_CUSTODIAN = 27985, + NPC_DARK_RUNE_PROTECTOR = 27983, + NPC_DARK_RUNE_STORMCALLER = 27984, + NPC_IRON_GOLEM_CUSTODIAN = 27985, - QUEST_HALLS_OF_STONE = 13207, -}; - -#define GOSSIP_ITEM_START "Brann, it would be our honor!" -#define GOSSIP_ITEM_PROGRESS "Let's move Brann, enough of the history lessons!" - -struct Location -{ - float fX, fY, fZ; -}; - -static Location SpawnLoc[]= -{ - {946.992f, 397.016f, 208.374f}, - {960.748f, 382.944f, 208.374f}, + QUEST_HALLS_OF_STONE = 13207, }; /*###### ## npc_brann_hos ######*/ -struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI +struct npc_brann_hosAI : public npc_escortAI { npc_brann_hosAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -146,9 +137,9 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI uint32 m_uiStep; uint32 m_uiPhaseTimer; - GUIDList m_luiDwarfGUIDs; + GuidList m_luiDwarfGUIDs; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -161,9 +152,9 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI } } - void KilledUnit(Unit* pVictim) // TODO - possible better as SummonedJustDied + void KilledUnit(Unit* /*pVictim*/) override // TODO - possible better as SummonedJustDied { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -171,7 +162,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -183,7 +174,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_pInstance->SetData(TYPE_TRIBUNAL, IN_PROGRESS); } - for (GUIDList::const_iterator itr = m_luiDwarfGUIDs.begin(); itr != m_luiDwarfGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_luiDwarfGUIDs.begin(); itr != m_luiDwarfGUIDs.end(); ++itr) { if (Creature* pDwarf = m_creature->GetMap()->GetCreature(*itr)) pDwarf->ForcedDespawn(); @@ -191,7 +182,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_luiDwarfGUIDs.clear(); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!pWho) return; @@ -202,18 +193,28 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI npc_escortAI::AttackStart(pWho); } + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + // If Brann takes damage, mark the achiev as failed + if (uiDamage && m_pInstance) + m_pInstance->SetBrannSpankin(false); + } + void ContinueEvent() { if (!m_pInstance || m_pInstance->GetData(TYPE_TRIBUNAL) != IN_PROGRESS) return; + // Set the achiev in progress + m_pInstance->SetBrannSpankin(true); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); SetRun(true); SetEscortPaused(false); m_bHasContinued = true; } - void JustStartedEscort() + void JustStartedEscort() override { if (m_pInstance) m_pInstance->SetData(TYPE_TRIBUNAL, IN_PROGRESS); @@ -221,8 +222,8 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI DoScriptText(SAY_ESCORT_START, m_creature); } - void WaypointReached(uint32 uiPointId) - { + void WaypointReached(uint32 uiPointId) override + { switch (uiPointId) { case 13: // Before Tribunal Event, Continue with Gossip Interaction @@ -245,44 +246,64 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_uiPhaseTimer = 1000; break; } - } + } void SpawnDwarf(uint32 uEntry) { + if (!m_pInstance) + return; + + // each case has an individual spawn stalker switch (uEntry) { case NPC_DARK_RUNE_PROTECTOR: { + Creature* pStalker = m_creature->GetMap()->GetCreature(m_pInstance->GetProtectorStalkerGuid()); + if (!pStalker) + return; + uint32 uiSpawnNumber = (m_bIsRegularMode ? 2 : 3); for (uint8 i = 0; i < uiSpawnNumber; ++i) - m_creature->SummonCreature(NPC_DARK_RUNE_PROTECTOR, SpawnLoc[0].fX, SpawnLoc[0].fY, SpawnLoc[0].fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 30000); - m_creature->SummonCreature(NPC_DARK_RUNE_STORMCALLER, SpawnLoc[0].fX, SpawnLoc[0].fY, SpawnLoc[0].fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 30000); + pStalker->CastSpell(pStalker, SPELL_SUMMON_PROTECTOR, true, NULL, NULL, m_creature->GetObjectGuid()); + pStalker->CastSpell(pStalker, SPELL_SUMMON_STORMCALLER, true, NULL, NULL, m_creature->GetObjectGuid()); break; } case NPC_DARK_RUNE_STORMCALLER: + { + Creature* pStalker = m_creature->GetMap()->GetCreature(m_pInstance->GeStormcallerStalkerGuid()); + if (!pStalker) + return; + for (uint8 i = 0; i < 2; ++i) - m_creature->SummonCreature(NPC_DARK_RUNE_STORMCALLER, SpawnLoc[1].fX, SpawnLoc[1].fY, SpawnLoc[1].fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 30000); + pStalker->CastSpell(pStalker, SPELL_SUMMON_STORMCALLER, true, NULL, NULL, m_creature->GetObjectGuid()); break; + } case NPC_IRON_GOLEM_CUSTODIAN: - m_creature->SummonCreature(NPC_IRON_GOLEM_CUSTODIAN, SpawnLoc[1].fX, SpawnLoc[1].fY, SpawnLoc[1].fZ, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 30000); + { + Creature* pStalker = m_creature->GetMap()->GetCreature(m_pInstance->GetCustodianStalkerGuid()); + if (!pStalker) + return; + + pStalker->CastSpell(pStalker, SPELL_SUMMON_CUSTODIAN, true, NULL, NULL, m_creature->GetObjectGuid()); break; + } } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { m_luiDwarfGUIDs.push_back(pSummoned->GetObjectGuid()); pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_uiPhaseTimer && m_uiPhaseTimer <= uiDiff) { switch (m_uiStep) { - // Begin Event + // Begin Event case 0: // TODO, this is wrong, must be "using or similar" m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); @@ -303,7 +324,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_uiPhaseTimer = 8500; break; - // Activate Kaddrak + // Activate Kaddrak case 4: DoScriptText(SAY_EVENT_A_1, m_creature); m_uiPhaseTimer = 6500; @@ -327,7 +348,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_uiPhaseTimer = 20000; break; - // Activate Marnak + // Activate Marnak case 9: DoScriptText(SAY_EVENT_B_1, m_creature); m_uiPhaseTimer = 6000; @@ -365,7 +386,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_uiPhaseTimer = 20000; break; - // Activate Abedneum + // Activate Abedneum case 17: if (m_pInstance) m_pInstance->DoFaceSpeak(FACE_ABEDNEUM, SAY_EVENT_C_2_ABED); @@ -425,12 +446,18 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_uiPhaseTimer = 10000; break; - // End Event + // End Event case 29: DoScriptText(SAY_EVENT_END_01, m_creature); m_creature->SetStandState(UNIT_STAND_STATE_STAND);// TODO TODO if (m_pInstance) m_pInstance->SetData(TYPE_TRIBUNAL, SPECIAL); // Kill remaining npcs + + // ToDo: the loot and the achiev should be triggered at this point + // Brann should get the gossip option "There will be plenty of time for this later Brann, we need to get moving!" + // This will allow Brann to continue the escort to the last encounter + // When reaching the last door he has the gossip "We're with you Brann! Open it!" + SetEscortPaused(false); m_uiPhaseTimer = 3000; // break; @@ -537,8 +564,6 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI m_pInstance->SetData(TYPE_TRIBUNAL, DONE); } - // Should cast spell 59046 (doesn't exist in client dbc), criterias are ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET - Player* pPlayer = GetPlayerForEscort(); if (pPlayer) pPlayer->GroupEventHappens(QUEST_HALLS_OF_STONE, m_creature); @@ -572,7 +597,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI } // Respawn Handling: Relocate and Set Escort to WP 13 - void JustRespawned() + void JustRespawned() override { if (!m_pInstance) return; @@ -593,7 +618,7 @@ struct MANGOS_DLL_DECL npc_brann_hosAI : public npc_escortAI SetCurrentWaypoint(13); } - } + } }; bool GossipHello_npc_brann_hos(Player* pPlayer, Creature* pCreature) @@ -605,12 +630,12 @@ bool GossipHello_npc_brann_hos(Player* pPlayer, Creature* pCreature) { if (pInstance->GetData(TYPE_TRIBUNAL) == NOT_STARTED || pInstance->GetData(TYPE_TRIBUNAL) == FAIL) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ID_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(TEXT_ID_START, pCreature->GetObjectGuid()); } else if (pInstance->GetData(TYPE_TRIBUNAL) == IN_PROGRESS) { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_PROGRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ID_PROGRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(TEXT_ID_PROGRESS, pCreature->GetObjectGuid()); } } @@ -618,16 +643,16 @@ bool GossipHello_npc_brann_hos(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_brann_hos(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_brann_hos(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { switch (uiAction) { case GOSSIP_ACTION_INFO_DEF + 1: - if (npc_brann_hosAI* pBrannAi = dynamic_cast (pCreature->AI())) + if (npc_brann_hosAI* pBrannAi = dynamic_cast(pCreature->AI())) pBrannAi->Start(false, pPlayer); break; case GOSSIP_ACTION_INFO_DEF + 2: - if (npc_brann_hosAI* pBrannAi = dynamic_cast (pCreature->AI())) + if (npc_brann_hosAI* pBrannAi = dynamic_cast(pCreature->AI())) pBrannAi->ContinueEvent(); break; } @@ -641,6 +666,119 @@ CreatureAI* GetAI_npc_brann_hos(Creature* pCreature) return new npc_brann_hosAI(pCreature); } +enum +{ + SPELL_SUMMON_DARK_MATTER_TARGET = 51003, + SPELL_DARK_MATTER = 51012, + SPELL_DARK_MATTER_H = 59868, + NPC_DARK_MATTER_TARGET = 28237, + + SPELL_SEARING_GAZE = 51136, + SPELL_SEARING_GAZE_H = 59867, + // NPC_SEARING_GAZE_TARGET = 28265, +}; + +/*###### +## npc_dark_matter +######*/ + +struct npc_dark_matterAI : public ScriptedAI +{ + npc_dark_matterAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + + uint32 m_uiSummonTimer; + + void Reset() override + { + m_uiSummonTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_DARK_MATTER_START) + m_uiSummonTimer = 5000; + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DARK_MATTER_TARGET) + m_creature->GetMotionMaster()->MovePoint(1, pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ()); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // Cast the Dark Matter spell and despawn for reset + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DARK_MATTER : SPELL_DARK_MATTER_H) == CAST_OK) + { + m_creature->SetRespawnDelay(3); + m_creature->ForcedDespawn(1000); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSummonTimer) + { + if (m_uiSummonTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_DARK_MATTER_TARGET) == CAST_OK) + m_uiSummonTimer = 0; + } + else + m_uiSummonTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_dark_matter(Creature* pCreature) +{ + return new npc_dark_matterAI(pCreature); +} + +/*###### +## npc_searing_gaze +######*/ + +// TODO Move this 'script' to eventAI when combat can be proper prevented from core-side +struct npc_searing_gazeAI : public Scripted_NoMovementAI +{ + npc_searing_gazeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + + void Reset() override + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SEARING_GAZE : SPELL_SEARING_GAZE_H); + // despawn manually because of combat bug + m_creature->ForcedDespawn(30000); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_searing_gaze(Creature* pCreature) +{ + return new npc_searing_gazeAI(pCreature); +} + void AddSC_halls_of_stone() { Script* pNewScript; @@ -651,4 +789,14 @@ void AddSC_halls_of_stone() pNewScript->pGossipHello = &GossipHello_npc_brann_hos; pNewScript->pGossipSelect = &GossipSelect_npc_brann_hos; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dark_matter"; + pNewScript->GetAI = &GetAI_npc_dark_matter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_searing_gaze"; + pNewScript->GetAI = &GetAI_npc_searing_gaze; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h b/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h index 6d856527d..90f2322c4 100644 --- a/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h +++ b/scripts/northrend/ulduar/halls_of_stone/halls_of_stone.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -21,6 +21,9 @@ enum NPC_MARNAK = 30897, NPC_TRIBUNAL_OF_AGES = 28234, NPC_WORLDTRIGGER = 22515, + NPC_DARK_MATTER = 28235, // used by the Tribunal event + NPC_LIGHTNING_STALKER = 28130, // used by the Tribunal event as spawn point for the dwarfs + NPC_IRON_SLUDGE = 28165, // checked in the Sjonnir achiev NPC_SJONNIR = 27978, GO_DOOR_MAIDEN = 191292, @@ -40,12 +43,19 @@ enum GO_SJONNIR_CONSOLE = 193906, + SPELL_DARK_MATTER_START = 51001, // Channeled spells used by the Tribunal event + MAX_FACES = 3, FACE_MARNAK = 0, FACE_ABEDNEUM = 1, FACE_KADDRAK = 2, + MAX_ACHIEV_SLUDGES = 5, + ACHIEV_START_MAIDEN_ID = 20383, + + ACHIEV_CRIT_BRANN = 7590, // Brann, achiev 2154 + ACHIEV_CRIT_ABUSE_OOZE = 7593, // Snonnir, achiev 2155 }; struct Face @@ -60,25 +70,34 @@ struct Face uint32 m_uiTimer; }; -class MANGOS_DLL_DECL instance_halls_of_stone : public ScriptedInstance +class instance_halls_of_stone : public ScriptedInstance { public: instance_halls_of_stone(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; + + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; void ActivateFace(uint8 uiFace, bool bAfterEvent); void DoFaceSpeak(uint8 uiFace, int32 iTextId); + void SetBrannSpankin(bool bIsMet) { m_bIsBrannSpankin = bIsMet; } + + ObjectGuid GetProtectorStalkerGuid() { return m_protectorStalkerGuid; } + ObjectGuid GeStormcallerStalkerGuid() { return m_stormcallerStalkerGuid; } + ObjectGuid GetCustodianStalkerGuid() { return m_custodianStalkerGuid; } private: void SortFaces(); @@ -88,11 +107,18 @@ class MANGOS_DLL_DECL instance_halls_of_stone : public ScriptedInstance Face m_aFaces[MAX_FACES]; std::string m_strInstData; - GUIDList m_lKaddrakGUIDs; - GUIDList m_lAbedneumGUIDs; - GUIDList m_lMarnakGUIDs; - GUIDList m_lTribunalGUIDs; - GUIDList m_lWorldtriggerGUIDs; + uint8 m_uiIronSludgeKilled; + bool m_bIsBrannSpankin; + + ObjectGuid m_protectorStalkerGuid; + ObjectGuid m_stormcallerStalkerGuid; + ObjectGuid m_custodianStalkerGuid; + + GuidList m_lKaddrakGUIDs; + GuidList m_lAbedneumGUIDs; + GuidList m_lMarnakGUIDs; + GuidList m_lTribunalGUIDs; + GuidList m_lWorldtriggerGUIDs; }; #endif diff --git a/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp b/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp index dca0cea13..d28d3eac5 100644 --- a/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp +++ b/scripts/northrend/ulduar/halls_of_stone/instance_halls_of_stone.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Instance_Halls_of_Stone -SD%Complete: 10% +SD%Complete: 50% SDComment: SDCategory: Halls of Stone EndScriptData */ @@ -31,19 +31,18 @@ enum SPELL_GLARE_OF_THE_TRIBUNAL_H = 59870, // MARNAK - SPELL_SUMMON_DARK_MATTER_TARGET = 51003, - SPELL_DARK_MATTER = 51012, // Exact mechanics unknown - SPELL_DARK_MATTER_H = 59868, - // NPC_DARK_MATTER_TARGET = 28237, + // Spells are handled in individual script // ABEDNEUM - SPELL_SUMMON_SEARING_GAZE_TARGET = 51146, - SPELL_SEARING_GAZE = 51136, - SPELL_SEARING_GAZE_H = 59867, - // NPC_SEARING_GAZE_TARGET = 28265, + SPELL_SUMMON_SEARING_GAZE_TARGET = 51146, // The other spells are handled in individual script + + SPELL_KILL_TRIBUNAL_ADD = 51288, // Cleanup event on finish + SPELL_ACHIEVEMENT_CHECK = 59046, // Doesn't exist in client dbc - added in spell_template }; -instance_halls_of_stone::instance_halls_of_stone(Map* pMap) : ScriptedInstance(pMap) +instance_halls_of_stone::instance_halls_of_stone(Map* pMap) : ScriptedInstance(pMap), + m_uiIronSludgeKilled(0), + m_bIsBrannSpankin(false) { Initialize(); } @@ -55,22 +54,32 @@ void instance_halls_of_stone::Initialize() void instance_halls_of_stone::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_KADDRAK: m_lKaddrakGUIDs.push_back(pCreature->GetObjectGuid()); break; case NPC_ABEDNEUM: m_lAbedneumGUIDs.push_back(pCreature->GetObjectGuid()); break; case NPC_MARNAK: m_lMarnakGUIDs.push_back(pCreature->GetObjectGuid()); break; case NPC_TRIBUNAL_OF_AGES: m_lTribunalGUIDs.push_back(pCreature->GetObjectGuid()); break; case NPC_WORLDTRIGGER: m_lWorldtriggerGUIDs.push_back(pCreature->GetObjectGuid()); break; + case NPC_LIGHTNING_STALKER: + // Sort the dwarf summoning stalkers + if (pCreature->GetPositionY() > 400.0f) + m_protectorStalkerGuid = pCreature->GetObjectGuid(); + else if (pCreature->GetPositionY() > 380.0f) + m_stormcallerStalkerGuid = pCreature->GetObjectGuid(); + else + m_custodianStalkerGuid = pCreature->GetObjectGuid(); + break; + case NPC_DARK_MATTER: case NPC_SJONNIR: - m_mNpcEntryGuidStore[NPC_SJONNIR] = pCreature->GetObjectGuid(); + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; } } void instance_halls_of_stone::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_TRIBUNAL_CHEST: case GO_TRIBUNAL_CHEST_H: @@ -113,6 +122,11 @@ void instance_halls_of_stone::SetData(uint32 uiType, uint32 uiData) SortFaces(); break; case DONE: + // Cast achiev check spell - Note: it's not clear who casts this spell, but for the moment we'll use Abedneum + if (Creature* pEye = instance->GetCreature(m_aFaces[1].m_leftEyeGuid)) + pEye->CastSpell(pEye, SPELL_ACHIEVEMENT_CHECK, true); + // Spawn the loot + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_TRIBUNAL_CHEST : GO_TRIBUNAL_CHEST_H, 30 * MINUTE); DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_TRIBUNAL_CHEST : GO_TRIBUNAL_CHEST_H, GO_FLAG_NO_INTERACT, false); // Door workaround because of the missing Bran event DoUseDoorOrButton(GO_DOOR_SJONNIR); @@ -132,8 +146,13 @@ void instance_halls_of_stone::SetData(uint32 uiType, uint32 uiData) { m_aFaces[i].m_bIsActive = false; m_aFaces[i].m_uiTimer = 1000; - // TODO - Kill NPCs // TODO - Check which stay red and how long (also find out how they get red..) + + // Cleanup when finished + if (Creature* pEye = instance->GetCreature(m_aFaces[i].m_leftEyeGuid)) + pEye->CastSpell(pEye, SPELL_KILL_TRIBUNAL_ADD, true); + if (Creature* pEye = instance->GetCreature(m_aFaces[i].m_rightEyeGuid)) + pEye->CastSpell(pEye, SPELL_KILL_TRIBUNAL_ADD, true); } break; } @@ -149,6 +168,8 @@ void instance_halls_of_stone::SetData(uint32 uiType, uint32 uiData) case TYPE_SJONNIR: m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_DOOR_SJONNIR); + if (uiData == IN_PROGRESS) + m_uiIronSludgeKilled = 0; break; } @@ -166,7 +187,7 @@ void instance_halls_of_stone::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_halls_of_stone::GetData(uint32 uiType) +uint32 instance_halls_of_stone::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -174,6 +195,20 @@ uint32 instance_halls_of_stone::GetData(uint32 uiType) return 0; } +bool instance_halls_of_stone::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_BRANN: + return m_bIsBrannSpankin; + case ACHIEV_CRIT_ABUSE_OOZE: + return m_uiIronSludgeKilled >= MAX_ACHIEV_SLUDGES; + + default: + return false; + } +} + struct SortHelper { SortHelper(WorldObject const* pRef): m_pRef(pRef) {} @@ -185,10 +220,10 @@ struct SortHelper }; // Small Helper-function -static void GetValidNPCsOfList(Map* pMap, GUIDList& lGUIDs, std::list& lNPCs) +static void GetValidNPCsOfList(Map* pMap, GuidList& lGUIDs, std::list& lNPCs) { lNPCs.clear(); - for (GUIDList::const_iterator itr = lGUIDs.begin(); itr != lGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = lGUIDs.begin(); itr != lGUIDs.end(); ++itr) { if (Creature* pMob = pMap->GetCreature(*itr)) lNPCs.push_back(pMob); @@ -298,6 +333,12 @@ void instance_halls_of_stone::DoFaceSpeak(uint8 uiFace, int32 iTextId) DoScriptText(iTextId, pSpeaker); } +void instance_halls_of_stone::OnCreatureDeath(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_IRON_SLUDGE && GetData(TYPE_SJONNIR) == IN_PROGRESS) + ++m_uiIronSludgeKilled; +} + void instance_halls_of_stone::Update(uint32 uiDiff) { if (m_auiEncounter[TYPE_TRIBUNAL] == IN_PROGRESS) @@ -328,7 +369,7 @@ void instance_halls_of_stone::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -347,23 +388,26 @@ void instance_halls_of_stone::ProcessFace(uint8 uiFace) pEye->CastSpell(pEye, instance->IsRegularDifficulty() ? SPELL_GLARE_OF_THE_TRIBUNAL : SPELL_GLARE_OF_THE_TRIBUNAL_H, true); if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_rightEyeGuid)) pEye->CastSpell(pEye, instance->IsRegularDifficulty() ? SPELL_GLARE_OF_THE_TRIBUNAL : SPELL_GLARE_OF_THE_TRIBUNAL_H, true, NULL, NULL, m_aFaces[uiFace].m_leftEyeGuid); - m_aFaces[uiFace].m_uiTimer = 1500; // TODO, verify + m_aFaces[uiFace].m_uiTimer = urand(1000, 2000); break; case FACE_MARNAK: - if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_leftEyeGuid)) - pEye->CastSpell(pEye, SPELL_SUMMON_DARK_MATTER_TARGET, true); + if (Creature* pDarkMatter = GetSingleCreatureFromStorage(NPC_DARK_MATTER)) + pDarkMatter->CastSpell(pDarkMatter, SPELL_DARK_MATTER_START, true); + // Note: Marnak doesn't cast anything directly. Keep this code for reference only. + // if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_leftEyeGuid)) + // pEye->CastSpell(pEye, SPELL_SUMMON_DARK_MATTER_TARGET, true); // One should be enough.. - //if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_rightEyeGuid)) + // if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_rightEyeGuid)) // pEye->CastSpell(pEye, SPELL_SUMMON_DARK_MATTER_TARGET, true); - m_aFaces[uiFace].m_uiTimer = 21000; // TODO, verify, was 3s+0..1s + m_aFaces[uiFace].m_uiTimer = urand(21000, 30000); break; case FACE_ABEDNEUM: if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_leftEyeGuid)) pEye->CastSpell(pEye, SPELL_SUMMON_SEARING_GAZE_TARGET, true); // One should be enough.. - //if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_rightEyeGuid)) + // if (Creature* pEye = instance->GetCreature(m_aFaces[uiFace].m_rightEyeGuid)) // pEye->CastSpell(pEye, SPELL_SUMMON_SEARING_GAZE_TARGET, true); - m_aFaces[uiFace].m_uiTimer = 21000; // TODO, verify, was 3s+0..2s + m_aFaces[uiFace].m_uiTimer = urand(15000, 20000); break; default: return; diff --git a/scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp b/scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp index c8066b012..4f81f02a3 100644 --- a/scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp +++ b/scripts/northrend/ulduar/ulduar/assembly_of_iron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -57,7 +57,7 @@ enum SPELL_SUPERCHARGE = 61920, SPELL_LIGHTNING_CHANNEL_PREFIGHT = 61942, // cast by Brundir on Steelbreaker SPELL_RUNE_OF_POWER_PREFIGHT = 61975, // cast by Molgeim on Stellbreaker - //SPELL_COUNCIL_KILL_CREDIT = 65195, // currently missing from DBC + SPELL_COUNCIL_KILL_CREDIT = 65195, // currently missing from DBC // Steelbreaker SPELL_HIGH_VOLTAGE = 61890, // phase 1 spells @@ -112,7 +112,7 @@ enum POINT_ID_LAND = 2, }; -struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI +struct boss_brundirAI : public ScriptedAI { boss_brundirAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -136,7 +136,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI ObjectGuid m_followTargetGuid; - void Reset() + void Reset() override { m_uiPhase = PHASE_NO_CHARGE; m_uiVisualTimer = 5000; @@ -151,7 +151,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI m_creature->SetLevitate(false); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (!m_pInstance) return; @@ -164,12 +164,15 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_BRUNDIR, false); } else + { m_pInstance->SetData(TYPE_ASSEMBLY, DONE); + m_creature->CastSpell(m_creature, SPELL_COUNCIL_KILL_CREDIT, true); + } DoScriptText(urand(0, 1) ? SAY_BRUNDIR_DEATH_1 : SAY_BRUNDIR_DEATH_2, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_BRUNDIR_AGGRO, m_creature); @@ -180,18 +183,18 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_BRUNDIR_SLAY_1 : SAY_BRUNDIR_SLAY_2, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ASSEMBLY, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_OVERLOAD_VISUAL) { @@ -202,7 +205,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { // Increase the phase when hit with the supercharge spell by his brothers if (pSpell->Id == SPELL_SUPERCHARGE) @@ -223,7 +226,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI } } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { if (pTarget->GetTypeId() != TYPEID_PLAYER) return; @@ -238,19 +241,19 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI case SPELL_CHAIN_LIGHTNING_H: case SPELL_LIGHTNING_WHIRL_DAMAGE: case SPELL_LIGHTNING_WHIRL_DAMAGE_H: - m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_STUNNED, false); + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_STUNNED, false); break; } } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) return; switch (uiPointId) { - // After lift up follow a target and set the target change timer + // After lift up follow a target and set the target change timer case POINT_ID_LIFT_OFF: // TODO: the boss should follow without changing his Z position - missing core feature // Current implementation with move point is wrong @@ -262,7 +265,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI m_uiTendrilsTargetTimer = 5000; m_uiTendrilsFollowTimer = 500; break; - // After reached the land remove all the auras and resume basic combat + // After reached the land remove all the auras and resume basic combat case POINT_ID_LAND: m_creature->SetLevitate(false); SetCombatMovement(true); @@ -285,7 +288,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Pre fight visual spell if (m_uiVisualTimer) @@ -302,7 +305,7 @@ struct MANGOS_DLL_DECL boss_brundirAI : public ScriptedAI if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - switch(m_uiPhase) + switch (m_uiPhase) { case PHASE_CHARGE_TWO: @@ -419,7 +422,7 @@ CreatureAI* GetAI_boss_brundir(Creature* pCreature) return new boss_brundirAI(pCreature); } -struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI +struct boss_molgeimAI : public ScriptedAI { boss_molgeimAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -438,7 +441,7 @@ struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI uint32 m_uiRuneDeathTimer; uint32 m_uiRuneSummonTimer; - void Reset() + void Reset() override { m_uiPhase = PHASE_NO_CHARGE; m_uiVisualTimer = 5000; @@ -448,7 +451,7 @@ struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI m_uiRuneDeathTimer = 30000; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (!m_pInstance) return; @@ -461,12 +464,15 @@ struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_MOLGEIM, false); } else + { m_pInstance->SetData(TYPE_ASSEMBLY, DONE); + m_creature->CastSpell(m_creature, SPELL_COUNCIL_KILL_CREDIT, true); + } DoScriptText(urand(0, 1) ? SAY_MOLGEIM_DEATH_1 : SAY_MOLGEIM_DEATH_2, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_MOLGEIM_AGGRO, m_creature); @@ -477,18 +483,18 @@ struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_MOLGEIM_SLAY_1 : SAY_MOLGEIM_SLAY_2, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ASSEMBLY, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_RUNE_OF_SUMMONING) pSummoned->CastSpell(pSummoned, SPELL_RUNE_OF_SUMMONING_AURA, true, NULL, NULL, m_creature->GetObjectGuid()); @@ -503,7 +509,7 @@ struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { // Increase the phase when hit with the supercharge spell by his brothers if (pSpell->Id == SPELL_SUPERCHARGE) @@ -521,7 +527,7 @@ struct MANGOS_DLL_DECL boss_molgeimAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Pre fight visual spell if (m_uiVisualTimer) @@ -601,7 +607,7 @@ CreatureAI* GetAI_boss_molgeim(Creature* pCreature) return new boss_molgeimAI(pCreature); } -struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI +struct boss_steelbreakerAI : public ScriptedAI { boss_steelbreakerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -618,7 +624,7 @@ struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI uint32 m_uiDisruptionTimer; uint32 m_uiPowerTimer; - void Reset() + void Reset() override { m_uiPhase = PHASE_NO_CHARGE; m_uiFusionPunchTimer = 15000; @@ -626,7 +632,7 @@ struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI m_uiPowerTimer = 10000; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (!m_pInstance) return; @@ -639,12 +645,15 @@ struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_STEELBREAKER, false); } else + { m_pInstance->SetData(TYPE_ASSEMBLY, DONE); + m_creature->CastSpell(m_creature, SPELL_COUNCIL_KILL_CREDIT, true); + } DoScriptText(urand(0, 1) ? SAY_STEEL_DEATH_1 : SAY_STEEL_DEATH_2, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_STEEL_AGGRO, m_creature); @@ -655,18 +664,18 @@ struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HIGH_VOLTAGE : SPELL_HIGH_VOLTAGE_H, CAST_TRIGGERED); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_STEEL_SLAY_1 : SAY_STEEL_SLAY_2, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_ASSEMBLY, FAIL); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { // Increase the phase when hit with the supercharge spell by his brothers if (pSpell->Id == SPELL_SUPERCHARGE) @@ -687,7 +696,7 @@ struct MANGOS_DLL_DECL boss_steelbreakerAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/ulduar/ulduar/boss_algalon.cpp b/scripts/northrend/ulduar/ulduar/boss_algalon.cpp index d1ccfd97f..2aed14fc6 100644 --- a/scripts/northrend/ulduar/ulduar/boss_algalon.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_algalon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_algalon -SD%Complete: 0% -SDComment: +SD%Complete: 85% +SDComment: Achievements NYI; Some details might need some fine tunning. SDCategory: Ulduar EndScriptData */ @@ -49,10 +49,789 @@ enum SAY_OUTRO_3 = -1603123, SAY_OUTRO_4 = -1603124, SAY_OUTRO_5 = -1603125, + SAY_BRANN_OUTRO = -1603246, + // intro spells + SPELL_ARRIVAL = 64997, // intro animation spells + SPELL_RIDE_LIGHTNING = 64986, + SPELL_SUMMON_AZEROTH = 64994, // summons npc 34246 + SPELL_REORIGINATION = 64996, // channeled animation on Azeroth globe + + // generic spells + // SPELL_ALGALON_EVENT_BEAM = 64367, // puspose unk + // SPELL_ALGALON_EVENT_CLIMAX = 64580, + SPELL_KILL_CREDIT = 65184, // achiev check spell + SPELL_SUPERMASSIVE_FAIL = 65311, // related to the Supermassive achievements + SPELL_BERSERK = 47008, + SPELL_ASCEND_HEAVENS = 64487, // cast when time's up + + // combat spells + SPELL_QUANTUM_STRIKE = 64395, + SPELL_QUANTUM_STRIKE_H = 64592, + SPELL_PHASE_PUNCH = 64412, + SPELL_PHASE_PUNCH_SHIFT = 64417, + SPELL_COSMIC_SMASH_SUMMON = 62301, // triggers the spells which summon 33104 and 33105 + SPELL_COSMIC_SMASH_SUMMON_H = 64598, + SPELL_BIG_BANG = 64443, // removes players from phase + SPELL_BIG_BANG_H = 64584, + + // cosmic smash spells + SPELL_COSMIC_SMASH_STATE = 62300, // visual spell; cast by 33104 + // SPELL_COSMIC_SMASH = 62304, // damage spells; cast by 33105 after 5 secs from spawn + // SPELL_COSMIC_SMASH_H = 64597, + + // collapsing star spells + SPELL_COLLAPSE = 62018, // cast by npc 32955 + SPELL_BLACK_HOLE_EXPLOSION = 64122, // cast on death + SPELL_BLACK_HOLE_EXPLOSION_H = 65108, + SPELL_SUMMON_BLACK_HOLE = 62189, // summon npc 32953; cast on death + + // black hole spells + SPELL_BLACK_HOLE_SPAWN_VISUAL = 62003, // spawn visual spell + SPELL_BLACK_HOLE_STATE = 64135, // visual spell + SPELL_BLACK_HOLE_TRIGG = 62185, // apply aoe phase aura + SPELL_BLACK_HOLE_PHASE = 62168, + SPELL_BLACK_HOLE_DMG = 62169, // damage aura applied to players in phase realm + SPELL_BLACK_HOLE_CREDIT = 65312, // dummy aoe spell; related to the Supermassive achievements + SPELL_BLACK_HOLE_DESPAWN = 64391, // purpose unk + + // living constellation spells + // SPELL_CONSTELATION_PHASE = 65508, // shift phase - use unk + SPELL_ARCANE_BARRAGE = 64599, + SPELL_ARCANE_BARRAGE_H = 64607, + + // worm hole spells + SPELL_WORM_HOLE_TRIGGER = 65251, // apply aoe phase aura + SPELL_WORM_HOLE_PHASE = 65250, + SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450, // summon npc 34097 + SPELL_SUMMON_VOID_ZONE_VISUAL = 64470, // summon npc 34100 + + // void zone visual + SPELL_VOID_ZONE_VISUAL = 64469, + + // npcs + NPC_AZEROTH = 34246, + NPC_ASTEROID_STALKER_1 = 33104, + // NPC_ASTEROID_STALKER_2 = 33105, // cast 62304 : 64597 on timer; handled in eventAI + NPC_COLLAPSING_STAR = 32955, + NPC_BLACK_HOLE = 32953, + NPC_VOID_ZONE_VISUAL = 34100, + NPC_LIVING_CONSTELLATION = 33052, + // NPC_DARK_MATTER = 33089, // found in phaseMask 16 + NPC_WORM_HOLE = 34099, // spawned when below 20% hp + NPC_UNLEASHED_DARK_MATTER = 34097, + + // other + FACTION_ID_FRIENDLY = 35, + MAX_CONSTELATIONS = 11, + MAX_ACTIVE_CONSTELATIONS = 3, + MAX_BLACK_HOLES = 4, + MAX_WORM_HOLES = 4, +}; + +static const DialogueEntry aAlgalonDialogue[] = +{ + {SAY_INTRO_1, NPC_ALGALON, 6000}, + {SPELL_SUMMON_AZEROTH, 0, 5000}, + {SAY_INTRO_2, NPC_ALGALON, 8000}, + {SAY_INTRO_3, NPC_ALGALON, 12000}, + {SPELL_SUPERMASSIVE_FAIL, 0, 0}, + {SAY_AGGRO, NPC_ALGALON, 14000}, + {SAY_ENGAGE, NPC_ALGALON, 0}, + {SPELL_ASCEND_HEAVENS, 0, 3000}, + {SPELL_BERSERK, 0, 0}, + {SAY_DESPAWN_1, NPC_ALGALON, 15000}, + {SAY_DESPAWN_2, NPC_ALGALON, 8000}, + {SAY_DESPAWN_3, NPC_ALGALON, 10000}, + {SPELL_TELEPORT, 0, 0}, + {NPC_ALGALON, 0, 12000}, + {SAY_OUTRO_1, NPC_ALGALON, 39000}, + {SAY_OUTRO_2, NPC_ALGALON, 18000}, + {SAY_OUTRO_3, NPC_ALGALON, 12000}, + {SAY_OUTRO_4, NPC_ALGALON, 12000}, + {SAY_BRANN_OUTRO, NPC_BRANN_ALGALON, 11000}, + {SAY_OUTRO_5, NPC_ALGALON, 15000}, + {SPELL_TELEPORT, 0, 0}, + {0, 0, 0}, +}; + +static const float afWormHoles[MAX_WORM_HOLES][3] = +{ + {1649.364f, -328.4229f, 417.4044f}, + {1615.728f, -320.9379f, 417.4044f}, + {1618.209f, -292.0328f, 417.4044f}, + {1646.932f, -296.028f, 417.4044f}, +}; + +static const float afConstellations[MAX_CONSTELATIONS][4] = +{ + {1678.677f, -276.328f, 427.7531f, 3.97f}, + {1685.613f, -300.1219f, 443.2366f, 3.38f}, + {1668.317f, -324.7676f, 457.9394f, 3.21f}, + {1635.821f, -363.3442f, 424.3459f, 1.46f}, + {1672.188f, -357.2484f, 436.7337f, 2.33f}, + {1593.389f, -299.4325f, 432.4636f, 6.07f}, + {1591.706f, -263.8201f, 441.4153f, 5.25f}, + {1658.279f, -262.549f, 441.9073f, 4.18f}, + {1592.242f, -325.5323f, 446.9508f, 0.22f}, + {1625.208f, -267.2771f, 446.4296f, 5.04f}, + {1615.8f, -348.0065f, 442.9586f, 1.13f}, +}; + +/*###### +## boss_algalon +######*/ + +struct boss_algalonAI : public ScriptedAI, private DialogueHelper +{ + boss_algalonAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aAlgalonDialogue) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + m_creature->SetActiveObjectState(true); + m_bEventFinished = false; + Reset(); + + // start intro event on first spawn + if (pCreature->GetPositionZ() > 450.0f) + DoStartIntroEvent(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + bool m_bEventFinished; + bool m_bIsLowHealth; + + uint32 m_uiBerserkTimer; + uint8 m_uiActiveConstelations; + uint8 m_uiActiveStars; + + uint32 m_uiBigBangTimer; + uint32 m_uiCosmicSmashTimer; + uint32 m_uiPhasePunchTimer; + uint32 m_uiQuantumStrikeTimer; + uint32 m_uiCollapsingStarTimer; + uint32 m_uiConstellationTimer; + + GuidList m_lSummonedGuids; + GuidList m_lConstellationsGuids; + + void Reset() override + { + m_uiBerserkTimer = 6 * MINUTE * IN_MILLISECONDS; + m_bIsLowHealth = false; + m_uiActiveConstelations = 0; + m_uiActiveStars = 0; + + m_uiQuantumStrikeTimer = 4000; + m_uiCollapsingStarTimer = 20000; + m_uiConstellationTimer = 60000; + m_uiBigBangTimer = 90000; + m_uiPhasePunchTimer = 15000; + m_uiCosmicSmashTimer = 30000; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + // start the counter at the first aggro + if (m_pInstance->GetData(TYPE_ALGALON) == SPECIAL) + { + m_pInstance->DoUpdateWorldState(WORLD_STATE_TIMER, 1); + m_pInstance->SetData(TYPE_ALGALON_TIMER, 60); + } + + m_pInstance->SetData(TYPE_ALGALON, IN_PROGRESS); + } + + DoCastSpellIfCan(m_creature, SPELL_SUPERMASSIVE_FAIL, CAST_TRIGGERED); + // Note: it's not clear wether these texts should be yelled on every aggro + StartNextDialogueText(SAY_AGGRO); + } + + void AttackStart(Unit* pWho) override + { + // don't attack again after being defeated + if (m_bEventFinished) + return; + + ScriptedAI::AttackStart(pWho); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (!m_bEventFinished) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_ALGALON, DONE); + + m_creature->setFaction(FACTION_ID_FRIENDLY); + m_bEventFinished = true; + EnterEvadeMode(); + } + } + } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + if (m_bEventFinished) + { + if (m_pInstance->GetData(TYPE_ALGALON) == DONE) + { + // complete the achiev and start outro dialogue + DoCastSpellIfCan(m_creature, SPELL_KILL_CREDIT, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUPERMASSIVE_FAIL, CAST_TRIGGERED); + StartNextDialogueText(NPC_ALGALON); + } + else + StartNextDialogueText(SAY_DESPAWN_1); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + else + { + m_pInstance->SetData(TYPE_ALGALON, FAIL); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + // despawn everything + for (GuidList::const_iterator itr = m_lSummonedGuids.begin(); itr != m_lSummonedGuids.end(); ++itr) + { + if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) + pSummoned->ForcedDespawn(); + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + // move Brann to the center of the platform (and override pathfinding because of missing GO support) + case NPC_BRANN_ALGALON: + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(0, 1631.986f, -297.7831f, 417.321f, false); + break; + case NPC_AZEROTH: + pSummoned->ForcedDespawn(30000); + break; + case NPC_ASTEROID_STALKER_1: + // visual impact point for Cosmic Smash + pSummoned->CastSpell(pSummoned, SPELL_COSMIC_SMASH_STATE, true); + break; + case NPC_COLLAPSING_STAR: + // cast Collapse and move around spawn point + pSummoned->CastSpell(pSummoned, SPELL_COLLAPSE, true); + pSummoned->GetMotionMaster()->MoveRandomAroundPoint(pSummoned->GetPositionX(), pSummoned->GetPositionY(), pSummoned->GetPositionZ(), 30.0f); + ++m_uiActiveStars; + m_lSummonedGuids.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_LIVING_CONSTELLATION: + m_lConstellationsGuids.push_back(pSummoned->GetObjectGuid()); + m_lSummonedGuids.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_BLACK_HOLE: + // cast Black Hole visuals + pSummoned->CastSpell(pSummoned, SPELL_BLACK_HOLE_SPAWN_VISUAL, true); + pSummoned->CastSpell(pSummoned, SPELL_BLACK_HOLE_STATE, true); + pSummoned->CastSpell(pSummoned, SPELL_BLACK_HOLE_TRIGG, true); + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_VOID_ZONE_VISUAL, true, NULL, NULL, m_creature->GetObjectGuid()); + m_lSummonedGuids.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_WORM_HOLE: + pSummoned->CastSpell(pSummoned, SPELL_WORM_HOLE_TRIGGER, true); + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_VOID_ZONE_VISUAL, true, NULL, NULL, m_creature->GetObjectGuid()); + m_lSummonedGuids.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_VOID_ZONE_VISUAL: + pSummoned->CastSpell(pSummoned, SPELL_VOID_ZONE_VISUAL, true); + m_lSummonedGuids.push_back(pSummoned->GetObjectGuid()); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_COLLAPSING_STAR) + { + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_BLACK_HOLE_EXPLOSION : SPELL_BLACK_HOLE_EXPLOSION_H, true); + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_BLACK_HOLE, true, NULL, NULL, m_creature->GetObjectGuid()); + --m_uiActiveStars; + // Note: there should be some emote here informing the players how many Black Holes are spawned + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // start intro and reset home position + StartNextDialogueText(SAY_INTRO_1); + m_creature->SetLevitate(false); + m_creature->RemoveAurasDueToSpell(SPELL_RIDE_LIGHTNING); + m_creature->SetRespawnCoord(afAlgalonMovePos[0], afAlgalonMovePos[1], afAlgalonMovePos[2], afAlgalonMovePos[3]); + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case SPELL_SUMMON_AZEROTH: + DoCastSpellIfCan(m_creature, SPELL_SUMMON_AZEROTH, CAST_TRIGGERED); + break; + case SAY_INTRO_2: + DoCastSpellIfCan(m_creature, SPELL_REORIGINATION); + break; + case SPELL_SUPERMASSIVE_FAIL: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + break; + case SAY_ENGAGE: + // summon Living Constellations at this point + DoSpawnConstellations(); + break; + case SPELL_BERSERK: + EnterEvadeMode(); + break; + case SPELL_TELEPORT: + // despawn when time has run out + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + DoCastSpellIfCan(m_creature, SPELL_TELEPORT, CAST_TRIGGERED); + m_creature->ForcedDespawn(2000); + break; + case NPC_ALGALON: + // spawn Brann for epilogue dialogue + m_creature->SummonCreature(NPC_BRANN_ALGALON, 1631.962f, -208.6464f, 420.8867f, 4.71f, TEMPSUMMON_DEAD_DESPAWN, 0); + break; + case SAY_OUTRO_1: + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // notify boss that time is over + // this will trigger the wipe spell and make the boss evade and finally despawn + if (eventType == AI_EVENT_CUSTOM_A) + { + m_bEventFinished = true; + DoCastSpellIfCan(m_creature, SPELL_ASCEND_HEAVENS, CAST_INTERRUPT_PREVIOUS); + StartNextDialogueText(SPELL_ASCEND_HEAVENS); + } + } + + // function to start the intro part on first spawn + void DoStartIntroEvent() + { + m_creature->SetLevitate(true); + DoCastSpellIfCan(m_creature, SPELL_ARRIVAL); + DoCastSpellIfCan(m_creature, SPELL_RIDE_LIGHTNING, CAST_TRIGGERED); + m_creature->GetMotionMaster()->MovePoint(1, afAlgalonMovePos[0], afAlgalonMovePos[1], afAlgalonMovePos[2]); + } + + // function which summons constellations + void DoSpawnConstellations() + { + for (uint8 i = 0; i < MAX_CONSTELATIONS; ++i) + m_creature->SummonCreature(NPC_LIVING_CONSTELLATION, afConstellations[i][0], afConstellations[i][1], afConstellations[i][2], afConstellations[i][3], TEMPSUMMON_DEAD_DESPAWN, 0); + } + + // Activate a random Constellation + void ActivateRandomConstellation() + { + // spawn a new set of constellations if empty + if (m_lConstellationsGuids.empty()) + { + DoSpawnConstellations(); + m_uiConstellationTimer = 5000; + return; + } + + GuidList::iterator iter = m_lConstellationsGuids.begin(); + advance(iter, urand(0, m_lConstellationsGuids.size() - 1)); + + if (Creature* pConstellation = m_creature->GetMap()->GetCreature(*iter)) + { + // follow second top aggro player + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + { + pConstellation->GetMotionMaster()->MoveFollow(pTarget, CONTACT_DISTANCE, 0); + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pConstellation); + ++m_uiActiveConstelations; + } + } + + m_lConstellationsGuids.remove(*iter); + } + + // spawn a collapsing star + void DoSpawnCollapsingStar() + { + float fX, fY, fZ; + m_creature->GetRandomPoint(afAlgalonMovePos[0], afAlgalonMovePos[1], afAlgalonMovePos[2], 30.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_COLLAPSING_STAR, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + // it's unclear wether it casts Berserk or Ascend to Heavens + if (DoCastSpellIfCan(m_creature, SPELL_ASCEND_HEAVENS, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiQuantumStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_QUANTUM_STRIKE : SPELL_QUANTUM_STRIKE_H) == CAST_OK) + m_uiQuantumStrikeTimer = 4000; + } + else + m_uiQuantumStrikeTimer -= uiDiff; + + if (m_uiBigBangTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_BIG_BANG : SPELL_BIG_BANG_H) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_BIG_BANG_1 : SAY_BIG_BANG_2, m_creature); + m_uiBigBangTimer = 90000; + } + } + else + m_uiBigBangTimer -= uiDiff; + + if (m_uiCosmicSmashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_COSMIC_SMASH_SUMMON : SPELL_COSMIC_SMASH_SUMMON_H) == CAST_OK) + m_uiCosmicSmashTimer = urand(40000, 50000); + } + else + m_uiCosmicSmashTimer -= uiDiff; + + if (m_uiPhasePunchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PHASE_PUNCH) == CAST_OK) + m_uiPhasePunchTimer = 15000; + } + else + m_uiPhasePunchTimer -= uiDiff; + + // summons are happening only above 20% hp + if (!m_bIsLowHealth) + { + if (m_uiCollapsingStarTimer < uiDiff) + { + // spawn as many stars as it's needed to a max of 4 + uint8 uiMaxStars = MAX_BLACK_HOLES - m_uiActiveStars; + if (uiMaxStars) + { + for (uint8 i = 0; i < uiMaxStars; ++i) + DoSpawnCollapsingStar(); + + DoScriptText(SAY_SUMMON_STAR, m_creature); + m_uiCollapsingStarTimer = 60000; + } + else + m_uiCollapsingStarTimer = 10000; + } + else + m_uiCollapsingStarTimer -= uiDiff; + + if (m_uiConstellationTimer < uiDiff) + { + // activate as many constelations as it's needed to a max of 3 + uint8 uiMaxConstellations = MAX_ACTIVE_CONSTELATIONS - m_uiActiveConstelations; + if (uiMaxConstellations) + { + m_uiConstellationTimer = 50000; + + for (uint8 i = 0; i < uiMaxConstellations; ++i) + ActivateRandomConstellation(); + } + else + m_uiConstellationTimer = 10000; + } + else + m_uiConstellationTimer -= uiDiff; + } + + // switch to second phase + if (!m_bIsLowHealth && m_creature->GetHealthPercent() < 20.0f) + { + DoScriptText(SAY_PHASE_2, m_creature); + m_bIsLowHealth = true; + + // despawn all remaining blackholes and collapsing stars + for (GuidList::const_iterator itr = m_lSummonedGuids.begin(); itr != m_lSummonedGuids.end(); ++itr) + { + if (Creature* pBlackHole = m_creature->GetMap()->GetCreature(*itr)) + pBlackHole->ForcedDespawn(); + } + + // spawn new worm holes + for (uint8 i = 0; i < MAX_WORM_HOLES; ++i) + m_creature->SummonCreature(NPC_WORM_HOLE, afWormHoles[i][0], afWormHoles[i][1], afWormHoles[i][2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_algalon(Creature* pCreature) +{ + return new boss_algalonAI(pCreature); +} + +/*###### +## npc_living_constellation +######*/ + +struct npc_living_constellationAI : public ScriptedAI +{ + npc_living_constellationAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + uint32 m_uiArcaneBarrageTimer; + + void Reset() override + { + m_uiArcaneBarrageTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // start casting Arcane Barrage + if (eventType == AI_EVENT_CUSTOM_A) + { + m_uiArcaneBarrageTimer = urand(5000, 7000); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiArcaneBarrageTimer) + { + if (m_uiArcaneBarrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_BARRAGE : SPELL_ARCANE_BARRAGE_H) == CAST_OK) + m_uiArcaneBarrageTimer = urand(5000, 7000); + } + else + m_uiArcaneBarrageTimer -= uiDiff; + } + } }; +CreatureAI* GetAI_npc_living_constellation(Creature* pCreature) +{ + return new npc_living_constellationAI(pCreature); +} + +/*###### +## npc_worm_hole +######*/ + +struct npc_worm_holeAI : public Scripted_NoMovementAI +{ + npc_worm_holeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiDarkMatterTimer; + + void Reset() override + { + m_uiDarkMatterTimer = urand(1000, 3000); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_UNLEASHED_DARK_MATTER) + pSummoned->SetInCombatWithZone(); + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpellEntry->Id == SPELL_WORM_HOLE_PHASE) + pTarget->CastSpell(pTarget, SPELL_BLACK_HOLE_DMG, true, NULL, NULL, m_creature->GetObjectGuid()); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDarkMatterTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_UNLEASHED_DARK_MATTER) == CAST_OK) + m_uiDarkMatterTimer = urand(10000, 15000); + } + else + m_uiDarkMatterTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_worm_hole(Creature* pCreature) +{ + return new npc_worm_holeAI(pCreature); +} + +/*###### +## npc_black_hole +######*/ + +struct npc_black_holeAI : public Scripted_NoMovementAI +{ + npc_black_holeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + bool m_bIsDespawned; + + void Reset() override + { + m_bIsDespawned = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + // despawn when a Living Constellation is nearby + if (!m_bIsDespawned && pWho->GetEntry() == NPC_LIVING_CONSTELLATION && pWho->IsWithinDistInMap(m_creature, 6.0f)) + { + DoCastSpellIfCan(m_creature, SPELL_BLACK_HOLE_CREDIT, CAST_TRIGGERED); + pWho->CastSpell(m_creature, SPELL_BLACK_HOLE_DESPAWN, true); + m_bIsDespawned = true; + + // despawn everything + ((Creature*)pWho)->ForcedDespawn(1000); + m_creature->ForcedDespawn(1000); + if (Creature* pVoidZone = GetClosestCreatureWithEntry(m_creature, NPC_VOID_ZONE_VISUAL, 5.0f)) + pVoidZone->ForcedDespawn(1000); + } + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpellEntry->Id == SPELL_BLACK_HOLE_PHASE) + pTarget->CastSpell(pTarget, SPELL_BLACK_HOLE_DMG, true, NULL, NULL, m_creature->GetObjectGuid()); + } + + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_black_hole(Creature* pCreature) +{ + return new npc_black_holeAI(pCreature); +} + +/*###### +## npc_collapsing_star +######*/ + +struct npc_collapsing_starAI : public ScriptedAI +{ + npc_collapsing_starAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_collapsing_star(Creature* pCreature) +{ + return new npc_collapsing_starAI(pCreature); +} + +/*###### +## go_celestial_access +######*/ + +bool GOUse_go_celestial_access(Player* pPlayer, GameObject* pGo) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_ALGALON) != NOT_STARTED) + return true; + + // Set instance data and allow DB scripts to continue the event + pInstance->SetData(TYPE_ALGALON, SPECIAL); + return false; +} + void AddSC_boss_algalon() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_algalon"; + pNewScript->GetAI = GetAI_boss_algalon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_living_constellation"; + pNewScript->GetAI = GetAI_npc_living_constellation; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_worm_hole"; + pNewScript->GetAI = GetAI_npc_worm_hole; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_black_hole"; + pNewScript->GetAI = GetAI_npc_black_hole; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_collapsing_star"; + pNewScript->GetAI = GetAI_npc_collapsing_star; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_celestial_access"; + pNewScript->pGOUse = &GOUse_go_celestial_access; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp b/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp index 7c85b613d..18cd17ebf 100644 --- a/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_auriaya -SD%Complete: 0% -SDComment: Aura Remove for Feral Defender needs love +SD%Complete: 100% +SDComment: SDCategory: Ulduar EndScriptData */ @@ -50,21 +50,26 @@ enum SPELL_FERAL_ESSENCE_REMOVAL = 64456, // remove 1 stack of 64455 SPELL_FERAL_POUNCE = 64478, SPELL_FERAL_POUNCE_H = 64669, - SPELL_FERAL_RUSH = 64489, // should trigger repeatedly on random targets 64496 - 64674 + SPELL_FERAL_RUSH = 64489, // triggers 64496 + SPELL_FERAL_RUSH_H = 64673, // triggers 64674 SPELL_SEEPING_FERAL_ESSENCE_SUMMON = 64457, - SPELL_FEIGN_DEATH = 64461, // dummy - possible related to the feral defender feign death - not used + SPELL_FEIGN_DEATH = 64461, // related to the feral defender feign death SPELL_FULL_HEAL = 64460, // on feign death remove // Seeping Feral Essence SPELL_SEEPING_FERAL_ESSENCE = 64458, SPELL_SEEPING_FERAL_ESSENCE_H = 64676, - //NPC_SEEPING_FERAL_ESSENCE = 34098, // summoned by the feral defender on feign death - //NPC_GUARDIAN_SWARN = 34034, // summoned by spell + NPC_SEEPING_FERAL_ESSENCE = 34098, // summoned by the feral defender on feign death + // NPC_GUARDIAN_SWARN = 34034, // summoned by spell NPC_FERAL_DEFENDER_STALKER = 34096, }; -struct MANGOS_DLL_DECL boss_auriayaAI : public ScriptedAI +/*###### +## boss_auriaya +######*/ + +struct boss_auriayaAI : public ScriptedAI { boss_auriayaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -83,17 +88,17 @@ struct MANGOS_DLL_DECL boss_auriayaAI : public ScriptedAI uint32 m_uiTerrifyingScreechTimer; uint32 m_uiDefenderTimer; - void Reset() + void Reset() override { - m_uiEnrageTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; m_uiSwarmTimer = 50000; m_uiSonicScreechTimer = 58000; m_uiSentinelBlastTimer = 40000; m_uiTerrifyingScreechTimer = 38000; - m_uiDefenderTimer = 1*MINUTE*IN_MILLISECONDS; + m_uiDefenderTimer = 1 * MINUTE * IN_MILLISECONDS; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -101,7 +106,7 @@ struct MANGOS_DLL_DECL boss_auriayaAI : public ScriptedAI m_pInstance->SetData(TYPE_AURIAYA, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS); @@ -109,25 +114,25 @@ struct MANGOS_DLL_DECL boss_auriayaAI : public ScriptedAI DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_AURIAYA, FAIL); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Summon the feral defender if (pSummoned->GetEntry() == NPC_FERAL_DEFENDER_STALKER) DoCastSpellIfCan(pSummoned, SPELL_ACTIVATE_FERAL_DEFENDER, CAST_INTERRUPT_PREVIOUS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -189,7 +194,7 @@ struct MANGOS_DLL_DECL boss_auriayaAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) { DoScriptText(SAY_BERSERK, m_creature); - m_uiEnrageTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; } } else @@ -204,41 +209,51 @@ CreatureAI* GetAI_boss_auriaya(Creature* pCreature) return new boss_auriayaAI(pCreature); } -struct MANGOS_DLL_DECL boss_feral_defenderAI : public ScriptedAI +/*###### +## boss_feral_defender +######*/ + +struct boss_feral_defenderAI : public ScriptedAI { boss_feral_defenderAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_uiMaxFeralRush = m_bIsRegularMode ? 6 : 10; Reset(); } instance_ulduar* m_pInstance; bool m_bIsRegularMode; + uint8 m_uiFeralRushCount; + uint8 m_uiMaxFeralRush; uint32 m_uiPounceTimer; uint32 m_uiFeralRushTimer; uint32 m_uiReviveDelayTimer; + uint32 m_uiAttackDelayTimer; uint32 m_uiKilledCount; - void Reset() + void Reset() override { + m_uiFeralRushCount = 0; m_uiReviveDelayTimer = 0; - m_uiPounceTimer = 5000; - m_uiFeralRushTimer = 10000; + m_uiAttackDelayTimer = 0; + m_uiPounceTimer = urand(9000, 12000); + m_uiFeralRushTimer = urand(3000, 5000); m_uiKilledCount = 0; DoCastSpellIfCan(m_creature, SPELL_FERAL_ESSENCE); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { // Set achiev criteria to true if (m_pInstance) m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_NINE_LIVES, true); } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { // If we don't have the feral essence anymore then ignore this if (m_uiKilledCount >= 8) // 9-1 == 8 @@ -250,15 +265,18 @@ struct MANGOS_DLL_DECL boss_feral_defenderAI : public ScriptedAI return; } - if (uiDamage > m_creature->GetHealth()) + if (uiDamage >= m_creature->GetHealth()) { uiDamage = 0; - m_creature->InterruptNonMeleeSpells(true); + // Set Feign death, remove one aura stack and summon a feral essence + DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FERAL_ESSENCE_REMOVAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SEEPING_FERAL_ESSENCE_SUMMON, CAST_TRIGGERED); + + // the feign death aura doesn't do everything, so keep the following here as well m_creature->SetHealth(0); - m_creature->StopMoving(); m_creature->ClearComboPointHolders(); - //m_creature->RemoveAllAurasOnDeath(); // TODO Should only remove negative auras m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -267,22 +285,19 @@ struct MANGOS_DLL_DECL boss_feral_defenderAI : public ScriptedAI m_creature->GetMotionMaster()->MoveIdle(); m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - // Remove one aura stack and summon a feral essence - DoCastSpellIfCan(m_creature, SPELL_FERAL_ESSENCE_REMOVAL, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_SEEPING_FERAL_ESSENCE_SUMMON, CAST_TRIGGERED); - m_uiReviveDelayTimer = 30000; ++m_uiKilledCount; } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Cast seeping feral essence on the summoned - pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_SEEPING_FERAL_ESSENCE : SPELL_SEEPING_FERAL_ESSENCE_H, true, NULL, NULL, m_creature->GetObjectGuid()); + if (pSummoned->GetEntry() == NPC_SEEPING_FERAL_ESSENCE) + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_SEEPING_FERAL_ESSENCE : SPELL_SEEPING_FERAL_ESSENCE_H, true, NULL, NULL, m_creature->GetObjectGuid()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -291,21 +306,34 @@ struct MANGOS_DLL_DECL boss_feral_defenderAI : public ScriptedAI { if (m_uiReviveDelayTimer <= uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_FULL_HEAL) == CAST_OK) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); + // ToDo: figure out how to enable the ressurrect animation + DoCastSpellIfCan(m_creature, SPELL_FULL_HEAL, CAST_TRIGGERED); + m_uiReviveDelayTimer = 0; + m_uiAttackDelayTimer = 3000; + } + else + m_uiReviveDelayTimer -= uiDiff; - DoResetThreat(); - m_uiReviveDelayTimer = 0; + // No Further action while faking + return; + } - // Assume Attack - it should jump to victim - if (m_creature->getVictim()) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - } + if (m_uiAttackDelayTimer) + { + if (m_uiAttackDelayTimer <= uiDiff) + { + DoResetThreat(); + m_creature->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_uiPounceTimer = urand(9000, 10000); + m_uiFeralRushCount = 0; + m_uiFeralRushTimer = 1000; + m_uiAttackDelayTimer = 0; } else - m_uiReviveDelayTimer -= uiDiff; + m_uiAttackDelayTimer -= uiDiff; // No Further action while faking return; @@ -316,7 +344,7 @@ struct MANGOS_DLL_DECL boss_feral_defenderAI : public ScriptedAI if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FERAL_POUNCE : SPELL_FERAL_POUNCE_H) == CAST_OK) - m_uiPounceTimer = 5000; + m_uiPounceTimer = urand(13000, 16000); } } else @@ -324,8 +352,18 @@ struct MANGOS_DLL_DECL boss_feral_defenderAI : public ScriptedAI if (m_uiFeralRushTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_FERAL_RUSH) == CAST_OK) - m_uiFeralRushTimer = 35000; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FERAL_RUSH : SPELL_FERAL_RUSH_H) == CAST_OK) + { + ++m_uiFeralRushCount; + + if (m_uiFeralRushCount == m_uiMaxFeralRush) + { + m_uiFeralRushCount = 0; + m_uiFeralRushTimer = 12000; + } + else + m_uiFeralRushTimer = 400; + } } else m_uiFeralRushTimer -= uiDiff; diff --git a/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp b/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp index 520d467cb..feec1ae5c 100644 --- a/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_flame_leviathan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_flame_leviathan -SD%Complete: 0% -SDComment: +SD%Complete: 75% +SDComment: Defense turret AI and related event NYI. SDCategory: Ulduar EndScriptData */ @@ -29,17 +29,16 @@ enum SAY_AGGRO = -1603159, SAY_SLAY = -1603160, SAY_DEATH = -1603161, - SAY_CHANGE_1 = -1603162, SAY_CHANGE_2 = -1603163, SAY_CHANGE_3 = -1603164, + SAY_PLAYER_RIDE = -1603165, SAY_OVERLOAD_1 = -1603166, SAY_OVERLOAD_2 = -1603167, SAY_OVERLOAD_3 = -1603168, SAY_HARD_MODE = -1603169, - SAY_TOWER_FROST = -1603170, SAY_TOWER_FIRE = -1603171, SAY_TOWER_ENERGY = -1603172, @@ -47,9 +46,715 @@ enum SAY_TOWER_DOWN = -1603174, EMOTE_PURSUE = -1603175, + EMOTE_HODIR_FURY = -1603242, + EMOTE_FREYA_WARD = -1603243, + EMOTE_MIMIRON_INFERNO = -1603244, + EMOTE_THORIM_HAMMER = -1603245, + + // Leviathan spells + SPELL_INVISIBILITY_DETECTION = 18950, + SPELL_PURSUED = 62374, + SPELL_MISSILE_BARRAGE_TARGET = 62401, // triggers 62400 on target + SPELL_MISSILE_BARRAGE = 62400, // has radius of 5k; requires core update + SPELL_FLAME_VENTS = 62396, + SPELL_BATTERING_RAM = 62376, + SPELL_GATHERING_SPEED = 62375, + + // leviathan turret spells - handled in eventAI + // SPELL_FLAME_CANNON = 62395, + + // defense turret spells + SPELL_OVERLOAD_CIRCUIT = 62399, + SPELL_SEARING_FLAME = 62402, + SPELL_SYSTEMS_SHUTDOWN = 62475, // sends event 21605 for achiev check + // Leviathan seat has missing aura 62421 + + // leviathan other spells - for the moment these are not used + // SPELL_SMOKE_TRAIL = 63575, + // SPELL_EJECT_ALL_PASSENGERS = 50630, // used by vehicles on death; currently handled by DB linking + // SPELL_EJECT_PASSENGER_4 = 64614, + // SPELL_EJECT_PASSENGER_1 = 60603, + + // tower buffs to Leviathan (applied on combat start if the towers are alive) + SPELL_TOWER_OF_FROST = 65077, + // SPELL_TOWER_OF_FROST_DEBUFF = 65079, // removed by hotfix + SPELL_TOWER_OF_LIFE = 64482, + SPELL_TOWER_OF_STORMS = 65076, + SPELL_TOWER_OF_FLAMES = 65075, + + // tower beacon abilities + SPELL_HODIR_FURY = 62533, // tower of frost + SPELL_FREYA_WARD = 62906, // tower of life + SPELL_THORIM_HAMMER = 62911, // tower of storms + SPELL_MIMIRON_INFERNO = 62909, // tower of flames + + // beacon vehicles visuals + SPELL_LIGHTNING_SKYBEAM = 62897, // storm beacon + SPELL_RED_SKYBEAM = 63772, // flames beacon + SPELL_BLUE_SKYBEAM = 63769, // frost beacon + SPELL_GREEN_SKYBEAM = 62895, // life beacon + + // other beacon vehicles spells + // SPELL_TARGET_SEARCH_A = 63761, // cast by npc 33369 and targets missing npc 33835 + // SPELL_TARGET_SEARCH_B = 63762, // moves the caster to the target location + // SPELL_TARGET_SEARCH_C = 63763, // these are not used since we are doing this by waypoint movement + // SPELL_TARGET_SEARCH_D = 63764, + // SPELL_BEAM_TARGET_STATE = 62898, // cast by all tower reticles; purpose unk + // SPELL_BIRTH = 40031, // not used; purpose unk + + // vehicle accessories + // NPC_LEVIATHAN_SEAT = 33114, + // NPC_LEVIATHAN_TURRET = 33139, + // NPC_DEFENSE_TURRET = 33142, + // NPC_OVERLOAD_DEVICE = 33143, + + // hard mode beacons - they cast the actual damage spells + NPC_HODIR_FURY = 33212, + // NPC_FREYA_WARD = 33367, + // NPC_THORIM_HAMMER = 33365, // handled in eventAI + // NPC_MIMIRON_INFERNO = 33370, + + // beacon vehicles + NPC_THORIM_HAMMER_VEHICLE = 33364, // has accessory 33365 + NPC_MIMIRON_INFERNO_VEHICLE = 33369, // has accessory 33370 + NPC_HODIR_FURY_VEHICLE = 33108, // has accessory 33212 + NPC_FREYA_WARD_VEHICLE = 33366, // has accessory 33367 + + // freya's ward summons - handled by eventAI + NPC_WRITHING_LASHER = 33387, // both spam spell 65062 on target + NPC_WARD_OF_LIFE = 34275, + + // other npcs (spawned at epilogue) + SPELL_RIDE_VEHICLE = 43671, + NPC_BRANN_FLYING_MACHINE = 34120, + NPC_BRANN_BRONZEBEARD_LEVIATHAN = 34119, + NPC_ARCHMANGE_RHYDIAN = 33696, + + MAX_FREYA_WARD = 4, + MAX_HODIR_FURY = 2, + // Mimiron inferno is only one + MAX_THORIM_HAMMER = 22, + + TOWER_ID_HODIR = 0, + TOWER_ID_FREYA = 1, + TOWER_ID_MIMIRON = 2, + TOWER_ID_THORIM = 3, +}; + +static const int32 aLeviathanTowerYell[KEEPER_ENCOUNTER] = { SAY_TOWER_FROST, SAY_TOWER_NATURE, SAY_TOWER_FIRE, SAY_TOWER_ENERGY }; +static const int32 aLeviathanTowerEmote[KEEPER_ENCOUNTER] = { EMOTE_HODIR_FURY, EMOTE_FREYA_WARD, EMOTE_MIMIRON_INFERNO, EMOTE_THORIM_HAMMER }; + +static const float afFreyaWard[MAX_FREYA_WARD][4] = +{ + {156.9291f, 61.52306f, 409.887f, 5.68f}, + {376.641f, 68.61361f, 411.2287f, 3.85f}, + {383.6206f, -130.8576f, 410.7088f, 2.26f}, + {154.9095f, -137.4339f, 409.887f, 0.79f}, +}; + +static const float afHodirFury[MAX_HODIR_FURY][3] = +{ + {219.9013f, 7.913357f, 409.7861f}, + {326.0777f, -74.99034f, 409.887f}, +}; + +static const float afMimironInferno[3] = {329.1809f, 8.02577f, 409.887f}; + +/*###### +## boss_flame_leviathan +######*/ + +struct boss_flame_leviathanAI : public ScriptedAI +{ + boss_flame_leviathanAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bInitTowers = false; + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + bool m_bInitTowers; + bool m_bUlduarTower[KEEPER_ENCOUNTER]; + + uint32 m_uiBatteringRamTimer; + uint32 m_uiFlameVentsTimer; + uint32 m_uiMissileBarrageTimer; + uint32 m_uiPursueTimer; + uint32 m_uiGatheringSpeedTimer; + + uint32 m_uiHardModeTimer; + uint8 m_uiHardModeStep; + + uint8 m_uiThorimHammerCount; + uint32 m_uiThorimHammerTimer; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_INVISIBILITY_DETECTION, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + for (uint8 i = 0; i < KEEPER_ENCOUNTER; ++i) + m_bUlduarTower[i] = false; + + m_uiBatteringRamTimer = 10000; + m_uiFlameVentsTimer = 30000; + m_uiMissileBarrageTimer = 1000; + m_uiPursueTimer = 1000; + m_uiGatheringSpeedTimer = 10000; + + m_uiHardModeTimer = 10000; + m_uiHardModeStep = 0; + m_uiThorimHammerCount = 0; + m_uiThorimHammerTimer = 0; + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_LEVIATHAN, DONE); + + // clear hard mode auras + if (Creature* pOrbital = m_pInstance->GetSingleCreatureFromStorage(NPC_ORBITAL_SUPPORT)) + pOrbital->RemoveAllAuras(); + } + + DoScriptText(SAY_DEATH, m_creature); + + // start epilogue event + if (Creature* pFlyMachine = m_creature->SummonCreature(NPC_BRANN_FLYING_MACHINE, 175.2838f, -210.4325f, 501.2375f, 1.42f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + if (Creature* pBrann = m_creature->SummonCreature(NPC_BRANN_BRONZEBEARD_LEVIATHAN, 175.2554f, -210.6305f, 500.7375f, 1.42f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + pBrann->CastSpell(pFlyMachine, SPELL_RIDE_VEHICLE, true); + + pFlyMachine->SetWalk(false); + pFlyMachine->GetMotionMaster()->MovePoint(1, 229.9419f, -130.3764f, 409.5681f); + } + } + + void Aggro(Unit* /*pWho*/) override + { + // check the towers again to make sure that some of them were not destroyed in the meanwhile + FetchTowers(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_LEVIATHAN, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + if (urand(0, 1)) + DoScriptText(SAY_SLAY, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_LEVIATHAN, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_THORIM_HAMMER_VEHICLE: + pSummoned->CastSpell(pSummoned, SPELL_LIGHTNING_SKYBEAM, true); + break; + case NPC_MIMIRON_INFERNO_VEHICLE: + pSummoned->CastSpell(pSummoned, SPELL_RED_SKYBEAM, true); + break; + case NPC_HODIR_FURY_VEHICLE: + pSummoned->CastSpell(pSummoned, SPELL_BLUE_SKYBEAM, true); + break; + case NPC_FREYA_WARD_VEHICLE: + pSummoned->CastSpell(pSummoned, SPELL_GREEN_SKYBEAM, true); + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (pSummoned->GetEntry() == NPC_BRANN_FLYING_MACHINE) + { + // spawn the Archmange and eject Brann + if (Creature* pArchmage = m_creature->SummonCreature(NPC_ARCHMANGE_RHYDIAN, 235.5596f, -136.1876f, 409.6508f, 1.78f, TEMPSUMMON_CORPSE_DESPAWN, 0)) + { + pArchmage->SetWalk(false); + pArchmage->GetMotionMaster()->MovePoint(1, 239.3158f, -123.6443f, 409.8174f); + } + + pSummoned->RemoveAllAuras(); + } + else if (pSummoned->GetEntry() == NPC_ARCHMANGE_RHYDIAN) + { + if (Creature* pBrann = GetClosestCreatureWithEntry(pSummoned, NPC_BRANN_BRONZEBEARD_LEVIATHAN, 30.0f)) + { + // rest will be handled by DB scripts + pBrann->SetWalk(false); + pBrann->GetMotionMaster()->MoveWaypoint(); + } + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // set boss in combat (if not already) + m_creature->SetInCombatWithZone(); + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->IsVehicle() && pSpellEntry->Id == SPELL_PURSUED) + { + m_creature->FixateTarget(pTarget); + + if (Player* pPlayer = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself()) + DoScriptText(EMOTE_PURSUE, m_creature, pPlayer); + } + } + + // check for all active towers + void FetchTowers() + { + if (!m_pInstance) + return; + + // the orbital support applies the tower auras + Creature* pOrbital = m_pInstance->GetSingleCreatureFromStorage(NPC_ORBITAL_SUPPORT); + if (!pOrbital) + return; + + uint8 uiActiveTowers = 0; + + // check the states twice: at reset and at aggro to make sure that some towers were not destroyed in the meanwhile + if (m_pInstance->GetData(TYPE_TOWER_HODIR) == DONE) + { + pOrbital->CastSpell(pOrbital, SPELL_TOWER_OF_FROST, true); + ++uiActiveTowers; + m_bUlduarTower[TOWER_ID_HODIR] = true; + } + else + pOrbital->RemoveAurasDueToSpell(SPELL_TOWER_OF_FROST); + if (m_pInstance->GetData(TYPE_TOWER_FREYA) == DONE) + { + pOrbital->CastSpell(pOrbital, SPELL_TOWER_OF_LIFE, true); + ++uiActiveTowers; + m_bUlduarTower[TOWER_ID_FREYA] = true; + } + else + pOrbital->RemoveAurasDueToSpell(SPELL_TOWER_OF_LIFE); + if (m_pInstance->GetData(TYPE_TOWER_MIMIRON) == DONE) + { + pOrbital->CastSpell(pOrbital, SPELL_TOWER_OF_FLAMES, true); + ++uiActiveTowers; + m_bUlduarTower[TOWER_ID_MIMIRON] = true; + } + else + pOrbital->RemoveAurasDueToSpell(SPELL_TOWER_OF_FLAMES); + if (m_pInstance->GetData(TYPE_TOWER_THORIM) == DONE) + { + pOrbital->CastSpell(pOrbital, SPELL_TOWER_OF_STORMS, true); + ++uiActiveTowers; + m_bUlduarTower[TOWER_ID_THORIM] = true; + } + else + pOrbital->RemoveAurasDueToSpell(SPELL_TOWER_OF_STORMS); + + // inform instance about all active towers for future use in achievements and hard mode loot + m_pInstance->SetData(TYPE_LEVIATHAN_HARD, uiActiveTowers); + } + + // Functions which handle the spawn of each type of add + void DoSpawnHodirFury() + { + for (uint8 i = 0; i < MAX_HODIR_FURY; ++i) + m_creature->SummonCreature(NPC_HODIR_FURY_VEHICLE, afHodirFury[i][0], afHodirFury[i][1], afHodirFury[i][2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void DoSpawnFreyaWard() + { + for (uint8 i = 0; i < MAX_FREYA_WARD; ++i) + m_creature->SummonCreature(NPC_FREYA_WARD_VEHICLE, afFreyaWard[i][0], afFreyaWard[i][1], afFreyaWard[i][2], afFreyaWard[i][3], TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void DoSpawnMimironInferno() + { + // Mimiron inferno has waypoint movement + m_creature->SummonCreature(NPC_MIMIRON_INFERNO_VEHICLE, afMimironInferno[0], afMimironInferno[1], afMimironInferno[2], 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + void DoSpawnThorimHammer() + { + if (!m_pInstance) + return; + + // get a random point compared to the center and spawn the npcs + if (Creature* pOrbital = m_pInstance->GetSingleCreatureFromStorage(NPC_ORBITAL_SUPPORT)) + { + float fX, fY, fZ; + m_creature->GetRandomPoint(pOrbital->GetPositionX(), pOrbital->GetPositionY(), pOrbital->GetPositionZ(), 150.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_THORIM_HAMMER_VEHICLE, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 8000); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // fetch all tower buffs on the first update + if (!m_bInitTowers) + { + FetchTowers(); + m_bInitTowers = true; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPursueTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PURSUED) == CAST_OK) + { + // don't yell from the beginning + if (!m_uiHardModeTimer) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_CHANGE_1, m_creature); break; + case 1: DoScriptText(SAY_CHANGE_2, m_creature); break; + case 2: DoScriptText(SAY_CHANGE_3, m_creature); break; + } + } + m_uiPursueTimer = 30000; + } + } + else + m_uiPursueTimer -= uiDiff; + + if (m_uiFlameVentsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_VENTS) == CAST_OK) + m_uiFlameVentsTimer = urand(15000, 25000); + } + else + m_uiFlameVentsTimer -= uiDiff; + + if (m_uiBatteringRamTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BATTERING_RAM) == CAST_OK) + m_uiBatteringRamTimer = urand(10000, 15000); + } + else + m_uiBatteringRamTimer -= uiDiff; + + if (m_uiMissileBarrageTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MISSILE_BARRAGE_TARGET) == CAST_OK) + m_uiMissileBarrageTimer = urand(1000, 2000); + } + } + else + m_uiMissileBarrageTimer -= uiDiff; + + if (m_uiGatheringSpeedTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GATHERING_SPEED) == CAST_OK) + m_uiGatheringSpeedTimer = 10000; + } + else + m_uiGatheringSpeedTimer -= uiDiff; + + // start hard mode + if (m_uiHardModeTimer) + { + if (m_uiHardModeTimer <= uiDiff) + { + // if all towers are deactivated then skip the rest + if (!m_bUlduarTower[TOWER_ID_HODIR] && !m_bUlduarTower[TOWER_ID_FREYA] && !m_bUlduarTower[TOWER_ID_MIMIRON] && !m_bUlduarTower[TOWER_ID_THORIM]) + { + DoScriptText(SAY_TOWER_DOWN, m_creature); + m_uiHardModeTimer = 0; + } + else + { + // yell hard mode start and start activating each tower one by one + switch (m_uiHardModeStep) + { + case 0: + DoScriptText(SAY_HARD_MODE, m_creature); + m_uiHardModeTimer = 10000; + ++m_uiHardModeStep; + break; + default: + // iterate through all towers to check which is active; skip the ones which are deactivated without triggering the timer + for (uint8 i = m_uiHardModeStep - 1; i < KEEPER_ENCOUNTER; ++i) + { + if (m_bUlduarTower[i]) + { + // yell tower active + DoScriptText(aLeviathanTowerYell[i], m_creature); + DoScriptText(aLeviathanTowerEmote[i], m_creature); + + // activate the timer for each tower ability + switch (i) + { + case TOWER_ID_HODIR: DoSpawnHodirFury(); break; + case TOWER_ID_FREYA: DoSpawnFreyaWard(); break; + case TOWER_ID_MIMIRON: DoSpawnMimironInferno(); break; + case TOWER_ID_THORIM: m_uiThorimHammerTimer = 1000; break; + } + + // reset timer and wait for another turn + m_uiHardModeTimer = 10000; + ++m_uiHardModeStep; + break; + } + else + ++m_uiHardModeStep; + + // stop the timer after the final element + if (i == KEEPER_ENCOUNTER - 1) + m_uiHardModeTimer = 0; + } + break; + } + } + } + else + m_uiHardModeTimer -= uiDiff; + } + + // Tower of Storm abilities + if (m_uiThorimHammerTimer) + { + if (m_uiThorimHammerTimer <= uiDiff) + { + DoSpawnThorimHammer(); + ++m_uiThorimHammerCount; + + if (m_uiThorimHammerCount == MAX_THORIM_HAMMER) + m_uiThorimHammerTimer = 0; + else + m_uiThorimHammerTimer = 1000; + } + else + m_uiThorimHammerTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_flame_leviathan(Creature* pCreature) +{ + return new boss_flame_leviathanAI(pCreature); +} + +/*###### +## npc_hodir_fury_reticle +######*/ + +struct npc_hodir_fury_reticleAI : public ScriptedAI +{ + npc_hodir_fury_reticleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiTargetChaseTimer; + ObjectGuid m_hodirFuryGuid; + + void Reset() override + { + m_uiTargetChaseTimer = 5000; + SetCombatMovement(false); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_HODIR_FURY) + m_hodirFuryGuid = pSummoned->GetObjectGuid(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // cast Hodir Fury on point reached and search for another target + if (Creature* pHodirFury = m_creature->GetMap()->GetCreature(m_hodirFuryGuid)) + pHodirFury->CastSpell(m_creature, SPELL_HODIR_FURY, true); + + m_uiTargetChaseTimer = 5000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiTargetChaseTimer) + { + if (m_uiTargetChaseTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN)) + { + if (Unit* pTarget = pLeviathan->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + m_creature->GetMotionMaster()->MovePoint(1, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + } + } + m_uiTargetChaseTimer = 0; + } + else + m_uiTargetChaseTimer -= uiDiff; + } + } }; +CreatureAI* GetAI_npc_hodir_fury_reticle(Creature* pCreature) +{ + return new npc_hodir_fury_reticleAI(pCreature); +} + +/*###### +## npc_hodir_fury +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_hodir_furyAI : public Scripted_NoMovementAI +{ + npc_hodir_furyAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_hodir_fury(Creature* pCreature) +{ + return new npc_hodir_furyAI(pCreature); +} + +/*###### +## npc_freya_ward +######*/ + +// TODO Move this 'script' to eventAI when combat can be proper prevented from core-side +struct npc_freya_wardAI : public Scripted_NoMovementAI +{ + npc_freya_wardAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset();} + + uint32 m_uiFreyaWardTimer; + + void Reset() override + { + m_uiFreyaWardTimer = 30000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_WRITHING_LASHER || pSummoned->GetEntry() == NPC_WARD_OF_LIFE) + pSummoned->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiFreyaWardTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FREYA_WARD) == CAST_OK) + m_uiFreyaWardTimer = 30000; + } + else + m_uiFreyaWardTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_freya_ward(Creature* pCreature) +{ + return new npc_freya_wardAI(pCreature); +} + +/*###### +## npc_mimiron_inferno +######*/ + +// TODO Move this 'script' to eventAI when combat can be proper prevented from core-side +struct npc_mimiron_infernoAI : public Scripted_NoMovementAI +{ + npc_mimiron_infernoAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiMimironInfernoTimer; + + void Reset() override + { + m_uiMimironInfernoTimer = 15000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiMimironInfernoTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MIMIRON_INFERNO) == CAST_OK) + m_uiMimironInfernoTimer = 1000; + } + else + m_uiMimironInfernoTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_mimiron_inferno(Creature* pCreature) +{ + return new npc_mimiron_infernoAI(pCreature); +} + void AddSC_boss_flame_leviathan() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_flame_leviathan"; + pNewScript->GetAI = GetAI_boss_flame_leviathan; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_hodir_fury_reticle"; + pNewScript->GetAI = GetAI_npc_hodir_fury_reticle; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_hodir_fury"; + pNewScript->GetAI = GetAI_npc_hodir_fury; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_freya_ward"; + pNewScript->GetAI = GetAI_npc_freya_ward; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_mimiron_inferno"; + pNewScript->GetAI = GetAI_npc_mimiron_inferno; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_freya.cpp b/scripts/northrend/ulduar/ulduar/boss_freya.cpp index b9d05399b..a13d3e49e 100644 --- a/scripts/northrend/ulduar/ulduar/boss_freya.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_freya.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_freya -SD%Complete: 0% -SDComment: +SD%Complete: 95% +SDComment: Elders and some of the Nature Allies handled in ACID. Script might require some minor improvements. SDCategory: Ulduar EndScriptData */ @@ -33,14 +33,11 @@ enum SAY_ADDS_LASHER = -1603004, SAY_SLAY_1 = -1603005, SAY_SLAY_2 = -1603006, - SAY_DEATH = -1603007, + SAY_EPILOGUE = -1603007, SAY_BERSERK = -1603008, - SAY_HELP_YOGG = -1603009, EMOTE_ALLIES_NATURE = -1603010, - EMOTE_LIFEBINDER = -1603011, - EMOTE_TREMOR = -1603012, - EMOTE_IRON_ROOTS = -1603013, + EMOTE_REGEN_ALLIES = -1603011, SAY_AGGRO_BRIGHT = -1603014, SAY_SLAY_1_BRIGHT = -1603015, @@ -56,9 +53,1003 @@ enum SAY_SLAY_1_STONE = -1603023, SAY_SLAY_2_STONE = -1603024, SAY_DEATH_STONE = -1603025, + + // general spells + SPELL_FREYA_CREDIT = 65074, // kill credit spell; added in spell_template + SPELL_DEFORESTATION_CREDIT = 65015, // used for achievs 2985 and 2984 + SPELL_BERSERK = 47008, + // SPELL_FREYA_DUMMY_YELLOW = 63292, // dummy spells used to light up the crystals; used in dbscripts_on_creature_move + // SPELL_FREYA_DUMMY_BLUE = 63294, + // SPELL_FREYA_DUMMY_GREEN = 63295, + + // combat spells + SPELL_ATTUNED_TO_NATURE = 62519, + SPELL_TOUCH_OF_EONAR = 62528, + SPELL_TOUCH_OF_EONAR_H = 62892, + SPELL_SUNBEAM = 62623, + SPELL_SUNBEAM_H = 62872, + + // summon creature spells + SPELL_SUMMON_ALLIES_OF_NATURE = 62678, // triggers random of 62685, 62686 or 62688 + SPELL_SUMMON_ALLIES_OF_NATURE_H = 62873, // spell needs to be confirmed; identical to normal mode version + SPELL_SUMMON_WAVE_1 = 62685, // summon npc 33203 + SPELL_SUMMON_WAVE_3 = 62686, // summon npcs 33202, 32916 and 32919 + SPELL_SUMMON_WAVE_10 = 62688, // summon 10 * npc 32918 + SPELL_LIFEBINDERS_GIFT_SUMMON = 62572, + SPELL_NATURE_BOMB_SUMMON = 64604, + + // summon loot spells + SPELL_SUMMON_CHEST_0 = 62950, // summon loot chest spells, depending on the number of elders alive + SPELL_SUMMON_CHEST_1 = 62952, + SPELL_SUMMON_CHEST_2 = 62953, + SPELL_SUMMON_CHEST_3 = 62954, + SPELL_SUMMON_CHEST_0_H = 62955, + SPELL_SUMMON_CHEST_1_H = 62956, + SPELL_SUMMON_CHEST_2_H = 62957, + SPELL_SUMMON_CHEST_3_H = 62958, + + // hard mode spells + SPELL_FULL_HEAL = 43978, + SPELL_DRAINED_OF_POWER = 62467, // stun effect for each elder alive after finish channeling + + SPELL_BRIGHTLEAF_ESSENCE_CHANNEL = 62485, // brightleaf + SPELL_BRIGHTLEAF_ESSENCE_CHANNEL_H = 65587, + SPELL_UNSTABLE_SUN_BEAM = 62450, + SPELL_UNSTABLE_SUN_BEAM_H = 62868, + + SPELL_IRONBRANCH_ESSENCE_CHANNEL = 62484, // ironbrach + SPELL_IRONBRANCH_ESSENCE_CHANNEL_H = 65588, + SPELL_IRON_ROOTS = 62439, + SPELL_IRON_ROOTS_H = 62862, + + SPELL_STONEBARK_ESSEMCE_CHANNEL = 62483, // stonebark + SPELL_STONEBARK_ESSEMCE_CHANNEL_H = 65589, + SPELL_GROUND_TREMOR = 62437, + SPELL_GROUND_TREMOR_H = 62859, + + // summons spells + SPELL_SPORE_SUMMON_PERIODIC = 62566, // triggers 62582, 62591, 62592, 62593; cast by 33203 + SPELL_HEALTHY_SPORE_VISUAL = 62538, // cast by npc 33215 + SPELL_POTENT_PHEROMONES = 62541, // cast by npc 33215 + + // sun beam spells; handled by eventAI + // SPELL_UNSTABLE_SUN_BEAM_VISUAL = 62216, // cast by npc 33170 + // SPELL_UNSTABLE_ENERGY = 62451, // cast by npc 33170 + // SPELL_UNSTABLE_ENERGY_H = 62865, + + // iron roots spells + SPELL_STRENGTHEN_IRON_ROOTS = 62440, // remove stun and damange aura from summoner + SPELL_STRENGTHEN_IRON_ROOTS_H = 63601, + SPELL_IRON_ROOTS_REMOVE = 62282, // same as above, but for the Elder version + SPELL_IRON_ROOTS_REMOVE_H = 63598, + + // nature bomb spells + SPELL_NATURE_BOMB_GO = 64600, // spawns go 194902 + SPELL_NATURE_BOMB = 64587, + SPELL_NATURE_BOMB_H = 64650, + + // allies of nature spells + SPELL_ATTUNED_10_STACKS = 62525, // remove 10 stacks of 62519 + SPELL_ATTUNED_2_STACKS = 62524, // remove 2 stacks of 62519 + SPELL_ATTUNED_25_STACKS = 62521, // remove 25 stacks of 62519 + + // three allies spells + SPELL_FEIGN_DEATH = 65985, + SPELL_CLEAR_DEBUFFS = 34098, + SPELL_TIDAL_WAVE = 62652, // triggers 62653 or 62935 + SPELL_TIDAL_WAVE_VISUAL = 62655, + SPELL_HARDENED_BARK = 62664, + SPELL_HARDENED_BARK_H = 64191, + SPELL_LIGHTNING_LASH = 62648, + SPELL_LIGHTNING_LASH_H = 62939, + SPELL_STORMBOLT = 62649, + SPELL_STORMBOLT_H = 62938, + + // eonar's gift spells + SPELL_LIFEBINDERS_GIFT = 62584, + SPELL_LIFEBINDERS_GIFT_H = 64185, + SPELL_LIFEBINDERS_GIFT_VISUAL = 62579, + SPELL_AUTO_GROW = 62559, // cast by npcs 33228 and 33215 + SPELL_PHEROMONES = 62619, + + // allies of nature summons + NPC_DETONATING_LASHER = 32918, // has auras 64481 and 28819 + NPC_ANCIENT_CONSERVATOR = 33203, + NPC_WATER_SPIRIT = 33202, + NPC_STORM_LASHER = 32919, + NPC_SNAPLASHER = 32916, + + // other summons + NPC_NATURE_BOMB = 34129, + // NPC_SUN_BEAM = 33170, // handled in eventAI + // NPC_UNSTABLE_SUN_BEAM = 33050, // handled in eventAI + NPC_IRON_ROOTS = 33088, + NPC_STRENGHENED_IRON_ROOTS = 33168, + NPC_EONARS_GIFT = 33228, + // NPC_HEALTHY_SPORE = 33215, + + // other + // GO_NATURE_BOMB = 194902, + MIN_ATTUNED_NATURE_STACKS = 25, + MAX_ALLIES_SPELLS = 3, + MAX_ALLIES_WAVES = 6, +}; + +static const uint32 aAlliesSpawnSpells[MAX_ALLIES_SPELLS] = {SPELL_SUMMON_WAVE_1, SPELL_SUMMON_WAVE_3, SPELL_SUMMON_WAVE_10}; + +/*###### +## boss_freya +######*/ + +struct boss_freyaAI : public ScriptedAI +{ + boss_freyaAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + // init the Allies of Nature spells + spawnSpellsVector.reserve(MAX_ALLIES_SPELLS); + for (uint8 i = 0; i < MAX_ALLIES_SPELLS; ++i) + spawnSpellsVector.push_back(aAlliesSpawnSpells[i]); + + m_bEventFinished = false; + m_uiEpilogueTimer = 0; + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + bool m_bEventFinished; + + uint32 m_uiEpilogueTimer; + uint32 m_uiBerserkTimer; + + uint32 m_uiAlliesNatureTimer; + uint8 m_uiAlliesWaveCount; + + uint32 m_uiSunbeamTimer; + uint32 m_uiNatureBombTimer; + uint32 m_uiLifebindersGiftTimer; + uint32 m_uiThreeAlliesTimer; + + uint32 m_uiUnstableEnergyTimer; + uint32 m_uiIronRootsTimer; + uint32 m_uiGroundTremorTimer; + + ObjectGuid m_waterSpiritGuid; + ObjectGuid m_stormLasherGuid; + ObjectGuid m_snaplasherGuid; + + std::vector spawnSpellsVector; + + void Reset() override + { + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_uiAlliesNatureTimer = 10000; + m_uiAlliesWaveCount = 0; + m_uiNatureBombTimer = 65000; + m_uiSunbeamTimer = 20000; + m_uiLifebindersGiftTimer = 25000; + m_uiThreeAlliesTimer = 0; + + m_uiUnstableEnergyTimer = 0; + m_uiIronRootsTimer = 0; + m_uiGroundTremorTimer = 0; + + // make the spawn spells random + std::random_shuffle(spawnSpellsVector.begin(), spawnSpellsVector.end()); + } + + void Aggro(Unit* /*pWho*/) override + { + // don't attack again after being defeated + if (m_bEventFinished) + return; + + if (m_pInstance) + m_pInstance->SetData(TYPE_FREYA, IN_PROGRESS); + + DoCastSpellIfCan(m_creature, SPELL_ATTUNED_TO_NATURE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_TOUCH_OF_EONAR : SPELL_TOUCH_OF_EONAR_H, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + FetchElders(); + } + + void AttackStart(Unit* pWho) override + { + // don't attack again after being defeated + if (m_bEventFinished) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // don't attack again after being defeated + if (m_bEventFinished) + return; + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FREYA, FAIL); + + // reset elders + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF)) + { + if (pElder->isAlive()) + pElder->AI()->EnterEvadeMode(); + } + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH)) + { + if (pElder->isAlive()) + pElder->AI()->EnterEvadeMode(); + } + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK)) + { + if (pElder->isAlive()) + pElder->AI()->EnterEvadeMode(); + } + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive() && !m_bEventFinished) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (!m_bEventFinished) + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_FREYA, DONE); + + // spawn chest loot + switch (m_pInstance->GetData(TYPE_FREYA_HARD)) + { + case 0: DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_CHEST_0 : SPELL_SUMMON_CHEST_0_H, CAST_TRIGGERED); break; + case 1: DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_CHEST_1 : SPELL_SUMMON_CHEST_1_H, CAST_TRIGGERED); break; + case 2: DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_CHEST_2 : SPELL_SUMMON_CHEST_2_H, CAST_TRIGGERED); break; + case 3: DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_CHEST_3 : SPELL_SUMMON_CHEST_3_H, CAST_TRIGGERED); break; + } + + // check aura stacks for achiev + if (SpellAuraHolder* pNatureAura = m_creature->GetSpellAuraHolder(SPELL_ATTUNED_TO_NATURE)) + { + if (pNatureAura && pNatureAura->GetStackAmount() >= MIN_ATTUNED_NATURE_STACKS) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_BACK_NATURE, true); + } + } + + DoScriptText(SAY_EPILOGUE, m_creature); + m_creature->CastSpell(m_creature, SPELL_FREYA_CREDIT, true); + + m_uiEpilogueTimer = 10000; + m_bEventFinished = true; + EnterEvadeMode(); + } + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_EONARS_GIFT: + pSummoned->CastSpell(pSummoned, SPELL_LIFEBINDERS_GIFT_VISUAL, true); + pSummoned->CastSpell(pSummoned, SPELL_AUTO_GROW, true); + pSummoned->CastSpell(pSummoned, SPELL_PHEROMONES, true); + break; + case NPC_DETONATING_LASHER: + case NPC_ANCIENT_CONSERVATOR: + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + case NPC_WATER_SPIRIT: + m_waterSpiritGuid = pSummoned->GetObjectGuid(); + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + case NPC_STORM_LASHER: + m_stormLasherGuid = pSummoned->GetObjectGuid(); + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + case NPC_SNAPLASHER: + m_snaplasherGuid = pSummoned->GetObjectGuid(); + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + case NPC_NATURE_BOMB: + pSummoned->CastSpell(pSummoned, SPELL_NATURE_BOMB_GO, true); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_DETONATING_LASHER: + pSummoned->CastSpell(m_creature, SPELL_ATTUNED_2_STACKS, true); + break; + case NPC_ANCIENT_CONSERVATOR: + pSummoned->CastSpell(m_creature, SPELL_ATTUNED_25_STACKS, true); + break; + case NPC_WATER_SPIRIT: + case NPC_STORM_LASHER: + case NPC_SNAPLASHER: + pSummoned->CastSpell(m_creature, SPELL_ATTUNED_10_STACKS, true); + break; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + // handle Allies of Nature spawn + if (eventType == AI_EVENT_CUSTOM_A) + { + // adjust the index to the size of the vector + uint8 uiIndex = m_uiAlliesWaveCount; + if (uiIndex >= MAX_ALLIES_SPELLS) + uiIndex = m_uiAlliesWaveCount - MAX_ALLIES_SPELLS; + + switch (spawnSpellsVector[uiIndex]) + { + case SPELL_SUMMON_WAVE_1: DoScriptText(SAY_ADDS_CONSERVATOR, m_creature); break; + case SPELL_SUMMON_WAVE_3: DoScriptText(SAY_ADDS_TRIO, m_creature); break; + case SPELL_SUMMON_WAVE_10: DoScriptText(SAY_ADDS_LASHER, m_creature); break; + } + + DoCastSpellIfCan(m_creature, spawnSpellsVector[uiIndex], CAST_TRIGGERED); + + ++m_uiAlliesWaveCount; + + // re-shuffle the spells + if (m_uiAlliesWaveCount == MAX_ALLIES_SPELLS) + { + uint32 uiLastSpell = spawnSpellsVector[MAX_ALLIES_SPELLS - 1]; + std::random_shuffle(spawnSpellsVector.begin(), spawnSpellsVector.end()); + + // make sure we won't repeat the last spell + while (spawnSpellsVector[0] == uiLastSpell) + std::random_shuffle(spawnSpellsVector.begin(), spawnSpellsVector.end()); + } + } + else if (eventType == AI_EVENT_CUSTOM_B) + { + if (!m_uiThreeAlliesTimer) + m_uiThreeAlliesTimer = 12000; + } + } + + // check for all elders alive + void FetchElders() + { + if (!m_pInstance) + return; + + uint8 uiEldersAlive = 0; + + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF)) + { + if (pElder->isAlive()) + { + pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_BRIGHTLEAF_ESSENCE_CHANNEL : SPELL_BRIGHTLEAF_ESSENCE_CHANNEL_H, true); + pElder->CastSpell(pElder, SPELL_FULL_HEAL, true); + + m_uiUnstableEnergyTimer = 25000; + ++uiEldersAlive; + } + } + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH)) + { + if (pElder->isAlive()) + { + pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_IRONBRANCH_ESSENCE_CHANNEL : SPELL_IRONBRANCH_ESSENCE_CHANNEL_H, true); + pElder->CastSpell(pElder, SPELL_FULL_HEAL, true); + + m_uiIronRootsTimer = 60000; + ++uiEldersAlive; + } + } + if (Creature* pElder = m_pInstance->GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK)) + { + if (pElder->isAlive()) + { + pElder->CastSpell(pElder, m_bIsRegularMode ? SPELL_STONEBARK_ESSEMCE_CHANNEL : SPELL_STONEBARK_ESSEMCE_CHANNEL_H, true); + pElder->CastSpell(pElder, SPELL_FULL_HEAL, true); + + m_uiGroundTremorTimer = 10000; + ++uiEldersAlive; + } + } + + // store the info about the elders alive + m_pInstance->SetData(TYPE_FREYA_HARD, uiEldersAlive); + + if (uiEldersAlive) + DoScriptText(SAY_AGGRO_HARD, m_creature); + else + DoScriptText(SAY_AGGRO, m_creature); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiEpilogueTimer) + { + if (m_uiEpilogueTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT, CAST_TRIGGERED) == CAST_OK) + { + m_creature->ForcedDespawn(2000); + m_uiEpilogueTimer = 0; + } + } + else + m_uiEpilogueTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiThreeAlliesTimer) + { + if (m_uiThreeAlliesTimer <= uiDiff) + { + Creature* pSpirit = m_creature->GetMap()->GetCreature(m_waterSpiritGuid); + Creature* pStormLasher = m_creature->GetMap()->GetCreature(m_stormLasherGuid); + Creature* pSnapLasher = m_creature->GetMap()->GetCreature(m_snaplasherGuid); + if (!pSpirit || !pStormLasher || !pSnapLasher) + return; + + if (pSpirit->HasAura(SPELL_FEIGN_DEATH) && pStormLasher->HasAura(SPELL_FEIGN_DEATH) && pSnapLasher->HasAura(SPELL_FEIGN_DEATH)) + { + m_creature->DealDamage(pSpirit, pSpirit->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + m_creature->DealDamage(pStormLasher, pStormLasher->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + m_creature->DealDamage(pSnapLasher, pSnapLasher->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + else + { + pSpirit->CastSpell(pSpirit, SPELL_FULL_HEAL, true); + pStormLasher->CastSpell(pStormLasher, SPELL_FULL_HEAL, true); + pSnapLasher->CastSpell(pSnapLasher, SPELL_FULL_HEAL, true); + } + + m_uiThreeAlliesTimer = 0; + } + else + m_uiThreeAlliesTimer -= uiDiff; + } + + if (m_uiAlliesWaveCount < MAX_ALLIES_WAVES) + { + if (m_uiAlliesNatureTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_ALLIES_OF_NATURE : SPELL_SUMMON_ALLIES_OF_NATURE_H) == CAST_OK) + { + DoScriptText(EMOTE_ALLIES_NATURE, m_creature); + m_uiAlliesNatureTimer = 60000; + } + } + else + m_uiAlliesNatureTimer -= uiDiff; + } + else + { + if (m_uiNatureBombTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NATURE_BOMB_SUMMON) == CAST_OK) + m_uiNatureBombTimer = 15000; + } + else + m_uiNatureBombTimer -= uiDiff; + } + + if (m_uiSunbeamTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SUNBEAM : SPELL_SUNBEAM_H) == CAST_OK) + m_uiSunbeamTimer = 15000; + } + } + else + m_uiSunbeamTimer -= uiDiff; + + if (m_uiLifebindersGiftTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LIFEBINDERS_GIFT_SUMMON) == CAST_OK) + m_uiLifebindersGiftTimer = 40000; + } + else + m_uiLifebindersGiftTimer -= uiDiff; + + // Brightleaf ability + if (m_uiUnstableEnergyTimer) + { + if (m_uiUnstableEnergyTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_UNSTABLE_SUN_BEAM : SPELL_UNSTABLE_SUN_BEAM_H) == CAST_OK) + m_uiUnstableEnergyTimer = 25000; + } + else + m_uiUnstableEnergyTimer -= uiDiff; + } + + // Ironbranch ability + if (m_uiIronRootsTimer) + { + if (m_uiIronRootsTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_IRON_ROOTS : SPELL_IRON_ROOTS_H) == CAST_OK) + m_uiIronRootsTimer = 60000; + } + else + m_uiIronRootsTimer -= uiDiff; + } + + // Stonebark ability + if (m_uiGroundTremorTimer) + { + if (m_uiGroundTremorTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_GROUND_TREMOR : SPELL_GROUND_TREMOR_H) == CAST_OK) + m_uiGroundTremorTimer = 30000; + } + else + m_uiGroundTremorTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_freya(Creature* pCreature) +{ + return new boss_freyaAI(pCreature); +} + +bool EffectScriptEffectCreature_boss_freya(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if ((uiSpellId == SPELL_SUMMON_ALLIES_OF_NATURE || uiSpellId == SPELL_SUMMON_ALLIES_OF_NATURE_H) && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_FREYA) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + + return true; + } + + return false; +} + +/*###### +## three_nature_allies +######*/ + +struct three_nature_alliesAI : public ScriptedAI +{ + three_nature_alliesAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + bool m_bIsFakeDeath; + + void Reset() override + { + m_bIsFakeDeath = false; + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (pDoneBy->GetEntry() == NPC_FREYA) + return; + + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_bIsFakeDeath) + return; + + if (m_pInstance) + { + if (Creature* pFreya = m_pInstance->GetSingleCreatureFromStorage(NPC_FREYA)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pFreya); + } + + DoCastSpellIfCan(m_creature, SPELL_CLEAR_DEBUFFS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH, CAST_TRIGGERED); + + m_creature->SetHealth(1); + m_creature->ClearComboPointHolders(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + DoScriptText(EMOTE_REGEN_ALLIES, m_creature); + m_bIsFakeDeath = true; + } + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_FULL_HEAL) + { + m_bIsFakeDeath = false; + DoResetThreat(); + m_creature->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } +}; + +/*###### +## npc_water_spirit +######*/ + +struct npc_water_spiritAI : public three_nature_alliesAI +{ + npc_water_spiritAI(Creature* pCreature) : three_nature_alliesAI(pCreature) { Reset(); } + + uint32 m_uiTidalWaveTimer; + + void Reset() override + { + m_uiTidalWaveTimer = 10000; + three_nature_alliesAI::Reset(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiTidalWaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TIDAL_WAVE) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_TIDAL_WAVE_VISUAL, CAST_TRIGGERED); + m_uiTidalWaveTimer = 10000; + } + } + else + m_uiTidalWaveTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_water_spirit(Creature* pCreature) +{ + return new npc_water_spiritAI(pCreature); +} + +/*###### +## npc_snaplasher +######*/ + +struct npc_snaplasherAI : public three_nature_alliesAI +{ + npc_snaplasherAI(Creature* pCreature) : three_nature_alliesAI(pCreature) { Reset(); } + + void Reset() override + { + three_nature_alliesAI::Reset(); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HARDENED_BARK : SPELL_HARDENED_BARK_H); + } +}; + +CreatureAI* GetAI_npc_snaplasher(Creature* pCreature) +{ + return new npc_snaplasherAI(pCreature); +} + +/*###### +## npc_storm_lasher +######*/ + +struct npc_storm_lasherAI : public three_nature_alliesAI +{ + npc_storm_lasherAI(Creature* pCreature) : three_nature_alliesAI(pCreature) { Reset(); } + + uint32 m_uiLightningLashTimer; + uint32 m_uiStormBoltTimer; + + void Reset() override + { + m_uiLightningLashTimer = urand(5000, 10000); + m_uiStormBoltTimer = 5000; + three_nature_alliesAI::Reset(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiLightningLashTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIGHTNING_LASH : SPELL_LIGHTNING_LASH_H) == CAST_OK) + m_uiLightningLashTimer = urand(5000, 10000); + } + } + else + m_uiLightningLashTimer -= uiDiff; + + if (m_uiStormBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STORMBOLT : SPELL_STORMBOLT_H) == CAST_OK) + m_uiStormBoltTimer = 5000; + } + } + else + m_uiStormBoltTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_storm_lasher(Creature* pCreature) +{ + return new npc_storm_lasherAI(pCreature); +} + +/*###### +## npc_eonars_gift +######*/ + +struct npc_eonars_giftAI : public Scripted_NoMovementAI +{ + npc_eonars_giftAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + uint32 m_uiGiftTimer; + + void Reset() override + { + m_uiGiftTimer = 10000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiGiftTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_LIFEBINDERS_GIFT : SPELL_LIFEBINDERS_GIFT_H) == CAST_OK) + m_uiGiftTimer = 10000; + } + else + m_uiGiftTimer -= uiDiff; + } }; +CreatureAI* GetAI_npc_eonars_gift(Creature* pCreature) +{ + return new npc_eonars_giftAI(pCreature); +} + +/*###### +## npc_nature_bomb +######*/ + +struct npc_nature_bombAI : public Scripted_NoMovementAI +{ + npc_nature_bombAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + uint32 m_uiNatureBombTimer; + + ObjectGuid m_natureBombGuid; + + void Reset() override + { + m_uiNatureBombTimer = 10000; + } + + void JustSummoned(GameObject* pGo) override + { + m_natureBombGuid = pGo->GetObjectGuid(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiNatureBombTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_NATURE_BOMB : SPELL_NATURE_BOMB_H) == CAST_OK) + { + if (GameObject* pBomb = m_creature->GetMap()->GetGameObject(m_natureBombGuid)) + pBomb->Use(m_creature); + + m_creature->ForcedDespawn(2000); + m_uiNatureBombTimer = 10000; + } + } + else + m_uiNatureBombTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_nature_bomb(Creature* pCreature) +{ + return new npc_nature_bombAI(pCreature); +} + +/*###### +## npc_iron_roots +######*/ + +struct npc_iron_rootsAI : public Scripted_NoMovementAI +{ + npc_iron_rootsAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_creature->IsTemporarySummon()) + return; + + if (m_creature->GetEntry() == NPC_IRON_ROOTS) + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_IRON_ROOTS_REMOVE : SPELL_IRON_ROOTS_REMOVE_H, CAST_TRIGGERED); + else if (m_creature->GetEntry() == NPC_STRENGHENED_IRON_ROOTS) + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STRENGTHEN_IRON_ROOTS : SPELL_STRENGTHEN_IRON_ROOTS_H, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_iron_roots(Creature* pCreature) +{ + return new npc_iron_rootsAI(pCreature); +} + +/*###### +## npc_healthy_spore +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_healthy_sporeAI : public Scripted_NoMovementAI +{ + npc_healthy_sporeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_AUTO_GROW, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_POTENT_PHEROMONES, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_HEALTHY_SPORE_VISUAL, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + m_creature->ForcedDespawn(25000); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_healthy_spore(Creature* pCreature) +{ + return new npc_healthy_sporeAI(pCreature); +} + void AddSC_boss_freya() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_freya"; + pNewScript->GetAI = GetAI_boss_freya; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_boss_freya; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_water_spirit"; + pNewScript->GetAI = GetAI_npc_water_spirit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_snaplasher"; + pNewScript->GetAI = GetAI_npc_snaplasher; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_storm_lasher"; + pNewScript->GetAI = GetAI_npc_storm_lasher; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_eonars_gift"; + pNewScript->GetAI = GetAI_npc_eonars_gift; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_nature_bomb"; + pNewScript->GetAI = GetAI_npc_nature_bomb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_iron_roots"; + pNewScript->GetAI = GetAI_npc_iron_roots; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_healthy_spore"; + pNewScript->GetAI = GetAI_npc_healthy_spore; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp b/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp index 95cbf9615..6ce3e2a3e 100644 --- a/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_general_vezax.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: boss_general_vezax -SD%Complete: 80% +SD%Complete: 100% SDComment: SDCategory: Ulduar EndScriptData */ @@ -38,34 +38,46 @@ enum EMOTE_SURGE = -1603104, EMOTE_ANIMUS = -1603105, + // normal spells SPELL_AURA_OF_DESPAIR = 62692, SPELL_SHADOW_CRASH = 62660, + SPELL_SHADOW_CRASH_DAMAGE = 62659, // used for achiev check SPELL_MARK_OF_FACELESS = 63276, // triggers 63278 SPELL_SEARING_FLAMES = 62661, SPELL_SURGE_OF_DARKNESS = 62662, + SPELL_SUMMON_VAPORS = 63081, // cast by Vezax bunny SPELL_BERSERK = 26662, + + // hard mode spells SPELL_SARONITE_BARRIER = 63364, // also sends event 9735 SPELL_SUMMON_ANIMUS = 63145, // the animus should spam 63420 on target - to be done in acid - SPELL_SUMMON_VAPORS = 63081, - SPELL_ANIMUS_FORMATION = 63319, // visual aura on the vapors + SPELL_ANIMUS_FORMATION = 63319, // visual aura on Saronite summoner bunny + + // other spells SPELL_SARONITE_VAPORS = 63323, // cast by vapor on death SPELL_CORRUPTED_RAGE = 68415, // Unused - SPELL_CORRUPTED_WISDOM = 64646, + SPELL_CORRUPTED_WISDOM = 64646, // Unused MAX_HARD_MODE_VAPORS = 6, NPC_SARONITE_VAPOR = 33488, }; -struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI +/*###### +## boss_general_vezax +######*/ + +struct boss_general_vezaxAI : public ScriptedAI { boss_general_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } instance_ulduar* m_pInstance; + bool m_bIsRegularMode; uint32 m_uiEnrageTimer; uint32 m_uiCrashTimer; @@ -73,25 +85,29 @@ struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI uint32 m_uiFlamesTimer; uint32 m_uiSurgeTimer; uint32 m_uiSaroniteVaporTimer; - uint32 m_uiSaroniteBarrierTimer; + uint32 m_uiHardModeTimer; + uint8 m_uiHardModeStage; uint8 m_uiVaporsGathered; - GUIDList m_lVaporsGuids; + GuidList m_lVaporsGuids; - void Reset() + void Reset() override { - m_uiEnrageTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; m_uiFlamesTimer = 8000; m_uiSaroniteVaporTimer = 30000; m_uiSurgeTimer = 60000; m_uiMarkTimer = 20000; m_uiCrashTimer = 15000; - m_uiSaroniteBarrierTimer = 0; + m_uiHardModeTimer = 0; + m_uiHardModeStage = 0; m_uiVaporsGathered = 0; + + m_lVaporsGuids.clear(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) { @@ -104,13 +120,13 @@ struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI DoScriptText(SAY_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_VEZAX, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_VEZAX, DONE); @@ -118,12 +134,12 @@ struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SARONITE_VAPOR) { @@ -133,79 +149,117 @@ struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI if (m_lVaporsGuids.size() == MAX_HARD_MODE_VAPORS) DoPrepareAnimusIfCan(); } - // ToDo: faction should be set in DB else if (pSummoned->GetEntry() == NPC_SARONITE_ANIMUS) - pSummoned->setFaction(14); + pSummoned->SetInCombatWithZone(); } - void SummonedCreatureJustDied(Creature* pSummoned) + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override { - // decrease the number of vapors when they die - if (pSummoned->GetEntry() == NPC_SARONITE_VAPOR) + if (pSender->GetEntry() == NPC_SARONITE_VAPOR) { - pSummoned->CastSpell(pSummoned, SPELL_SARONITE_VAPORS, true); - m_lVaporsGuids.remove(pSummoned->GetObjectGuid()); + // decrease the number of vapors when they die + if (eventType == AI_EVENT_CUSTOM_A) + m_lVaporsGuids.remove(pSender->GetObjectGuid()); + else if (eventType == AI_EVENT_CUSTOM_B) + { + ++m_uiVaporsGathered; + + // Cast the saronite formation aura when all vapors arive + if (m_uiVaporsGathered == MAX_HARD_MODE_VAPORS) + { + // visual on the summoning bunny + if (m_pInstance) + { + if (Creature* pBunny = m_creature->GetMap()->GetCreature(m_pInstance->GetVezaxBunnyGuid(true))) + pBunny->CastSpell(pBunny, SPELL_ANIMUS_FORMATION, true); + } + + // Despawn the vapors + for (GuidList::const_iterator itr = m_lVaporsGuids.begin(); itr != m_lVaporsGuids.end(); ++itr) + { + if (Creature* pVapor = m_creature->GetMap()->GetCreature(*itr)) + pVapor->ForcedDespawn(); + } + + DoScriptText(EMOTE_ANIMUS, m_creature); + m_uiHardModeTimer = 4000; + } + } } // remove saronite barrier when animus dies - else if (pSummoned->GetEntry() == NPC_SARONITE_ANIMUS) - { + else if (pSender->GetEntry() == NPC_SARONITE_ANIMUS && eventType == AI_EVENT_CUSTOM_C) m_creature->RemoveAurasDueToSpell(SPELL_SARONITE_BARRIER); - - if (m_creature->isAlive() && m_pInstance) - m_pInstance->SetData(TYPE_VEZAX_HARD, DONE); - } } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - if (uiMoveType != POINT_MOTION_TYPE || uiPointId != 0 || pSummoned->GetEntry() != NPC_SARONITE_VAPOR) + if (pTarget->GetTypeId() != TYPEID_PLAYER || !m_pInstance) return; - ++m_uiVaporsGathered; - - // Cast the saronite formation aura when all vapors arive - if (m_uiVaporsGathered == MAX_HARD_MODE_VAPORS) - { - pSummoned->CastSpell(pSummoned, SPELL_ANIMUS_FORMATION, true); - - // Despawn the vapors - for (GUIDList::const_iterator itr = m_lVaporsGuids.begin(); itr != m_lVaporsGuids.end(); ++itr) - { - if (Creature* pVapor = m_creature->GetMap()->GetCreature(*itr)) - pVapor->ForcedDespawn(4000); - } - - DoScriptText(EMOTE_ANIMUS, m_creature); - m_uiSaroniteBarrierTimer = 4000; - } + // Check achiev criterias + if (pSpell->Id == SPELL_SHADOW_CRASH_DAMAGE) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_SHADOWDODGER, false); } // Merge vapors void DoPrepareAnimusIfCan() { - // Gather the vapors to the boss - NOTE: not sure if position is ok - for (GUIDList::const_iterator itr = m_lVaporsGuids.begin(); itr != m_lVaporsGuids.end(); ++itr) + if (!m_pInstance) + return; + + Creature* pBunny = m_creature->GetMap()->GetCreature(m_pInstance->GetVezaxBunnyGuid(true)); + if (!pBunny) + return; + + // Gather the vapors to the spawn point + for (GuidList::const_iterator itr = m_lVaporsGuids.begin(); itr != m_lVaporsGuids.end(); ++itr) { - // Better place: near him or some fixed position? if (Creature* pVapor = m_creature->GetMap()->GetCreature(*itr)) - pVapor->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + { + pVapor->SetWalk(false); + pVapor->GetMotionMaster()->MovePoint(1, pBunny->GetPositionX(), pBunny->GetPositionY(), pBunny->GetPositionZ()); + } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiSaroniteBarrierTimer) + if (m_uiHardModeTimer) { - if (m_uiSaroniteBarrierTimer <= uiDiff) + if (m_uiHardModeTimer <= uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_SARONITE_BARRIER) == CAST_OK) - m_uiSaroniteBarrierTimer = 0; + switch (m_uiHardModeStage) + { + case 0: + { + if (DoCastSpellIfCan(m_creature, SPELL_SARONITE_BARRIER, CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_HARD_MODE, m_creature); + m_uiHardModeTimer = 2000; + } + break; + } + case 1: + { + if (m_pInstance) + { + if (Creature* pBunny = m_creature->GetMap()->GetCreature(m_pInstance->GetVezaxBunnyGuid(true))) + { + pBunny->RemoveAurasDueToSpell(SPELL_ANIMUS_FORMATION); + pBunny->CastSpell(pBunny, SPELL_SUMMON_ANIMUS, true, NULL, NULL, m_creature->GetObjectGuid()); + } + } + m_uiHardModeTimer = 0; + break; + } + } + ++m_uiHardModeStage; } else - m_uiSaroniteBarrierTimer -= uiDiff; + m_uiHardModeTimer -= uiDiff; } // summon saronite vapors before the hard mode @@ -213,23 +267,33 @@ struct MANGOS_DLL_DECL boss_general_vezaxAI : public ScriptedAI { if (m_uiSaroniteVaporTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_VAPORS) == CAST_OK) + // get a bunny that will summon the vapors + if (m_pInstance) { - DoScriptText(EMOTE_VAPOR, m_creature); - m_uiSaroniteVaporTimer = 30000; + if (Creature* pBunny = m_creature->GetMap()->GetCreature(m_pInstance->GetVezaxBunnyGuid(false))) + { + pBunny->CastSpell(pBunny, SPELL_SUMMON_VAPORS, true, NULL, NULL, m_creature->GetObjectGuid()); + DoScriptText(EMOTE_VAPOR, m_creature); + + m_uiSaroniteVaporTimer = 30000; + } } } else m_uiSaroniteVaporTimer -= uiDiff; } - if (m_uiFlamesTimer < uiDiff) + // Searing flames only while animus is not around + if (m_pInstance && (m_pInstance->GetData(TYPE_VEZAX_HARD) != IN_PROGRESS || !m_bIsRegularMode)) { - if (DoCastSpellIfCan(m_creature, SPELL_SEARING_FLAMES) == CAST_OK) - m_uiFlamesTimer = urand(5000, 10000); + if (m_uiFlamesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SEARING_FLAMES) == CAST_OK) + m_uiFlamesTimer = urand(9000, 16000); + } + else + m_uiFlamesTimer -= uiDiff; } - else - m_uiFlamesTimer -= uiDiff; if (m_uiSurgeTimer < uiDiff) { @@ -285,7 +349,54 @@ CreatureAI* GetAI_boss_general_vezax(Creature* pCreature) return new boss_general_vezaxAI(pCreature); } -bool ProcessEventId_event_spell_saronite_barrier(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +/*###### +## npc_saronite_vapor +######*/ + +struct npc_saronite_vaporAI : public Scripted_NoMovementAI +{ + npc_saronite_vaporAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + void Reset() override { } + + void JustDied(Unit* /*pKiller*/) override + { + // inform Vezax of death + if (m_pInstance) + { + if (Creature* pVezax = m_pInstance->GetSingleCreatureFromStorage(NPC_VEZAX)) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pVezax); + } + + DoCastSpellIfCan(m_creature, SPELL_SARONITE_VAPORS, CAST_TRIGGERED); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != POINT_MOTION_TYPE || !uiPointId || !m_pInstance) + return; + + // inform vezax of point reached + if (Creature* pVezax = m_pInstance->GetSingleCreatureFromStorage(NPC_VEZAX)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pVezax); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } +}; + +CreatureAI* GetAI_npc_saronite_vapor(Creature* pCreature) +{ + return new npc_saronite_vaporAI(pCreature); +} + +bool ProcessEventId_event_spell_saronite_barrier(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) { if (pSource->GetTypeId() == TYPEID_UNIT && ((Creature*)pSource)->GetEntry() == NPC_VEZAX) { @@ -293,10 +404,6 @@ bool ProcessEventId_event_spell_saronite_barrier(uint32 uiEventId, Object* pSour { // Start hard mode for Vezax and summon the Animus pInstance->SetData(TYPE_VEZAX_HARD, IN_PROGRESS); - - ((Creature*)pSource)->CastSpell((Creature*)pSource, SPELL_SUMMON_ANIMUS, true); - DoScriptText(SAY_HARD_MODE, (Creature*)pSource); - return true; } } @@ -312,6 +419,11 @@ void AddSC_boss_general_vezax() pNewScript->GetAI = &GetAI_boss_general_vezax; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_saronite_vapor"; + pNewScript->GetAI = &GetAI_npc_saronite_vapor; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "event_spell_saronite_barrier"; pNewScript->pProcessEventId = &ProcessEventId_event_spell_saronite_barrier; diff --git a/scripts/northrend/ulduar/ulduar/boss_hodir.cpp b/scripts/northrend/ulduar/ulduar/boss_hodir.cpp index fe826b053..e9658877d 100644 --- a/scripts/northrend/ulduar/ulduar/boss_hodir.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_hodir.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,14 @@ /* ScriptData SDName: boss_hodir -SD%Complete: 0% -SDComment: +SD%Complete: 90% +SDComment: Achievements NYI. SDCategory: Ulduar EndScriptData */ #include "precompiled.h" #include "ulduar.h" +#include "TemporarySummon.h" enum { @@ -31,15 +32,444 @@ enum SAY_SLAY_2 = -1603088, SAY_FLASH_FREEZE = -1603089, SAY_FROZEN_BLOWS = -1603090, - SAY_DEATH = -1603091, + SAY_EPILOGUE = -1603091, SAY_BERSERK = -1603092, - SAY_HELP_YOGG = -1603093, EMOTE_FLASH_FREEZE = -1603094, EMOTE_FROZEN_BLOWS = -1603095, + + // spells + SPELL_BERSERK = 26662, + SPELL_HODIR_CREDIT = 64899, // kill credit spell; added in spell_template + SPELL_SHATTER_CHEST = 65272, // hard mode timer until chest is shattered; triggers 62501 which will send event 20907 if completed + SPELL_FROZEN_BLOWS = 62478, + SPELL_FROZEN_BLOWS_H = 63512, + SPELL_FREEZE = 62469, + SPELL_BITTING_COLD = 62038, // triggers 62039 and 62188 + SPELL_ICICLE_AURA = 62227, // periodic targeting aura; triggers the spell which summons npc 33169 + SPELL_ICICLE_SNOWPACK = 62476, // cast right before Flash Freeze; triggers the spell which summons npc 33173 + SPELL_ICICLE_SNOWPACK_H = 62477, + SPELL_FLASH_FREEZE = 61968, // main spell; sends event 20896 + + // icicle spells + SPELL_ICICLE = 62236, + SPELL_ICICLE_DUMMY = 62453, + + // snowpacked icicle spells + // SPELL_ICICLE_ICE_SHARDS = 62460, // triggers the spell which summons npc 33174 and go 194173 + + // snowpacked icicle target spells + SPELL_SAFE_AREA = 65705, // grant immunity from flash freeze + + // flash freeze related spells + // SPELL_FLASH_FREEZE_VISUAL = 62148, // cast by npc 30298 (handled by event 20896) + // SPELL_FLASH_FREEZE_SUMMON = 61970, // cast by all Flash Freeze targets; summons 32926 + // SPELL_FLASH_FREEZE_SUMMON_NPC = 61989, // used to flash freeze all npc targets before the encounter; summons 32938 + // SPELL_FLASH_FREEZE_STUN = 64175, // use and purpose unk + // SPELL_FLASH_FREEZE_FRIENDLY = 64176, // use and purpose unk + + // flash freeze spells + SPELL_FLASH_FREEZE_AURA = 61969, // stuns the summoner + SPELL_FLASH_FREEZE_KILL = 62226, // kill frozen targets + + // flash freeze npc spells + SPELL_FLASH_FREEZE_AURA_NPC = 61990, // stuns the summoner (npc) + SPELL_FLASH_FREEZE_INITIAL = 62878, // trigger aggro on Hodir if damaged; sends event 21045 + + // npcs + NPC_ICICLE = 33169, + // NPC_SNOWPACKED_ICICLE = 33173, // entry used to generate npc 33173 and go 194173; handled in eventAI + // NPC_SNOWPACKED_ICICLE_TARGET = 33174, // entry used to handle safe area aura from Flash Freeze; handled in eventAI + NPC_FLASH_FREEZE = 32926, // entry used during the encounter + NPC_FLASH_FREEZE_NPC = 32938, // entry which stuns the friendly npcs before the actual fight + + // GO_SNOWDRIFT = 194173, + EVENT_ID_ATTACK_START = 21045, + EVENT_ID_SHATTER_CHEST = 20907, + FACTION_ID_FRIENDLY = 35, }; +/*###### +## boss_hodir +######*/ + +struct boss_hodirAI : public ScriptedAI +{ + boss_hodirAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_bEventFinished = false; + m_uiEpilogueTimer = 0; + m_uiEpilogueStage = 0; + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + bool m_bEventFinished; + + uint32 m_uiEpilogueTimer; + uint32 m_uiBerserkTimer; + uint32 m_uiFlashFreezeTimer; + uint32 m_uiFrozenBlowsTimer; + uint32 m_uiFreezeTimer; + uint8 m_uiEpilogueStage; + + void Reset() override + { + m_uiBerserkTimer = 8 * MINUTE * IN_MILLISECONDS; + m_uiFlashFreezeTimer = 50000; + m_uiFrozenBlowsTimer = 70000; + m_uiFreezeTimer = urand(25000, 30000); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_HODIR, IN_PROGRESS); + m_pInstance->SetData(TYPE_HODIR_HARD, DONE); + } + + DoScriptText(SAY_AGGRO, m_creature); + DoCastSpellIfCan(m_creature, SPELL_BITTING_COLD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ICICLE_AURA, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_SHATTER_CHEST, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + + void AttackStart(Unit* pWho) override + { + // don't attack again after being defeated + if (m_bEventFinished) + return; + + ScriptedAI::AttackStart(pWho); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_HODIR, FAIL); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive() && !m_bEventFinished) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (!m_bEventFinished) + { + // Inform the faction helpers that the fight is over + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + // only check creatures + if (!(*itr)->getUnitGuid().IsCreature()) + continue; + + if (Creature* pTarget = m_creature->GetMap()->GetCreature((*itr)->getUnitGuid())) + pTarget->AI()->EnterEvadeMode(); + } + + m_uiEpilogueTimer = 10000; + m_creature->CastSpell(m_creature, SPELL_HODIR_CREDIT, true); + m_creature->SetFactionTemporary(FACTION_ID_FRIENDLY, TEMPFACTION_NONE); + m_bEventFinished = true; + EnterEvadeMode(); + } + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ICICLE) + { + pSummoned->CastSpell(pSummoned, SPELL_ICICLE_DUMMY, false); + pSummoned->CastSpell(pSummoned, SPELL_ICICLE, true); + pSummoned->ForcedDespawn(5000); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiEpilogueTimer) + { + if (m_uiEpilogueTimer <= uiDiff) + { + switch (m_uiEpilogueStage) + { + case 0: + if (m_pInstance) + m_pInstance->SetData(TYPE_HODIR, DONE); + + DoScriptText(SAY_EPILOGUE, m_creature); + m_uiEpilogueTimer = 10000; + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT) == CAST_OK) + { + m_creature->ForcedDespawn(2000); + m_uiEpilogueTimer = 0; + } + break; + } + ++m_uiEpilogueStage; + } + else + m_uiEpilogueTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiFlashFreezeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLASH_FREEZE) == CAST_OK) + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ICICLE_SNOWPACK : SPELL_ICICLE_SNOWPACK_H, CAST_TRIGGERED); + DoScriptText(EMOTE_FLASH_FREEZE, m_creature); + DoScriptText(SAY_FLASH_FREEZE, m_creature); + m_uiFlashFreezeTimer = 50000; + } + } + else + m_uiFlashFreezeTimer -= uiDiff; + + if (m_uiFrozenBlowsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FROZEN_BLOWS : SPELL_FROZEN_BLOWS_H) == CAST_OK) + { + DoScriptText(SAY_FROZEN_BLOWS, m_creature); + DoScriptText(EMOTE_FROZEN_BLOWS, m_creature); + m_uiFrozenBlowsTimer = 60000; + } + } + else + m_uiFrozenBlowsTimer -= uiDiff; + + if (m_uiFreezeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FREEZE) == CAST_OK) + m_uiFreezeTimer = 15000; + } + } + else + m_uiFreezeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_hodir(Creature* pCreature) +{ + return new boss_hodirAI(pCreature); +} + +/*###### +## npc_flash_freeze +######*/ + +struct npc_flash_freezeAI : public Scripted_NoMovementAI +{ + npc_flash_freezeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + bool m_bFreezeInit; + + void Reset() override + { + m_bFreezeInit = false; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustDied(Unit* /*pKiller*/) override + { + // On Flash Freeze death, the owner should attack Hodir + if (m_creature->GetEntry() == NPC_FLASH_FREEZE_NPC && m_creature->IsTemporarySummon() && m_pInstance) + { + if (Creature* pHodir = m_pInstance->GetSingleCreatureFromStorage(NPC_HODIR)) + { + // ignore if event already completed + if (pHodir->getFaction() == FACTION_ID_FRIENDLY) + return; + + if (Creature* pSummoner = m_creature->GetMap()->GetCreature(((TemporarySummon*)m_creature)->GetSummonerGuid())) + pSummoner->AI()->AttackStart(pHodir); + } + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + // Flash Freeze npcs should be always be summoned + if (!m_creature->IsTemporarySummon()) + return; + + // do the freezing on the first update tick + if (!m_bFreezeInit) + { + // Flash Freeze npc will always stun or kill the summoner + if (m_creature->GetEntry() == NPC_FLASH_FREEZE_NPC) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLASH_FREEZE_AURA_NPC) == CAST_OK) + DoCastSpellIfCan(m_creature, SPELL_FLASH_FREEZE_INITIAL, CAST_TRIGGERED); + } + else if (m_creature->GetEntry() == NPC_FLASH_FREEZE) + { + if (Unit* pSummoner = m_creature->GetMap()->GetUnit(((TemporarySummon*)m_creature)->GetSummonerGuid())) + { + // kill frozen players + if (pSummoner->HasAura(SPELL_FREEZE)) + DoCastSpellIfCan(pSummoner, SPELL_FLASH_FREEZE_KILL); + else + DoCastSpellIfCan(m_creature, SPELL_FLASH_FREEZE_AURA); + + if (pSummoner->GetTypeId() == TYPEID_PLAYER && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_CHEESE_FREEZE, false); + } + } + + m_bFreezeInit = true; + } + } +}; + +CreatureAI* GetAI_npc_flash_freeze(Creature* pCreature) +{ + return new npc_flash_freezeAI(pCreature); +} + +/*###### +## event_boss_hodir +######*/ + +bool ProcessEventId_event_boss_hodir(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (pSource->GetTypeId() == TYPEID_UNIT) + { + instance_ulduar* pInstance = (instance_ulduar*)((Creature*)pSource)->GetInstanceData(); + if (!pInstance) + return true; + + if (uiEventId == EVENT_ID_SHATTER_CHEST) + { + // Mark hard mode as failed and despawn the Rare cache + pInstance->SetData(TYPE_HODIR_HARD, FAIL); + + if (GameObject* pChest = pInstance->GetSingleGameObjectFromStorage(pInstance->instance->IsRegularDifficulty() ? GO_CACHE_OF_RARE_WINTER_10 : GO_CACHE_OF_RARE_WINTER_25)) + pChest->SetLootState(GO_JUST_DEACTIVATED); + } + else if (uiEventId == EVENT_ID_ATTACK_START) + { + // Start encounter + if (Creature* pHodir = pInstance->GetSingleCreatureFromStorage(NPC_HODIR)) + { + // ignore if event already completed + if (pHodir->getFaction() == FACTION_ID_FRIENDLY) + return true; + + pHodir->SetInCombatWithZone(); + } + } + + return true; + } + + return false; +} + +/*###### +## npc_icicle_target +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_icicle_targetAI : public Scripted_NoMovementAI +{ + npc_icicle_targetAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_SAFE_AREA); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_icicle_target(Creature* pCreature) +{ + return new npc_icicle_targetAI(pCreature); +} + void AddSC_boss_hodir() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_hodir"; + pNewScript->GetAI = GetAI_boss_hodir; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_flash_freeze"; + pNewScript->GetAI = GetAI_npc_flash_freeze; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_boss_hodir"; + pNewScript->pProcessEventId = &ProcessEventId_event_boss_hodir; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_icicle_target"; + pNewScript->GetAI = GetAI_npc_icicle_target; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_ignis.cpp b/scripts/northrend/ulduar/ulduar/boss_ignis.cpp index 172239919..f8036714a 100644 --- a/scripts/northrend/ulduar/ulduar/boss_ignis.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_ignis.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: boss_ignis -SD%Complete: 0% +SD%Complete: 100% SDComment: SDCategory: Ulduar EndScriptData */ @@ -27,9 +27,9 @@ EndScriptData */ enum { SAY_AGGRO = -1603026, - SAY_SCORCH_1 = -1603027, - SAY_SCORCH_2 = -1603028, - SAY_SLAGPOT = -1603029, + SAY_SLAGPOT_1 = -1603027, + SAY_SLAGPOT_2 = -1603028, + SAY_FLAME_JETS = -1603029, SAY_ADDS = -1603030, SAY_SLAY_1 = -1603031, SAY_SLAY_2 = -1603032, @@ -37,9 +37,346 @@ enum SAY_DEATH = -1603034, EMOTE_FLAME_JETS = -1603035, + EMOTE_EXTINGUISH_SCORCH = -1603238, + + // spells + SPELL_FLAME_JETS = 62680, + SPELL_FLAME_JETS_H = 63472, + SPELL_SLAG_POT = 62717, // damage aura applied when passenger is switched to second seat + // SPELL_SLAG_IMBUED = 63536, // buff received if target survives the slag pot + SPELL_GRAB = 62707, // charge spells for Slag pot - triggers 62708 which will load the player into Ingis' hand (seat 1) + SPELL_GRAB_POT = 62711, // aura triggered after 1,5 sec after the first grab; switches the seats from hand to pot (seat 2) + SPELL_SCORCH = 62546, + SPELL_SCORCH_H = 63474, + SPELL_SCORCH_SUMMON = 62551, // summons npc 33221 + SPELL_ACTIVATE_CONSTRUCT = 62488, // activates constructs and set them in combat (handled in core) + SPELL_KILL_ALL_CONSTRUCTS = 65109, // on death + SPELL_BERSERK = 26662, + + // iron construct + SPELL_CONSTRUCT_HITTING_YA = 65110, // procs on melee damage; purpose unk + SPELL_STONED = 62468, // mechanical stun aura + SPELL_HEAT = 65667, // stackable aura which heats the construct + SPELL_MOLTEN = 62373, // aura gained by the construct when heated to 10 stacks in Scorch + SPELL_CHILL = 62381, // chill a construct when moved in water + SPELL_BRITTLE = 62382, // stun a construct when chilled in water + SPELL_BRITTLE_H = 67114, + SPELL_SHATTER = 62383, // sends event 21620 for the achiev check + SPELL_STRENGTH_REMOVE = 64475, // remove 1 stack of the Strength of Creator on construct death + SPELL_WATER_EFFECT = 64503, // spell effect which cools the heated constructs and scorch npcs + // SPELL_WATER = 64502, // cast by world triggers, in order to check when the constructs reach the water + + // scorch target + SPELL_SCORCH_AURA = 62548, + SPELL_SCORCH_AURA_H = 63476, + + // NPC ids + NPC_SCORCH = 33221, + NPC_IRON_CONSTRUCT = 33121, // constructs which are activated on demand by Ignis + + MAX_HEAT_STACKS = 10, }; +/*###### +## boss_ignis +######*/ + +struct boss_ignisAI : public ScriptedAI +{ + boss_ignisAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiBerserkTimer; + uint32 m_uiFlameJetsTimer; + uint32 m_uiSlagPotTimer; + uint32 m_uiScorchTimer; + uint32 m_uiConstructTimer; + + void Reset() override + { + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + m_uiFlameJetsTimer = 20000; + m_uiSlagPotTimer = 25000; + m_uiScorchTimer = 13000; + m_uiConstructTimer = 10000; + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_IGNIS, DONE); + + DoCastSpellIfCan(m_creature, SPELL_KILL_ALL_CONSTRUCTS, CAST_TRIGGERED); + DoScriptText(SAY_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_IGNIS, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_IGNIS, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SCORCH) + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_SCORCH_AURA : SPELL_SCORCH_AURA_H, true); + } + + // TODO: Use the vehicle boarding wrappers when they are implemented in core + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pCaster->GetTypeId() != TYPEID_PLAYER) + return; + + // Handle the case when passenger is loaded to the second seat + if (pSpell->Id == SPELL_GRAB_POT) + DoCastSpellIfCan(pCaster, SPELL_SLAG_POT, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiFlameJetsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FLAME_JETS : SPELL_FLAME_JETS_H) == CAST_OK) + { + DoScriptText(EMOTE_FLAME_JETS, m_creature); + DoScriptText(SAY_FLAME_JETS, m_creature); + m_uiFlameJetsTimer = 35000; + } + } + else + m_uiFlameJetsTimer -= uiDiff; + + if (m_uiSlagPotTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_GRAB, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_GRAB) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SLAGPOT_1 : SAY_SLAGPOT_2, m_creature); + m_uiSlagPotTimer = 30000; + } + } + } + else + m_uiSlagPotTimer -= uiDiff; + + if (m_uiConstructTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ACTIVATE_CONSTRUCT) == CAST_OK) + { + DoScriptText(SAY_ADDS, m_creature); + m_uiConstructTimer = 40000; + } + } + else + m_uiConstructTimer -= uiDiff; + + if (m_uiScorchTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SCORCH : SPELL_SCORCH_H) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_SCORCH_SUMMON, CAST_TRIGGERED); + m_uiScorchTimer = 25000; + } + } + else + m_uiScorchTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_ignis(Creature* pCreature) +{ + return new boss_ignisAI(pCreature); +} + +/*###### +## npc_iron_construct +######*/ + +struct npc_iron_constructAI : public ScriptedAI +{ + npc_iron_constructAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + bool m_bHasShattered; + + void Reset() override + { + m_bHasShattered = false; + + DoCastSpellIfCan(m_creature, SPELL_STONED, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CONSTRUCT_HITTING_YA, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + // reset flags if necessary + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoCastSpellIfCan(m_creature, SPELL_STONED, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_CONSTRUCT_HITTING_YA, CAST_TRIGGERED); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + // ToDo: This may need more research related to spell proc + if (m_creature->HasAura(m_bIsRegularMode ? SPELL_BRITTLE : SPELL_BRITTLE_H) && !m_bHasShattered) + { + if (uiDamage > 5000) + { + DoCastSpellIfCan(m_creature, SPELL_SHATTER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_STRENGTH_REMOVE, CAST_TRIGGERED); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetMotionMaster()->MoveIdle(); + m_bHasShattered = true; + } + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_HEAT) + { + if (SpellAuraHolder* pHeatAura = m_creature->GetSpellAuraHolder(SPELL_HEAT)) + { + if (pHeatAura && pHeatAura->GetStackAmount() == MAX_HEAT_STACKS) + DoCastSpellIfCan(m_creature, SPELL_MOLTEN); + } + } + } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // stop attacking after shattered + if (m_bHasShattered) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_iron_construct(Creature* pCreature) +{ + return new npc_iron_constructAI(pCreature); +} + +bool EffectScriptEffectCreature_npc_iron_construct(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_WATER_EFFECT && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_IRON_CONSTRUCT) + { + // chill the iron construct if molten (effect handled in core) + if (pCreatureTarget->HasAura(SPELL_MOLTEN)) + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_CHILL, true); + + return true; + } + + return false; +} + +/*###### +## npc_scorch +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_scorchAI : public Scripted_NoMovementAI +{ + npc_scorchAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_scorch(Creature* pCreature) +{ + return new npc_scorchAI(pCreature); +} + +bool EffectScriptEffectCreature_npc_scorch(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_WATER_EFFECT && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_SCORCH) + { + // despawn the Scorch in water + DoScriptText(EMOTE_EXTINGUISH_SCORCH, pCreatureTarget); + pCreatureTarget->ForcedDespawn(); + return true; + } + + return false; +} + void AddSC_boss_ignis() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ignis"; + pNewScript->GetAI = GetAI_boss_ignis; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_iron_construct"; + pNewScript->GetAI = &GetAI_npc_iron_construct; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_npc_iron_construct; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_scorch"; + pNewScript->GetAI = &GetAI_npc_scorch; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_npc_scorch; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp b/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp index 3dd3c6ece..af3994911 100644 --- a/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_kologarn.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,14 @@ /* ScriptData SDName: boss_kologarn -SD%Complete: 0% +SD%Complete: 100% SDComment: SDCategory: Ulduar EndScriptData */ #include "precompiled.h" #include "ulduar.h" +#include "TemporarySummon.h" enum { @@ -39,9 +40,521 @@ enum EMOTE_ARM_RIGHT = -1603135, EMOTE_ARM_LEFT = -1603136, EMOTE_STONE_GRIP = -1603137, + + // Kologarn + SPELL_INSTAKILL_KOLOGARN_ARM = 63628, // kill both arms on death + SPELL_OVERHEAD_SMASH = 63356, // cast if both arms are alive + SPELL_OVERHEAD_SMASH_H = 64003, + SPELL_ONE_ARMED_SMASH = 63573, // cast if only one arm is alive + SPELL_ONE_ARMED_SMASH_H = 64006, + SPELL_STONE_SHOUT = 63716, // cast if no arms are alive + SPELL_STONE_SHOUT_H = 64005, + SPELL_PETRIFYING_BREATH = 62030, // cast if nobody is in melee range + SPELL_PETRIFYING_BREATH_H = 63980, + SPELL_BERSERK = 64238, + SPELL_REDUCE_PARRY_CHANCE = 64651, + + // Arms spells + SPELL_ARM_VISUAL = 64753, // spawn visual + SPELL_ARM_DEAD_DAMAGE_KOLOGARN = 63629, // damage to Kologarn on arm death + SPELL_ARM_DEAD_DAMAGE_KOLOGARN_H = 63979, + SPELL_RIDE_KOLOGARN_ARMS = 65343, + + // Left arm + SPELL_ARM_SWEEP = 63766, // triggers shockwave effect and visual spells + SPELL_ARM_SWEEP_H = 63983, + + // Right arm + SPELL_STONE_GRIP = 62166, // triggers vehicle control, damage and visual spells + SPELL_STONE_GRIP_H = 63981, + + // Focused Eyebeam + SPELL_FOCUSED_EYEBEAM_SUMMON = 63342, // triggers summons spells for npcs 33632 and 33802 + SPELL_EYEBEAM_PERIODIC = 63347, + SPELL_EYEBEAM_PERIODIC_H = 63977, + SPELL_EYEBEAM_DAMAGE = 63346, // triggered by the periodic spell + SPELL_EYEBEAM_DAMAGE_H = 63976, + SPELL_EYEBEAM_VISUAL_LEFT = 63676, // visual link to Kologarn + SPELL_EYEBEAM_VISUAL_RIGHT = 63702, + + // Rubble stalkers + SPELL_SUMMON_RUBBLE = 63633, // triggers 63634 five times + SPELL_FALLING_RUBBLE = 63821, + SPELL_FALLING_RUBBLE_H = 64001, + SPELL_CANCEL_STONE_GRIP = 65594, // cancels stone grip aura from players + + // NPC ids + NPC_FOCUSED_EYEBEAM_RIGHT = 33802, + NPC_FOCUSED_EYEBEAM_LEFT = 33632, + NPC_RUBBLE = 33768, + + // other + SEAT_ID_LEFT = 1, + SEAT_ID_RIGHT = 2, + MAX_ACHIEV_RUBBLE = 25, }; +static const float afKoloArmsLoc[4] = {1797.15f, -24.4027f, 448.741f, 3.1939f}; + +/*###### +## boss_kologarn +######*/ + +struct boss_kologarnAI : public Scripted_NoMovementAI +{ + boss_kologarnAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiMountArmsTimer; + + uint32 m_uiOverheadSmashTimer; + uint32 m_uiStoneShoutTimer; + uint32 m_uiEyebeamTimer; + uint32 m_uiPetrifyingBreathTimer; + uint32 m_uiRespawnRightTimer; + uint32 m_uiRespawnLeftTimer; + + uint32 m_uiStoneGripTimer; + uint32 m_uiShockwaveTimer; + + uint32 m_uiBerserkTimer; + + uint8 m_uiRubbleCount; + uint32 m_uiDisarmedTimer; + + void Reset() override + { + m_uiMountArmsTimer = 5000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_uiOverheadSmashTimer = urand(5000, 10000); + m_uiStoneShoutTimer = 1000; + m_uiEyebeamTimer = 10000; + m_uiPetrifyingBreathTimer = 4000; + + m_uiShockwaveTimer = urand(15000, 20000); + m_uiStoneGripTimer = 10000; + + m_uiRespawnRightTimer = 0; + m_uiRespawnLeftTimer = 0; + + m_uiRubbleCount = 0; + m_uiDisarmedTimer = 0; + + DoCastSpellIfCan(m_creature, SPELL_REDUCE_PARRY_CHANCE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KOLOGARN, DONE); + + DoScriptText(SAY_DEATH, m_creature); + DoCastSpellIfCan(m_creature, SPELL_INSTAKILL_KOLOGARN_ARM, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_INSTAKILL_KOLOGARN_ARM, CAST_TRIGGERED); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KOLOGARN, IN_PROGRESS); + + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KOLOGARN, FAIL); + + // kill both hands - will be respawned + m_creature->RemoveAllAuras(); + DoCastSpellIfCan(m_creature, SPELL_INSTAKILL_KOLOGARN_ARM, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_INSTAKILL_KOLOGARN_ARM, CAST_TRIGGERED); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_RIGHT_ARM: + { + int32 uiSeat = (int32)SEAT_ID_RIGHT; + pSummoned->CastCustomSpell(m_creature, SPELL_RIDE_KOLOGARN_ARMS, &uiSeat, NULL, NULL, true); + pSummoned->CastSpell(pSummoned, SPELL_ARM_VISUAL, true); + + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + } + case NPC_LEFT_ARM: + { + int32 uiSeat = (int32)SEAT_ID_LEFT; + pSummoned->CastCustomSpell(m_creature, SPELL_RIDE_KOLOGARN_ARMS, &uiSeat, NULL, NULL, true); + pSummoned->CastSpell(pSummoned, SPELL_ARM_VISUAL, true); + + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); + break; + } + case NPC_FOCUSED_EYEBEAM_RIGHT: + case NPC_FOCUSED_EYEBEAM_LEFT: + // force despawn - if the npc gets in combat it won't despawn automatically + pSummoned->ForcedDespawn(10000); + + // cast visuals and damage spell + pSummoned->CastSpell(m_creature, pSummoned->GetEntry() == NPC_FOCUSED_EYEBEAM_LEFT ? SPELL_EYEBEAM_VISUAL_LEFT : SPELL_EYEBEAM_VISUAL_RIGHT, true); + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_EYEBEAM_PERIODIC : SPELL_EYEBEAM_PERIODIC_H, true); + + // follow the summoner + if (pSummoned->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)pSummoned; + + if (Unit* pPlayer = m_creature->GetMap()->GetUnit(pTemporary->GetSummonerGuid())) + pSummoned->GetMotionMaster()->MoveChase(pPlayer); + } + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (!m_creature->isAlive() || !m_creature->getVictim()) + return; + + if (pSummoned->GetEntry() == NPC_LEFT_ARM) + { + if (m_pInstance) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_pInstance->GetKoloRubbleStalker(false))) + { + pStalker->CastSpell(pStalker, m_bIsRegularMode ? SPELL_FALLING_RUBBLE : SPELL_FALLING_RUBBLE_H, true); + pStalker->CastSpell(pStalker, SPELL_SUMMON_RUBBLE, true); + pStalker->CastSpell(pStalker, SPELL_CANCEL_STONE_GRIP, true); + } + + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_OPEN_ARMS, false); + } + + m_creature->RemoveAurasByCasterSpell(SPELL_RIDE_KOLOGARN_ARMS, pSummoned->GetObjectGuid()); + pSummoned->CastSpell(m_creature, m_bIsRegularMode ? SPELL_ARM_DEAD_DAMAGE_KOLOGARN : SPELL_ARM_DEAD_DAMAGE_KOLOGARN_H, true); + DoScriptText(SAY_ARM_LOST_LEFT, m_creature); + m_uiRespawnLeftTimer = 48000; + + // start disarmed achiev timer or set achiev crit as true if timer already started + if (m_uiDisarmedTimer) + { + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_DISARMED, true); + } + else + m_uiDisarmedTimer = 12000; + } + else if (pSummoned->GetEntry() == NPC_RIGHT_ARM) + { + // spawn Rubble and cancel stone grip + if (m_pInstance) + { + if (Creature* pStalker = m_creature->GetMap()->GetCreature(m_pInstance->GetKoloRubbleStalker(true))) + { + pStalker->CastSpell(pStalker, m_bIsRegularMode ? SPELL_FALLING_RUBBLE : SPELL_FALLING_RUBBLE_H, true); + pStalker->CastSpell(pStalker, SPELL_SUMMON_RUBBLE, true); + pStalker->CastSpell(pStalker, SPELL_CANCEL_STONE_GRIP, true); + } + + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_OPEN_ARMS, false); + } + + m_creature->RemoveAurasByCasterSpell(SPELL_RIDE_KOLOGARN_ARMS, pSummoned->GetObjectGuid()); + pSummoned->CastSpell(m_creature, m_bIsRegularMode ? SPELL_ARM_DEAD_DAMAGE_KOLOGARN : SPELL_ARM_DEAD_DAMAGE_KOLOGARN_H, true); + DoScriptText(SAY_ARM_LOST_RIGHT, m_creature); + m_uiRespawnRightTimer = 48000; + + // start disarmed achiev timer or set achiev crit as true if timer already started + if (m_uiDisarmedTimer) + { + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_DISARMED, true); + } + else + m_uiDisarmedTimer = 12000; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // count the summoned Rubble + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_RUBBLE_STALKER) + { + ++m_uiRubbleCount; + + if (m_uiRubbleCount == MAX_ACHIEV_RUBBLE && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_RUBBLE, true); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiMountArmsTimer) + { + if (m_uiMountArmsTimer <= uiDiff) + { + m_creature->SummonCreature(NPC_RIGHT_ARM, afKoloArmsLoc[0], afKoloArmsLoc[1], afKoloArmsLoc[2], afKoloArmsLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_creature->SummonCreature(NPC_LEFT_ARM, afKoloArmsLoc[0], afKoloArmsLoc[1], afKoloArmsLoc[2], afKoloArmsLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiMountArmsTimer = 0; + } + else + m_uiMountArmsTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiRespawnLeftTimer && m_uiRespawnRightTimer) + { + if (m_uiStoneShoutTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STONE_SHOUT : SPELL_STONE_SHOUT_H) == CAST_OK) + m_uiStoneShoutTimer = urand(3000, 4000); + } + else + m_uiStoneShoutTimer -= uiDiff; + } + else + { + if (m_uiOverheadSmashTimer < uiDiff) + { + CanCastResult castResult; + if (!m_uiRespawnLeftTimer && !m_uiRespawnRightTimer) + castResult = DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_OVERHEAD_SMASH : SPELL_OVERHEAD_SMASH_H); + else + castResult = DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_ONE_ARMED_SMASH : SPELL_ONE_ARMED_SMASH_H); + + if (castResult == CAST_OK) + m_uiOverheadSmashTimer = 15000; + } + else + m_uiOverheadSmashTimer -= uiDiff; + } + + if (m_uiEyebeamTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FOCUSED_EYEBEAM_SUMMON) == CAST_OK) + m_uiEyebeamTimer = 20000; + } + else + m_uiEyebeamTimer -= uiDiff; + + // respawn left arm if killed + if (m_uiRespawnLeftTimer) + { + if (m_uiRespawnLeftTimer <= uiDiff) + { + DoScriptText(EMOTE_ARM_LEFT, m_creature); + m_creature->SummonCreature(NPC_LEFT_ARM, afKoloArmsLoc[0], afKoloArmsLoc[1], afKoloArmsLoc[2], afKoloArmsLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiRespawnLeftTimer = 0; + } + else + m_uiRespawnLeftTimer -= uiDiff; + } + // use left arm ability if available - spell always cast by Kologarn + else + { + if (m_uiShockwaveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARM_SWEEP : SPELL_ARM_SWEEP_H) == CAST_OK) + { + DoScriptText(SAY_SHOCKWAVE, m_creature); + m_uiShockwaveTimer = 17000; + } + } + else + m_uiShockwaveTimer -= uiDiff; + } + + // respawn right arm if killed + if (m_uiRespawnRightTimer) + { + if (m_uiRespawnRightTimer <= uiDiff) + { + DoScriptText(EMOTE_ARM_RIGHT, m_creature); + m_creature->SummonCreature(NPC_RIGHT_ARM, afKoloArmsLoc[0], afKoloArmsLoc[1], afKoloArmsLoc[2], afKoloArmsLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiRespawnRightTimer = 0; + } + else + m_uiRespawnRightTimer -= uiDiff; + } + // use right arm ability if available - spell always cast by Kologarn + else + { + if (m_uiStoneGripTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_STONE_GRIP : SPELL_STONE_GRIP_H) == CAST_OK) + { + DoScriptText(SAY_GRAB, m_creature); + DoScriptText(EMOTE_STONE_GRIP, m_creature); + m_uiStoneGripTimer = urand(20000, 30000); + } + } + else + m_uiStoneGripTimer -= uiDiff; + } + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + if (m_pInstance) + { + if (Creature* pRightArm = m_pInstance->GetSingleCreatureFromStorage(NPC_RIGHT_ARM)) + pRightArm->CastSpell(pRightArm, SPELL_BERSERK, true); + if (Creature* pLeftArm = m_pInstance->GetSingleCreatureFromStorage(NPC_LEFT_ARM)) + pLeftArm->CastSpell(pLeftArm, SPELL_BERSERK, true); + } + + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiDisarmedTimer) + { + if (m_uiDisarmedTimer <= uiDiff) + { + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_DISARMED, false); + m_uiDisarmedTimer = 0; + } + else + m_uiDisarmedTimer -= uiDiff; + } + + // melee range check + if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + { + if (m_uiPetrifyingBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_PETRIFYING_BREATH : SPELL_PETRIFYING_BREATH_H) == CAST_OK) + m_uiPetrifyingBreathTimer = 4000; + } + else + m_uiPetrifyingBreathTimer -= uiDiff; + } + else + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_kologarn(Creature* pCreature) +{ + return new boss_kologarnAI(pCreature); +} + +/*###### +## npc_focused_eyebeam +######*/ + +struct npc_focused_eyebeamAI : public ScriptedAI +{ + npc_focused_eyebeamAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && (pSpellEntry->Id == SPELL_EYEBEAM_DAMAGE || pSpellEntry->Id == SPELL_EYEBEAM_DAMAGE_H) && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_LOOKS_KILL, false); + } + + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_focused_eyebeam(Creature* pCreature) +{ + return new npc_focused_eyebeamAI(pCreature); +} + +/*###### +## npc_rubble_stalker +######*/ + +struct npc_rubble_stalkerAI : public Scripted_NoMovementAI +{ + npc_rubble_stalkerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_RUBBLE && m_pInstance) + { + if (Creature* pKologarn = m_pInstance->GetSingleCreatureFromStorage(NPC_KOLOGARN)) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pKologarn); + + pSummoned->SetInCombatWithZone(); + } + } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_rubble_stalker(Creature* pCreature) +{ + return new npc_rubble_stalkerAI(pCreature); +} + void AddSC_boss_kologarn() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_kologarn"; + pNewScript->GetAI = GetAI_boss_kologarn; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_focused_eyebeam"; + pNewScript->GetAI = GetAI_npc_focused_eyebeam; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_rubble_stalker"; + pNewScript->GetAI = GetAI_npc_rubble_stalker; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp b/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp index db78f3f07..f35764424 100644 --- a/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_mimiron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_mimiron -SD%Complete: 0% -SDComment: +SD%Complete: 95% +SDComment: Laser Barrage rotation require additional research. SDCategory: Ulduar EndScriptData */ @@ -26,7 +26,7 @@ EndScriptData */ enum { - SAY_AGGRO = -1603176, + SAY_INTRO = -1603176, SAY_HARD_MODE = -1603177, SAY_BERSERK = -1603178, @@ -50,12 +50,2020 @@ enum SAY_ROBOT_SLAY_2 = -1603193, SAY_ROBOT_DEATH = -1603194, - SAY_HELP_YOGG = -1603195, - EMOTE_PLASMA_BLAST = -1603196, + + SAY_SELF_DESTRUCT = -1603248, + SAY_SELF_DESTRUCT_END = -1603260, + SAY_DESTRUCT_10_MIN = -1603249, + SAY_DESTRUCT_9_MIN = -1603250, + SAY_DESTRUCT_8_MIN = -1603251, + SAY_DESTRUCT_7_MIN = -1603252, + SAY_DESTRUCT_6_MIN = -1603253, + SAY_DESTRUCT_5_MIN = -1603254, + SAY_DESTRUCT_4_MIN = -1603255, + SAY_DESTRUCT_3_MIN = -1603256, + SAY_DESTRUCT_2_MIN = -1603257, + SAY_DESTRUCT_1_MIN = -1603258, + SAY_DESTRUCT_0_MIN = -1603259, + + // mimiron spells + SPELL_WELD = 63339, + SPELL_TELEPORT_VISUAL = 41232, + SPELL_TELEPORT_VISUAL_2 = 64446, + SPELL_RIDE_VEHICLE_MIMIRON_0 = 52391, // seat 0 + SPELL_RIDE_VEHICLE_MIMIRON_1 = 63313, // seat 1 + SPELL_RIDE_VEHICLE_MIMIRON_2 = 63314, // seat 2 + SPELL_RIDE_VEHICLE_MIMIRON_3 = 63315, // seat 3 + SPELL_RIDE_VEHICLE_MIMIRON_4 = 63316, // seat 4 + SPELL_RIDE_VEHICLE_MIMIRON_5 = 63344, // seat 5 + SPELL_RIDE_VEHICLE_MIMIRON_6 = 63345, // seat 6 + SPELL_JET_PACK_VISUAL = 63307, // fly animation + SPELL_JET_PACK = 63341, // seat switch spell + SPELL_SLEEP_VISUAL = 64393, + SPELL_SLEEP_WAKE = 64394, + SPELL_NOT_FRIENDLY_FIRE = 65040, // achiev check spell + SPELL_BERSERK = 26662, + + // generic spells + SPELL_FREEZE_ANIM = 16245, + SPELL_SELF_REPAIR = 64383, // self repair for the robot phase + SPELL_HALF_HEAL = 64188, // heal to prepare the robot phase + SPELL_CLEAR_DEBUFFS = 34098, + SPELL_RIDE_VEHICLE_ROBOT_1 = 64387, // seat 7 + SPELL_RIDE_VEHICLE_ROBOT_2 = 64388, // seat 3 + SPELL_VEHICLE_DAMAGED = 63415, + SPELL_DESPAWN_ASSAULT_BOTS = 64463, + + // Leviathan spells + SPELL_PROXIMITY_MINES = 63027, // triggers 65347 + SPELL_NAPALM_SHELL = 64539, // triggers 63667 which casts 63666 or 65026 + SPELL_PLASMA_BLAST = 62997, // cast by the turret + SPELL_PLASMA_BLAST_H = 64529, + SPELL_SHOCK_BLAST = 63631, + SPELL_FREEZE_ANIM_DEFEATED = 63354, // visual aura after defeat + SPELL_FLAME_SUPPRESSANT = 64570, // hard mode spells + SPELL_EMERGENCY_MODE_LEVIATHAN = 65101, + + // VX001 spells + SPELL_RAPID_BURST_SUMMON = 64840, + SPELL_RAPID_BURST_EFFECT = 64841, + SPELL_RAPID_BURST_AURA = 63382, // triggers alternative the left and right Rapid Burst or Hand Pulse + // SPELL_RAPID_BURST_LEFT = 63387, // used in the VX phase; each spell has a different robot animation + // SPELL_RAPID_BURST_RIGHT = 64019, + // SPELL_RAPID_BURST_LEFT_H = 64531, + // SPELL_RAPID_BURST_RIGHT_H = 64532, + // SPELL_LASER_BARRAGE = 63274, + SPELL_SPINNING_UP = 63414, // triggers 63274 and 66490; + SPELL_ROCKET_STRIKE = 64402, // targets npc 34050; triggers 63681 and 63036 from target; will spawn npc 34047 + SPELL_HEAT_WAVE = 63679, + SPELL_HEAT_WAVE_H = 64534, + SPELL_HAND_PULSE_LEFT = 64348, // spells used only in the final phase + SPELL_HAND_PULSE_RIGHT = 64352, // each as a different visual for robot hand animation + SPELL_HAND_PULSE_LEFT_H = 64536, + SPELL_HAND_PULSE_RIGHT_H = 64537, + SPELL_TORSO_DISABLED = 64120, // visual aura on defeat + SPELL_FLAME_SUPPRESSANT_CLOSE = 65192, // hard mode spell + SPELL_FROST_BOMB_SUMMON = 64623, // hard mode spell; triggers 64627 in order to summon npc 34149 + + // Aerial unit spells + SPELL_PLASMA_BALL_FLY = 63689, // used during the air phase + SPELL_PLASMA_BALL_FLY_H = 64535, + SPELL_PLASMA_BALL = 65647, // used during the final phase + SPELL_PLASMA_BALL_H = 65648, + SPELL_SUMMON_ASSAULT_BOT_TRIGGER = 64425, // triggers 64427 and 64426; used to summon npc 34057 + SPELL_SUMMON_ASSAULT_BOT_VISUAL = 64426, + SPELL_SUMMON_ASSAULT_BOT = 64427, + SPELL_SUMMON_SCRAP_BOT_TRIGGER = 63820, // triggers 63819 and 64398; used to summon npc 33855 + SPELL_SUMMON_SCRAP_BOT_VISUAL = 64398, + SPELL_SUMMON_SCRAP_BOT = 63819, + SPELL_BOMB_BOT_SUMMON = 63811, // summon npc 33836 + SPELL_MAGNETIC_CORE_PULL = 64436, + SPELL_MAGNETIC_CORE_VISUAL = 64438, + SPELL_SUMMON_FIRE_BOT_TRIGGER = 64620, // triggers 64621, 64622; hard mode spell; used to summon npc 34147 + SPELL_SUMMON_FIRE_BOT_VISUAL = 64621, + SPELL_SUMMON_FIRE_BOT = 64622, + + // proximity mine + SPELL_PROXIMITY_MINE = 65345, + SPELL_EXPLOSION = 66351, + SPELL_EXPLOSION_H = 63009, + + // bots spells + // SPELL_BOMB_BOT = 63767, + SPELL_ROCKET_STRIKE_DAMAGE = 64064, + + // hard mode spells + SPELL_SELF_DESTRUCTION = 64613, + SPELL_SELF_DESTRUCTION_DAMAGE = 64610, + SPELL_EMERGENCY_MODE = 64582, + + // fire spells + SPELL_SUMMON_FLAMES_INITIAL = 64563, // cast by npc 21252 + SPELL_FLAMES = 64561, // cast by npcs 34363 and 34121 + SPELL_SUMMON_FLAMES_SPREAD = 64562, // cast by npc 34363 + + // frost bomb spells + SPELL_EXPLOSION_FROST = 64626, + SPELL_FROST_BOMB_VISUAL = 64624, + SPELL_CLEAR_FIRES = 65354, + + // summoned + NPC_PROXIMITY_MINE = 34362, // has aura 65345 + NPC_ROCKET_VISUAL = 34050, // mounted on vehicle 33651 + NPC_ROCKET_STRIKE = 34047, // has aura 64064 + NPC_BURST_TARGET = 34211, // casts 64841 on VX001 which triggers 63382 + NPC_ASSALT_BOT = 34057, // handled in eventAI + NPC_BOMB_BOT = 33836, // has aura 63767; handled in eventAI + NPC_MAGNETIC_CORE = 34068, // has auras 64438 and 64436 + NPC_JUNK_BOT = 33855, + + // hard mode summoned + // NPC_FLAME_INITIAL = 34363, + // NPC_FLAME_SPREAD = 34121, + NPC_FROST_BOMB = 34149, + // NPC_EMERGENCY_FIRE_BOT = 34147, // handled in eventAI + + // other + POINT_ID_PARK = 1, + POINT_ID_CENTER = 2, + SEAT_ID_TURRET = 4, + + // phases + PHASE_INTRO = 0, + PHASE_LEVIATHAN = 1, + PHASE_VX001 = 2, + PHASE_AERIAL_UNIT = 3, + PHASE_FULL_ROBOT = 4, + PHASE_TRANSITION = 5, + PHASE_DAMAGED = 6, +}; + +static const DialogueEntry aMimironDialogue[] = +{ + {NPC_MIMIRON, 0, 3000}, // encounter start, normal + {SAY_TANK_ACTIVE, NPC_MIMIRON, 6000}, + {PHASE_LEVIATHAN, 0, 3000}, + {NPC_LEVIATHAN_MK, 0, 0}, + + {SAY_SELF_DESTRUCT, NPC_COMPUTER, 3000}, // encounter start, hard mode + {SAY_DESTRUCT_10_MIN, NPC_COMPUTER, 3000}, + {SAY_HARD_MODE, NPC_MIMIRON, 5000}, + {NPC_LEVIATHAN_MK, 0, 0}, + + {NPC_LEVIATHAN_MK_TURRET, 0, 1000}, // Leviathan defeated, first transition + {SAY_TANK_DEATH, NPC_MIMIRON, 5000}, + {GO_MIMIRON_ELEVATOR, 0, 15000}, + {NPC_VX001, 0, 8000}, + {SPELL_JET_PACK_VISUAL, 0, 1000}, + {SPELL_JET_PACK, 0, 3000}, + {SAY_TORSO_ACTIVE, NPC_MIMIRON, 3000}, + {PHASE_VX001, 0, 3000}, + {SEAT_ID_TURRET, 0, 0}, + + {SPELL_TORSO_DISABLED, 0, 5000}, // VX001 defeated, second transition + {NPC_ROCKET_STRIKE, 0, 1000}, + {SAY_TORSO_DEATH, NPC_MIMIRON, 5000}, + {NPC_AERIAL_UNIT, 0, 9000}, + {PHASE_TRANSITION, 0, 1000}, + {PHASE_AERIAL_UNIT, 0, 6000}, + {SAY_HEAD_ACTIVE, NPC_MIMIRON, 3000}, + {NPC_MAGNETIC_CORE, 0, 0}, + + {NPC_JUNK_BOT, 0, 4000}, // Aerial Unit defeated, last transition + {SAY_HEAD_DEATH, NPC_MIMIRON, 2000}, + {NPC_COMPUTER, 0, 4000}, + {SPELL_HALF_HEAL, 0, 4000}, + {NPC_BOMB_BOT, 0, 3000}, + {NPC_BURST_TARGET, 0, 4000}, + {SAY_ROBOT_ACTIVE, NPC_MIMIRON, 3000}, + {NPC_ROCKET_VISUAL, 0, 4000}, + {NPC_PROXIMITY_MINE, 0, 0}, + + {SPELL_SLEEP_VISUAL, 0, 7000}, // Robot defeated, epilogue + {SPELL_SLEEP_WAKE, 0, 3000}, + {SAY_ROBOT_DEATH, NPC_MIMIRON, 10000}, + {SPELL_TELEPORT_VISUAL, 0, 0}, + {0, 0, 0}, +}; + +// a random list of seats which can be used by Mimiron in idle mode +static const uint32 aRandomAnimationSpells[] = {SPELL_RIDE_VEHICLE_MIMIRON_0, SPELL_RIDE_VEHICLE_MIMIRON_1, SPELL_RIDE_VEHICLE_MIMIRON_2, SPELL_RIDE_VEHICLE_MIMIRON_4}; + +// teleporters +static const uint32 aMimironTeleporters[] = {GO_MIMIRON_TEL1, GO_MIMIRON_TEL2, GO_MIMIRON_TEL3, GO_MIMIRON_TEL4, GO_MIMIRON_TEL5, GO_MIMIRON_TEL6, GO_MIMIRON_TEL7, GO_MIMIRON_TEL8, GO_MIMIRON_TEL9}; + +// spawn or move positions +static const float afTankEvadePos[4] = {2792.07f, 2596.32f, 364.3136f, 3.5f}; +static const float afRobotSpawnPos[4] = {2744.431f, 2569.385f, 364.3968f, 3.141f}; +static const float afRocketSpawnPos[4] = {2746.262f, 2567.085f, 369.2921f, 3.14f}; +static const float afAerialSpawnPos[4] = {2744.365f, 2569.303f, 392.2355f, 3.15f}; +static const float afAerialMovePos[3] = {2743.32f, 2569.285f, 378.2812f}; +static const float afTankMovePos[3] = {2763.82f, 2568.87f, 364.3136f}; +static const float afCenterMovePos[3] = {2744.61f, 2569.38f, 364.3136f}; + +/*###### +## boss_mimiron +######*/ + +struct boss_mimironAI : public ScriptedAI, private DialogueHelper +{ + boss_mimironAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aMimironDialogue) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + m_bHasDoneIntro = false; + Reset(); + } + + instance_ulduar* m_pInstance; + + uint8 m_uiPhase; + uint8 m_uiDestructStage; + uint32 m_uiDestructTimer; + + uint32 m_uiWeldTimer; + uint32 m_uiAnimationTimer; + uint32 m_uiCurrentSeatAura; + + uint32 m_uiWakeUpTimer; + uint32 m_uiFlamesTimer; + uint32 m_uiBerserkTimer; + + bool m_bHasDoneIntro; + + void Reset() override + { + m_uiPhase = PHASE_INTRO; + m_uiDestructStage = 0; + m_uiDestructTimer = 0; + m_uiWakeUpTimer = 0; + m_uiWeldTimer = 1000; + m_uiAnimationTimer = 10000; + m_uiFlamesTimer = 0; + m_uiBerserkTimer = 0; + m_uiCurrentSeatAura = SPELL_RIDE_VEHICLE_MIMIRON_0; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + void AttackStart(Unit* /*pWho*/) override { } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasDoneIntro && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 70.0f)) + { + DoScriptText(SAY_INTRO, m_creature); + m_bHasDoneIntro = true; + } + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + // start encounter on first damage + if (m_uiPhase == PHASE_INTRO && uiDamage) + { + m_uiPhase = PHASE_LEVIATHAN; + + if (m_pInstance) + m_pInstance->SetData(TYPE_MIMIRON, IN_PROGRESS); + + StartNextDialogueText(NPC_MIMIRON); + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + // Encounter intro (normal and hard mode) + case NPC_MIMIRON: + case NPC_LEVIATHAN_MK_TURRET: + // jump on the top of the robot for intro / phase end text + m_creature->RemoveAurasDueToSpell(SPELL_WELD); + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + { + pLeviathan->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + DoCastSpellIfCan(pLeviathan, SPELL_RIDE_VEHICLE_MIMIRON_5, CAST_TRIGGERED); + } + break; + case PHASE_LEVIATHAN: + case SAY_HARD_MODE: + // mount inside the robot + m_creature->RemoveAurasDueToSpell(SPELL_WELD); + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + { + pLeviathan->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + DoCastSpellIfCan(pLeviathan, SPELL_RIDE_VEHICLE_MIMIRON_6, CAST_TRIGGERED); + + // hard mode aura + if (m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + { + pLeviathan->CastSpell(pLeviathan, SPELL_EMERGENCY_MODE, true); + pLeviathan->CastSpell(pLeviathan, SPELL_EMERGENCY_MODE_LEVIATHAN, true); + } + + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; + } + break; + case NPC_LEVIATHAN_MK: + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + { + pLeviathan->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + pLeviathan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pLeviathan->SetInCombatWithZone(); + } + // Note: maybe the flags are handled by the vehicle seats. Set them manually for the moment. + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + break; + + // Start phase 2 transition + case GO_MIMIRON_ELEVATOR: + m_pInstance->DoUseDoorOrButton(GO_MIMIRON_ELEVATOR); + break; + case NPC_VX001: + if (GameObject* pElevator = m_pInstance->GetSingleGameObjectFromStorage(GO_MIMIRON_ELEVATOR)) + pElevator->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + m_creature->SummonCreature(NPC_VX001, afRobotSpawnPos[0], afRobotSpawnPos[1], afRobotSpawnPos[2], afRobotSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0); + break; + case SPELL_JET_PACK_VISUAL: + DoCastSpellIfCan(m_creature, SPELL_JET_PACK_VISUAL); + break; + case SPELL_JET_PACK: + // fly from the Leviathan to VX001 + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + pLeviathan->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + DoCastSpellIfCan(pVx001, SPELL_RIDE_VEHICLE_MIMIRON_0, CAST_TRIGGERED); + break; + case SAY_TORSO_ACTIVE: + m_creature->RemoveAurasDueToSpell(SPELL_JET_PACK_VISUAL); + break; + case PHASE_VX001: + // mount inside the robot + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + { + pVx001->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + DoCastSpellIfCan(pVx001, SPELL_RIDE_VEHICLE_MIMIRON_1, CAST_TRIGGERED); + + // hard mode aura + if (m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + pVx001->CastSpell(pVx001, SPELL_EMERGENCY_MODE, true); + } + break; + case SEAT_ID_TURRET: + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + { + pVx001->SetHealth(pVx001->GetMaxHealth()); + pVx001->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + pVx001->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pVx001->SetInCombatWithZone(); + } + break; + + // Start phase 3 transition + case NPC_ROCKET_STRIKE: + // mount on the top of the robot for phase end text + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + { + pVx001->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + DoCastSpellIfCan(pVx001, SPELL_RIDE_VEHICLE_MIMIRON_4, CAST_TRIGGERED); + } + break; + case NPC_AERIAL_UNIT: + m_creature->SummonCreature(NPC_AERIAL_UNIT, afAerialSpawnPos[0], afAerialSpawnPos[1], afAerialSpawnPos[2], afAerialSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0); + break; + case PHASE_TRANSITION: + DoCastSpellIfCan(m_creature, SPELL_JET_PACK_VISUAL); + break; + case PHASE_AERIAL_UNIT: + // mount inside the flying robot + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + pVx001->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + if (Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT)) + { + DoCastSpellIfCan(pAerial, SPELL_RIDE_VEHICLE_MIMIRON_0, CAST_TRIGGERED); + + // hard mode aura + if (m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + pAerial->CastSpell(pAerial, SPELL_EMERGENCY_MODE, true); + } + break; + case SAY_HEAD_ACTIVE: + m_creature->RemoveAurasDueToSpell(SPELL_JET_PACK_VISUAL); + break; + case NPC_MAGNETIC_CORE: + if (Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT)) + { + pAerial->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pAerial->SetInCombatWithZone(); + } + break; + + // Start phase 4 transition + case NPC_COMPUTER: + // get the tank into combat position + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + { + pLeviathan->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM_DEFEATED); + pLeviathan->GetMotionMaster()->MovePoint(POINT_ID_CENTER, afTankMovePos[0], afTankMovePos[1], afTankMovePos[2]); + } + break; + case SPELL_HALF_HEAL: + { + // mount the torso on top of the tank + Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK); + Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001); + if (!pLeviathan || !pVx001) + return; + + pVx001->RemoveAurasDueToSpell(SPELL_TORSO_DISABLED); + pVx001->CastSpell(pLeviathan, SPELL_RIDE_VEHICLE_ROBOT_1, true); + break; + } + case NPC_BOMB_BOT: + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + pLeviathan->GetMotionMaster()->MovePoint(POINT_ID_CENTER, afCenterMovePos[0], afCenterMovePos[1], afCenterMovePos[2]); + break; + case NPC_BURST_TARGET: + { + // mount the head on top of the torso + Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT); + Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001); + if (!pAerial || !pVx001) + return; + + pAerial->CastSpell(pVx001, SPELL_RIDE_VEHICLE_ROBOT_2, true); + break; + } + case NPC_ROCKET_VISUAL: + // switch from the head to inside the torso + if (Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT)) + pAerial->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + DoCastSpellIfCan(pVx001, SPELL_RIDE_VEHICLE_MIMIRON_1, CAST_TRIGGERED); + break; + case NPC_PROXIMITY_MINE: + // set the whole robot in combat and inform about phase 4 + if (Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT)) + { + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pAerial); + pAerial->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001)) + { + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pVx001); + pVx001->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pVx001->SetInCombatWithZone(); + } + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + { + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pLeviathan); + pLeviathan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + break; + + // Start encounter epilogue + case SPELL_SLEEP_VISUAL: + DoCastSpellIfCan(m_creature, SPELL_SLEEP_VISUAL); + if (m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + { + if (Creature* pComputer = m_pInstance->GetSingleCreatureFromStorage(NPC_COMPUTER)) + { + DoScriptText(SAY_SELF_DESTRUCT_END, pComputer); + m_uiFlamesTimer = 0; + m_uiDestructTimer = 0; + } + } + break; + case SPELL_SLEEP_WAKE: + if (DoCastSpellIfCan(m_creature, SPELL_SLEEP_WAKE) == CAST_OK) + m_creature->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL); + break; + case SPELL_TELEPORT_VISUAL: + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT_VISUAL) == CAST_OK) + m_creature->ForcedDespawn(2000); + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_AERIAL_UNIT) + pSummoned->GetMotionMaster()->MovePoint(1, afAerialMovePos[0], afAerialMovePos[1], afAerialMovePos[2]); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + switch (eventType) + { + // Red button pressed + case AI_EVENT_CUSTOM_A: + StartNextDialogueText(SAY_SELF_DESTRUCT); + m_uiPhase = PHASE_LEVIATHAN; + + if (m_pInstance) + m_pInstance->SetData(TYPE_MIMIRON, IN_PROGRESS); + m_uiDestructTimer = MINUTE * IN_MILLISECONDS; + m_uiFlamesTimer = 7000; + break; + // Leviathan phase finished + case AI_EVENT_CUSTOM_B: + StartNextDialogueText(NPC_LEVIATHAN_MK_TURRET); + break; + // VX001 phase finished + case AI_EVENT_CUSTOM_C: + StartNextDialogueText(SPELL_TORSO_DISABLED); + break; + // Aerial unit phase finished + case AI_EVENT_CUSTOM_D: + StartNextDialogueText(NPC_COMPUTER); + break; + // Robot piece destroyed + case AI_EVENT_CUSTOM_E: + if (!m_uiWakeUpTimer) + m_uiWakeUpTimer = 10000; + break; + } + } + + // function to switch to another seat on the Leviathan + void DoFlyToNextRandomSeat() + { + if (!m_pInstance) + return; + + Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK); + if (!pLeviathan) + return; + + m_creature->RemoveAurasDueToSpell(SPELL_WELD); + pLeviathan->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + + uint32 uiNextAuraId = aRandomAnimationSpells[urand(0, countof(aRandomAnimationSpells) - 1)]; + + while (uiNextAuraId == m_uiCurrentSeatAura) + uiNextAuraId = aRandomAnimationSpells[urand(0, countof(aRandomAnimationSpells) - 1)]; + + m_uiCurrentSeatAura = uiNextAuraId; + DoCastSpellIfCan(pLeviathan, m_uiCurrentSeatAura, CAST_TRIGGERED); + } + + // function to trigger the flames explosion for hard mode + void DoSpawnFlamesInitial() + { + if (!m_pInstance) + return; + + Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK); + Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_WORLD_TRIGGER_FLAMES); + if (!pLeviathan || !pTrigger) + return; + + for (uint8 i = 0; i < 3; ++i) + { + // Select targets based on Leviathan threat list; if the Leviathan is not in combat select them using instance + Unit* pTarget; + if (pLeviathan->getVictim()) + pTarget = pLeviathan->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SUMMON_FLAMES_INITIAL, SELECT_FLAG_PLAYER); + else + pTarget = m_pInstance->GetPlayerInMap(true, false); + + if (pTarget) + pTrigger->CastSpell(pTarget, SPELL_SUMMON_FLAMES_INITIAL, true); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + { + script_error_log("Instance Ulduar: ERROR Failed to load instance data for this instace."); + return; + } + + DialogueUpdate(uiDiff); + + if (m_uiPhase == PHASE_INTRO) + { + // in idle mode Mimiron jumps around the Leviathan + if (m_uiAnimationTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_JET_PACK) == CAST_OK) + { + DoFlyToNextRandomSeat(); + m_uiWeldTimer = 2000; + m_uiAnimationTimer = urand(12000, 15000); + } + } + else + m_uiAnimationTimer -= uiDiff; + + if (m_uiWeldTimer) + { + if (m_uiWeldTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WELD) == CAST_OK) + m_uiWeldTimer = 0; + } + else + m_uiWeldTimer -= uiDiff; + } + } + + if (m_uiWakeUpTimer) + { + // check if all robot pieces are damaged + if (m_uiWakeUpTimer <= uiDiff) + { + Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK); + Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001); + Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT); + if (!pAerial || !pVx001 || !pLeviathan) + return; + + // if all robot pieces are damaged finish the encounter + if (pLeviathan->HasAura(SPELL_FREEZE_ANIM) && pVx001->getStandState() == UNIT_STAND_STATE_DEAD && pAerial->getStandState() == UNIT_STAND_STATE_DEAD) + { + // eject from the robot and start dialogue + pVx001->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, m_creature->GetObjectGuid()); + StartNextDialogueText(SPELL_SLEEP_VISUAL); + + // kill the robot parts + m_creature->DealDamage(pLeviathan, pLeviathan->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + m_creature->DealDamage(pVx001, pVx001->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + m_creature->DealDamage(pAerial, pAerial->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + m_uiWakeUpTimer = 0; + } + else + m_uiWakeUpTimer -= uiDiff; + } + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + pLeviathan->CastSpell(pLeviathan, SPELL_BERSERK, true); + if (Creature* pVx001 = m_pInstance->GetSingleCreatureFromStorage(NPC_VX001, true)) + pVx001->CastSpell(pVx001, SPELL_BERSERK, true); + if (Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT, true)) + pAerial->CastSpell(pAerial, SPELL_BERSERK, true); + + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiFlamesTimer) + { + if (m_uiFlamesTimer <= uiDiff) + { + DoSpawnFlamesInitial(); + m_uiFlamesTimer = urand(25000, 30000); + } + else + m_uiFlamesTimer -= uiDiff; + } + + if (m_uiDestructTimer) + { + // handle the platform destruction for hard mode + if (m_uiDestructTimer <= uiDiff) + { + Creature* pComputer = m_pInstance->GetSingleCreatureFromStorage(NPC_COMPUTER); + if (!pComputer) + return; + + ++m_uiDestructStage; + m_uiDestructTimer = MINUTE * IN_MILLISECONDS; + + switch (m_uiDestructStage) + { + case 1: DoScriptText(SAY_DESTRUCT_9_MIN, pComputer); break; + case 2: DoScriptText(SAY_DESTRUCT_8_MIN, pComputer); break; + case 3: DoScriptText(SAY_DESTRUCT_7_MIN, pComputer); break; + case 4: DoScriptText(SAY_DESTRUCT_6_MIN, pComputer); break; + case 5: DoScriptText(SAY_DESTRUCT_5_MIN, pComputer); break; + case 6: DoScriptText(SAY_DESTRUCT_4_MIN, pComputer); break; + case 7: DoScriptText(SAY_DESTRUCT_3_MIN, pComputer); break; + case 8: DoScriptText(SAY_DESTRUCT_2_MIN, pComputer); break; + case 9: DoScriptText(SAY_DESTRUCT_1_MIN, pComputer); break; + case 10: + DoScriptText(SAY_DESTRUCT_0_MIN, pComputer); + pComputer->CastSpell(pComputer, SPELL_SELF_DESTRUCTION, true); + pComputer->CastSpell(pComputer, SPELL_SELF_DESTRUCTION_DAMAGE, true); + m_uiDestructTimer = 0; + break; + } + } + else + m_uiDestructTimer -= uiDiff; + } + } }; +CreatureAI* GetAI_boss_mimiron(Creature* pCreature) +{ + return new boss_mimironAI(pCreature); +} + +/*###### +## boss_leviathan_mk2 +######*/ + +struct boss_leviathan_mk2AI : public ScriptedAI +{ + boss_leviathan_mk2AI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + m_uiPhase = PHASE_INTRO; + m_uiMountTimer = 1000; + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + uint8 m_uiPhase; + + uint32 m_uiMountTimer; + + uint32 m_uiMinesTimer; + uint32 m_uiNapalmTimer; + uint32 m_uiPlasmaBlastTimer; + uint32 m_uiShockBlastTimer; + uint32 m_uiFlameSuppressTimer; + + void Reset() override + { + m_uiMinesTimer = 1000; + m_uiNapalmTimer = 20000; + m_uiPlasmaBlastTimer = 10000; + m_uiShockBlastTimer = 30000; + m_uiFlameSuppressTimer = 0; + + SetCombatMovement(true); + } + + void Aggro(Unit* /*pWho*/) override + { + m_uiPhase = PHASE_LEVIATHAN; + + if (m_pInstance && m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + m_uiFlameSuppressTimer = 50000; + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MIMIRON, DONE); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (pDoneBy->GetEntry() == NPC_MIMIRON && m_uiPhase == PHASE_DAMAGED) + return; + + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_uiPhase == PHASE_LEVIATHAN) + { + // unmount and destroy the turret + if (m_pInstance) + { + if (Creature* pTurret = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK_TURRET)) + { + m_creature->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE, pTurret->GetObjectGuid()); + m_creature->DealDamage(pTurret, pTurret->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + } + + // move to parking position + SetCombatMovement(false); + m_uiPhase = PHASE_TRANSITION; + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PARK, afTankEvadePos[0], afTankEvadePos[1], afTankEvadePos[2]); + } + else if (m_uiPhase == PHASE_FULL_ROBOT) + { + // start self repair + if (DoCastSpellIfCan(m_creature, SPELL_SELF_REPAIR, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_VEHICLE_DAMAGED, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM, CAST_TRIGGERED); + + // inform Mimiron about the damaged state + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + SendAIEvent(AI_EVENT_CUSTOM_E, m_creature, pMimiron); + + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + m_uiPhase = PHASE_DAMAGED; + } + } + } + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // self repair succesfull; resume fight + if (pSpell->Id == SPELL_SELF_REPAIR) + { + m_creature->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); + m_uiPhase = PHASE_FULL_ROBOT; + } + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_MIMIRON, FAIL); + + // respawn the turret if necessary + if (Creature* pTurret = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK_TURRET)) + { + if (!pTurret->isAlive()) + pTurret->Respawn(); + } + } + + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // reset all the vehicle accessories + m_uiMountTimer = 1000; + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER || !m_pInstance) + return; + + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + { + if (m_uiPhase == PHASE_FULL_ROBOT) + DoScriptText(urand(0, 1) ? SAY_ROBOT_SLAY_1 : SAY_ROBOT_SLAY_2, pMimiron); + else + DoScriptText(urand(0, 1) ? SAY_TANK_SLAY_1 : SAY_TANK_SLAY_2, pMimiron); + } + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) + return; + + if (uiPointId == POINT_ID_PARK) + { + // start transition phase + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pMimiron); + + // park the Leviathan + DoCastSpellIfCan(m_creature, SPELL_CLEAR_DEBUFFS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_HALF_HEAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM_DEFEATED, CAST_TRIGGERED); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetFacingTo(afTankEvadePos[3]); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + // switch to full robot abilities + if (eventType == AI_EVENT_CUSTOM_A) + { + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_uiPhase = PHASE_FULL_ROBOT; + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_PROXIMITY_MINE) + pSummoned->CastSpell(pSummoned, SPELL_PROXIMITY_MINE, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + { + script_error_log("Instance Ulduar: ERROR Failed to load instance data for this instace."); + return; + } + + // Mount Mimiron and the Turret manually + if (m_uiMountTimer) + { + if (m_uiMountTimer <= uiDiff) + { + m_creature->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + + if (Creature* pTurret = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK_TURRET)) + { + int32 iSeat = (int32)SEAT_ID_TURRET; + pTurret->CastCustomSpell(m_creature, SPELL_RIDE_VEHICLE_HARDCODED, &iSeat, NULL, NULL, true); + } + + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + pMimiron->CastSpell(m_creature, SPELL_RIDE_VEHICLE_MIMIRON_0, true); + + m_uiMountTimer = 0; + } + else + m_uiMountTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // no combat during transition or when damaged + if (m_uiPhase == PHASE_TRANSITION || m_uiPhase == PHASE_DAMAGED) + return; + + // Leviathan phase spells + if (m_uiPhase == PHASE_LEVIATHAN) + { + if (m_uiPlasmaBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (Creature* pTurret = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK_TURRET)) + pTurret->CastSpell(pTarget, m_bIsRegularMode ? SPELL_PLASMA_BLAST : SPELL_PLASMA_BLAST_H, false); + + DoScriptText(EMOTE_PLASMA_BLAST, m_creature); + m_uiPlasmaBlastTimer = 30000; + } + } + else + m_uiPlasmaBlastTimer -= uiDiff; + + if (m_uiNapalmTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_NAPALM_SHELL) == CAST_OK) + m_uiNapalmTimer = 7000; + } + else + m_uiNapalmTimer -= uiDiff; + + if (m_uiFlameSuppressTimer) + { + if (m_uiFlameSuppressTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_SUPPRESSANT) == CAST_OK) + m_uiFlameSuppressTimer = 60000; + } + else + m_uiFlameSuppressTimer -= uiDiff; + } + } + + if (m_uiMinesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_PROXIMITY_MINES) == CAST_OK) + m_uiMinesTimer = 35000; + } + else + m_uiMinesTimer -= uiDiff; + + if (m_uiShockBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHOCK_BLAST) == CAST_OK) + m_uiShockBlastTimer = 34000; + } + else + m_uiShockBlastTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_leviathan_mk2(Creature* pCreature) +{ + return new boss_leviathan_mk2AI(pCreature); +} + +/*###### +## boss_vx001 +######*/ + +struct boss_vx001AI : public ScriptedAI +{ + boss_vx001AI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + DoCastSpellIfCan(m_creature, SPELL_FREEZE_ANIM, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + m_uiPhase = PHASE_INTRO; + SetCombatMovement(false); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + uint8 m_uiPhase; + + uint32 m_uiRocketStrikeTimer; + uint32 m_uiRapidBurstTimer; + uint32 m_uLaserBarrageTimer; + uint32 m_uiHandPulseTimer; + uint32 m_uiBurstEndTimer; + uint32 m_uiLaserEndTimer; + uint32 m_uiFlameSuppressTimer; + uint32 m_uiFrostBombTimer; + + void Reset() override + { + m_uiBurstEndTimer = 0; + m_uiLaserEndTimer = 0; + m_uiRapidBurstTimer = 1000; + m_uiHandPulseTimer = 1000; + m_uiRocketStrikeTimer = 20000; + m_uLaserBarrageTimer = urand(30000, 60000); + m_uiFlameSuppressTimer = 0; + m_uiFrostBombTimer = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_uiPhase == PHASE_INTRO) + { + m_uiPhase = PHASE_VX001; + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HEAT_WAVE : SPELL_HEAT_WAVE_H, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + // Set levitate for animation purpose + m_creature->SetLevitate(true); + } + + if (m_pInstance && m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + { + m_uiFrostBombTimer = 1000; + m_uiFlameSuppressTimer = 5000; + } + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (pDoneBy->GetEntry() == NPC_MIMIRON && m_uiPhase == PHASE_DAMAGED) + return; + + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_uiPhase == PHASE_VX001) + { + // shut down the VX001 + if (DoCastSpellIfCan(m_creature, SPELL_TORSO_DISABLED, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + Reset(); + m_uiPhase = PHASE_TRANSITION; + + // start transition phase + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + SendAIEvent(AI_EVENT_CUSTOM_C, m_creature, pMimiron); + + DoCastSpellIfCan(m_creature, SPELL_CLEAR_DEBUFFS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_HALF_HEAL, CAST_TRIGGERED); + + // custom evade in order to properly handle the animations + // Note: we won't remove all auras because of the hard mode; Debuffs should be removed by the spell above + // m_creature->RemoveAllAurasOnEvade(); + m_creature->RemoveAurasDueToSpell(m_bIsRegularMode ? SPELL_HEAT_WAVE : SPELL_HEAT_WAVE_H); + m_creature->DeleteThreatList(); + m_creature->CombatStop(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + else if (m_uiPhase == PHASE_FULL_ROBOT) + { + // start self repair + if (DoCastSpellIfCan(m_creature, SPELL_SELF_REPAIR, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + // inform Mimiron about the damaged state + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + SendAIEvent(AI_EVENT_CUSTOM_E, m_creature, pMimiron); + + m_uiPhase = PHASE_DAMAGED; + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + } + } + } + } + + void EnterEvadeMode() override {} + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // self repair succesfull; resume fight + if (pSpell->Id == SPELL_SELF_REPAIR) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiPhase = PHASE_FULL_ROBOT; + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER || !m_pInstance) + return; + + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + { + if (m_uiPhase == PHASE_FULL_ROBOT) + DoScriptText(urand(0, 1) ? SAY_ROBOT_SLAY_1 : SAY_ROBOT_SLAY_2, pMimiron); + else + DoScriptText(urand(0, 1) ? SAY_TORSO_SLAY_1 : SAY_TORSO_SLAY_2, pMimiron); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + // switch to full robot abilities + if (eventType == AI_EVENT_CUSTOM_A) + { + m_uiPhase = PHASE_FULL_ROBOT; + + // Set levitate for animation purpose + m_creature->SetLevitate(true); + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_BURST_TARGET: + pSummoned->CastSpell(m_creature, SPELL_RAPID_BURST_EFFECT, true); + m_uiBurstEndTimer = 3000; + + // Remove the target focus but allow the boss to face the burst target + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->SetFacingToObject(pSummoned); + break; + case NPC_FROST_BOMB: + pSummoned->CastSpell(pSummoned, SPELL_FROST_BOMB_VISUAL, true); + break; + } + } + + // Custom threat management + bool SelectCustomHostileTarget() + { + Unit* pTarget = NULL; + Unit* pOldTarget = m_creature->getVictim(); + + if (!m_creature->getThreatManager().isThreatListEmpty()) + pTarget = m_creature->getThreatManager().getHostileTarget(); + + if (pTarget) + { + if (pOldTarget != pTarget && !m_uiBurstEndTimer && !m_uiLaserEndTimer) + AttackStart(pTarget); + + // Set victim to old target (if not while Burst or Laser) + if (pOldTarget && pOldTarget->isAlive() && !m_uiBurstEndTimer && !m_uiLaserEndTimer) + { + m_creature->SetTargetGuid(pOldTarget->GetObjectGuid()); + m_creature->SetInFront(pOldTarget); + } + + return true; + } + + // Will call EnterEvadeMode if fit + return m_creature->SelectHostileTarget() && m_creature->getVictim(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectCustomHostileTarget()) + return; + + // no combat during transition or when damaged + if (m_uiPhase == PHASE_TRANSITION || m_uiPhase == PHASE_DAMAGED) + return; + + // count the burst or laser expire timer for target reset + if (m_uiBurstEndTimer) + { + if (m_uiBurstEndTimer <= uiDiff) + m_uiBurstEndTimer = 0; + else + m_uiBurstEndTimer -= uiDiff; + } + + if (m_uiLaserEndTimer) + { + if (m_uiLaserEndTimer <= uiDiff) + m_uiLaserEndTimer = 0; + else + m_uiLaserEndTimer -= uiDiff; + + // no other abilities during Laser + return; + } + + if (m_uiPhase == PHASE_VX001) + { + if (m_uiRapidBurstTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_RAPID_BURST_SUMMON, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_RAPID_BURST_SUMMON) == CAST_OK) + m_uiRapidBurstTimer = 4000; + } + } + else + m_uiRapidBurstTimer -= uiDiff; + + if (m_uiFlameSuppressTimer) + { + if (m_uiFlameSuppressTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_SUPPRESSANT_CLOSE) == CAST_OK) + m_uiFlameSuppressTimer = 10000; + } + else + m_uiFlameSuppressTimer -= uiDiff; + } + } + else if (m_uiPhase == PHASE_FULL_ROBOT) + { + if (m_uiHandPulseTimer < uiDiff) + { + CanCastResult uiResult; + if (urand(0, 1)) + uiResult = DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HAND_PULSE_LEFT : SPELL_HAND_PULSE_LEFT_H); + else + uiResult = DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HAND_PULSE_RIGHT : SPELL_HAND_PULSE_RIGHT_H); + + if (uiResult == CAST_OK) + m_uiHandPulseTimer = urand(1000, 2000); + } + else + m_uiHandPulseTimer -= uiDiff; + } + + if (m_uiRocketStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ROCKET_STRIKE) == CAST_OK) + m_uiRocketStrikeTimer = 20000; + } + else + m_uiRocketStrikeTimer -= uiDiff; + + if (m_uLaserBarrageTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SPINNING_UP) == CAST_OK) + { + m_uiLaserEndTimer = 14000; + m_uLaserBarrageTimer = 40000; + } + } + else + m_uLaserBarrageTimer -= uiDiff; + + if (m_uiFrostBombTimer) + { + if (m_uiFrostBombTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FROST_BOMB_SUMMON) == CAST_OK) + m_uiFrostBombTimer = 30000; + } + else + m_uiFrostBombTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_vx001(Creature* pCreature) +{ + return new boss_vx001AI(pCreature); +} + +/*###### +## boss_aerial_unit +######*/ + +struct boss_aerial_unitAI : public ScriptedAI +{ + boss_aerial_unitAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_creature->SetLevitate(true); + m_uiPhase = PHASE_TRANSITION; + SetCombatMovement(false); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + uint8 m_uiPhase; + + uint32 m_uiCombatMoveTimer; + uint32 m_uiPlasmaBallTimer; + uint32 m_uiBombBotTimer; + uint32 m_uiAssaultBotTimer; + uint32 m_uiScrapBotTimer; + uint32 m_uiFireBotTimer; + uint32 m_uiMagneticTimer; + + void Reset() override + { + m_uiCombatMoveTimer = 2000; + m_uiPlasmaBallTimer = 2000; + m_uiAssaultBotTimer = 5000; + m_uiBombBotTimer = 15000; + m_uiScrapBotTimer = 10000; + m_uiMagneticTimer = 0; + m_uiFireBotTimer = 0; + + SetCombatMovement(false); + } + + void Aggro(Unit* /*pWho*/) override + { + m_uiPhase = PHASE_AERIAL_UNIT; + m_creature->SetWalk(false); + + // init hard mode spells + if (m_pInstance && m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIRE_BOT_TRIGGER); + m_uiFireBotTimer = 45000; + } + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + if (pDoneBy->GetEntry() == NPC_MIMIRON && m_uiPhase == PHASE_DAMAGED) + return; + + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (m_uiPhase == PHASE_AERIAL_UNIT) + { + // start transition phase + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + SendAIEvent(AI_EVENT_CUSTOM_D, m_creature, pMimiron); + + // shut down the aerial unit and prepare for the final phase + DoCastSpellIfCan(m_creature, SPELL_CLEAR_DEBUFFS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_HALF_HEAL, CAST_TRIGGERED); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, afAerialMovePos[0], afAerialMovePos[1], afAerialMovePos[2]); + m_uiPhase = PHASE_TRANSITION; + } + else if (m_uiPhase == PHASE_FULL_ROBOT) + { + // start self repair + if (DoCastSpellIfCan(m_creature, SPELL_SELF_REPAIR, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + // inform Mimiron about the damaged state + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + SendAIEvent(AI_EVENT_CUSTOM_E, m_creature, pMimiron); + + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + m_uiPhase = PHASE_DAMAGED; + } + } + } + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // self repair succesfull; resume fight + if (pSpell->Id == SPELL_SELF_REPAIR) + { + m_uiPhase = PHASE_FULL_ROBOT; + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + } + else if (pSpell->Id == SPELL_MAGNETIC_CORE_PULL && pCaster->GetEntry() == NPC_MAGNETIC_CORE) + { + DoCastSpellIfCan(m_creature, SPELL_MAGNETIC_CORE_VISUAL, CAST_INTERRUPT_PREVIOUS); + m_uiMagneticTimer = 20000; + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, pCaster->GetPositionX(), pCaster->GetPositionY(), pCaster->GetPositionZ()); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MIMIRON, FAIL); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER || !m_pInstance) + return; + + if (Creature* pMimiron = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + { + if (m_uiPhase == PHASE_FULL_ROBOT) + DoScriptText(urand(0, 1) ? SAY_ROBOT_SLAY_1 : SAY_ROBOT_SLAY_2, pMimiron); + else + DoScriptText(urand(0, 1) ? SAY_HEAD_SLAY_1 : SAY_HEAD_SLAY_2, pMimiron); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + // switch to full robot abilities + if (eventType == AI_EVENT_CUSTOM_A) + m_uiPhase = PHASE_FULL_ROBOT; + } + + void JustSummoned(Creature* pSummoned) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_MIMIRON_HARD) == DONE) + pSummoned->CastSpell(pSummoned, SPELL_EMERGENCY_MODE, true); + + pSummoned->AI()->AttackStart(m_creature->getVictim()); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiMagneticTimer) + { + if (m_uiMagneticTimer <= uiDiff) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), afAerialMovePos[2]); + + m_creature->RemoveAurasDueToSpell(SPELL_MAGNETIC_CORE_VISUAL); + m_uiMagneticTimer = 0; + } + else + m_uiMagneticTimer -= uiDiff; + + // no other abilities during the magnetic pull + return; + } + + // no combat during transition or when damaged + if (m_uiPhase == PHASE_TRANSITION || m_uiPhase == PHASE_DAMAGED) + return; + + // aerial phase spells + if (m_uiPhase == PHASE_AERIAL_UNIT) + { + // move to a closer point to target + if (m_uiCombatMoveTimer < uiDiff) + { + if (m_creature->GetDistance(m_creature->getVictim()) > 30.0f) + { + float fX, fY, fZ; + m_creature->getVictim()->GetContactPoint(m_creature, fX, fY, fZ, 3 * ATTACK_DISTANCE); + + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(0, fX, fY, m_creature->GetPositionZ()); + } + m_uiCombatMoveTimer = 2000; + } + else + m_uiCombatMoveTimer -= uiDiff; + + if (m_uiPlasmaBallTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_PLASMA_BALL_FLY : SPELL_PLASMA_BALL_FLY_H) == CAST_OK) + m_uiPlasmaBallTimer = urand(2000, 3000); + } + else + m_uiPlasmaBallTimer -= uiDiff; + + if (m_uiAssaultBotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ASSAULT_BOT_TRIGGER) == CAST_OK) + m_uiAssaultBotTimer = 30000; + } + else + m_uiAssaultBotTimer -= uiDiff; + + if (m_uiBombBotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BOMB_BOT_SUMMON) == CAST_OK) + m_uiBombBotTimer = 15000; + } + else + m_uiBombBotTimer -= uiDiff; + + if (m_uiScrapBotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SCRAP_BOT_TRIGGER) == CAST_OK) + m_uiScrapBotTimer = 10000; + } + else + m_uiScrapBotTimer -= uiDiff; + + if (m_uiFireBotTimer) + { + if (m_uiFireBotTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_FIRE_BOT_TRIGGER) == CAST_OK) + m_uiFireBotTimer = 45000; + } + else + m_uiFireBotTimer -= uiDiff; + } + } + // full robot abilities + else if (m_uiPhase == PHASE_FULL_ROBOT) + { + if (m_uiPlasmaBallTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_PLASMA_BALL : SPELL_PLASMA_BALL_H) == CAST_OK) + m_uiPlasmaBallTimer = 2000; + } + else + m_uiPlasmaBallTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_aerial_unit(Creature* pCreature) +{ + return new boss_aerial_unitAI(pCreature); +} + +/*###### +## npc_proximity_mine +######*/ + +struct npc_proximity_mineAI : public Scripted_NoMovementAI +{ + npc_proximity_mineAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiExplodeTimer; + + void Reset() override + { + m_uiExplodeTimer = 35000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiExplodeTimer) + { + if (m_uiExplodeTimer <= uiDiff) + { + // just despawn if already exploded + if (!m_creature->HasAura(SPELL_PROXIMITY_MINE)) + m_creature->ForcedDespawn(); + else + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLOSION_H) == CAST_OK) + { + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAurasDueToSpell(SPELL_PROXIMITY_MINE); + m_creature->ForcedDespawn(2000); + m_uiExplodeTimer = 0; + } + } + } + else + m_uiExplodeTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_proximity_mine(Creature* pCreature) +{ + return new npc_proximity_mineAI(pCreature); +} + +/*###### +## npc_bot_trigger +######*/ + +struct npc_bot_triggerAI : public Scripted_NoMovementAI +{ + npc_bot_triggerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + uint32 m_uiSummonTimer; + uint32 m_uiSummonSpell; + + void Reset() override + { + m_uiSummonTimer = 0; + m_uiSummonSpell = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_CUSTOM_A) + { + m_uiSummonTimer = 6000; + m_uiSummonSpell = uiMiscValue; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSummonTimer) + { + if (m_uiSummonTimer <= uiDiff) + { + if (m_pInstance) + { + if (Creature* pAerial = m_pInstance->GetSingleCreatureFromStorage(NPC_AERIAL_UNIT)) + { + if (DoCastSpellIfCan(m_creature, m_uiSummonSpell, CAST_TRIGGERED, pAerial->GetObjectGuid()) == CAST_OK) + m_uiSummonTimer = 0; + } + } + + // search for a nearby teleporter and disable the visual + for (uint8 i = 0; i < countof(aMimironTeleporters); ++i) + { + if (GameObject* pTeleporter = GetClosestGameObjectWithEntry(m_creature, aMimironTeleporters[i], 2.0f)) + { + pTeleporter->ResetDoorOrButton(); + break; + } + } + } + else + m_uiSummonTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_bot_trigger(Creature* pCreature) +{ + return new npc_bot_triggerAI(pCreature); +} + +bool EffectDummyCreature_npc_bot_trigger(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if ((uiSpellId == SPELL_SUMMON_ASSAULT_BOT_TRIGGER || uiSpellId == SPELL_SUMMON_SCRAP_BOT_TRIGGER || uiSpellId == SPELL_SUMMON_FIRE_BOT_TRIGGER) && uiEffIndex == EFFECT_INDEX_0) + { + uint32 uiVisualSpell = 0; + uint32 uiSummonSpell = 0; + + switch (uiSpellId) + { + case SPELL_SUMMON_SCRAP_BOT_TRIGGER: + uiVisualSpell = SPELL_SUMMON_ASSAULT_BOT_VISUAL; + uiSummonSpell = SPELL_SUMMON_ASSAULT_BOT; + break; + case SPELL_SUMMON_ASSAULT_BOT_TRIGGER: + uiVisualSpell = SPELL_SUMMON_SCRAP_BOT_VISUAL; + uiSummonSpell = SPELL_SUMMON_SCRAP_BOT; + break; + case SPELL_SUMMON_FIRE_BOT_TRIGGER: + uiVisualSpell = SPELL_SUMMON_FIRE_BOT_VISUAL; + uiSummonSpell = SPELL_SUMMON_FIRE_BOT; + break; + } + + pCreatureTarget->CastSpell(pCreatureTarget, uiVisualSpell, true); + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget, uiSummonSpell); + + // search for a nearby teleporter and enable the visual + for (uint8 i = 0; i < countof(aMimironTeleporters); ++i) + { + if (GameObject* pTeleporter = GetClosestGameObjectWithEntry(pCreatureTarget, aMimironTeleporters[i], 2.0f)) + { + pTeleporter->UseDoorOrButton(); + break; + } + } + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_mimiron_flames +######*/ + +struct npc_mimiron_flamesAI : public Scripted_NoMovementAI +{ + npc_mimiron_flamesAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + uint32 m_uiSpreadTimer; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_FLAMES, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + m_uiSpreadTimer = 4000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + // function to select the closest player to spread the fire + Unit* SelectClosestSpreadTarget() + { + if (!m_pInstance) + return NULL; + + Creature* pLeviathan = m_pInstance->GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK); + if (!pLeviathan) + return NULL; + + std::list lTargets; + ThreatList const& threatList = pLeviathan->getThreatManager().getThreatList(); + + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pTarget->GetTypeId() == TYPEID_PLAYER) + lTargets.push_back(pTarget); + } + } + + // return the closest target to the caster + if (!lTargets.empty()) + { + lTargets.sort(ObjectDistanceOrder(m_creature)); + return lTargets.front(); + } + + return NULL; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSpreadTimer < uiDiff) + { + if (Unit* pTarget = SelectClosestSpreadTarget()) + { + if (DoCastSpellIfCan(pTarget, SPELL_SUMMON_FLAMES_SPREAD) == CAST_OK) + m_uiSpreadTimer = 4000; + } + } + else + m_uiSpreadTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_npc_mimiron_flames(Creature* pCreature) +{ + return new npc_mimiron_flamesAI(pCreature); +} + +/*###### +## npc_frost_bomb +######*/ + +// TODO Move this 'script' to EventAI when combat can be proper prevented from core-side +struct npc_frost_bombAI : public Scripted_NoMovementAI +{ + npc_frost_bombAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiExplosionTimer; + uint32 m_uiFireClearTimer; + + void Reset() override + { + m_uiExplosionTimer = 10000; + m_uiFireClearTimer = 12000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiExplosionTimer) + { + if (m_uiExplosionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLOSION_FROST) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_FROST_BOMB_VISUAL); + m_uiExplosionTimer = 0; + } + } + else + m_uiExplosionTimer -= uiDiff; + } + + if (m_uiFireClearTimer) + { + if (m_uiFireClearTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CLEAR_FIRES) == CAST_OK) + { + m_creature->ForcedDespawn(2000); + m_uiFireClearTimer = 0; + } + } + else + m_uiFireClearTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_frost_bomb(Creature* pCreature) +{ + return new npc_frost_bombAI(pCreature); +} + +/*###### +## npc_rocket_strike +######*/ + +struct npc_rocket_strikeAI : public Scripted_NoMovementAI +{ + npc_rocket_strikeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_ROCKET_STRIKE_DAMAGE, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + m_creature->ForcedDespawn(7000); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetEntry() == NPC_ASSALT_BOT) + DoCastSpellIfCan(m_creature, SPELL_NOT_FRIENDLY_FIRE, CAST_TRIGGERED); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_rocket_strike(Creature* pCreature) +{ + return new npc_rocket_strikeAI(pCreature); +} + +/*###### +## boss_leviathan_mk2_turret +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct boss_leviathan_mk2_turretAI : public Scripted_NoMovementAI +{ + boss_leviathan_mk2_turretAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_boss_leviathan_mk2_turret(Creature* pCreature) +{ + return new boss_leviathan_mk2_turretAI(pCreature); +} + +/*###### +## npc_computer +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_computerAI : public Scripted_NoMovementAI +{ + npc_computerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_computer(Creature* pCreature) +{ + return new npc_computerAI(pCreature); +} + +/*###### +## go_big_red_button +######*/ + +bool GOUse_go_big_red_button(Player* pPlayer, GameObject* pGo) +{ + ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); + if (!pInstance) + return true; + + if (pInstance->GetData(TYPE_MIMIRON) == IN_PROGRESS || pInstance->GetData(TYPE_MIMIRON) == DONE) + return true; + + // Inform Mimiron about the button being pressed + if (Creature* pMimiron = pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON)) + pMimiron->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pMimiron); + + // Set instance data and allow Mimiron script to continue the event + pInstance->SetData(TYPE_MIMIRON_HARD, DONE); + return false; +} + void AddSC_boss_mimiron() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_mimiron"; + pNewScript->GetAI = GetAI_boss_mimiron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_leviathan_mk2"; + pNewScript->GetAI = GetAI_boss_leviathan_mk2; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_vx001"; + pNewScript->GetAI = GetAI_boss_vx001; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_aerial_unit"; + pNewScript->GetAI = GetAI_boss_aerial_unit; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_proximity_mine"; + pNewScript->GetAI = GetAI_npc_proximity_mine; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_bot_trigger"; + pNewScript->GetAI = GetAI_npc_bot_trigger; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_bot_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_mimiron_flames"; + pNewScript->GetAI = GetAI_npc_mimiron_flames; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_frost_bomb"; + pNewScript->GetAI = GetAI_npc_frost_bomb; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_rocket_strike"; + pNewScript->GetAI = GetAI_npc_rocket_strike; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_leviathan_mk2_turret"; + pNewScript->GetAI = GetAI_boss_leviathan_mk2_turret; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_computer"; + pNewScript->GetAI = GetAI_npc_computer; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "go_big_red_button"; + pNewScript->pGOUse = &GOUse_go_big_red_button; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp b/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp index 3303f7d1c..e3caa2c56 100644 --- a/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_razorscale.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_razorscale -SD%Complete: 0% -SDComment: +SD%Complete: 85% +SDComment: Fine script details require additional core support. Not all achievements are implemented. SDCategory: Ulduar EndScriptData */ @@ -31,14 +31,913 @@ enum SAY_INTRO_2 = -1603038, SAY_INTRO_3 = -1603039, SAY_GROUNDED = -1603040, - SAY_EXTINGUISH_FIRE = -1603041, + SAY_EXTINGUISH_FIRE = -1603042, - EMOTE_BREATH = -1603042, + EMOTE_BREATH = -1603041, EMOTE_HARPOON_READY = -1603043, EMOTE_GROUNDED = -1603044, + + // general spells (used in both ground and air phases) + SPELL_BERSERK = 47008, + SPELL_DEVOURING_FLAME = 63236, // has summon property = 61, so it won't behave as expected + SPELL_FLAME_BREATH = 63317, + SPELL_FLAME_BREATH_H = 64021, + + // razorscale air phase spells + SPELL_FIREBALL = 62796, + SPELL_FIREBALL_H = 63815, + SPELL_STUN = 62794, + + // helper npc spells + SPELL_THREAT = 65146, // used by npc 33816 to apply threat to Razorscale + SPELL_SHACKLE = 62646, // channeled on Razorscale grounding phase by npc 33259 + + // phase 2 transition spells + SPELL_WING_BUFFET = 62666, + SPELL_FIREBOLT = 62669, // target npc 33282 - destroy the harpoons + SPELL_HARPOON_FIRE = 62696, // visual when harpoons are destroyed, cast by 33282 + + // ground spells + SPELL_FLAME_BUFFET = 64016, + SPELL_FLAME_BUFFET_H = 64023, + SPELL_FUSE_ARMOR = 64771, + + // summoned spells + SPELL_DEVOURING_FLAME_AURA = 64709, + SPELL_DEVOURING_FLAME_AURA_H = 64734, + + // razorscale spawner spells + // controlled by some dummy spells: 63114, 63115, 63116, 63968, 63969, 63970 + SPELL_SUMMON_DWARF_WATCHER = 63135, // summons npc 33453 + SPELL_SUMMON_DWARF_GUARDIAN = 62926, // summons npc 33388 + SPELL_SUMMON_IRON_VRYKUL = 63798, // summons npc 33846 + SPELL_SUMMON_MOLE_MACHINE = 62899, // summons go 194316 + + // summons + NPC_DEVOURING_FLAME = 34188, + NPC_RAZORSCALE_SPAWNER = 33245, // dwarf spawner npc for Razorscale + // NPC_DARK_RUNE_WATCHER = 33453, + // NPC_DARK_RUNE_GUARDIAN = 33388, + // NPC_DARK_RUNE_SENTINEL = 33846, + // GO_MOLE_MACHINE = 194316, + + // other + NPC_HARPOON_FIRE_STATE = 33282, // harpoon visual dummy for phase 2 transition + // EVENT_ID_HARPOON_SHOT = 20964, // event which informs the script that a harpoon has been shot + SPEED_RATE_RAZORSCALE = 10, // it seems that Razorscale and npcs have a special run speed during air phase, which isn't reflected in DB + SPEED_RATE_HELPERS = 8, + + // gossip + GOSSIP_ITEM_START_RAZORSCALE = -3603009, + GOSSIP_MENU_ID_WELCOME = 14317, + + // phases + PHASE_AIR = 1, + PHASE_GROUNDED = 2, + PHASE_ONLY_GROUND = 3, + PHASE_TRANSITION = 4, }; +static const DialogueEntry aIntroDialogue[] = +{ + {NPC_EXPEDITION_ENGINEER, 0, 3000}, + {SAY_INTRO_2, NPC_EXPEDITION_COMMANDER, 4000}, + {NPC_RAZORSCALE, 0, 25000}, + {NPC_EXPEDITION_DEFENDER, 0, 0}, + {0, 0, 0}, +}; + +static const float afRazorscaleGroundPos[3] = { 585.401f, -173.543f, 391.6421f }; + +static const float afRazorscaleSpawnersPos[3][3] = +{ + {577.103f, -231.223f, 391.180f}, // right + {606.138f, -231.266f, 391.517f}, // left + {589.451f, -209.737f, 391.517f}, // center +}; + +/*###### +## boss_razorscale +######*/ + +struct boss_razorscaleAI : public ScriptedAI +{ + boss_razorscaleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_uiMaxHarpoons = m_bIsRegularMode ? 2 : 4; + + m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint8 m_uiPhase; + bool m_bIsGrounded; + + uint32 m_uiBerserkTimer; + + uint32 m_uiFireballTimer; + uint32 m_uiDevouringFlameTimer; + uint32 m_uiDwarfSpawnTimer; + uint32 m_uiRepairHarpoonTimer; + + uint32 m_uiShackleTimer; + uint32 m_uiGroundedTimer; + uint8 m_uiGroundedStep; + + uint32 m_uiFlameBuffetTimer; + uint32 m_uiFuseArmorTimer; + uint32 m_uiFlameBreathTimer; + + uint8 m_uiMaxHarpoons; + uint8 m_uiCurrentHarpoon; + uint8 m_uiHarpoonsUsed; + uint8 m_uiFlyPhaseCount; + + GuidList m_lEngineersGuids; + GuidList m_lTrappersGuids; + GuidVector m_vHarpoonsGuids; + + void Reset() override + { + m_uiPhase = PHASE_AIR; + m_bIsGrounded = false; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_uiFireballTimer = 5000; + m_uiDevouringFlameTimer = 10000; + m_uiDwarfSpawnTimer = 1000; + m_uiRepairHarpoonTimer = 0; + + m_uiShackleTimer = 5000; + m_uiHarpoonsUsed = 0; + m_uiCurrentHarpoon = 0; + m_uiFlyPhaseCount = 0; + + m_uiGroundedTimer = 30000; + m_uiGroundedStep = 0; + + m_uiFlameBuffetTimer = 10000; + m_uiFuseArmorTimer = 13000; + m_uiFlameBreathTimer = 15000; + + // no combat movement in phase 1 + SetCombatMovement(false); + + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_RAZORSCALE, DONE); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_RAZORSCALE, IN_PROGRESS); + + // load engineers and harpoon data + m_pInstance->GetEngineersGuids(m_lEngineersGuids); + m_pInstance->GetTrappersGuids(m_lTrappersGuids); + m_pInstance->GetHarpoonsGuids(m_vHarpoonsGuids); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_RAZORSCALE, FAIL); + + m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_DEVOURING_FLAME) + pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_DEVOURING_FLAME_AURA : SPELL_DEVOURING_FLAME_AURA_H, true); + else if (pSummoned->GetEntry() == NPC_RAZORSCALE_SPAWNER) + { + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_MOLE_MACHINE, true); + + // for central spawners inform that they should spawn a sentinel + if (pSummoned->GetPositionY() > -220.0f) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pSummoned); + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // inform about the harpoon repair event + if (eventType == AI_EVENT_CUSTOM_A) + { + DoMoveEngineersToHarpoon(); + m_uiRepairHarpoonTimer = 20000; + } + // inform about a harpoon being shot + if (eventType == AI_EVENT_CUSTOM_B) + { + ++m_uiHarpoonsUsed; + + // start grounded phase + if (m_uiHarpoonsUsed == m_uiMaxHarpoons) + { + // use upgraded speed rate for FlyOrLand. This isn't supported by DB but it's confirmed to happen on retail + uint32 uiSpeedRate = m_creature->GetSpeedRate(MOVE_RUN); + m_creature->SetWalk(false); + m_creature->SetSpeedRate(MOVE_RUN, SPEED_RATE_RAZORSCALE); + m_creature->GetMotionMaster()->MoveFlyOrLand(1, afRazorscaleGroundPos[0], afRazorscaleGroundPos[1], afRazorscaleGroundPos[2], false); + m_creature->SetSpeedRate(MOVE_RUN, uiSpeedRate); + + m_uiPhase = PHASE_TRANSITION; + m_uiShackleTimer = 5000; + + // move the trappers around + float fX, fY, fZ; + uint8 uiIndex = 5; + if (m_pInstance) + { + if (Creature* pController = m_pInstance->GetSingleCreatureFromStorage(NPC_RAZORSCALE_CONTROLLER)) + { + for (GuidList::const_iterator itr = m_lTrappersGuids.begin(); itr != m_lTrappersGuids.end(); ++itr) + { + if (Creature* pTrapper = m_creature->GetMap()->GetCreature(*itr)) + { + pController->GetNearPoint(pController, fX, fY, fZ, 0, 50.0f, M_PI_F / 4 * uiIndex); + + pTrapper->SetWalk(false); + uiSpeedRate = pTrapper->GetSpeedRate(MOVE_RUN); + pTrapper->SetSpeedRate(MOVE_RUN, SPEED_RATE_HELPERS); + pTrapper->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + pTrapper->SetSpeedRate(MOVE_RUN, uiSpeedRate); + ++uiIndex; + } + } + } + + // yell that Razor is grounded + if (Creature* pCommander = m_pInstance->GetSingleCreatureFromStorage(NPC_EXPEDITION_COMMANDER)) + DoScriptText(SAY_GROUNDED, pCommander); + } + } + } + } + + // function to spawn the mole machines + void DoSpawnMoleMachines() + { + // Note: this should be a little more random in therms of position and timer delays between the spawns + uint8 uiMaxMachines = roll_chance_i(33) ? 3 : 2; + float fX, fY, fZ; + + for (uint8 i = 0; i < uiMaxMachines; ++i) + { + m_creature->GetRandomPoint(afRazorscaleSpawnersPos[i][0], afRazorscaleSpawnersPos[i][1], afRazorscaleSpawnersPos[i][2], 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_RAZORSCALE_SPAWNER, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 10000); + } + } + + // function to enable harpoon repair animation + void DoMoveEngineersToHarpoon() + { + float fX, fY, fZ; + uint8 uiIndex = 1; + + // get the current harpoon and move the engineers in front of it + if (GameObject* pHarpoon = m_creature->GetMap()->GetGameObject(m_vHarpoonsGuids[m_uiCurrentHarpoon])) + { + for (GuidList::const_iterator itr = m_lEngineersGuids.begin(); itr != m_lEngineersGuids.end(); ++itr) + { + if (Creature* pEngineer = m_creature->GetMap()->GetCreature(*itr)) + { + pHarpoon->GetNearPoint(pHarpoon, fX, fY, fZ, 0, INTERACTION_DISTANCE, M_PI_F / 4 * uiIndex); + + // ToDo: maybe there should be some emotes here + pEngineer->SetWalk(false); + pEngineer->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + ++uiIndex; + } + } + } + ++m_uiCurrentHarpoon; + } + + // function to repair nearby harpoon + void DoRepairHarpoon(GameObject* pSource) + { + // search for each entry of the nearby harpoon + GameObject* pNewHarpoon = GetClosestGameObjectWithEntry(pSource, GO_HARPOON_GUN_1, 5.0f); + if (!pNewHarpoon) + pNewHarpoon = GetClosestGameObjectWithEntry(pSource, GO_HARPOON_GUN_2, 5.0f); + if (!pNewHarpoon) + pNewHarpoon = GetClosestGameObjectWithEntry(pSource, GO_HARPOON_GUN_3, 5.0f); + if (!pNewHarpoon) + pNewHarpoon = GetClosestGameObjectWithEntry(pSource, GO_HARPOON_GUN_4, 5.0f); + + if (pNewHarpoon) + { + pNewHarpoon->SetRespawnTime(HOUR); + pNewHarpoon->Refresh(); + } + } + + // custom threat management to support air phase with a high distance from the ground + bool SelectCustomHostileTarget() + { + if (m_uiPhase == PHASE_ONLY_GROUND || m_uiPhase == PHASE_GROUNDED) + return m_creature->SelectHostileTarget() && m_creature->getVictim(); + + // Special handling for PHASE_AIR + + // Not started combat or evading prevented + if (!m_creature->isInCombat() || m_creature->HasAuraType(SPELL_AURA_MOD_TAUNT)) + return false; + + // Check if there are still enemies (players) + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if ((*itr)->getUnitGuid().IsPlayer()) + return true; + } + + // Evade in air-phase + EnterEvadeMode(); + return false; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectCustomHostileTarget()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_AIR: + + if (m_uiFireballTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FIREBALL : SPELL_FIREBALL_H) == CAST_OK) + m_uiFireballTimer = 2000; + } + } + else + m_uiFireballTimer -= uiDiff; + + if (m_uiDevouringFlameTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEVOURING_FLAME) == CAST_OK) + m_uiDevouringFlameTimer = 10000; + } + } + else + m_uiDevouringFlameTimer -= uiDiff; + + // harpoon is repaired; move to next one, or to home position if all are completed + if (m_uiRepairHarpoonTimer) + { + if (m_uiRepairHarpoonTimer <= uiDiff) + { + // handle fire extinguish after a grounded phase + if (!m_uiCurrentHarpoon) + { + // extinguish fires + if (m_pInstance) + { + if (Creature* pCommander = m_pInstance->GetSingleCreatureFromStorage(NPC_EXPEDITION_COMMANDER)) + { + if (Creature* pEngineer = GetClosestCreatureWithEntry(pCommander, NPC_EXPEDITION_ENGINEER, 15.0f)) + DoScriptText(SAY_EXTINGUISH_FIRE, pEngineer); + } + } + + // move engineers to the first harpoon again + DoMoveEngineersToHarpoon(); + m_uiRepairHarpoonTimer = 20000; + } + else + { + DoScriptText(EMOTE_HARPOON_READY, m_creature); + + // despawn the current broken harpoon and spawn the repaired one + if (GameObject* pHarpoon = m_creature->GetMap()->GetGameObject(m_vHarpoonsGuids[m_uiCurrentHarpoon - 1])) + { + pHarpoon->SetRespawnTime(HOUR); + pHarpoon->SetLootState(GO_JUST_DEACTIVATED); + + DoRepairHarpoon(pHarpoon); + } + + // if all harpoons have been repaired stop + if (m_uiCurrentHarpoon == m_uiMaxHarpoons) + { + for (GuidList::const_iterator itr = m_lEngineersGuids.begin(); itr != m_lEngineersGuids.end(); ++itr) + { + if (Creature* pEngineer = m_creature->GetMap()->GetCreature(*itr)) + pEngineer->GetMotionMaster()->MoveTargetedHome(); + } + + m_uiRepairHarpoonTimer = 0; + } + // move to next harpoon + else + { + DoMoveEngineersToHarpoon(); + m_uiRepairHarpoonTimer = 20000; + } + } + } + else + m_uiRepairHarpoonTimer -= uiDiff; + } + + // spawn Mole Machines with dwarfes + if (m_uiDwarfSpawnTimer < uiDiff) + { + DoSpawnMoleMachines(); + m_uiDwarfSpawnTimer = 40000; + } + else + m_uiDwarfSpawnTimer -= uiDiff; + + break; + case PHASE_TRANSITION: + + if (m_uiShackleTimer < uiDiff) + { + // cast trap visual + for (GuidList::const_iterator itr = m_lTrappersGuids.begin(); itr != m_lTrappersGuids.end(); ++itr) + { + if (Creature* pTrapper = m_creature->GetMap()->GetCreature(*itr)) + pTrapper->CastSpell(m_creature, SPELL_SHACKLE, false); + } + + // stun Razorscale + if (DoCastSpellIfCan(m_creature, SPELL_STUN) == CAST_OK) + { + m_creature->SetLevitate(false); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + m_uiPhase = PHASE_GROUNDED; + m_uiGroundedTimer = 30000; + m_uiGroundedStep = 0; + m_uiShackleTimer = 5000; + } + } + else + m_uiShackleTimer -= uiDiff; + + break; + case PHASE_GROUNDED: + + if (m_uiGroundedTimer < uiDiff) + { + switch (m_uiGroundedStep) + { + case 0: + m_creature->RemoveAurasDueToSpell(SPELL_STUN); + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FLAME_BREATH : SPELL_FLAME_BREATH_H) == CAST_OK) + { + DoScriptText(EMOTE_BREATH, m_creature); + m_uiGroundedTimer = 2500; + } + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_WING_BUFFET) == CAST_OK) + m_uiGroundedTimer = 1500; + break; + case 2: + if (DoCastSpellIfCan(m_creature, SPELL_FIREBOLT) == CAST_OK) + m_uiGroundedTimer = 2000; + break; + case 3: + // if fully grounded then go to ground phase + if (m_bIsGrounded) + { + SetCombatMovement(true); + DoResetThreat(); + DoStartMovement(m_creature->getVictim()); + m_uiPhase = PHASE_ONLY_GROUND; + } + // resume air phase + else + { + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + + float fX, fY, fZ; + m_creature->GetRespawnCoord(fX, fY, fZ); + + // use upgraded speed rate for FlyOrLand. This isn't supported by DB but it's confirmed to happen on retail + uint32 uiSpeedRate = m_creature->GetSpeedRate(MOVE_RUN); + m_creature->SetSpeedRate(MOVE_RUN, SPEED_RATE_RAZORSCALE); + m_creature->GetMotionMaster()->MoveFlyOrLand(1, fX, fY, fZ, true); + m_creature->SetSpeedRate(MOVE_RUN, uiSpeedRate); + + // reset timers + m_uiPhase = PHASE_AIR; + m_uiCurrentHarpoon = 0; + m_uiHarpoonsUsed = 0; + m_uiRepairHarpoonTimer = 20000; + m_uiFireballTimer = 5000; + m_uiDevouringFlameTimer = 10000; + ++m_uiFlyPhaseCount; + + // set achiev criteria as failed + if (m_uiFlyPhaseCount >= 2 && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_QUICK_SHAVE, false); + } + + // make the Trappers evade or move to home position + for (GuidList::const_iterator itr = m_lTrappersGuids.begin(); itr != m_lTrappersGuids.end(); ++itr) + { + if (Creature* pTrapper = m_creature->GetMap()->GetCreature(*itr)) + pTrapper->AI()->EnterEvadeMode(); + } + break; + } + ++m_uiGroundedStep; + } + else + m_uiGroundedTimer -= uiDiff; + + // make boss land at 50% hp + if (!m_bIsGrounded && m_creature->GetHealthPercent() < 50.0f) + { + DoScriptText(EMOTE_GROUNDED, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_STUN); + m_uiGroundedStep = 1; + m_uiGroundedTimer = 0; + m_bIsGrounded = true; + } + + break; + case PHASE_ONLY_GROUND: + + if (m_uiDevouringFlameTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DEVOURING_FLAME) == CAST_OK) + m_uiDevouringFlameTimer = 10000; + } + } + else + m_uiDevouringFlameTimer -= uiDiff; + + if (m_uiFuseArmorTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FUSE_ARMOR) == CAST_OK) + m_uiFuseArmorTimer = 13000; + } + else + m_uiFuseArmorTimer -= uiDiff; + + if (m_uiFlameBuffetTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FLAME_BUFFET : SPELL_FLAME_BUFFET_H) == CAST_OK) + m_uiFlameBuffetTimer = 10000; + } + else + m_uiFlameBuffetTimer -= uiDiff; + + if (m_uiFlameBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FLAME_BREATH : SPELL_FLAME_BREATH_H) == CAST_OK) + { + DoScriptText(EMOTE_BREATH, m_creature); + m_uiFlameBreathTimer = 15000; + } + } + else + m_uiFlameBreathTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + } + } +}; + +CreatureAI* GetAI_boss_razorscale(Creature* pCreature) +{ + return new boss_razorscaleAI(pCreature); +} + +/*###### +## npc_expedition_commander +######*/ + +struct npc_expedition_commanderAI : public ScriptedAI, private DialogueHelper +{ + npc_expedition_commanderAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + m_bIntroDone = false; + Reset(); + } + + instance_ulduar* m_pInstance; + + bool m_bIntroDone; + + ObjectGuid m_playerGuid; + + void Reset() override { } + + void MoveInLineOfSight(Unit* pWho) override + { + // ToDo: verify if all this is correct. There may other parts of the intro which are currently missing + if (!m_bIntroDone && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 20.0f)) + { + DoScriptText(SAY_INTRO_WELCOME, m_creature); + m_bIntroDone = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + { + script_error_log("Instance Ulduar: ERROR Failed to load instance data for this instace."); + return; + } + + switch (iEntry) + { + case NPC_EXPEDITION_ENGINEER: + { + if (Creature* pEngineer = GetClosestCreatureWithEntry(m_creature, NPC_EXPEDITION_ENGINEER, 15.0f)) + DoScriptText(SAY_INTRO_1, pEngineer); + + GuidList m_lDefenderGuids; + m_pInstance->GetDefenderGuids(m_lDefenderGuids); + + // move the defenders into attack position + for (GuidList::const_iterator itr = m_lDefenderGuids.begin(); itr != m_lDefenderGuids.end(); ++itr) + { + if (Creature* pDefender = m_creature->GetMap()->GetCreature(*itr)) + { + pDefender->CastSpell(pDefender, SPELL_THREAT, true); + pDefender->SetWalk(false); + pDefender->GetMotionMaster()->MoveWaypoint(); + } + } + break; + } + case NPC_RAZORSCALE: + if (Creature* pRazorscale = m_pInstance->GetSingleCreatureFromStorage(NPC_RAZORSCALE)) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pRazorscale->AI()->AttackStart(pPlayer); + } + break; + case NPC_EXPEDITION_DEFENDER: + if (Creature* pEngineer = GetClosestCreatureWithEntry(m_creature, NPC_EXPEDITION_ENGINEER, 15.0f)) + DoScriptText(SAY_INTRO_3, pEngineer); + + // inform Razorscale about the start of the harpoon event + if (Creature* pRazorscale = m_pInstance->GetSingleCreatureFromStorage(NPC_RAZORSCALE)) + m_creature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pRazorscale); + break; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // start intro dialogue + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + StartNextDialogueText(NPC_EXPEDITION_ENGINEER); + m_playerGuid = pInvoker->GetObjectGuid(); + } + } + + void UpdateAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); } +}; + +CreatureAI* GetAI_npc_expedition_commander(Creature* pCreature) +{ + return new npc_expedition_commanderAI(pCreature); +} + +bool GossipHello_npc_expedition_commander(Player* pPlayer, Creature* pCreature) +{ + if (ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_RAZORSCALE) == NOT_STARTED || pInstance->GetData(TYPE_RAZORSCALE) == FAIL) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START_RAZORSCALE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_MENU_ID_WELCOME, pCreature->GetObjectGuid()); + return true; + } + + return false; +} + +bool GossipSelect_npc_expedition_commander(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + // start intro dialogue + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pPlayer, pCreature); + pCreature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## npc_razorscale_spawner +######*/ + +struct npc_razorscale_spawnerAI : public Scripted_NoMovementAI +{ + npc_razorscale_spawnerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiSpawnTimer; + bool m_bIsSentinelSpawn; + + void Reset() override + { + m_uiSpawnTimer = 5000; + m_bIsSentinelSpawn = false; + } + + void JustSummoned(Creature* pSummoned) override + { + pSummoned->SetInCombatWithZone(); + } + + void JustSummoned(GameObject* pGo) override + { + pGo->Use(m_creature); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // inform that it should spawn a sentinel + if (eventType == AI_EVENT_CUSTOM_A) + m_bIsSentinelSpawn = true; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSpawnTimer) + { + if (m_uiSpawnTimer <= uiDiff) + { + if (m_bIsSentinelSpawn) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_IRON_VRYKUL, CAST_TRIGGERED); + else + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DWARF_GUARDIAN, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_DWARF_WATCHER, CAST_TRIGGERED); + } + m_uiSpawnTimer = 0; + } + else + m_uiSpawnTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_razorscale_spawner(Creature* pCreature) +{ + return new npc_razorscale_spawnerAI(pCreature); +} + +/*###### +## npc_harpoon_fire_state +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_harpoon_fire_stateAI : public Scripted_NoMovementAI +{ + npc_harpoon_fire_stateAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_harpoon_fire_state(Creature* pCreature) +{ + return new npc_harpoon_fire_stateAI(pCreature); +} + +bool EffectDummyCreature_npc_harpoon_fire_state(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_FIREBOLT && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_HARPOON_FIRE_STATE) + { + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_HARPOON_FIRE, true); + + // search for each entry of the nearby harpoon + GameObject* pHarpoon = GetClosestGameObjectWithEntry(pCreatureTarget, GO_HARPOON_GUN_1, 5.0f); + if (!pHarpoon) + pHarpoon = GetClosestGameObjectWithEntry(pCreatureTarget, GO_HARPOON_GUN_2, 5.0f); + if (!pHarpoon) + pHarpoon = GetClosestGameObjectWithEntry(pCreatureTarget, GO_HARPOON_GUN_3, 5.0f); + if (!pHarpoon) + pHarpoon = GetClosestGameObjectWithEntry(pCreatureTarget, GO_HARPOON_GUN_4, 5.0f); + + // despawn the repaired harpoon + if (pHarpoon) + pHarpoon->SetLootState(GO_JUST_DEACTIVATED); + + // respawn broken harpoon + if (GameObject* pNewHarpoon = GetClosestGameObjectWithEntry(pCreatureTarget, GO_BROKEN_HARPOON, 5.0f)) + pNewHarpoon->Respawn(); + + // force reset for harpoon trigger npcs + if (Creature* pTrigger = GetClosestCreatureWithEntry(pCreatureTarget, NPC_RAZORSCALE_CONTROLLER, 5.0f)) + pTrigger->InterruptNonMeleeSpells(false); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## event_spell_harpoon_shot +######*/ + +bool ProcessEventId_event_spell_harpoon_shot(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (((Creature*)pSource)->GetEntry() == NPC_RAZORSCALE_CONTROLLER) + { + if (instance_ulduar* pInstance = (instance_ulduar*)((Creature*)pSource)->GetInstanceData()) + { + // event doesn't have target, so we need to give an explicit one + if (Creature* pRazorscale = pInstance->GetSingleCreatureFromStorage(NPC_RAZORSCALE)) + ((Creature*)pSource)->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, (Creature*)pSource, pRazorscale); + + return true; + } + } + + return false; +} + void AddSC_boss_razorscale() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_razorscale"; + pNewScript->GetAI = GetAI_boss_razorscale; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_expedition_commander"; + pNewScript->GetAI = &GetAI_npc_expedition_commander; + pNewScript->pGossipHello = GossipHello_npc_expedition_commander; + pNewScript->pGossipSelect = GossipSelect_npc_expedition_commander; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_razorscale_spawner"; + pNewScript->GetAI = GetAI_npc_razorscale_spawner; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_harpoon_fire_state"; + pNewScript->GetAI = GetAI_npc_harpoon_fire_state; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_harpoon_fire_state; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "event_spell_harpoon_shot"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_harpoon_shot; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_thorim.cpp b/scripts/northrend/ulduar/ulduar/boss_thorim.cpp index 9e101a02e..244702f9f 100644 --- a/scripts/northrend/ulduar/ulduar/boss_thorim.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_thorim.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_thorim -SD%Complete: 0% -SDComment: +SD%Complete: 90% +SDComment: Platform lightning NYI. Script might need minor improvements. SDCategory: Ulduar EndScriptData */ @@ -43,19 +43,1036 @@ enum SAY_OUTRO_1 = -1603149, SAY_OUTRO_2 = -1603150, SAY_OUTRO_3 = -1603151, - SAY_OUTRO_HARD_1 = -1603152, SAY_OUTRO_HARD_2 = -1603153, SAY_OUTRO_HARD_3 = -1603154, - SAY_HELP_YOGG = -1603155, - SAY_SIF_BEGIN = -1603156, SAY_SIF_EVENT = -1603157, SAY_SIF_DESPAWN = -1603158, + + EMOTE_RUNIC_BARRIER = -1603247, + + // phase 1 spells + SPELL_SHEAT_OF_LIGHTNING = 62276, // damage reduction aura + SPELL_STORMHAMMER = 62042, // triggers 62470 and 64909 on target + SPELL_CHARGE_ORB = 62016, // target npc 33378; + SPELL_TOUCH_OF_DOMINION = 62507, // hard mode timer; triggers 62565 after 2.5 min + SPELL_TOUCH_OF_DOMINION_AURA = 62565, // buff received by Thorim on hard mode fail + SPELL_BERSERK_1 = 62560, + SPELL_SUMMON_LIGHTNING_ORB = 62391, // on berserk + SPELL_LIGHTNING_DESTRUCTION = 62393, // cast by npc 33138 on berserk + + // phase 2 spells + SPELL_CHAIN_LIGHTNING = 62131, // spells need to be confirmed + SPELL_CHAIN_LIGHTNING_H = 64390, + // SPELL_LIGHTNING_CHARGE = 62279, // buff gained on each charge + SPELL_LIGHTNING_CHARGE_DAMAGE = 62466, // damage spell for lightning charge; dummy effect hits npc 33378 and triggers spell 64098; cone target effect hits npc 32780 + SPELL_UNBALANCING_STRIKE = 62130, + SPELL_BERSERK_2 = 62555, + SPELL_THORIM_CREDIT = 64985, // kill credit spell; added in spell_template + SPELL_STORMHAMMER_OUTRO = 64767, // target npc 33196 and trigger spells 62470, 64909 and 64778 and despawn target in 10 sec + + // Lightning charge related spells + SPELL_LIGHTNING_PILLAR_ORB = 63238, // cast on spell 62016 hit; cast by the lower Orb + SPELL_LIGHTNING_ORG_CHARGED = 62186, // cast by npc 33378; makes Thorim to cast 62466; + SPELL_LIGHTNING_ORB_TRIGGER = 62278, // spell triggered by 62186; however this won't work because 62186 has a duration of 5s while 62278 is triggered after 8s + SPELL_LIGHTNING_PILLAR = 62976, // cast by npc 33378 (upper Orb) to npc 33378 (lower Orb) at the same time with spell 62186 + + // Other lightning related spells + SPELL_ACTIVATE_LIGHTNING_ORB_PERIODIC = 62184, // cast by npc 32879; starts the whole lightning event + SPELL_LIGHTNING_FIELD = 64972, // cast by npc 32892 + + // Sif spells + SPELL_FROSTBOLT = 62583, + SPELL_FROSTBOLT_H = 62601, + SPELL_FROSTBOLT_VOLLEY = 62580, + SPELL_FROSTBOLT_VOLLEY_H = 62604, + SPELL_FROST_NOVA = 62597, + SPELL_FROST_NOVA_H = 62605, + SPELL_BLIZZARD = 62577, // targets npc 32892 + SPELL_BLIZZARD_H = 62603, + SPELL_BLINK = 62578, + + // Colossus runic smash spells + SPELL_RUNIC_SMASH_L = 62058, // triggers missing spell 62406 + SPELL_RUNIC_SMASH_R = 62057, // triggers missing spell 62403 + SPELL_RUNIC_SMASH = 62465, // cast by npcs 33140 and 33141 + MAX_RUNIC_SMASH = 10, // defines the max rows of runic smash + + // Colossus combat spells + SPELL_SMASH = 62339, // maybe use 62414 on heroic? + SPELL_RUNIC_BARRIER = 62338, + SPELL_CHARGE = 62613, + SPELL_CHARGE_H = 62614, + + SPELL_LEAP = 61934, // used by the arena dwarfes + + // event npcs + NPC_LIGHTNING_ORB = 33138, // spawned on arena berserk + NPC_DARK_RUNE_CHAMPION = 32876, // arena npcs + NPC_DARK_RUNE_WARBRINGER = 32877, + NPC_DARK_RUNE_EVOKER = 32878, + NPC_DARK_RUNE_COMMONER = 32904, + // NPC_IRON_RING_GUARD = 32874, // hallway npcs + // NPC_DARK_RUNE_ACOLYTE_HALLWAY = 33110, + // NPC_IRON_HONOR_GUARD = 32875, // stairs npcs + // NPC_TRAP_BUNNY_1 = 33725, // thorim traps; have auras 62241 and 63540 + // NPC_TRAP_BUNNY_2 = 33054, + + FACTION_ID_FRIENDLY = 35, + PHASE_ARENA = 1, + PHASE_SOLO = 2, + PHASE_TRANSITION = 3, +}; + +static const DialogueEntry aThorimDialogue[] = +{ + {SAY_AGGRO_1, NPC_THORIM, 9000}, + {SAY_AGGRO_2, NPC_THORIM, 7000}, + {NPC_SIF, 0, 5000}, + {SPELL_TOUCH_OF_DOMINION, 0, 0}, + {SAY_JUMP, NPC_THORIM, 10000}, + {PHASE_SOLO, 0, 0}, + {SAY_DEFEATED, NPC_THORIM, 3000}, + {SAY_OUTRO_1, NPC_THORIM, 10000}, + {SAY_OUTRO_2, NPC_THORIM, 12000}, + {SAY_OUTRO_3, NPC_THORIM, 10000}, + {SPELL_TELEPORT, 0, 0}, + {SPELL_STORMHAMMER_OUTRO, 0, 3000}, + {SAY_OUTRO_HARD_1, NPC_THORIM, 6000}, + {SAY_OUTRO_HARD_2, NPC_THORIM, 12000}, + {SAY_OUTRO_HARD_3, NPC_THORIM, 10000}, + {SPELL_THORIM_CREDIT, 0, 0}, + {0, 0, 0}, }; +static const float afSifSpawnLoc[4] = {2148.301f, -297.8453f, 438.3308f, 2.68f}; +static const float afArenaCenterLoc[3] = {2134.8f, -263.056f, 419.983f}; + +/*###### +## boss_thorim +######*/ + +struct boss_thorimAI : public ScriptedAI, private DialogueHelper +{ + boss_thorimAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aThorimDialogue) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + m_bEventFinished = false; + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + bool m_bEventFinished; + bool m_bArenaSpawned; + + uint32 m_uiBerserkTimer; + uint8 m_uiPhase; + uint8 m_uiDwarfIndex; + + uint32 m_uiStormHammerTimer; + uint32 m_uiChargeOrbTimer; + uint32 m_uiArenaDwarfTimer; + uint32 m_uiAttackTimer; + uint32 m_uiChainLightningTimer; + uint32 m_uiUnbalancingStrikeTimer; + + GuidList m_lUpperOrbsGuids; + GuidList m_lUpperBunniesGuids; + GuidList m_lLowerBunniesGuids; + + void Reset() override + { + m_uiPhase = PHASE_ARENA; + m_uiBerserkTimer = 5 * MINUTE * IN_MILLISECONDS; + + m_uiStormHammerTimer = 45000; + m_uiChargeOrbTimer = 35000; + m_uiArenaDwarfTimer = 20000; + m_uiChainLightningTimer = urand(10000, 15000); + m_uiUnbalancingStrikeTimer = 20000; + m_uiAttackTimer = 0; + m_uiDwarfIndex = urand(0, 2); + + m_bArenaSpawned = false; + + SetCombatMovement(false); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (m_creature->isAlive() && !m_bEventFinished) + m_creature->GetMotionMaster()->MoveTargetedHome(); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override + { + // switch to phase 2 as soon as it's hit by any damage + if (m_uiPhase == PHASE_ARENA && uiDamage > 0) + { + StartNextDialogueText(SAY_JUMP); + m_uiPhase = PHASE_TRANSITION; + + // prepare the hard mode if necessary + if (m_pInstance && m_pInstance->GetData(TYPE_THORIM_HARD) != FAIL) + { + if (Creature* pSif = m_pInstance->GetSingleCreatureFromStorage(NPC_SIF)) + pSif->InterruptNonMeleeSpells(false); + + m_pInstance->SetData(TYPE_THORIM_HARD, DONE); + } + return; + } + + // handle outro + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + if (!m_bEventFinished) + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_THORIM, DONE); + + // start a different outro version for hard mode + if (m_pInstance->GetData(TYPE_THORIM_HARD) == DONE) + StartNextDialogueText(SPELL_STORMHAMMER_OUTRO); + else + StartNextDialogueText(SAY_DEFEATED); + } + + m_creature->CastSpell(m_creature, SPELL_THORIM_CREDIT, true); + m_creature->SetFactionTemporary(FACTION_ID_FRIENDLY, TEMPFACTION_NONE); + m_bEventFinished = true; + EnterEvadeMode(); + } + } + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS); + m_pInstance->SetData(TYPE_THORIM_HARD, NOT_STARTED); + + m_pInstance->GetThunderOrbsGuids(m_lUpperOrbsGuids); + m_pInstance->GetThorimBunniesGuids(m_lUpperBunniesGuids, true); + m_pInstance->GetThorimBunniesGuids(m_lLowerBunniesGuids, false); + } + + StartNextDialogueText(SAY_AGGRO_1); + } + + void AttackStart(Unit* pWho) override + { + // don't attack again after being defeated + if (m_bEventFinished) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // spawn the arena npcs only when players are close to Thorim in order to avoid the possible bugs + if (!m_bArenaSpawned && pWho->GetTypeId() == TYPEID_PLAYER && pWho->isAlive() && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, DEFAULT_VISIBILITY_INSTANCE)) + { + if (m_pInstance && m_pInstance->GetData(TYPE_THORIM) != DONE) + m_pInstance->DoSpawnThorimNpcs((Player*)pWho); + + m_bArenaSpawned = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_THORIM, FAIL); + } + + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != EFFECT_MOTION_TYPE || !uiPointId) + return; + + m_uiPhase = PHASE_SOLO; + m_uiAttackTimer = 1000; + m_uiChargeOrbTimer = 20000; + m_uiBerserkTimer = 5 * MINUTE * IN_MILLISECONDS; + m_creature->RemoveAurasDueToSpell(SPELL_SHEAT_OF_LIGHTNING); + + // make Sif attack too if hard mode is active + if (m_pInstance && m_pInstance->GetData(TYPE_THORIM_HARD) == DONE) + { + if (Creature* pSif = m_pInstance->GetSingleCreatureFromStorage(NPC_SIF)) + { + DoScriptText(SAY_SIF_EVENT, pSif); + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pSif); + pSif->AI()->AttackStart(m_creature->getVictim()); + } + } + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // hard mode is failed; despawn Sif + if (pSpell->Id == SPELL_TOUCH_OF_DOMINION_AURA && m_pInstance) + { + m_pInstance->SetData(TYPE_THORIM_HARD, FAIL); + + if (Creature* pSif = m_pInstance->GetSingleCreatureFromStorage(NPC_SIF)) + { + DoScriptText(SAY_SIF_DESPAWN, pSif); + pSif->ForcedDespawn(5000); + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + // the lightning orb should clean out the whole hallway on arena berserk + case NPC_LIGHTNING_ORB: + pSummoned->CastSpell(pSummoned, SPELL_LIGHTNING_DESTRUCTION, true); + break; + case NPC_DARK_RUNE_CHAMPION: + case NPC_DARK_RUNE_WARBRINGER: + case NPC_DARK_RUNE_EVOKER: + case NPC_DARK_RUNE_COMMONER: + case NPC_DARK_RUNE_ACOLYTE: + if (Creature* pTarget = GetClosestLowerBunny(pSummoned)) + pSummoned->CastSpell(pTarget, SPELL_LEAP, true); + pSummoned->SetInCombatWithZone(); + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case NPC_SIF: + DoCastSpellIfCan(m_creature, SPELL_SHEAT_OF_LIGHTNING, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + if (Creature* pSif = m_creature->SummonCreature(NPC_SIF, afSifSpawnLoc[0], afSifSpawnLoc[1], afSifSpawnLoc[2], afSifSpawnLoc[3], TEMPSUMMON_CORPSE_DESPAWN, 0)) + DoScriptText(SAY_SIF_BEGIN, pSif); + break; + case SPELL_TOUCH_OF_DOMINION: + if (Creature* pSif = m_pInstance->GetSingleCreatureFromStorage(NPC_SIF)) + pSif->CastSpell(m_creature, SPELL_TOUCH_OF_DOMINION, false); + break; + case PHASE_SOLO: + m_creature->GetMotionMaster()->MoveJump(afArenaCenterLoc[0], afArenaCenterLoc[1], afArenaCenterLoc[2], 45.55969f, 5.0f, 1); + break; + case SPELL_STORMHAMMER_OUTRO: + DoScriptText(SAY_DEFEATED, m_creature); + break; + case SAY_OUTRO_HARD_1: + DoCastSpellIfCan(m_creature, SPELL_STORMHAMMER_OUTRO); + break; + case SPELL_TELEPORT: + case SPELL_THORIM_CREDIT: + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT) == CAST_OK) + m_creature->ForcedDespawn(2000); + // despawn Sif if not despawned by accident + if (Creature* pSif = m_pInstance->GetSingleCreatureFromStorage(NPC_SIF)) + pSif->ForcedDespawn(); + break; + } + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pSpellEntry->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && pTarget->GetTypeId() == TYPEID_PLAYER) + { + if (m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_LIGHTNING, false); + } + } + + // function to return a random arena Thunder Orb + ObjectGuid SelectRandomOrbGuid() + { + if (m_lUpperOrbsGuids.empty()) + return ObjectGuid(); + + GuidList::iterator iter = m_lUpperOrbsGuids.begin(); + advance(iter, urand(0, m_lUpperOrbsGuids.size() - 1)); + + return *iter; + } + + // function to return a random arena upper Bunny + Creature* SelectRandomUpperBunny() + { + if (m_lUpperBunniesGuids.empty()) + return NULL; + + GuidList::iterator iter = m_lUpperBunniesGuids.begin(); + advance(iter, urand(0, m_lUpperBunniesGuids.size() - 1)); + + return m_creature->GetMap()->GetCreature(*iter); + } + + // function to return the closest ground Bunny + Creature* GetClosestLowerBunny(Creature* pSource) + { + if (m_lLowerBunniesGuids.empty()) + return NULL; + + std::list lBunnies; + for (GuidList::const_iterator itr = m_lLowerBunniesGuids.begin(); itr != m_lLowerBunniesGuids.end(); ++itr) + { + if (Creature* pBunny = m_creature->GetMap()->GetCreature(*itr)) + lBunnies.push_back(pBunny); + } + + lBunnies.sort(ObjectDistanceOrder(pSource)); + return lBunnies.front(); + } + + // function to return a random player from the arena + Unit* GetRandomArenaPlayer() + { + if (!m_pInstance) + return NULL; + + Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_THORIM_COMBAT_TRIGGER); + if (!pTrigger) + return NULL; + + std::vector suitableTargets; + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); + + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && pTarget->IsWithinDistInMap(pTrigger, 50.0f) && pTarget->IsWithinLOSInMap(pTrigger)) + suitableTargets.push_back(pTarget); + } + } + + // if no player in the arena was found trigger berserk automatically + if (suitableTargets.empty()) + { + m_uiBerserkTimer = 1000; + m_uiStormHammerTimer = 60000; + return NULL; + } + else + return suitableTargets[urand(0, suitableTargets.size() - 1)]; + } + + // function to spawn a random pack of dwarfes + void DoSpawnArenaDwarf() + { + switch (m_uiDwarfIndex) + { + case 0: // commoners (always in groups of 6-7) + { + std::vector vBunnies; + for (GuidList::const_iterator itr = m_lUpperBunniesGuids.begin(); itr != m_lUpperBunniesGuids.end(); ++itr) + { + if (Creature* pBunny = m_creature->GetMap()->GetCreature(*itr)) + vBunnies.push_back(pBunny); + } + std::random_shuffle(vBunnies.begin(), vBunnies.end()); + + uint8 uiMaxCommoners = urand(6, 7); + if (uiMaxCommoners > vBunnies.size() - 1) + uiMaxCommoners = vBunnies.size(); + + for (uint8 i = 0; i < uiMaxCommoners; ++i) + m_creature->SummonCreature(NPC_DARK_RUNE_COMMONER, vBunnies[i]->GetPositionX(), vBunnies[i]->GetPositionY(), vBunnies[i]->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + break; + } + case 1: // warbringers (along with champions or evokers) + if (Creature* pBunny = SelectRandomUpperBunny()) + m_creature->SummonCreature(NPC_DARK_RUNE_WARBRINGER, pBunny->GetPositionX(), pBunny->GetPositionY(), pBunny->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + // warbringers can have another buddy summoned at the same time + if (roll_chance_i(75)) + { + if (Creature* pBunny = SelectRandomUpperBunny()) + m_creature->SummonCreature(roll_chance_i(70) ? NPC_DARK_RUNE_CHAMPION : NPC_DARK_RUNE_EVOKER, pBunny->GetPositionX(), pBunny->GetPositionY(), pBunny->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + break; + case 2: // evokers alone + if (Creature* pBunny = SelectRandomUpperBunny()) + m_creature->SummonCreature(NPC_DARK_RUNE_EVOKER, pBunny->GetPositionX(), pBunny->GetPositionY(), pBunny->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + break; + } + + // get a new index which will be different from the first one + uint8 uiNewIndex = (m_uiDwarfIndex + urand(1, 2)) % 3; + m_uiDwarfIndex = uiNewIndex; + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + switch (m_uiPhase) + { + // arena phase abilities + case PHASE_ARENA: + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK_1) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_LIGHTNING_ORB, CAST_TRIGGERED); + DoScriptText(SAY_ARENA_WIPE, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiArenaDwarfTimer < uiDiff) + { + DoSpawnArenaDwarf(); + m_uiArenaDwarfTimer = 10000; + } + else + m_uiArenaDwarfTimer -= uiDiff; + + if (m_uiChargeOrbTimer < uiDiff) + { + // this spell has AoE target, but we need to be very specific with the selected targets + if (Creature* pTarget = m_creature->GetMap()->GetCreature(SelectRandomOrbGuid())) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE_ORB) == CAST_OK) + m_uiChargeOrbTimer = 20000; + } + } + else + m_uiChargeOrbTimer -= uiDiff; + + if (m_uiStormHammerTimer < uiDiff) + { + if (Unit* pTarget = GetRandomArenaPlayer()) + { + if (DoCastSpellIfCan(pTarget, SPELL_STORMHAMMER) == CAST_OK) + m_uiStormHammerTimer = 15000; + } + } + else + m_uiStormHammerTimer -= uiDiff; + + break; + // solo phase abilities + case PHASE_SOLO: + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK_2) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiAttackTimer) + { + if (m_uiAttackTimer <= uiDiff) + { + // Add some small delay to combat movement because Jump triggers before it's actually finished + DoResetThreat(); + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_uiAttackTimer = 0; + } + else + m_uiAttackTimer -= uiDiff; + } + + if (m_uiChargeOrbTimer < uiDiff) + { + // this spell requires very specific targets + if (Creature* pTarget = m_creature->GetMap()->GetCreature(SelectRandomOrbGuid())) + { + pTarget->CastSpell(pTarget, SPELL_LIGHTNING_ORG_CHARGED, true); + + // charge the lower orb as well + if (Unit* pOrb = GetClosestCreatureWithEntry(pTarget, NPC_THUNDER_ORB, 25.0f, true, false, true)) + pTarget->CastSpell(pOrb, SPELL_LIGHTNING_PILLAR, true); + + m_uiChargeOrbTimer = 20000; + } + } + else + m_uiChargeOrbTimer -= uiDiff; + + if (m_uiChainLightningTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING_H) == CAST_OK) + m_uiChainLightningTimer = urand(10000, 15000); + } + } + else + m_uiChainLightningTimer -= uiDiff; + + if (m_uiUnbalancingStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_UNBALANCING_STRIKE) == CAST_OK) + m_uiUnbalancingStrikeTimer = 25000; + } + else + m_uiUnbalancingStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + break; + // transition phase; nothing here, wait for transition to finish + case PHASE_TRANSITION: + break; + } + } +}; + +CreatureAI* GetAI_boss_thorim(Creature* pCreature) +{ + return new boss_thorimAI(pCreature); +} + +/*###### +## boss_sif +######*/ + +struct boss_sifAI : public ScriptedAI +{ + boss_sifAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + bool m_bAttackReady; + + uint32 m_uiFrostBoltTimer; + uint32 m_uiVolleyTimer; + uint32 m_uiFrostNovaTimer; + uint32 m_uiBlizzardTimer; + uint32 m_uiBlinkTimer; + + GuidList m_lBunniesGuids; + + void Reset() override + { + m_bAttackReady = false; + + m_uiFrostBoltTimer = urand(2000, 3000); + m_uiVolleyTimer = urand(7000, 10000); + m_uiFrostNovaTimer = urand(30000, 35000); + m_uiBlizzardTimer = urand(20000, 30000); + m_uiBlinkTimer = urand(20000, 25000); + + SetCombatMovement(false); + } + + void AttackStart(Unit* pWho) override + { + // custom attack; only in hard mode + if (!m_bAttackReady) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void EnterEvadeMode() override + { + // custom evade; Sif doesn't need to move to home position + if (!m_bAttackReady) + return; + + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // activate attack on hard mode + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_THORIM) + { + m_bAttackReady = true; + + if (m_pInstance) + m_pInstance->GetThorimBunniesGuids(m_lBunniesGuids, false); + } + } + + // function to return a random arena bunny for Blizzard spell + ObjectGuid SelectRandomBunnyGuid() + { + if (m_lBunniesGuids.empty()) + return ObjectGuid(); + + GuidList::iterator iter = m_lBunniesGuids.begin(); + advance(iter, urand(0, m_lBunniesGuids.size() - 1)); + + return *iter; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiFrostBoltTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FROSTBOLT : SPELL_FROSTBOLT_H) == CAST_OK) + m_uiFrostBoltTimer = urand(2000, 3000); + } + } + else + m_uiFrostBoltTimer -= uiDiff; + + if (m_uiVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FROSTBOLT_VOLLEY : SPELL_FROSTBOLT_VOLLEY_H) == CAST_OK) + m_uiVolleyTimer = urand(15000, 18000); + } + else + m_uiVolleyTimer -= uiDiff; + + if (m_uiFrostNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FROST_NOVA : SPELL_FROST_NOVA_H) == CAST_OK) + m_uiFrostNovaTimer = urand(20000, 25000); + } + else + m_uiFrostNovaTimer -= uiDiff; + + if (m_uiBlizzardTimer < uiDiff) + { + // this spell has AoE target, but we need to be very specific with the selected targets + if (Unit* pTarget = m_creature->GetMap()->GetUnit(SelectRandomBunnyGuid())) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_BLIZZARD : SPELL_BLIZZARD_H) == CAST_OK) + m_uiBlizzardTimer = 40000; + } + } + else + m_uiBlizzardTimer -= uiDiff; + + if (m_uiBlinkTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BLINK) == CAST_OK) + m_uiBlinkTimer = urand(20000, 25000); + } + } + else + m_uiBlinkTimer -= uiDiff; + } +}; + +CreatureAI* GetAI_boss_sif(Creature* pCreature) +{ + return new boss_sifAI(pCreature); +} + +/*###### +## npc_runic_colossus +######*/ + +struct npc_runic_colossusAI : public ScriptedAI +{ + npc_runic_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiChargeTimer; + uint32 m_uiBarrierTimer; + uint32 m_uiSmashTimer; + + uint32 m_uiRunicSmashTimer; + uint32 m_uiSmashUpdateTimer; + uint8 m_uiSmashIndex; + + bool m_bSmashStarted; + bool m_bSmashActive; + + GuidList m_lCurrentSmashBunnies; + + void Reset() override + { + m_uiChargeTimer = 1000; + m_uiBarrierTimer = 15000; + m_uiSmashTimer = 0; + m_uiRunicSmashTimer = 0; + m_uiSmashUpdateTimer = 250; + m_uiSmashIndex = 1; + m_bSmashStarted = false; + m_bSmashActive = false; + } + + void Aggro(Unit* /*pWho*/) override + { + m_creature->InterruptNonMeleeSpells(false); + m_uiRunicSmashTimer = 0; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bSmashStarted && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->IsWithinDistInMap(pWho, 80.0f) && m_creature->IsWithinLOSInMap(pWho)) + { + m_uiRunicSmashTimer = 1000; + m_bSmashStarted = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // start runic smash event + if (pSpell->Id == SPELL_RUNIC_SMASH_L && m_pInstance) + { + m_lCurrentSmashBunnies.clear(); + m_pInstance->GetSmashTargetsGuids(m_lCurrentSmashBunnies, true); + m_bSmashActive = true; + } + else if (pSpell->Id == SPELL_RUNIC_SMASH_R && m_pInstance) + { + m_lCurrentSmashBunnies.clear(); + m_pInstance->GetSmashTargetsGuids(m_lCurrentSmashBunnies, false); + m_bSmashActive = true; + } + } + + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if ((pSpellEntry->Id == SPELL_CHARGE || pSpellEntry->Id == SPELL_CHARGE_H) && pTarget->GetTypeId() == TYPEID_PLAYER) + m_uiSmashTimer = 1000; + } + + // Wrapper to keep Runic Smash in a distinct function + void UpdateRunicSmash(const uint32 uiDiff) + { + if (!m_bSmashActive) + return; + + if (m_uiSmashUpdateTimer < uiDiff) + { + // check all the targets which are in a certain distance from the colossus + for (GuidList::const_iterator itr = m_lCurrentSmashBunnies.begin(); itr != m_lCurrentSmashBunnies.end(); ++itr) + { + if (Creature* pBunny = m_creature->GetMap()->GetCreature(*itr)) + { + // use 12 and 16 as multipliers in order to get the perfect combination + if (pBunny->GetPositionY() > m_creature->GetPositionY() + 12 * m_uiSmashIndex && + pBunny->GetPositionY() < m_creature->GetPositionY() + 16 * m_uiSmashIndex) + pBunny->CastSpell(pBunny, SPELL_RUNIC_SMASH, false); + } + } + + ++m_uiSmashIndex; + if (m_uiSmashIndex == MAX_RUNIC_SMASH + 1) + { + m_bSmashActive = false; + m_uiSmashIndex = 1; + } + + m_uiSmashUpdateTimer = 250; + } + else + m_uiSmashUpdateTimer -= uiDiff; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiRunicSmashTimer) + { + if (m_uiRunicSmashTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_RUNIC_SMASH_L : SPELL_RUNIC_SMASH_R) == CAST_OK) + m_uiRunicSmashTimer = 7000; + } + else + m_uiRunicSmashTimer -= uiDiff; + + UpdateRunicSmash(uiDiff); + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiChargeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, m_bIsRegularMode ? SPELL_CHARGE : SPELL_CHARGE_H, SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CHARGE : SPELL_CHARGE_H) == CAST_OK) + m_uiChargeTimer = urand(10000, 15000); + } + } + else + m_uiChargeTimer -= uiDiff; + + // smash is cast right after charge + if (m_uiSmashTimer) + { + if (m_uiSmashTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SMASH) == CAST_OK) + m_uiSmashTimer = 0; + } + else + m_uiSmashTimer -= uiDiff; + } + + if (m_uiBarrierTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_RUNIC_BARRIER) == CAST_OK) + { + DoScriptText(EMOTE_RUNIC_BARRIER, m_creature); + m_uiBarrierTimer = urand(30000, 35000); + } + } + else + m_uiBarrierTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_runic_colossus(Creature* pCreature) +{ + return new npc_runic_colossusAI(pCreature); +} + +/*###### +## npc_thunder_orb +######*/ + +struct npc_thunder_orbAI : public Scripted_NoMovementAI +{ + npc_thunder_orbAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiTriggerTimer; + + void Reset() override + { + m_uiTriggerTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // cast visual on the lower Orb + if (pSpell->Id == SPELL_CHARGE_ORB) + { + if (Creature* pOrb = GetClosestCreatureWithEntry(m_creature, NPC_THUNDER_ORB, 25.0f, true, false, true)) + pOrb->CastSpell(pOrb, SPELL_LIGHTNING_PILLAR_ORB, false); + } + // SPECIAL NOTE: this aura has a duration lower than the trigger period for the next spell; so we need to force this by timer + else if (pSpell->Id == SPELL_LIGHTNING_ORG_CHARGED) + m_uiTriggerTimer = 8000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiTriggerTimer) + { + if (m_uiTriggerTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_ORB_TRIGGER) == CAST_OK) + m_uiTriggerTimer = 0; + } + else + m_uiTriggerTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_thunder_orb(Creature* pCreature) +{ + return new npc_thunder_orbAI(pCreature); +} + void AddSC_boss_thorim() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_thorim"; + pNewScript->GetAI = GetAI_boss_thorim; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_sif"; + pNewScript->GetAI = GetAI_boss_sif; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_runic_colossus"; + pNewScript->GetAI = GetAI_npc_runic_colossus; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_thunder_orb"; + pNewScript->GetAI = GetAI_npc_thunder_orb; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_xt_002.cpp b/scripts/northrend/ulduar/ulduar/boss_xt_002.cpp index 79c23242b..44a3c93d4 100644 --- a/scripts/northrend/ulduar/ulduar/boss_xt_002.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_xt_002.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_xt_002 -SD%Complete: 0% -SDComment: +SD%Complete: 80% +SDComment: Timers may need adjustments; Achievements and hard mode abilities NYI. SDCategory: Ulduar EndScriptData */ @@ -38,9 +38,521 @@ enum EMOTE_HEART = -1603054, EMOTE_REPAIR = -1603055, + EMOTE_KILL_HEART = -1603236, + EMOTE_EARTH_QUAKE = -1603237, + + // spells + SPELL_TYMPANIC_TANTRUM = 62776, + SPELL_SEARING_LIGHT = 63018, + SPELL_SEARING_LIGHT_H = 65121, + SPELL_GRAVITY_BOMB = 63024, + SPELL_GRAVITY_BOMB_H = 64234, + SPELL_BERSERK = 26662, + // SPELL_SUBMERGED = 37751, // cast before a heart phase. not used because it's unk purpose + // SPELL_STAND = 37752, // cast after a heart phase. not used because it's unk purpose + + // hard mode spells + SPELL_HEARTBREAK = 65737, + SPELL_HEARTBREAK_H = 64193, + SPELL_VOIDZONE = 64203, + SPELL_VOIDZONE_H = 64235, + SPELL_LIFE_SPARK = 64210, + + // heart of XT002 spells + SPELL_HEART_RIDE_VEHICLE = 63852, // ride seat 0 - procs on damage (probably spell 17683) + SPELL_FULL_HEAL = 17683, + SPELL_RIDE_VEHICLE = 63313, // ride seat 1 + SPELL_LIGHTNING_TETHER = 64799, // dummy + SPELL_HEART_OVERLOAD = 62789, // triggers missing spell 62791 + SPELL_EXPOSED_HEART = 63849, // procs on damage; triggers missing spell 62791 + SPELL_ENERGY_ORB = 62790, // targets 33337, in order to start spawning robots + SPELL_ENERGY_ORB_DUMMY = 62826, // dummy effect which spawns robots - not used due to core targeting issues + + // robot summoning spells, used by the XT toy pile + SPELL_RECHARGE_ROBOT_1 = 62828, // summons 33343 + SPELL_RECHARGE_ROBOT_2 = 62835, // summons 33346 + SPELL_RECHARGE_ROBOT_3 = 62831, // summons 33344 + + // summoned spells + SPELL_CONSUMPTION = 64208, // cast by the void zone + SPELL_ARCANE_POWER_STATE = 49411, // cast by the life spark + SPELL_STATIC_CHARGED = 64227, // cast by the life spark (needs to be confirmed) + SPELL_STATIC_CHARGED_H = 64236, + SPELL_SCRAP_REPAIR = 62832, // cast on scrapbot in range to heal XT002; sends event 21606 + SPELL_RIDE_VEHICLE_SCRAPBOT = 47020, // cast by scrapbot on XT002 heal + + // NPC ids + NPC_SCRAPBOT = 33343, + NPC_BOOMBOT = 33346, + NPC_PUMMELLER = 33344, + NPC_VOIDZONE = 34001, + NPC_LIFE_SPARK = 34004, + + // phases + PHASE_NORMAL = 1, + PHASE_TRANSITION = 2, + PHASE_HEART = 3, + + MAX_SCRAPBOTS = 5, }; +/*###### +## boss_xt_002 +######*/ + +struct boss_xt_002AI : public ScriptedAI +{ + boss_xt_002AI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + m_uiMountTimer = 1000; + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiBerserkTimer; + uint32 m_uiMountTimer; + + uint8 m_uiPhase; + uint8 m_uiHeartStage; + + uint32 m_uiHeartTimer; + uint32 m_uiLightBombTimer; + uint32 m_uiGravityBombTimer; + uint32 m_uiTanctrumTimer; + + void Reset() override + { + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_uiPhase = PHASE_NORMAL; + m_uiHeartStage = 1; + + m_uiLightBombTimer = 10000; + m_uiGravityBombTimer = 20000; + m_uiTanctrumTimer = 35000; + + // reset flags and stand state + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_XT002, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); + } + + void Aggro(Unit* /*pWho*/) override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_XT002, IN_PROGRESS); + m_pInstance->SetData(TYPE_XT002_HARD, NOT_STARTED); + } + + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + m_pInstance->SetData(TYPE_XT002, FAIL); + + // mount the Heart back at the right seat after wipe or respawn (respawn handled in DB) + m_uiMountTimer = 1000; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // enable hard mode + if (eventType == AI_EVENT_CUSTOM_B && pInvoker->GetEntry() == NPC_HEART_DECONSTRUCTOR) + { + // reset to normal phase and don't allow the boss to get back to heart phases + DoResetToNormalPhase(); + m_uiHeartStage = 4; + + if (m_pInstance) + m_pInstance->SetData(TYPE_XT002_HARD, DONE); + + DoScriptText(EMOTE_KILL_HEART, m_creature); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HEARTBREAK : SPELL_HEARTBREAK_H, CAST_TRIGGERED); + + // no spell used for this action + m_creature->SetHealth(m_creature->GetMaxHealth()); + } + } + + // wrapper to reset to normal phase + void DoResetToNormalPhase() + { + DoScriptText(SAY_HEART_CLOSE, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoStartMovement(m_creature->getVictim()); + + // reset timers as well + m_uiLightBombTimer = 10000; + m_uiGravityBombTimer = 20000; + m_uiPhase = PHASE_NORMAL; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + { + script_error_log("Instance Ulduar: ERROR Failed to load instance data for this instace."); + return; + } + + // The heart needs to be mounted manually, not by vehicle_accessories + if (m_uiMountTimer) + { + if (m_uiMountTimer <= uiDiff) + { + if (Creature* pHeart = m_pInstance->GetSingleCreatureFromStorage(NPC_HEART_DECONSTRUCTOR)) + { + // safeguard in case the Heart isn't respawned + if (!pHeart->isAlive()) + pHeart->Respawn(); + + pHeart->AI()->EnterEvadeMode(); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + pHeart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pHeart->CastSpell(m_creature, SPELL_HEART_RIDE_VEHICLE, true); + } + + m_uiMountTimer = 0; + } + else + m_uiMountTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } + + switch (m_uiPhase) + { + case PHASE_NORMAL: + + if (m_uiLightBombTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SEARING_LIGHT : SPELL_SEARING_LIGHT_H) == CAST_OK) + m_uiLightBombTimer = 20000; + } + else + m_uiLightBombTimer -= uiDiff; + + if (m_uiGravityBombTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_GRAVITY_BOMB : SPELL_GRAVITY_BOMB_H) == CAST_OK) + m_uiGravityBombTimer = 20000; + } + else + m_uiGravityBombTimer -= uiDiff; + + if (m_uiTanctrumTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_TYMPANIC_TANTRUM) == CAST_OK) + { + DoScriptText(SAY_TANCTRUM, m_creature); + DoScriptText(EMOTE_EARTH_QUAKE, m_creature); + m_uiTanctrumTimer = 60000; + } + } + else + m_uiTanctrumTimer -= uiDiff; + + // start heart stage transition + if (m_creature->GetHealthPercent() < float(100 - 25 * m_uiHeartStage)) + { + DoScriptText(SAY_HEART_OPEN, m_creature); + + ++m_uiHeartStage; + m_uiHeartTimer = 5000; + m_uiPhase = PHASE_TRANSITION; + + // stop all movement + m_creature->GetMotionMaster()->MoveIdle(); + } + + DoMeleeAttackIfReady(); + + break; + case PHASE_TRANSITION: + + if (m_uiHeartTimer < uiDiff) + { + // inform the heart about the phase switch + if (Creature* pHeart = m_pInstance->GetSingleCreatureFromStorage(NPC_HEART_DECONSTRUCTOR)) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pHeart); + + DoScriptText(EMOTE_HEART, m_creature); + + m_creature->SetStandState(UNIT_STAND_STATE_CUSTOM); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + m_uiHeartTimer = 30000; + m_uiPhase = PHASE_HEART; + } + else + m_uiHeartTimer -= uiDiff; + + break; + case PHASE_HEART: + + // reset to normal phase when timer expires + if (m_uiHeartTimer < uiDiff) + { + DoResetToNormalPhase(); + m_uiHeartTimer = 0; + + // mount the heart back inside if not already killed + if (m_pInstance && m_pInstance->GetData(TYPE_XT002_HARD) != DONE) + { + if (Creature* pHeart = m_pInstance->GetSingleCreatureFromStorage(NPC_HEART_DECONSTRUCTOR)) + { + pHeart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + pHeart->CastSpell(m_creature, SPELL_HEART_RIDE_VEHICLE, true); + + // no spell found for this + pHeart->SetHealth(pHeart->GetMaxHealth()); + } + } + } + else + m_uiHeartTimer -= uiDiff; + + break; + } + } +}; + +CreatureAI* GetAI_boss_xt_002(Creature* pCreature) +{ + return new boss_xt_002AI(pCreature); +} + +/*###### +## boss_heart_deconstructor +######*/ + +struct boss_heart_deconstructorAI : public ScriptedAI +{ + boss_heart_deconstructorAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + Reset(); + } + + instance_ulduar* m_pInstance; + + uint32 m_uiRobotTimer; + + GuidVector m_vToyPileGuids; + + void Reset() override + { + m_uiRobotTimer = 0; + } + + void JustDied(Unit* /*pKiller*/) override + { + // notify XT that hard mode is enabled + if (m_pInstance) + { + if (Creature* pDeconstructor = m_pInstance->GetSingleCreatureFromStorage(NPC_XT002)) + SendAIEvent(AI_EVENT_CUSTOM_B, m_creature, pDeconstructor); + } + } + + void JustSummoned(Creature* pSummoned) override + { + // handle spawned robots + if (m_pInstance) + { + if (Creature* pDeconstructor = m_pInstance->GetSingleCreatureFromStorage(NPC_XT002)) + { + float fX, fY, fZ; + pDeconstructor->GetContactPoint(pSummoned, fX, fY, fZ, INTERACTION_DISTANCE); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + // start XT phase switch and start recharging robots + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_XT002) + { + // remove flags and previous vehicle aura before applying the new one + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pInvoker->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + + DoCastSpellIfCan(pInvoker, SPELL_RIDE_VEHICLE, CAST_TRIGGERED); + DoCastSpellIfCan(pInvoker, SPELL_LIGHTNING_TETHER, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_HEART_OVERLOAD, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_EXPOSED_HEART, CAST_TRIGGERED); + m_uiRobotTimer = 1000; + + // load the toy piles guids + if (m_pInstance && m_vToyPileGuids.empty()) + m_pInstance->GetToyPileGuids(m_vToyPileGuids); + } + } + + // TODO: Use the dummy effect on target when proper targeting will be supported in core + void SpellHitTarget(Unit* pTarget, SpellEntry const* pSpellEntry) override + { + if (pTarget->GetEntry() == NPC_XT_TOY_PILE && pSpellEntry->Id == SPELL_ENERGY_ORB) + { + // spawn a bunch of scrap bots + for (uint8 i = 0; i < MAX_SCRAPBOTS; ++i) + pTarget->CastSpell(pTarget, SPELL_RECHARGE_ROBOT_1, true, NULL, NULL, m_creature->GetObjectGuid()); + + // spawn a boombot or pummeller, depending on chance + pTarget->CastSpell(pTarget, roll_chance_i(80) ? SPELL_RECHARGE_ROBOT_2 : SPELL_RECHARGE_ROBOT_3, true, NULL, NULL, m_creature->GetObjectGuid()); + } + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiRobotTimer) + { + if (m_uiRobotTimer <= uiDiff) + { + // visual effect on XT (script target) + DoCastSpellIfCan(m_creature, SPELL_LIGHTNING_TETHER, CAST_TRIGGERED); + + // cast the enerby orb on each pile one by one + if (Creature* pToyPile = m_creature->GetMap()->GetCreature(m_vToyPileGuids[urand(0, m_vToyPileGuids.size() - 1)])) + DoCastSpellIfCan(pToyPile, SPELL_ENERGY_ORB, CAST_TRIGGERED); + + // reset timer after the overload aura expires + if (m_creature->HasAura(SPELL_EXPOSED_HEART)) + m_uiRobotTimer = urand(1000, 3000); + else + m_uiRobotTimer = 0; + } + else + m_uiRobotTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_heart_deconstructor(Creature* pCreature) +{ + return new boss_heart_deconstructorAI(pCreature); +} + +/*###### +## npc_scrapbot +######*/ + +struct npc_scrapbotAI : public ScriptedAI +{ + npc_scrapbotAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bIsHealed; + + void Reset() override + { + m_bIsHealed = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIsHealed && pWho->GetEntry() == NPC_XT002 && pWho->isAlive() && pWho->IsWithinDistInMap(m_creature, 10.0f)) + { + DoCastSpellIfCan(pWho, SPELL_RIDE_VEHICLE_SCRAPBOT, CAST_TRIGGERED); + pWho->CastSpell(m_creature, SPELL_SCRAP_REPAIR, true); + DoScriptText(EMOTE_REPAIR, pWho); + m_creature->ForcedDespawn(4000); + m_bIsHealed = true; + } + } +}; + +CreatureAI* GetAI_npc_scrapbot(Creature* pCreature) +{ + return new npc_scrapbotAI(pCreature); +} + +/*###### +## npc_xt_toy_pile +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_xt_toy_pileAI : public Scripted_NoMovementAI +{ + npc_xt_toy_pileAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_xt_toy_pile(Creature* pCreature) +{ + return new npc_xt_toy_pileAI(pCreature); +} + void AddSC_boss_xt_002() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_xt_002"; + pNewScript->GetAI = GetAI_boss_xt_002; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_heart_deconstructor"; + pNewScript->GetAI = GetAI_boss_heart_deconstructor; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_scrapbot"; + pNewScript->GetAI = GetAI_npc_scrapbot; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_xt_toy_pile"; + pNewScript->GetAI = GetAI_npc_xt_toy_pile; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/boss_yogg_saron.cpp b/scripts/northrend/ulduar/ulduar/boss_yogg_saron.cpp index 07219a9e9..44d0c1ea5 100644 --- a/scripts/northrend/ulduar/ulduar/boss_yogg_saron.cpp +++ b/scripts/northrend/ulduar/ulduar/boss_yogg_saron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,37 +16,46 @@ /* ScriptData SDName: boss_yogg_saron -SD%Complete: 0% -SDComment: +SD%Complete: 95% +SDComment: Illusion contain a lot of guesswork. SDCategory: Ulduar EndScriptData */ #include "precompiled.h" #include "ulduar.h" +#include "TemporarySummon.h" enum { + // phase 1 yells SAY_SARA_INTRO_1 = -1603197, SAY_SARA_INTRO_2 = -1603198, SAY_SARA_AGGRO = -1603199, - SAY_SARA_HELP_1 = -1603200, - SAY_SARA_HELP_2 = -1603201, - SAY_SARA_SLAY_1 = -1603202, - SAY_SARA_SLAY_2 = -1603203, - SAY_WIPE_PHASE_1 = -1603204, + SAY_SARA_HELP_1 = -1603201, + SAY_SARA_HELP_2 = -1603202, + SAY_SARA_SLAY_1 = -1603203, + SAY_SARA_SLAY_2 = -1603204, + SAY_WIPE_PHASE_1 = -1603205, - SAY_PHASE_2_INTRO = -1603205, - SAY_SARA_PHASE_2_INTRO_A = -1603206, - SAY_SARA_PHASE_2_INTRO_B = -1603207, + // phase 2 transition yells + SAY_PHASE_2_INTRO_1 = -1603206, + SAY_PHASE_2_INTRO_2 = -1603262, + SAY_PHASE_2_INTRO_3 = -1603263, + SAY_PHASE_2_INTRO_4 = -1603264, + SAY_PHASE_2_INTRO_5 = -1603265, + // phase 2 and 3 yells + SAY_SARA_PHYCHOSIS = -1603207, + SAY_SARA_DEATH_RAY = -1603208, SAY_MADNESS = -1603209, SAY_PHASE_3 = -1603210, - SAY_SLAY_1 = -1603211, - SAY_SLAY_2 = -1603212, + SAY_SLAY = -1603212, SAY_DEATH = -1603213, SAY_TO_INSANE_1 = -1603214, SAY_TO_INSANE_2 = -1603215, + SOUND_ID_LUNATIC_GAZE = 15757, + // icecrown illusion yells SAY_LICH_KING_1 = -1603216, SAY_CHAMPION_1 = -1603217, SAY_CHAMPION_2 = -1603218, @@ -54,25 +63,1677 @@ enum SAY_YOGG_V3_1 = -1603220, SAY_YOGG_V3_2 = -1603221, + // chamber illusion yells SAY_NELTHARION_1 = -1603222, SAY_YSERA = -1603223, SAY_NELTHARION_2 = -1603224, SAY_MALYGOS = -1603225, SAY_YOGG_V2 = -1603226, + // stormwind illusion yells SAY_GARONA_1 = -1603227, - SAY_GARONA_2 = -1603228, + SAY_GARONA_2 = -1603267, + SAY_GARONA_3 = -1603228, SAY_YOGG_V1_1 = -1603229, SAY_YOGG_V1_2 = -1603230, - SAY_GARONA_3 = -1603231, + SAY_KING_LLANE = -1603231, SAY_GARONA_4 = -1603232, SAY_YOGG_V1_3 = -1603233, + // emotes EMOTE_VISION_BLAST = -1603234, EMOTE_SHATTER_BLAST = -1603235, + EMOTE_CLOUD_BOIL = -1603261, + EMOTE_DEAFENING_ROAR = -1603266, + EMOTE_EMPOWERING_SHADOWS = -1603211, + + // generic spells + SPELL_EXTINGUISH_LIFE = 64166, // berserk spell + + // Sara phase spells + SPELL_SARAS_FERVOR = 63747, // triggers 63138 + SPELL_SARAS_BLESSING = 63745, // triggers 63134 + SPELL_SARAS_ANGER = 63744, // triggers 63147 + + // ominous cloud spells + // SPELL_OMINOUS_CLOUD_VISUAL = 63084, // in c_t_a + SPELL_BOIL_OMNIOUSLY = 63030, // cast when a player is in range; triggers 63031 + + // guardian of yogg spells + SPELL_SHADOW_NOVA = 62714, // used by the guardians when it dies + SPELL_SHADOW_NOVA_H = 65209, + SPELL_DARK_VOLLEY = 63038, + SPELL_DOMINATE_MIND = 63713, + + // Voice of Yogg spells + SPELL_SANITY = 63786, // add sanity when encounter starts + SPELL_INSANE = 63120, // charm effect on players + SPELL_INSANE_PERIODIC = 64554, // decrease sanity + SPELL_SUMMON_GUARDIAN_YOGG = 62978, // cast by npc 33280 on an Ominus cloud + + // Yogg transition spells + SPELL_SHADOWY_BARRIER_YOGG = 63894, + SPELL_KNOCK_AWAY = 64022, + SPELL_MATCH_HEALTH = 64066, // periodic aura on the Brain + SPELL_BRAIN_HURT_VISUAL = 64361, + + // Sara transition spells + SPELL_SHADOWY_BARRIER = 64775, // damage immunity spells + SPELL_FULL_HEAL = 43978, + SPELL_PHASE_2_TRANSFORM = 65157, + SPELL_RIDE_VEHICLE_YOGG = 61791, // mount vehicle Yogg + + // Vision phase spells + SPELL_PHYCHOSIS = 63795, // Sara combat spells + SPELL_PHYCHOSIS_H = 65301, + SPELL_MALADY_OF_THE_MIND = 63830, // jumps to another target using 63881; requires additional research + SPELL_BRAIN_LINK = 63802, // triggers 63803 for damage or 63804 for visual depending on range + SPELL_DEATH_RAY_SUMMON = 63891, // summons npc 33882 + + // Tentacle spawn spells + SPELL_CONSTRICTOR_TENTACLE = 64132, // triggers 64133 + SPELL_CORRUPTOR_TENTACLE = 64143, + SPELL_CRUSHER_TENTACLE = 64139, + + // Tentacle spells + SPELL_TENTACLE_VOID_ZONE = 64384, + SPELL_ERUPT = 64144, + SPELL_LUNGE = 64131, // triggers 64123 + SPELL_TENTACLE_VOID_ZONE_BIG = 64017, + SPELL_CRUSH = 64146, + SPELL_DIMINISH_POWER = 64148, + SPELL_FOCUSED_ANGER = 57688, + SPELL_SQUEEZE = 64125, + SPELL_SQUEEZE_H = 64126, + + // Vision spells + SPELL_LUNATIC_GAZE_SKULL = 64167, + SPELL_NONDESCRIPT_ARMOR = 64013, // stun auras for illusions + SPELL_NONDESCRIPT_CREATURE = 64010, + SPELL_GRIM_REPRISAL = 63305, // procs 64039 on damage taken + SPELL_SHATTERED_ILLUSION = 64173, // send event 21669 + SPELL_SHATTERED_ILLUSION_REMOVE = 65238, // remove aura 64173; send event 21671 + SPELL_INDUCE_MADNESS = 64059, // reduce sanity by 100% to all players with aura 63988 + + // Old God phase spells + SPELL_LUNATIC_GAZE_YOGG = 64163, + SPELL_SHADOW_BEACON = 64465, // triggers 64468 + // SPELL_EMPOWERING_SHADOWS = 64468, + // SPELL_EMPOWERING_SHADOWS_H = 64486, + SPELL_DEAFENING_ROAR = 64189, + SPELL_IMMORTAL_GUARDIAN = 64158, + + // death ray spells + SPELL_DEATH_RAY_TRIGG = 63883, // damage spell + SPELL_DEATH_RAY_VISUAL_WARN = 63882, // channeled; target creature 33882 + SPELL_DEATH_RAY_VISUAL_DAMAGE = 63886, // channeled; target creature 33882 + SPELL_DEATH_RAY_VISUAL_ORIGIN = 63893, // visual for creature 33882 + + // descend into madness spells + SPELL_TELEPORT_PORTAL_VISUAL = 64416, + SPELL_TELEPORT_TO_STORMWIND_ILLUSION = 63989, + SPELL_TELEPORT_TO_CHAMBER_ILLUSION = 63997, + SPELL_TELEPORT_TO_ICEECROWN_ILLUSION = 63998, + // SPELL_TELEPORT_BACK_TO_MAIN_ROOM = 63992, // triggered by spell 63993 + + // immortal guardian spells + SPELL_EMPOWERED = 64161, + SPELL_EMPOWERED_MOD = 65294, + SPELL_RECENTLY_SPAWNED = 64497, + SPELL_SIMPLE_TELEPORT = 64195, + SPELL_DRAIN_LIFE = 64159, + SPELL_DRAIN_LIFE_H = 64160, + SPELL_WEAKENED = 64162, + + // summoned creatures + NPC_DEATH_RAY = 33881, + NPC_DEATH_ORB = 33882, + NPC_CONSTRICTOR_TENTACLE = 33983, + NPC_CRUSHER_TENTACLE = 33966, + NPC_CORRUPTOR_TENTACLE = 33985, + NPC_DESCEND_INTO_MADNESS = 34072, + NPC_IMMORTAL_GUARDIAN = 33988, + // NPC_MARKED_IMMORTAL_GUARDIAN = 36064, // purpose unk - maybe used for Shadow Beacon event + // NPC_SANITY_WELL = 33991, // summoned by Freya + + // generic visions creatures + NPC_LAUGHING_SKULL = 33990, + NPC_INFLUENCE_TENTACLE = 33943, + + // dragon soul vision + NPC_RUBY_CONSORT = 33716, + NPC_AZURE_CONSORT = 33717, + // NPC_BRONZE_CONSORT = 33718, // Nozdormu is not part of the event for some reason + NPC_EMERALD_CONSORT = 33719, + NPC_OBSIDIAN_CONSORT = 33720, + + // stormwind vision + NPC_SUIT_OF_ARMOR = 33433, + SPELL_ASSASSINATE = 64063, + + // icecrown citadel vision + NPC_DEATHSWORM_ZEALOT = 33567, + SPELL_DEATHGRASP = 63037, + + // keepers + // Freya spells + SPELL_RESILIENCE_OF_NATURE = 62670, + SPELL_SUMMON_SANITY_WELL = 64170, // sends event 21432; used to spawn npc 33991 + + // sanity well spells + // SPELL_SANITY_WELL = 64169, + // SPELL_SANITY_WELL_VISUAL = 63288, + + // Hodir spells + SPELL_FORTITUDE_OF_FROST = 62650, + SPELL_HODIRS_PROTECTIVE_GAZE = 64174, + + // Mimiron spells + SPELL_SPEED_OF_INVENTION = 62671, + SPELL_DESTABILIZATION_MATRIX = 65206, + + // Thorim spells + SPELL_FURY_OF_THE_STORM = 62702, + SPELL_TITANIC_STORM = 64171, + + // other + FACTION_SARA_HOSTILE = 16, + MAX_ILLUSIONS = 3, + + // encounter phases + PHASE_INTRO = 0, + PHASE_SARA = 1, + PHASE_VISIONS = 2, + PHASE_OLD_GOD = 3, + PHASE_TRANSITION = 4, +}; + +static const DialogueEntry aYoggSaronDialog[] = +{ + {SAY_PHASE_2_INTRO_1, NPC_SARA, 4000}, + {SAY_PHASE_2_INTRO_2, NPC_SARA, 5000}, + {SAY_PHASE_2_INTRO_3, NPC_SARA, 5000}, + {SAY_PHASE_2_INTRO_4, NPC_SARA, 1000}, + {SPELL_PHASE_2_TRANSFORM, 0, 3000}, + {SAY_PHASE_2_INTRO_5, NPC_YOGGSARON, 0}, + {0, 0, 0}, }; +static const DialogueEntry aYoggIllusionsDialog[] = +{ + // stormwind + {NPC_KING_LLANE, 0, 10000}, + {SAY_GARONA_1, NPC_GARONA, 2000}, + {SAY_GARONA_2, NPC_GARONA, 8000}, + {SAY_GARONA_3, NPC_GARONA, 12000}, + {SAY_YOGG_V1_1, NPC_YOGGSARON_ILLUSION, 4000}, + {SAY_YOGG_V1_2, NPC_YOGGSARON_ILLUSION, 4000}, + {SAY_KING_LLANE, NPC_KING_LLANE, 12000}, + {SAY_GARONA_4, NPC_GARONA, 2000}, + {SPELL_ASSASSINATE, 0, 4000}, + {SAY_YOGG_V1_3, NPC_YOGGSARON_ILLUSION, 0}, + // chamber + {NPC_NELTHARION, 0, 10000}, + {SAY_NELTHARION_1, NPC_NELTHARION, 10000}, + {SAY_YSERA, NPC_YSERA, 7000}, + {SAY_NELTHARION_2, NPC_NELTHARION, 6000}, + {SAY_MALYGOS, NPC_MALYGOS, 9000}, + {SAY_YOGG_V2, NPC_YOGGSARON_ILLUSION, 0}, + // icecrown + {NPC_LICH_KING, 0, 10000}, + {SAY_LICH_KING_1, NPC_LICH_KING, 5000}, + {SAY_CHAMPION_1, NPC_IMMOLATED_CHAMPION, 8000}, + {SAY_CHAMPION_2, NPC_IMMOLATED_CHAMPION, 8000}, + {SAY_LICH_KING_2, NPC_LICH_KING, 7000}, + {SAY_YOGG_V3_1, NPC_YOGGSARON_ILLUSION, 5000}, + {SAY_YOGG_V3_2, NPC_YOGGSARON_ILLUSION, 0}, + {0, 0, 0}, +}; + +static const float afYoggSaronSpawn[4] = {1980.43f, -25.7708f, 324.9724f, 3.141f}; +static const uint32 aMadnessTeleportSpells[MAX_ILLUSIONS] = { SPELL_TELEPORT_TO_STORMWIND_ILLUSION, SPELL_TELEPORT_TO_CHAMBER_ILLUSION, SPELL_TELEPORT_TO_ICEECROWN_ILLUSION }; +static const uint32 aMadnessChamberDoors[MAX_ILLUSIONS] = { GO_BRAIN_DOOR_STORMWIND, GO_BRAIN_DOOR_CHAMBER, GO_BRAIN_DOOR_ICECROWN }; + +/*###### +## boss_sara +######*/ + +struct boss_saraAI : public Scripted_NoMovementAI, private DialogueHelper +{ + boss_saraAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature), + DialogueHelper(aYoggSaronDialog) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + bool m_bIsHostile; + + uint8 m_uiPhase; + uint32 m_uiSarasSpellTimer; + + uint32 m_uiPsychosisTimer; + uint32 m_uiMaladyTimer; + uint32 m_uiBrainLinkTimer; + uint32 m_uiDeathRayTimer; + + void Reset() override + { + m_uiPhase = PHASE_INTRO; + m_uiSarasSpellTimer = 15000; + m_bIsHostile = false; + + m_uiPsychosisTimer = 2000; + m_uiMaladyTimer = 15000; + m_uiBrainLinkTimer = 25000; + m_uiDeathRayTimer = 20000; + } + + void AttackStart(Unit* pWho) override + { + if (m_uiPhase == PHASE_SARA) + return; + + ScriptedAI::AttackStart(pWho); + } + + void EnterEvadeMode() override + { + if (!m_bIsHostile) + return; + + ScriptedAI::EnterEvadeMode(); + } + + void MoveInLineOfSight(Unit* pWho) override + { + // start the encounter on range check + // ToDo: research if there is any intro available before the actual encounter starts + if (m_uiPhase == PHASE_INTRO && pWho->GetTypeId() == TYPEID_PLAYER && pWho->isAlive() && !((Player*)pWho)->isGameMaster() && + m_creature->IsWithinDistInMap(pWho, 70.0f) && pWho->IsWithinLOSInMap(m_creature)) + { + m_uiPhase = PHASE_SARA; + DoScriptText(SAY_SARA_AGGRO, m_creature); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_YOGGSARON, IN_PROGRESS); + + // inform the voice controller over event start + if (Creature* pVoice = m_pInstance->GetSingleCreatureFromStorage(NPC_VOICE_OF_YOGG)) + SendAIEvent(AI_EVENT_START_EVENT, m_creature, pVoice); + } + + DoInitialiseKeepers(); + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_SARA_SLAY_1 : SAY_SARA_SLAY_2, m_creature); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + // start transition to the secon phase when all the health has been drained + if (m_uiPhase == PHASE_SARA) + { + m_uiPhase = PHASE_TRANSITION; + StartNextDialogueText(SAY_PHASE_2_INTRO_1); + + // despawn all clouds for phase 2 + if (!m_pInstance) + return; + + GuidList m_lCloudGuids; + m_pInstance->GetOminousCloudGuids(m_lCloudGuids); + + for (GuidList::const_iterator itr = m_lCloudGuids.begin(); itr != m_lCloudGuids.end(); ++itr) + { + if (Creature* pCloud = m_creature->GetMap()->GetCreature(*itr)) + pCloud->ForcedDespawn(); + } + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_YOGGSARON) + { + pSummoned->CastSpell(pSummoned, SPELL_SHADOWY_BARRIER_YOGG, true); + pSummoned->CastSpell(pSummoned, SPELL_KNOCK_AWAY, true); + pSummoned->SetInCombatWithZone(); + } + else if (pSummoned->GetEntry() == NPC_DEATH_ORB) + { + // the death orb is linked to 4 death rays that are randomly moving on the ground + float fX, fY, fZ; + for (uint8 i = 0; i < 4; ++i) + { + float fDist = frand(30.0f, 45.0f); + float fAng = frand(0, 2 * M_PI_F); + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, fDist, fAng); + m_creature->SummonCreature(NPC_DEATH_RAY, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + } + + pSummoned->CastSpell(pSummoned, SPELL_DEATH_RAY_VISUAL_ORIGIN, true); + } + else if (pSummoned->GetEntry() == NPC_DEATH_RAY) + pSummoned->CastSpell(pSummoned, SPELL_DEATH_RAY_VISUAL_WARN, false); + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case SAY_PHASE_2_INTRO_4: + // make trasition - set hostile and summon Yogg + DoCastSpellIfCan(m_creature, SPELL_FULL_HEAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PHASE_2_TRANSFORM, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SHADOWY_BARRIER, CAST_TRIGGERED); + + m_creature->SetFactionTemporary(FACTION_SARA_HOSTILE, TEMPFACTION_RESTORE_RESPAWN); + m_creature->SummonCreature(NPC_YOGGSARON, afYoggSaronSpawn[0], afYoggSaronSpawn[1], afYoggSaronSpawn[2], afYoggSaronSpawn[3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_bIsHostile = true; + m_creature->SetInCombatWithZone(); + break; + case SPELL_PHASE_2_TRANSFORM: + // complete transition phase - board Yogg and infor the voice controller of phase switch + if (m_pInstance) + { + if (Creature* pYogg = m_pInstance->GetSingleCreatureFromStorage(NPC_YOGGSARON)) + DoCastSpellIfCan(pYogg, SPELL_RIDE_VEHICLE_YOGG, CAST_TRIGGERED); + if (Creature* pVoice = m_pInstance->GetSingleCreatureFromStorage(NPC_VOICE_OF_YOGG)) + SendAIEvent(AI_EVENT_START_EVENT_A, m_creature, pVoice); + m_uiPhase = PHASE_VISIONS; + } + break; + } + } + + // wrapper to initialise keeper helpers + void DoInitialiseKeepers() + { + if (!m_pInstance) + return; + + uint8 uiKeeperCount = 0; + + if (m_pInstance->GetData(TYPE_KEEPER_FREYA) == DONE) + { + if (Creature* pHelper = m_pInstance->GetSingleCreatureFromStorage(NPC_FREYA_HELPER)) + { + pHelper->CastSpell(pHelper, SPELL_SUMMON_SANITY_WELL, false); + pHelper->CastSpell(pHelper, SPELL_RESILIENCE_OF_NATURE, true); + ++uiKeeperCount; + } + } + + if (m_pInstance->GetData(TYPE_KEEPER_HODIR) == DONE) + { + if (Creature* pHelper = m_pInstance->GetSingleCreatureFromStorage(NPC_HODIR_HELPER)) + { + pHelper->CastSpell(pHelper, SPELL_HODIRS_PROTECTIVE_GAZE, false); + pHelper->CastSpell(pHelper, SPELL_FORTITUDE_OF_FROST, true); + ++uiKeeperCount; + } + } + + if (m_pInstance->GetData(TYPE_KEEPER_MIMIRON) == DONE) + { + if (Creature* pHelper = m_pInstance->GetSingleCreatureFromStorage(NPC_MIMIRON_HELPER)) + { + pHelper->CastSpell(pHelper, SPELL_SPEED_OF_INVENTION, true); + SendAIEvent(AI_EVENT_START_EVENT, m_creature, pHelper); + ++uiKeeperCount; + } + } + + if (m_pInstance->GetData(TYPE_KEEPER_THORIM) == DONE) + { + if (Creature* pHelper = m_pInstance->GetSingleCreatureFromStorage(NPC_THORIM_HELPER)) + { + pHelper->CastSpell(pHelper, SPELL_TITANIC_STORM, false); + pHelper->CastSpell(pHelper, SPELL_FURY_OF_THE_STORM, true); + ++uiKeeperCount; + } + } + + // set hard mode data + m_pInstance->SetData(TYPE_YOGGSARON_HARD, uiKeeperCount); + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (m_uiPhase == PHASE_SARA) + { + if (m_uiSarasSpellTimer < uiDiff) + { + CanCastResult castResult = CAST_OK; + switch (urand(0, 2)) + { + case 0: castResult = DoCastSpellIfCan(m_creature, SPELL_SARAS_FERVOR); break; + case 1: castResult = DoCastSpellIfCan(m_creature, SPELL_SARAS_BLESSING); break; + case 2: castResult = DoCastSpellIfCan(m_creature, SPELL_SARAS_ANGER); break; + } + + if (castResult == CAST_OK) + { + if (roll_chance_i(30)) + DoScriptText(urand(0, 1) ? SAY_SARA_HELP_1 : SAY_SARA_HELP_2, m_creature); + + m_uiSarasSpellTimer = 5000; + } + } + else + m_uiSarasSpellTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPhase == PHASE_VISIONS) + { + if (m_uiPsychosisTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_PHYCHOSIS : SPELL_PHYCHOSIS_H) == CAST_OK) + { + if (roll_chance_i(10)) + DoScriptText(SAY_SARA_PHYCHOSIS, m_creature); + + m_uiPsychosisTimer = urand(3000, 4000); + } + } + else + m_uiPsychosisTimer -= uiDiff; + + if (m_uiMaladyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_MALADY_OF_THE_MIND) == CAST_OK) + m_uiMaladyTimer = 15000; + } + else + m_uiMaladyTimer -= uiDiff; + + if (m_uiBrainLinkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BRAIN_LINK) == CAST_OK) + m_uiBrainLinkTimer = 25000; + } + else + m_uiBrainLinkTimer -= uiDiff; + + if (m_uiDeathRayTimer < uiDiff) + { + if (urand(0, 1)) + DoScriptText(SAY_SARA_DEATH_RAY, m_creature); + + // spawn death orb at predefined location + m_creature->CastSpell(1980.43f, -25.7708f, 351.5418f, SPELL_DEATH_RAY_SUMMON, true); + m_uiDeathRayTimer = 20000; + } + else + m_uiDeathRayTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_sara(Creature* pCreature) +{ + return new boss_saraAI(pCreature); +} + +/*###### +## boss_yogg_saron +######*/ + +struct boss_yogg_saronAI : public Scripted_NoMovementAI +{ + boss_yogg_saronAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint8 m_uiPhase; + + uint32 m_uiLunaticGazeTimer; + uint32 m_uiDeafeningRoarTimer; + uint32 m_uiShadowBeaconTimer; + + void Reset() override + { + m_uiPhase = PHASE_VISIONS; + m_uiLunaticGazeTimer = 15000; + m_uiShadowBeaconTimer = 45000; + + // deafening roar only available in 25man mode with 3 keepers or less active + if (m_pInstance) + m_uiDeafeningRoarTimer = (!m_bIsRegularMode && m_pInstance->GetData(TYPE_YOGGSARON_HARD) <= 3) ? 20000 : 0; + } + + void JustReachedHome() override + { + // unboard passengers first to avoid issues + m_creature->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_YOGGSARON) != FAIL) + m_pInstance->SetData(TYPE_YOGGSARON, FAIL); + } + + m_creature->ForcedDespawn(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + // AI event received at 30% health + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetEntry() == NPC_YOGG_BRAIN && m_uiPhase == PHASE_VISIONS) + { + DoScriptText(SAY_PHASE_3, m_creature); + m_uiPhase = PHASE_OLD_GOD; + m_creature->RemoveAurasDueToSpell(SPELL_KNOCK_AWAY); + m_creature->RemoveAurasDueToSpell(SPELL_SHADOWY_BARRIER_YOGG); + + // despawn Sara and inform the voice controller of phase switch + if (m_pInstance) + { + if (Creature* pSara = m_pInstance->GetSingleCreatureFromStorage(NPC_SARA)) + pSara->ForcedDespawn(); + if (Creature* pVoice = m_pInstance->GetSingleCreatureFromStorage(NPC_VOICE_OF_YOGG)) + SendAIEvent(AI_EVENT_START_EVENT_B, m_creature, pVoice); + } + } + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(SAY_SLAY, m_creature); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_YOGGSARON, DONE); + + DoScriptText(SAY_DEATH, m_creature); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // last phase spells + if (m_uiPhase == PHASE_OLD_GOD) + { + if (m_uiLunaticGazeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LUNATIC_GAZE_YOGG) == CAST_OK) + { + if (urand(0, 1)) + DoPlaySoundToSet(m_creature, SOUND_ID_LUNATIC_GAZE); + + m_uiLunaticGazeTimer = 12000; + } + } + else + m_uiLunaticGazeTimer -= uiDiff; + + if (m_uiShadowBeaconTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_BEACON) == CAST_OK) + { + DoScriptText(EMOTE_EMPOWERING_SHADOWS, m_creature); + m_uiShadowBeaconTimer = 45000; + } + } + else + m_uiShadowBeaconTimer -= uiDiff; + + if (m_uiDeafeningRoarTimer) + { + if (m_uiDeafeningRoarTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEAFENING_ROAR) == CAST_OK) + { + DoScriptText(EMOTE_DEAFENING_ROAR, m_creature); + m_uiDeafeningRoarTimer = 20000; + } + } + else + m_uiDeafeningRoarTimer -= uiDiff; + } + } + } +}; + +CreatureAI* GetAI_boss_yogg_saron(Creature* pCreature) +{ + return new boss_yogg_saronAI(pCreature); +} + +/*###### +## npc_voice_yogg_saron +######*/ + +struct npc_voice_yogg_saronAI : public Scripted_NoMovementAI +{ + npc_voice_yogg_saronAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + for (uint8 i = 0; i < MAX_ILLUSIONS; ++i) + m_vuiMadnessPhases.push_back(i); + + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint8 m_uiPhase; + uint8 m_uiMaxPortals; + uint8 m_uiPortalsCount; + + uint32 m_uiBerserkTimer; + uint32 m_uiSanityCheckTimer; + uint32 m_uiSummonGuardianTimer; + uint32 m_uiCrusherTentacleTimer; + uint32 m_uiCorruptorTentacleTimer; + uint32 m_uiConstrictorTentacleTimer; + uint32 m_uiMadnessTimer; + uint32 m_uiGuardianTimer; + + std::vector m_vuiMadnessPhases; + + void Reset() override + { + m_uiPhase = PHASE_INTRO; + m_uiBerserkTimer = 0; + m_uiSanityCheckTimer = 0; + m_uiSummonGuardianTimer = 1000; + m_uiCrusherTentacleTimer = 1000; + m_uiCorruptorTentacleTimer = 1000; + m_uiConstrictorTentacleTimer = 1000; + m_uiMadnessTimer = 60000; + m_uiGuardianTimer = 1000; + + m_uiPortalsCount = 0; + m_uiMaxPortals = m_bIsRegularMode ? 4 : 10; + + std::random_shuffle(m_vuiMadnessPhases.begin(), m_vuiMadnessPhases.end()); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + switch (eventType) + { + case AI_EVENT_START_EVENT: + m_uiPhase = PHASE_SARA; + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; + + // start sanity + m_uiSanityCheckTimer = 15000; + DoCastSpellIfCan(m_creature, SPELL_SANITY); + break; + case AI_EVENT_START_EVENT_A: + m_uiPhase = PHASE_VISIONS; + break; + case AI_EVENT_START_EVENT_B: + m_uiPhase = PHASE_OLD_GOD; + break; + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_DESCEND_INTO_MADNESS: + SendAIEvent(AI_EVENT_START_EVENT, m_creature, pSummoned, aMadnessTeleportSpells[m_uiPortalsCount]); + pSummoned->CastSpell(pSummoned, SPELL_TELEPORT_PORTAL_VISUAL, true); + break; + case NPC_CONSTRICTOR_TENTACLE: + pSummoned->CastSpell(pSummoned, SPELL_TENTACLE_VOID_ZONE, true); + pSummoned->CastSpell(pSummoned, SPELL_ERUPT, true); + pSummoned->CastSpell(pSummoned, SPELL_LUNGE, true); + pSummoned->SetInCombatWithZone(); + break; + case NPC_CRUSHER_TENTACLE: + pSummoned->CastSpell(pSummoned, SPELL_TENTACLE_VOID_ZONE_BIG, true); + pSummoned->CastSpell(pSummoned, SPELL_CRUSH, true); + pSummoned->CastSpell(pSummoned, SPELL_DIMINISH_POWER, true); + pSummoned->CastSpell(pSummoned, SPELL_FOCUSED_ANGER, true); + pSummoned->CastSpell(pSummoned, SPELL_ERUPT, true); + pSummoned->SetInCombatWithZone(); + break; + case NPC_CORRUPTOR_TENTACLE: + pSummoned->CastSpell(pSummoned, SPELL_TENTACLE_VOID_ZONE_BIG, true); + pSummoned->CastSpell(pSummoned, SPELL_ERUPT, true); + pSummoned->SetInCombatWithZone(); + break; + case NPC_IMMORTAL_GUARDIAN: + pSummoned->CastSpell(pSummoned, SPELL_EMPOWERED, true); + pSummoned->CastSpell(pSummoned, SPELL_EMPOWERED_MOD, true); + pSummoned->CastSpell(pSummoned, SPELL_RECENTLY_SPAWNED, true); + pSummoned->CastSpell(pSummoned, SPELL_SIMPLE_TELEPORT, true); + pSummoned->SetInCombatWithZone(); + break; + } + } + + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_INSANE && pTarget->GetTypeId() == TYPEID_PLAYER && m_pInstance) + { + if (Creature* pYogg = m_pInstance->GetSingleCreatureFromStorage(NPC_YOGGSARON)) + DoScriptText(urand(0, 1) ? SAY_TO_INSANE_1 : SAY_TO_INSANE_2, pYogg, pTarget); + + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_DRIVE_CRAZY, false); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiBerserkTimer) + { + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXTINGUISH_LIFE) == CAST_OK) + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; + } + + if (m_uiSanityCheckTimer) + { + if (m_uiSanityCheckTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INSANE_PERIODIC) == CAST_OK) + m_uiSanityCheckTimer = 0; + } + else + m_uiSanityCheckTimer -= uiDiff; + } + + if (m_uiPhase == PHASE_SARA) + { + if (m_uiSummonGuardianTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_GUARDIAN_YOGG) == CAST_OK) + m_uiSummonGuardianTimer = 20000; + } + else + m_uiSummonGuardianTimer -= uiDiff; + } + else if (m_uiPhase == PHASE_VISIONS) + { + if (m_uiCorruptorTentacleTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CORRUPTOR_TENTACLE) == CAST_OK) + m_uiCorruptorTentacleTimer = 30000; + } + else + m_uiCorruptorTentacleTimer -= uiDiff; + + if (m_uiCrusherTentacleTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CRUSHER_TENTACLE) == CAST_OK) + m_uiCrusherTentacleTimer = 60000; + } + else + m_uiCrusherTentacleTimer -= uiDiff; + + if (m_uiConstrictorTentacleTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CONSTRICTOR_TENTACLE) == CAST_OK) + m_uiConstrictorTentacleTimer = 25000; + } + else + m_uiConstrictorTentacleTimer -= uiDiff; + + if (m_uiMadnessTimer < uiDiff) + { + // no more portals if we already had 3 + if (m_uiPortalsCount == MAX_ILLUSIONS) + { + m_uiMadnessTimer = m_uiBerserkTimer * 2; + return; + } + + if (!m_pInstance) + return; + + // infor the brain about the current illusion + if (Creature* pBrain = m_pInstance->GetSingleCreatureFromStorage(NPC_YOGG_BRAIN)) + SendAIEvent(AI_EVENT_START_EVENT, m_creature, pBrain, m_uiPortalsCount); + + if (Creature* pYogg = m_pInstance->GetSingleCreatureFromStorage(NPC_YOGGSARON)) + DoScriptText(SAY_MADNESS, pYogg); + + float fX, fY, fZ, fAng; + for (uint8 i = 0; i < m_uiMaxPortals; ++i) + { + fAng = (2 * M_PI_F / m_uiMaxPortals) * i; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 22.0f, fAng); + m_creature->SummonCreature(NPC_DESCEND_INTO_MADNESS, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + } + + DoScriptText(EMOTE_VISION_BLAST, m_creature); + ++m_uiPortalsCount; + m_uiMadnessTimer = 90000; + } + else + m_uiMadnessTimer -= uiDiff; + } + else if (m_uiPhase == PHASE_OLD_GOD) + { + if (m_uiGuardianTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_IMMORTAL_GUARDIAN) == CAST_OK) + m_uiGuardianTimer = 15000; + } + else + m_uiGuardianTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_voice_yogg_saron(Creature* pCreature) +{ + return new npc_voice_yogg_saronAI(pCreature); +} + +/*###### +## npc_brain_yogg_saron +######*/ + +struct npc_brain_yogg_saronAI : public Scripted_NoMovementAI, private DialogueHelper +{ + npc_brain_yogg_saronAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature), + DialogueHelper(aYoggIllusionsDialog) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + instance_ulduar* m_pInstance; + + uint8 m_uiIllusionIndex; + uint32 m_uiIllusionTimer; + + bool m_bBrainDefeated; + + GuidList m_lTentaclesGuids; + + void Reset() override + { + m_uiIllusionTimer = 0; + m_uiIllusionIndex = 0; + + m_bBrainDefeated = false; + + DoCastSpellIfCan(m_creature, SPELL_MATCH_HEALTH); + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + // start illusion when informed by the voice controller + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetEntry() == NPC_VOICE_OF_YOGG) + { + if (DoCastSpellIfCan(m_creature, SPELL_INDUCE_MADNESS) == CAST_OK) + { + m_lTentaclesGuids.clear(); + DoPrepareIllusion(uiMiscValue); + m_uiIllusionIndex = uiMiscValue; + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_LAUGHING_SKULL: + pSummoned->CastSpell(pSummoned, SPELL_LUNATIC_GAZE_SKULL, false); + break; + case NPC_SUIT_OF_ARMOR: + pSummoned->CastSpell(pSummoned, SPELL_NONDESCRIPT_ARMOR, true); + pSummoned->CastSpell(pSummoned, SPELL_GRIM_REPRISAL, true); + m_lTentaclesGuids.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_DEATHSWORM_ZEALOT: + case NPC_RUBY_CONSORT: + case NPC_OBSIDIAN_CONSORT: + case NPC_AZURE_CONSORT: + case NPC_EMERALD_CONSORT: + pSummoned->CastSpell(pSummoned, SPELL_NONDESCRIPT_CREATURE, true); + pSummoned->CastSpell(pSummoned, SPELL_GRIM_REPRISAL, true); + m_lTentaclesGuids.push_back(pSummoned->GetObjectGuid()); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_INFLUENCE_TENTACLE) + m_lTentaclesGuids.remove(pSummoned->GetObjectGuid()); + + // open door and stun all tentacles + if (m_lTentaclesGuids.empty()) + { + DoScriptText(EMOTE_SHATTER_BLAST, m_creature); + DoCastSpellIfCan(m_creature, SPELL_SHATTERED_ILLUSION, CAST_TRIGGERED); + m_uiIllusionTimer = 30000; + + if (!m_pInstance) + return; + + m_pInstance->DoUseDoorOrButton(aMadnessChamberDoors[m_uiIllusionIndex]); + + // respawn all nearby portals + std::list lFleePortals; + GetGameObjectListWithEntryInGrid(lFleePortals, m_creature, GO_FLEE_TO_SURFACE, 40.0f); + + for (std::list::const_iterator itr = lFleePortals.begin(); itr != lFleePortals.end(); ++itr) + m_pInstance->DoRespawnGameObject((*itr)->GetObjectGuid(), 30); + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + if (!m_pInstance) + return; + + switch (iEntry) + { + case SPELL_ASSASSINATE: + if (Creature* pGarona = m_pInstance->GetSingleCreatureFromStorage(NPC_GARONA)) + pGarona->CastSpell(pGarona, SPELL_ASSASSINATE, true); + break; + case SAY_LICH_KING_1: + if (Creature* pLichKing = m_pInstance->GetSingleCreatureFromStorage(NPC_LICH_KING)) + pLichKing->CastSpell(pLichKing, SPELL_DEATHGRASP, false); + break; + } + } + + // Wrapper that prepars the illusions + void DoPrepareIllusion(uint8 uiIndex) + { + switch (uiIndex) + { + // stormwind + case 0: + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1955.173f, 85.26153f, 239.7496f, 4.049f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1893.146f, 44.24343f, 239.7496f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1944.962f, 65.25938f, 240.4596f, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1956.503f, 72.19462f, 239.7495f, 3.281f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1951.04f, 49.88875f, 239.7495f, 2.495f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1931.14f, 38.46949f, 239.7495f, 1.710f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1908.993f, 44.26659f, 239.7495f, 0.295f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1897.344f, 64.31419f, 239.7495f, 0.139f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1903.393f, 86.60285f, 239.7495f, 5.619f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1923.342f, 98.01228f, 239.7495f, 4.834f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_SUIT_OF_ARMOR, 1945.442f, 92.17952f, 239.7495f, 4.049f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + // the following are guesswork + m_creature->SummonCreature(NPC_GARONA, 1931.348f, 61.0330f, 241.7094f, 2.008f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_KING_LLANE, 1930.465f, 62.6740f, 242.3763f, 5.196f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_YOGGSARON_ILLUSION, 1927.326f, 68.120f, 242.376f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + + // start dialogue + StartNextDialogueText(NPC_KING_LLANE); + break; + // chamber + case 1: + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 2063.156f, 27.95839f, 244.2707f, 5.288f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 2061.257f, -53.8788f, 239.8633f, 2.478f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_RUBY_CONSORT, 2069.479f, -5.699653f, 239.8058f, 5.427f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_RUBY_CONSORT, 2069.298f, -43.53168f, 239.8006f, 0.471f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + // the following are guesswork + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 2125.891f, -62.390f, 239.721f, 2.197f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 2115.778f, 21.288f, 239.746f, 4.282f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_OBSIDIAN_CONSORT, 2144.349f, -36.108f, 239.719f, 3.116f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_OBSIDIAN_CONSORT, 2143.837f, -17.539f, 239.733f, 3.179f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_AZURE_CONSORT, 2139.173f, -51.239f, 239.747f, 2.413f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_AZURE_CONSORT, 2112.182f, -65.787f, 239.721f, 1.651f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_EMERALD_CONSORT, 2110.621f, 15.579f, 239.758f, 4.644f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_EMERALD_CONSORT, 2137.336f, 5.452f, 239.717f, 3.866f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_NELTHARION, 2117.588f, -25.318f, 242.646f, 3.15f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_ALEXSTRASZA, 2091.679f, -25.289f, 242.646f, 6.282f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_YSERA, 2114.504f, -16.118f, 242.646f, 3.91f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_MALYGOS, 2113.388f, -34.381f, 242.646f, 2.26f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_YOGGSARON_ILLUSION, 2104.555f, -25.635f, 242.646f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + + // start dialogue + StartNextDialogueText(NPC_NELTHARION); + break; + // icecrown + case 2: + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1948.668f, -152.4481f, 240.073f, 1.919f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1879.845f, -72.91819f, 240.073f, 5.689f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1905.937f, -133.1651f, 240.073f, 5.777f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LAUGHING_SKULL, 1935.621f, -121.0064f, 240.073f, 3.630f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1917.559f, -135.7448f, 240.073f, 4.188f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1919.125f, -140.9566f, 240.073f, 3.979f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1948.469f, -136.2951f, 240.0707f, 3.438f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1956.444f, -138.4028f, 240.1078f, 3.368f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1912.129f, -136.934f, 240.073f, 4.188f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1952.965f, -130.5295f, 240.1347f, 3.804f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1902.132f, -111.3594f, 240.0698f, 4.852f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1905.326f, -104.7865f, 240.0523f, 4.764f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_DEATHSWORM_ZEALOT, 1897.345f, -106.6076f, 240.1444f, 4.939f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_LICH_KING, 1908.557f, -152.4427f, 240.0719f, 4.238f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + // the following is guesswork + m_creature->SummonCreature(NPC_IMMOLATED_CHAMPION, 1915.371f, -139.9342f, 239.9896f, 4.159f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + m_creature->SummonCreature(NPC_YOGGSARON_ILLUSION, 1915.371f, -139.9342f, 239.9896f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 90000); + + // start dialogue + StartNextDialogueText(NPC_LICH_KING); + break; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + // remove stun from tentacles after 30 sec + if (m_uiIllusionTimer) + { + if (m_uiIllusionTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHATTERED_ILLUSION_REMOVE) == CAST_OK) + m_uiIllusionTimer = 0; + } + else + m_uiIllusionTimer -= uiDiff; + } + + // inform Yogg that health has dropped + if (!m_bBrainDefeated && m_creature->GetHealthPercent() < 30.0f) + { + m_uiIllusionTimer = 0; + m_bBrainDefeated = true; + DoCastSpellIfCan(m_creature, SPELL_BRAIN_HURT_VISUAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SHATTERED_ILLUSION_REMOVE, CAST_TRIGGERED); + m_creature->RemoveAurasDueToSpell(SPELL_MATCH_HEALTH); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + + if (m_pInstance) + { + if (Creature* pYogg = m_pInstance->GetSingleCreatureFromStorage(NPC_YOGGSARON)) + SendAIEvent(AI_EVENT_START_EVENT, m_creature, pYogg); + } + } + } +}; + +CreatureAI* GetAI_npc_brain_yogg_saron(Creature* pCreature) +{ + return new npc_brain_yogg_saronAI(pCreature); +} + +/*###### +## npc_guardian_of_yogg +######*/ + +struct npc_guardian_of_yoggAI : public ScriptedAI +{ + npc_guardian_of_yoggAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + instance_ulduar* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiDarkVolleyTimer; + uint32 m_uiDominateMindTimer; + + void Reset() override + { + m_uiDarkVolleyTimer = 10000; + m_uiDominateMindTimer = 25000; + } + + void AttackStart(Unit* pWho) override + { + if (pWho->GetEntry() == NPC_SARA) + return; + + ScriptedAI::AttackStart(pWho); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_NOVA : SPELL_SHADOW_NOVA_H, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_YOGGSARON) != FAIL) + { + if (Creature* pVoice = m_pInstance->GetSingleCreatureFromStorage(NPC_VOICE_OF_YOGG)) + { + Map::PlayerList const& lPlayers = m_pInstance->instance->GetPlayers(); + + if (lPlayers.isEmpty()) + return; + + // whisper to all players + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + DoScriptText(SAY_WIPE_PHASE_1, pVoice, pPlayer); + } + } + + m_pInstance->SetData(TYPE_YOGGSARON, FAIL); + } + } + + m_creature->ForcedDespawn(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiDarkVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DARK_VOLLEY) == CAST_OK) + m_uiDarkVolleyTimer = urand(10000, 25000); + } + else + m_uiDarkVolleyTimer -= uiDiff; + + if (m_uiDominateMindTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DOMINATE_MIND) == CAST_OK) + m_uiDominateMindTimer = urand(30000, 40000); + } + else + m_uiDominateMindTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_guardian_of_yogg(Creature* pCreature) +{ + return new npc_guardian_of_yoggAI(pCreature); +} + +/*###### +## npc_immortal_guardian +######*/ + +struct npc_immortal_guardianAI : public ScriptedAI +{ + npc_immortal_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + bool m_bWeakened; + + uint32 m_uiDrainLifeTimer; + + void Reset() override + { + m_uiDrainLifeTimer = 10000; + m_bWeakened = false; + } + + void DamageTaken(Unit* pDealer, uint32& uiDamage) override + { + if (pDealer->GetEntry() == NPC_THORIM_HELPER) + return; + + if (uiDamage >= m_creature->GetHealth()) + { + uiDamage = 0; + + // mark as weakened for Thorim + if (!m_bWeakened) + { + if (DoCastSpellIfCan(m_creature, SPELL_WEAKENED) == CAST_OK) + m_bWeakened = true; + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiDrainLifeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_DRAIN_LIFE : SPELL_DRAIN_LIFE_H) == CAST_OK) + m_uiDrainLifeTimer = urand(10000, 15000); + } + } + else + m_uiDrainLifeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_immortal_guardian(Creature* pCreature) +{ + return new npc_immortal_guardianAI(pCreature); +} + +bool EffectDummyCreature_npc_immortal_guardian(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // NOTE: this may not be 100% correct and may require additional research + if (uiSpellId == SPELL_EMPOWERED && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_IMMORTAL_GUARDIAN) + { + uint8 uiProjectedStacks = pCreatureTarget->GetHealthPercent() * 0.1 - 1; + uint8 uiCurrentStacks = 0; + + if (SpellAuraHolder* pEmpowerAura = pCreatureTarget->GetSpellAuraHolder(SPELL_EMPOWERED_MOD)) + uiCurrentStacks = pEmpowerAura->GetStackAmount(); + + // if creature already has the required stacks, ignore + if (uiProjectedStacks == uiCurrentStacks) + return true; + + if (uiCurrentStacks > uiProjectedStacks) + pCreatureTarget->RemoveAuraHolderFromStack(SPELL_EMPOWERED_MOD, uiCurrentStacks - uiProjectedStacks); + else + { + for (uint8 i = 0; i < uiProjectedStacks - uiCurrentStacks; ++i) + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_EMPOWERED_MOD, true); + } + + if (uiCurrentStacks == 0 && uiCurrentStacks < uiProjectedStacks) + pCreatureTarget->RemoveAurasDueToSpell(SPELL_WEAKENED); + + return true; + } + + return false; +} + +/*###### +## npc_constrictor_tentacle +######*/ + +struct npc_constrictor_tentacleAI : public Scripted_NoMovementAI +{ + npc_constrictor_tentacleAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + bool m_bIsRegularMode; + + void Reset() override { } + + void JustDied(Unit* /*pKiller*/) override + { + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(((TemporarySummon*)m_creature)->GetSummonerGuid())) + pSummoner->RemoveAurasDueToSpell(m_bIsRegularMode ? SPELL_SQUEEZE : SPELL_SQUEEZE_H); + } +}; + +CreatureAI* GetAI_npc_constrictor_tentacle(Creature* pCreature) +{ + return new npc_constrictor_tentacleAI(pCreature); +} + +/*###### +## npc_ominous_cloud +######*/ + +struct npc_ominous_cloudAI : public Scripted_NoMovementAI +{ + npc_ominous_cloudAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiDelayTimer; + + void Reset() override + { + m_uiDelayTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_uiDelayTimer && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, 7.0f)) + { + if (DoCastSpellIfCan(m_creature, SPELL_BOIL_OMNIOUSLY) == CAST_OK) + { + DoScriptText(EMOTE_CLOUD_BOIL, m_creature, pWho); + m_uiDelayTimer = 10000; + } + } + } + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_SUMMON_GUARDIAN_YOGG) + m_uiDelayTimer = 10000; + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_GUARDIAN_OF_YOGG) + pSummoned->SetInCombatWithZone(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDelayTimer) + { + if (m_uiDelayTimer <= uiDiff) + m_uiDelayTimer = 0; + else + m_uiDelayTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_ominous_cloud(Creature* pCreature) +{ + return new npc_ominous_cloudAI(pCreature); +} + +/*###### +## npc_death_ray +######*/ + +struct npc_death_rayAI : public ScriptedAI +{ + npc_death_rayAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiDeathRayTimer; + + void Reset() override + { + m_uiDeathRayTimer = 5000; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* pWho) override { } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDeathRayTimer) + { + if (m_uiDeathRayTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEATH_RAY_VISUAL_DAMAGE, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoCastSpellIfCan(m_creature, SPELL_DEATH_RAY_TRIGG, CAST_TRIGGERED); + m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f); + m_uiDeathRayTimer = 0; + } + } + else + m_uiDeathRayTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_death_ray(Creature* pCreature) +{ + return new npc_death_rayAI(pCreature); +} + +/*###### +## npc_descent_madness +######*/ + +struct npc_descent_madnessAI : public Scripted_NoMovementAI +{ + npc_descent_madnessAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_uiCurentSpell = 0; + Reset(); + } + + uint32 m_uiCurentSpell; + + void Reset() override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_EVENT) + m_uiCurentSpell = uiMiscValue; + } + + uint32 GetCurrentSpell() { return m_uiCurentSpell; } +}; + +CreatureAI* GetAI_npc_descent_madness(Creature* pCreature) +{ + return new npc_descent_madnessAI(pCreature); +} + +bool NpcSpellClick_npc_descent_madness(Player* pPlayer, Creature* pClickedCreature, uint32 /*uiSpellId*/) +{ + if (pClickedCreature->GetEntry() == NPC_DESCEND_INTO_MADNESS) + { + uint32 uiClickSpell = 0; + if (npc_descent_madnessAI* pDescentAI = dynamic_cast(pClickedCreature->AI())) + uiClickSpell = pDescentAI->GetCurrentSpell(); + + if (!uiClickSpell) + return true; + + pPlayer->CastSpell(pPlayer, uiClickSpell, true); + pClickedCreature->ForcedDespawn(); + return true; + } + + return true; +} + +/*###### +## npc_laughing_skull +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_laughing_skullAI : public Scripted_NoMovementAI +{ + npc_laughing_skullAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_laughing_skull(Creature* pCreature) +{ + return new npc_laughing_skullAI(pCreature); +} + +/*###### +## npc_keeper_mimiron +######*/ + +struct npc_keeper_mimironAI : public Scripted_NoMovementAI +{ + npc_keeper_mimironAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiMatrixTimer; + + void Reset() override + { + m_uiMatrixTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetEntry() == NPC_SARA) + m_uiMatrixTimer = 30000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiMatrixTimer) + { + if (m_uiMatrixTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DESTABILIZATION_MATRIX) == CAST_OK) + m_uiMatrixTimer = 30000; + } + else + m_uiMatrixTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_keeper_mimiron(Creature* pCreature) +{ + return new npc_keeper_mimironAI(pCreature); +} + +/*###### +## npc_keeper_thorim +######*/ + +// TODO Remove this 'script' when combat can be proper prevented from core-side +struct npc_keeper_thorimAI : public Scripted_NoMovementAI +{ + npc_keeper_thorimAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_keeper_thorim(Creature* pCreature) +{ + return new npc_keeper_thorimAI(pCreature); +} + void AddSC_boss_yogg_saron() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_sara"; + pNewScript->GetAI = &GetAI_boss_sara; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "boss_yogg_saron"; + pNewScript->GetAI = &GetAI_boss_yogg_saron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_voice_yogg_saron"; + pNewScript->GetAI = &GetAI_npc_voice_yogg_saron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_brain_yogg_saron"; + pNewScript->GetAI = &GetAI_npc_brain_yogg_saron; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_guardian_of_yogg"; + pNewScript->GetAI = &GetAI_npc_guardian_of_yogg; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_immortal_guardian"; + pNewScript->GetAI = &GetAI_npc_immortal_guardian; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_immortal_guardian; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_constrictor_tentacle"; + pNewScript->GetAI = &GetAI_npc_constrictor_tentacle; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ominous_cloud"; + pNewScript->GetAI = &GetAI_npc_ominous_cloud; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_death_ray"; + pNewScript->GetAI = &GetAI_npc_death_ray; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_descent_madness"; + pNewScript->GetAI = &GetAI_npc_descent_madness; + pNewScript->pNpcSpellClick = &NpcSpellClick_npc_descent_madness; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_laughing_skull"; + pNewScript->GetAI = &GetAI_npc_laughing_skull; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_keeper_mimiron"; + pNewScript->GetAI = &GetAI_npc_keeper_mimiron; + pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_keeper_thorim"; + pNewScript->GetAI = &GetAI_npc_keeper_thorim; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp b/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp index 0c6f982cd..53e02fcf9 100644 --- a/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp +++ b/scripts/northrend/ulduar/ulduar/instance_ulduar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,28 +16,69 @@ /* ScriptData SDName: instance_ulduar -SD%Complete: -SDComment: +SD%Complete: +SDComment: SDCategory: Ulduar EndScriptData */ #include "precompiled.h" #include "ulduar.h" -struct sSpawnLocation +enum { - float m_fX, m_fY, m_fZ, m_fO; + SAY_PRE_LEVIATHAN_1 = -1603239, + SAY_PRE_LEVIATHAN_2 = -1603240, + SAY_PRE_LEVIATHAN_3 = -1603241, + + SAY_FREYA_HELP = -1603009, + SAY_HODIR_HELP = -1603093, + SAY_THORIM_HELP = -1603155, + SAY_MIMIRON_HELP = -1603195, + + SPELL_KEEPER_ACTIVE = 62647, + SPELL_CLEAR_INSANE = 63122, // clear all the sanity and insane on wipe / death +}; + +static const DialogueEntry aUlduarDialogue[] = +{ + {SAY_PRE_LEVIATHAN_1, NPC_BRONZEBEARD_RADIO, 7000}, + {SAY_PRE_LEVIATHAN_2, NPC_BRONZEBEARD_RADIO, 5000}, + {SAY_PRE_LEVIATHAN_3, NPC_BRONZEBEARD_RADIO, 2000}, + {NPC_LEVIATHAN, 0, 0}, + {0, 0, 0} +}; + +struct UlduarKeeperSpawns +{ + float fX, fY, fZ, fO; + uint32 uiEntry, uiType; + int32 iText; +}; + +static UlduarKeeperSpawns m_aKeepersSpawnLocs[] = +{ + {1945.682f, 33.34201f, 411.4408f, 5.270f, NPC_KEEPER_FREYA, TYPE_FREYA, 0}, + {2028.766f, 17.42014f, 411.4446f, 3.857f, NPC_KEEPER_MIMIRON, TYPE_MIMIRON, 0}, + {1945.761f, -81.52171f, 411.4407f, 1.029f, NPC_KEEPER_HODIR, TYPE_HODIR, 0}, + {2028.822f, -65.73573f, 411.4426f, 2.460f, NPC_KEEPER_THORIM, TYPE_THORIM, 0}, }; -static sSpawnLocation m_aKeepersSpawnLocs[] = +static UlduarKeeperSpawns m_aKeeperHelperLocs[] = { - {2036.892f, 25.621f, 411.358f, 3.83f}, // Freya - {1939.215f, 42.677f, 411.355f, 5.31f}, // Mimiron - {1939.195f, -90.662f, 411.357f, 1.06f}, // Hodir - {2036.674f, -73.814f, 411.355f, 2.51f}, // Thorim + {2036.873f, 25.42513f, 338.4984f, 3.909f, NPC_FREYA_HELPER, TYPE_KEEPER_FREYA, SAY_FREYA_HELP}, + {2036.658f, -73.58822f, 338.4985f, 2.460f, NPC_MIMIRON_HELPER, TYPE_KEEPER_MIMIRON, SAY_MIMIRON_HELP}, + {1939.045f, -90.87457f, 338.5426f, 0.994f, NPC_HODIR_HELPER, TYPE_KEEPER_HODIR, SAY_HODIR_HELP}, + {1939.148f, 42.49035f, 338.5427f, 5.235f, NPC_THORIM_HELPER, TYPE_KEEPER_THORIM, SAY_THORIM_HELP}, }; -instance_ulduar::instance_ulduar(Map* pMap) : ScriptedInstance(pMap) +instance_ulduar::instance_ulduar(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aUlduarDialogue), + m_bHelpersLoaded(false), + m_uiAlgalonTimer(MINUTE* IN_MILLISECONDS), + m_uiYoggResetTimer(0), + m_uiShatterAchievTimer(0), + m_uiGauntletStatus(0), + m_uiStairsSpawnTimer(0), + m_uiSlayedArenaMobs(0) { Initialize(); } @@ -47,14 +88,78 @@ void instance_ulduar::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); memset(&m_auiHardBoss, 0, sizeof(m_auiHardBoss)); memset(&m_auiUlduarKeepers, 0, sizeof(m_auiUlduarKeepers)); + memset(&m_auiUlduarTowers, 0, sizeof(m_auiUlduarTowers)); + + InitializeDialogueHelper(this); for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS; ++i) m_abAchievCriteria[i] = false; } +void instance_ulduar::OnPlayerEnter(Player* pPlayer) +{ + // spawn Flame Leviathan if necessary + if (GetData(TYPE_LEVIATHAN) == SPECIAL || GetData(TYPE_LEVIATHAN) == FAIL) + { + if (!GetSingleCreatureFromStorage(NPC_LEVIATHAN, true)) + { + pPlayer->SummonCreature(NPC_LEVIATHAN, afLeviathanMovePos[0], afLeviathanMovePos[1], afLeviathanMovePos[2], afLeviathanMovePos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + DoCallLeviathanHelp(); + } + } + + // spawn Brann at the archivum if necessary + if (GetData(TYPE_ASSEMBLY) == DONE) + { + if (!GetSingleCreatureFromStorage(NPC_BRANN_ARCHIVUM, true)) + { + pPlayer->SummonCreature(NPC_BRANN_ARCHIVUM, afBrannArchivumSpawnPos[0], afBrannArchivumSpawnPos[1], afBrannArchivumSpawnPos[2], afBrannArchivumSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + pPlayer->SummonCreature(instance->IsRegularDifficulty() ? NPC_PROSPECTOR_DOREN : NPC_PROSPECTOR_DOREN_H, afProspectorSpawnPos[0], afProspectorSpawnPos[1], afProspectorSpawnPos[2], afProspectorSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + } + } + + // spawn Algalon and init world states if necessary + if (GetData(TYPE_ALGALON_TIMER)) + { + if (!GetSingleCreatureFromStorage(NPC_ALGALON, true)) + pPlayer->SummonCreature(NPC_ALGALON, afAlgalonMovePos[0], afAlgalonMovePos[1], afAlgalonMovePos[2], afAlgalonMovePos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + + pPlayer->SendUpdateWorldState(WORLD_STATE_TIMER, 1); + pPlayer->SendUpdateWorldState(WORLD_STATE_TIMER_COUNT, GetData(TYPE_ALGALON_TIMER)); + } + + // spawn frienly keepers in the central hall, keeper helpers for Yogg-Saron and all the other faction npcs + if (!m_bHelpersLoaded) + { + for (uint8 i = 0; i < countof(m_aKeepersSpawnLocs); ++i) + { + if (GetData(m_aKeepersSpawnLocs[i].uiType) == DONE) + pPlayer->SummonCreature(m_aKeepersSpawnLocs[i].uiEntry, m_aKeepersSpawnLocs[i].fX, m_aKeepersSpawnLocs[i].fY, m_aKeepersSpawnLocs[i].fZ, m_aKeepersSpawnLocs[i].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true); + } + + if (GetData(TYPE_YOGGSARON) != DONE) + { + for (uint8 i = 0; i < countof(m_aKeeperHelperLocs); ++i) + { + if (GetData(m_aKeeperHelperLocs[i].uiType) == DONE) + pPlayer->SummonCreature(m_aKeeperHelperLocs[i].uiEntry, m_aKeeperHelperLocs[i].fX, m_aKeeperHelperLocs[i].fY, m_aKeeperHelperLocs[i].fZ, m_aKeeperHelperLocs[i].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true); + } + } + + DoSpawnHodirNpcs(pPlayer); + m_bHelpersLoaded = true; + } +} + +void instance_ulduar::OnPlayerDeath(Player* /*pPlayer*/) +{ + if (IsEncounterInProgress()) + SetData(TYPE_CHAMPION_FAILED, DONE); +} + bool instance_ulduar::IsEncounterInProgress() const { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i <= TYPE_ALGALON; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) return true; @@ -67,10 +172,14 @@ void instance_ulduar::OnCreatureCreate(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_LEVIATHAN: - case NPC_IGNIS: + case NPC_EXPLORER_DELLORAH: + case NPC_BRANN_BRONZEBEARD: + case NPC_ORBITAL_SUPPORT: case NPC_RAZORSCALE: - case NPC_COMMANDER: + case NPC_EXPEDITION_COMMANDER: case NPC_XT002: + case NPC_HEART_DECONSTRUCTOR: + case NPC_STEELBREAKER: case NPC_MOLGEIM: case NPC_BRUNDIR: @@ -79,10 +188,20 @@ void instance_ulduar::OnCreatureCreate(Creature* pCreature) case NPC_LEFT_ARM: case NPC_AURIAYA: case NPC_FERAL_DEFENDER: + case NPC_BRANN_ARCHIVUM: + case NPC_BRANN_ALGALON: + case NPC_LEVIATHAN_MK: + case NPC_LEVIATHAN_MK_TURRET: + case NPC_COMPUTER: + case NPC_VX001: + case NPC_AERIAL_UNIT: + case NPC_WORLD_TRIGGER_FLAMES: case NPC_RUNIC_COLOSSUS: case NPC_RUNE_GIANT: + case NPC_SIF: case NPC_JORMUNGAR_BEHEMOTH: + case NPC_THORIM_COMBAT_TRIGGER: case NPC_ELDER_BRIGHTLEAF: case NPC_ELDER_IRONBRACH: case NPC_ELDER_STONEBARK: @@ -91,42 +210,107 @@ void instance_ulduar::OnCreatureCreate(Creature* pCreature) case NPC_YOGGSARON: case NPC_SARA: case NPC_YOGG_BRAIN: + case NPC_VOICE_OF_YOGG: case NPC_ALGALON: - break; case NPC_MIMIRON: - if (m_auiEncounter[TYPE_MIMIRON] == DONE) - SpawnFriendlyKeeper(NPC_MIMIRON_IMAGE); - break; case NPC_HODIR: - if (m_auiEncounter[TYPE_HODIR] == DONE) - SpawnFriendlyKeeper(NPC_HODIR_IMAGE); - break; case NPC_THORIM: - if (m_auiEncounter[TYPE_THORIM] == DONE) - SpawnFriendlyKeeper(NPC_THORIM_IMAGE); - break; case NPC_FREYA: - if (m_auiEncounter[TYPE_FREYA] == DONE) - SpawnFriendlyKeeper(NPC_FREYA_IMAGE); + case NPC_THORIM_HELPER: + case NPC_MIMIRON_HELPER: + case NPC_HODIR_HELPER: + case NPC_FREYA_HELPER: + + case NPC_YSERA: + case NPC_NELTHARION: + case NPC_MALYGOS: + case NPC_ALEXSTRASZA: + case NPC_GARONA: + case NPC_KING_LLANE: + case NPC_LICH_KING: + case NPC_IMMOLATED_CHAMPION: + case NPC_YOGGSARON_ILLUSION: break; + case NPC_ULDUAR_COLOSSUS: + if (pCreature->GetPositionX() > 300.0f) + m_sColossusGuidSet.insert(pCreature->GetObjectGuid()); + return; + case NPC_EXPEDITION_DEFENDER: + m_lDefendersGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_EXPEDITION_ENGINEER: + m_lEngineersGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_EXPEDITION_TRAPPER: + m_lTrappersGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_RAZORSCALE_CONTROLLER: + // sort the controllers which are assigned to harpoons and allow the central one into the mail guid store + if (pCreature->GetPositionY() > -145.0f) + { + m_lHarpoonDummyGuids.push_back(pCreature->GetObjectGuid()); + return; + } + break; + case NPC_XT_TOY_PILE: + m_vToyPileGuidVector.push_back(pCreature->GetObjectGuid()); + return; + case NPC_RUBBLE_STALKER: + if (pCreature->GetPositionY() > -10.0f) + m_rightKoloStalkerGuid = pCreature->GetObjectGuid(); + else + m_leftKoloStalkerGuid = pCreature->GetObjectGuid(); + return; + case NPC_THORIM_EVENT_BUNNY: + // sort the event bunnies between the arena and tribune spawns; the platform spawns are ignored for the moment + if (pCreature->GetPositionZ() < 420.0f) + m_lThorimBunniesGuids.push_back(pCreature->GetObjectGuid()); + else if (pCreature->GetPositionZ() > 438.5f) + m_lUpperBunniesGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_THUNDER_ORB: + // get only the upper ones; the lower ones are searched dynamically in order to be paired correctly + if (pCreature->GetPositionZ() > 430.0f) + m_lUpperThunderOrbsGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_LEFT_HAND_BUNNY: + m_lLeftHandBunniesGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_RIGHT_HAND_BUNNY: + m_lRightHandBunniesGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_OMINOUS_CLOUD: + m_lOminousCloudsGuids.push_back(pCreature->GetObjectGuid()); + return; + case NPC_VEZAX_BUNNY: + if (pCreature->GetPositionY() < 100.0f) + m_animusVezaxBunnyGuid = pCreature->GetObjectGuid(); + else + m_vaporVezaxBunnyGuid = pCreature->GetObjectGuid(); + return; + default: return; - } - m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + } + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); } void instance_ulduar::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - // ----------------- Doors & Other ----------------- - // The siege + // ----------------- Doors & Other ----------------- + // The siege case GO_SHIELD_WALL: break; + case GO_LIGHTNING_DOOR: + if (m_auiEncounter[TYPE_LEVIATHAN] == SPECIAL || m_auiEncounter[TYPE_LEVIATHAN] == FAIL) + pGo->SetGoState(GO_STATE_READY); + break; case GO_LEVIATHAN_GATE: - if (m_auiEncounter[TYPE_LEVIATHAN] == DONE) + if (m_auiEncounter[TYPE_LEVIATHAN] != NOT_STARTED) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_XT002_GATE: @@ -136,117 +320,128 @@ void instance_ulduar::OnObjectCreate(GameObject* pGo) if (m_auiEncounter[TYPE_LEVIATHAN] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_BROKEN_HARPOON: - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + case GO_HODIR_CRYSTAL: + if (m_auiUlduarTowers[0] == FAIL) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_THORIM_CRYSTAL: + if (m_auiUlduarTowers[1] == FAIL) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_FREYA_CRYSTAL: + if (m_auiUlduarTowers[2] == FAIL) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_MIMIRON_CRYSTAL: + if (m_auiUlduarTowers[3] == FAIL) + pGo->SetGoState(GO_STATE_ACTIVE); break; - // Archivum + // Archivum case GO_IRON_ENTRANCE_DOOR: break; case GO_ARCHIVUM_DOOR: if (m_auiEncounter[TYPE_ASSEMBLY]) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_ARCHIVUM_CONSOLE: - case GO_UNIVERSE_FLOOR_ARCHIVUM: - // Celestial Planetarium + // Celestial Planetarium case GO_CELESTIAL_ACCES: - case GO_CELESTIAL_DOOR: - case GO_UNIVERSE_FLOOR_CELESTIAL: + case GO_CELESTIAL_ACCES_H: + // Note: weird, but unless flag is set, client will not respond as expected + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + break; + case GO_CELESTIAL_DOOR_1: + case GO_CELESTIAL_DOOR_2: + if (m_auiEncounter[TYPE_ALGALON] != NOT_STARTED) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_CELESTIAL_DOOR_COMBAT: + case GO_UNIVERSE_FLOOR: + case GO_UNIVERSE_FLOOR_COMBAT: case GO_AZEROTH_GLOBE: break; - // Shattered Hallway + // Shattered Hallway case GO_KOLOGARN_BRIDGE: - pGo->SetGoState(GO_STATE_ACTIVE); if (m_auiEncounter[TYPE_KOLOGARN] == DONE) pGo->SetGoState(GO_STATE_READY); break; - case GO_SHATTERED_DOOR: - break; - // ----------------- The Keepers ----------------- - // Hodir + // ----------------- The Keepers ----------------- + // Hodir case GO_HODIR_EXIT: - if (m_auiEncounter[TYPE_HODIR]) - pGo->SetGoState(GO_STATE_ACTIVE); - break; case GO_HODIR_ICE_WALL: - if (m_auiEncounter[TYPE_HODIR]) + if (m_auiEncounter[TYPE_HODIR] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_HODIR_ENTER: break; - // Mimiron - case G0_MIMIRON_BUTTON: - if (m_auiEncounter[TYPE_MIMIRON] == NOT_STARTED) - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); - break; + // Mimiron + case GO_MIMIRON_BUTTON: case GO_MIMIRON_DOOR_1: case GO_MIMIRON_DOOR_2: case GO_MIMIRON_DOOR_3: case GO_MIMIRON_ELEVATOR: - case GO_MIMIRON_TEL1: - case GO_MIMIRON_TEL2: - case GO_MIMIRON_TEL3: - case GO_MIMIRON_TEL4: - case GO_MIMIRON_TEL5: - case GO_MIMIRON_TEL6: - case GO_MIMIRON_TEL7: - case GO_MIMIRON_TEL8: - case GO_MIMIRON_TEL9: - // Thorim + // Thorim case GO_DARK_IRON_PORTCULIS: case GO_RUNED_STONE_DOOR: case GO_THORIM_STONE_DOOR: case GO_LIGHTNING_FIELD: - break; case GO_DOOR_LEVER: - pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; - // Prison + // Prison case GO_ANCIENT_GATE: - DoOpenMadnessDoorIfCan(); + if (m_auiEncounter[TYPE_MIMIRON] == DONE && m_auiEncounter[TYPE_HODIR] == DONE && m_auiEncounter[TYPE_THORIM] == DONE && m_auiEncounter[TYPE_FREYA] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_VEZAX_GATE: - pGo->SetGoState(GO_STATE_READY); - if (m_auiEncounter[TYPE_VEZAX]) + if (m_auiEncounter[TYPE_VEZAX] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_YOGG_GATE: - case GO_BRAIN_DOOR1: - case GO_BRAIN_DOOR2: - case GO_BRAIN_DOOR3: + case GO_BRAIN_DOOR_CHAMBER: + case GO_BRAIN_DOOR_ICECROWN: + case GO_BRAIN_DOOR_STORMWIND: break; - // ----------------- Chests ----------------- - // Kologarn + // ----------------- Chests ----------------- + // Kologarn case GO_CACHE_OF_LIVING_STONE_10: case GO_CACHE_OF_LIVING_STONE_25: - // Hodir + // Hodir case GO_CACHE_OF_WINTER_10: case GO_CACHE_OF_WINTER_25: case GO_CACHE_OF_RARE_WINTER_10: case GO_CACHE_OF_RARE_WINTER_25: - // Thorim + // Thorim case GO_CACHE_OF_STORMS_10: case GO_CACHE_OF_STORMS_25: case GO_CACHE_OF_STORMS_10_H: case GO_CACHE_OF_STORMS_25_H: - // Mimiron + // Mimiron case GO_CACHE_OF_INOV_10: case GO_CACHE_OF_INOV_25: case GO_CACHE_OF_INOV_10_H: case GO_CACHE_OF_INOV_25_H: - // Alagon + // Alagon case GO_GIFT_OF_OBSERVER_10: case GO_GIFT_OF_OBSERVER_25: break; + case GO_BROKEN_HARPOON: + m_vBrokenHarpoonsGuids.push_back(pGo->GetObjectGuid()); + return; + case GO_HARPOON_GUN_1: + case GO_HARPOON_GUN_2: + case GO_HARPOON_GUN_3: + case GO_HARPOON_GUN_4: + m_lRepairedHarpoonsGuids.push_back(pGo->GetObjectGuid()); + return; + default: return; } @@ -257,35 +452,122 @@ void instance_ulduar::OnObjectCreate(GameObject* pGo) void instance_ulduar::DoOpenMadnessDoorIfCan() { if (m_auiEncounter[TYPE_MIMIRON] == DONE && m_auiEncounter[TYPE_HODIR] == DONE && m_auiEncounter[TYPE_THORIM] == DONE && m_auiEncounter[TYPE_FREYA] == DONE) - { - if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_ANCIENT_GATE)) - pDoor->SetGoState(GO_STATE_ACTIVE); - } + DoUseDoorOrButton(GO_ANCIENT_GATE); } void instance_ulduar::SetData(uint32 uiType, uint32 uiData) { switch (uiType) { + // Siege of Ulduar case TYPE_LEVIATHAN: m_auiEncounter[uiType] = uiData; - DoUseDoorOrButton(GO_SHIELD_WALL); - if (uiData == DONE) + if (uiData != SPECIAL) + DoUseDoorOrButton(GO_SHIELD_WALL); + if (uiData == IN_PROGRESS) + { + // make sure that the Lightning door is closed when engaged in combat + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_LIGHTNING_DOOR)) + { + if (pDoor->GetGoState() != GO_STATE_READY) + DoUseDoorOrButton(GO_LIGHTNING_DOOR); + } + + SetSpecialAchievementCriteria(TYPE_ACHIEV_SHUTOUT, true); + } + else if (uiData == DONE) { DoUseDoorOrButton(GO_XT002_GATE); - DoUseDoorOrButton(GO_LIGHTNING_FIELD); + DoUseDoorOrButton(GO_LIGHTNING_DOOR); } + else if (uiData == FAIL) + DoCallLeviathanHelp(); break; case TYPE_IGNIS: m_auiEncounter[uiType] = uiData; + if (uiData == IN_PROGRESS) + { + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_IGNIS_ID); + SetSpecialAchievementCriteria(TYPE_ACHIEV_SHATTERED, false); + } break; case TYPE_RAZORSCALE: + if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_QUICK_SHAVE, true); + else if (uiData == FAIL) + { + // reset the commander + if (Creature* pCommander = GetSingleCreatureFromStorage(NPC_EXPEDITION_COMMANDER)) + pCommander->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + // reset all creatures + for (GuidList::const_iterator itr = m_lDefendersGuids.begin(); itr != m_lDefendersGuids.end(); ++itr) + { + if (Creature* pDefender = instance->GetCreature(*itr)) + { + if (!pDefender->isAlive()) + pDefender->Respawn(); + else + pDefender->GetMotionMaster()->MoveTargetedHome(); + } + } + for (GuidList::const_iterator itr = m_lEngineersGuids.begin(); itr != m_lEngineersGuids.end(); ++itr) + { + if (Creature* pEngineer = instance->GetCreature(*itr)) + { + if (!pEngineer->isAlive()) + pEngineer->Respawn(); + else + pEngineer->GetMotionMaster()->MoveTargetedHome(); + } + } + for (GuidList::const_iterator itr = m_lTrappersGuids.begin(); itr != m_lTrappersGuids.end(); ++itr) + { + if (Creature* pTrapper = instance->GetCreature(*itr)) + { + if (!pTrapper->isAlive()) + pTrapper->Respawn(); + else + pTrapper->GetMotionMaster()->MoveTargetedHome(); + } + } + for (GuidList::const_iterator itr = m_lHarpoonDummyGuids.begin(); itr != m_lHarpoonDummyGuids.end(); ++itr) + { + if (Creature* pHarpoon = instance->GetCreature(*itr)) + pHarpoon->InterruptNonMeleeSpells(false); + } + + // reset Harpoons: respawn the broken ones and despawn the repaired ones + for (GuidVector::const_iterator itr = m_vBrokenHarpoonsGuids.begin(); itr != m_vBrokenHarpoonsGuids.end(); ++itr) + { + if (GameObject* pHarpoon = instance->GetGameObject(*itr)) + { + if (!pHarpoon->isSpawned()) + pHarpoon->Respawn(); + } + } + for (GuidList::const_iterator itr = m_lRepairedHarpoonsGuids.begin(); itr != m_lRepairedHarpoonsGuids.end(); ++itr) + { + if (GameObject* pHarpoon = instance->GetGameObject(*itr)) + { + if (pHarpoon->isSpawned()) + pHarpoon->SetLootState(GO_JUST_DEACTIVATED); + } + } + } m_auiEncounter[uiType] = uiData; break; case TYPE_XT002: m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_XT002_GATE); + if (uiData == IN_PROGRESS) + { + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_XT002_ID); + SetSpecialAchievementCriteria(TYPE_ACHIEV_NERF_ENG, true); + } break; + + // Antechamber of Ulduar case TYPE_ASSEMBLY: // Don't set the same encounter data twice if (uiData == m_auiEncounter[uiType]) @@ -296,7 +578,15 @@ void instance_ulduar::SetData(uint32 uiType, uint32 uiData) return; DoUseDoorOrButton(GO_IRON_ENTRANCE_DOOR); if (uiData == DONE) + { DoUseDoorOrButton(GO_ARCHIVUM_DOOR); + + if (Player* pPlayer = GetPlayerInMap()) + { + pPlayer->SummonCreature(NPC_BRANN_ARCHIVUM, afBrannArchivumSpawnPos[0], afBrannArchivumSpawnPos[1], afBrannArchivumSpawnPos[2], afBrannArchivumSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + pPlayer->SummonCreature(instance->IsRegularDifficulty() ? NPC_PROSPECTOR_DOREN : NPC_PROSPECTOR_DOREN_H, afProspectorSpawnPos[0], afProspectorSpawnPos[1], afProspectorSpawnPos[2], afProspectorSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + } + } else if (uiData == IN_PROGRESS) { SetSpecialAchievementCriteria(TYPE_ACHIEV_BRUNDIR, true); @@ -307,12 +597,17 @@ void instance_ulduar::SetData(uint32 uiType, uint32 uiData) break; case TYPE_KOLOGARN: m_auiEncounter[uiType] = uiData; - DoUseDoorOrButton(GO_SHATTERED_DOOR); if (uiData == DONE) { - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_LIVING_STONE_10 : GO_CACHE_OF_LIVING_STONE_25, 30*MINUTE); - if (GameObject* pBridge = GetSingleGameObjectFromStorage(GO_KOLOGARN_BRIDGE)) - pBridge->SetGoState(GO_STATE_READY); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_LIVING_STONE_10 : GO_CACHE_OF_LIVING_STONE_25, 30 * MINUTE); + DoUseDoorOrButton(GO_KOLOGARN_BRIDGE); + } + else if (uiData == IN_PROGRESS) + { + SetSpecialAchievementCriteria(TYPE_ACHIEV_RUBBLE, false); + SetSpecialAchievementCriteria(TYPE_ACHIEV_DISARMED, false); + SetSpecialAchievementCriteria(TYPE_ACHIEV_LOOKS_KILL, true); + SetSpecialAchievementCriteria(TYPE_ACHIEV_OPEN_ARMS, true); } break; case TYPE_AURIAYA: @@ -323,17 +618,60 @@ void instance_ulduar::SetData(uint32 uiType, uint32 uiData) SetSpecialAchievementCriteria(TYPE_ACHIEV_NINE_LIVES, false); } break; - // Keepers + + // Keepers of Ulduar case TYPE_MIMIRON: + // Don't set the same encounter data twice + if (uiData == m_auiEncounter[uiType]) + return; m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_MIMIRON_DOOR_1); DoUseDoorOrButton(GO_MIMIRON_DOOR_2); DoUseDoorOrButton(GO_MIMIRON_DOOR_3); if (uiData == DONE) { - if (GetData(TYPE_MIMIRON_HARD) != DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_INOV_10 : GO_CACHE_OF_INOV_25, 30*MINUTE); - SpawnFriendlyKeeper(NPC_MIMIRON_IMAGE); + if (GetData(TYPE_MIMIRON_HARD) == DONE) + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_INOV_10_H : GO_CACHE_OF_INOV_25_H, 30 * MINUTE); + else + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_INOV_10 : GO_CACHE_OF_INOV_25, 30 * MINUTE); + + SpawnFriendlyKeeper(NPC_KEEPER_MIMIRON); + DoOpenMadnessDoorIfCan(); + } + else if (uiData == IN_PROGRESS) + DoToggleGameObjectFlags(GO_MIMIRON_BUTTON, GO_FLAG_NO_INTERACT, true); + else if (uiData == FAIL) + { + // reset objects + DoToggleGameObjectFlags(GO_MIMIRON_BUTTON, GO_FLAG_NO_INTERACT, false); + + if (GameObject* pButton = GetSingleGameObjectFromStorage(GO_MIMIRON_BUTTON)) + pButton->ResetDoorOrButton(); + if (GameObject* pElevator = GetSingleGameObjectFromStorage(GO_MIMIRON_ELEVATOR)) + pElevator->SetGoState(GO_STATE_ACTIVE); + + // reset vehicles + if (Creature* pLeviathan = GetSingleCreatureFromStorage(NPC_LEVIATHAN_MK)) + { + pLeviathan->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + pLeviathan->AI()->EnterEvadeMode(); + } + if (Creature* pVx001 = GetSingleCreatureFromStorage(NPC_VX001, true)) + { + pVx001->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + pVx001->ForcedDespawn(1000); + } + if (Creature* pAerial = GetSingleCreatureFromStorage(NPC_AERIAL_UNIT, true)) + { + pAerial->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); + pAerial->ForcedDespawn(1000); + } + if (Creature* pMimiron = GetSingleCreatureFromStorage(NPC_MIMIRON)) + pMimiron->AI()->EnterEvadeMode(); + if (Creature* pComputer = GetSingleCreatureFromStorage(NPC_COMPUTER)) + pComputer->AI()->EnterEvadeMode(); + + SetData(TYPE_MIMIRON_HARD, FAIL); } break; case TYPE_HODIR: @@ -343,108 +681,307 @@ void instance_ulduar::SetData(uint32 uiType, uint32 uiData) { DoUseDoorOrButton(GO_HODIR_ICE_WALL); DoUseDoorOrButton(GO_HODIR_EXIT); - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_WINTER_10 : GO_CACHE_OF_WINTER_25, 30*MINUTE); - SpawnFriendlyKeeper(NPC_HODIR_IMAGE); + + DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_CACHE_OF_WINTER_10 : GO_CACHE_OF_WINTER_25, GO_FLAG_NO_INTERACT, false); + if (GetData(TYPE_HODIR_HARD) == DONE) + DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_CACHE_OF_RARE_WINTER_10 : GO_CACHE_OF_RARE_WINTER_25, GO_FLAG_NO_INTERACT, false); + + SpawnFriendlyKeeper(NPC_KEEPER_HODIR); + DoOpenMadnessDoorIfCan(); + } + else if (uiData == FAIL) + { + if (GameObject* pChest = GetSingleGameObjectFromStorage(instance->IsRegularDifficulty() ? GO_CACHE_OF_RARE_WINTER_10 : GO_CACHE_OF_RARE_WINTER_25)) + pChest->Respawn(); + + if (Player* pPlayer = GetPlayerInMap()) + DoSpawnHodirNpcs(pPlayer); + + SetData(TYPE_HODIR_HARD, FAIL); + } + else if (uiData == IN_PROGRESS) + { + SetSpecialAchievementCriteria(TYPE_ACHIEV_CHEESE_FREEZE, true); + SetSpecialAchievementCriteria(TYPE_ACHIEV_COOL_FRIENDS, true); } break; case TYPE_THORIM: m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_LIGHTNING_FIELD); if (uiData == IN_PROGRESS) - DoUseDoorOrButton(GO_DARK_IRON_PORTCULIS); - if (uiData == DONE) { - if (GetData(TYPE_THORIM_HARD) != DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_STORMS_10 : GO_CACHE_OF_STORMS_25, 30*MINUTE); - SpawnFriendlyKeeper(NPC_THORIM_IMAGE); + DoToggleGameObjectFlags(GO_DOOR_LEVER, GO_FLAG_NO_INTERACT, false); + SetSpecialAchievementCriteria(TYPE_ACHIEV_LIGHTNING, true); + } + else if (uiData == DONE) + { + if (GetData(TYPE_THORIM_HARD) == DONE) + { + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_STORMS_10_H : GO_CACHE_OF_STORMS_25_H, 30 * MINUTE); + DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_CACHE_OF_STORMS_10_H : GO_CACHE_OF_STORMS_25_H, GO_FLAG_NO_INTERACT, false); + } + else + { + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_STORMS_10 : GO_CACHE_OF_STORMS_25, 30 * MINUTE); + DoToggleGameObjectFlags(instance->IsRegularDifficulty() ? GO_CACHE_OF_STORMS_10 : GO_CACHE_OF_STORMS_25, GO_FLAG_NO_INTERACT, false); + } + + SpawnFriendlyKeeper(NPC_KEEPER_THORIM); + DoOpenMadnessDoorIfCan(); + } + else if (uiData == FAIL) + { + DoToggleGameObjectFlags(GO_DOOR_LEVER, GO_FLAG_NO_INTERACT, true); + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_RUNED_STONE_DOOR)) + pDoor->ResetDoorOrButton(); + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_THORIM_STONE_DOOR)) + pDoor->ResetDoorOrButton(); + if (Creature* pColossus = GetSingleCreatureFromStorage(NPC_RUNIC_COLOSSUS)) + { + if (pColossus->isAlive()) + pColossus->AI()->EnterEvadeMode(); + } + + m_uiStairsSpawnTimer = 0; + m_uiSlayedArenaMobs = 0; } break; case TYPE_FREYA: m_auiEncounter[uiType] = uiData; if (uiData == DONE) - SpawnFriendlyKeeper(NPC_FREYA_IMAGE); + { + // despawn elders which are still alive on event complete + if (Creature* pElder = GetSingleCreatureFromStorage(NPC_ELDER_BRIGHTLEAF)) + { + if (pElder->isAlive()) + pElder->ForcedDespawn(); + } + if (Creature* pElder = GetSingleCreatureFromStorage(NPC_ELDER_IRONBRACH)) + { + if (pElder->isAlive()) + pElder->ForcedDespawn(); + } + if (Creature* pElder = GetSingleCreatureFromStorage(NPC_ELDER_STONEBARK)) + { + if (pElder->isAlive()) + pElder->ForcedDespawn(); + } + + SpawnFriendlyKeeper(NPC_KEEPER_FREYA); + DoOpenMadnessDoorIfCan(); + } break; - // Prison + + // Ulduar Prison case TYPE_VEZAX: m_auiEncounter[uiType] = uiData; if (uiData == DONE) DoUseDoorOrButton(GO_VEZAX_GATE); + else if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_SHADOWDODGER, true); break; case TYPE_YOGGSARON: + // Don't set the same encounter data twice + if (uiData == m_auiEncounter[uiType]) + return; m_auiEncounter[uiType] = uiData; DoUseDoorOrButton(GO_YOGG_GATE); + if (uiData == FAIL || uiData == DONE) + { + // reset/cleanup encounter + for (GuidList::const_iterator itr = m_lOminousCloudsGuids.begin(); itr != m_lOminousCloudsGuids.end(); ++itr) + { + if (Creature* pCloud = instance->GetCreature(*itr)) + pCloud->ForcedDespawn(); + } + + if (Creature* pVoice = GetSingleCreatureFromStorage(NPC_VOICE_OF_YOGG)) + { + pVoice->CastSpell(pVoice, SPELL_CLEAR_INSANE, true); + pVoice->ForcedDespawn(); + } + if (Creature* pSara = GetSingleCreatureFromStorage(NPC_SARA)) + pSara->ForcedDespawn(); + if (Creature* pBrain = GetSingleCreatureFromStorage(NPC_YOGG_BRAIN)) + pBrain->ForcedDespawn(); + + // reset illusion doors + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_BRAIN_DOOR_CHAMBER)) + pDoor->ResetDoorOrButton(); + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_BRAIN_DOOR_ICECROWN)) + pDoor->ResetDoorOrButton(); + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_BRAIN_DOOR_STORMWIND)) + pDoor->ResetDoorOrButton(); + + // reset all helpers + for (uint8 i = 0; i < countof(m_aKeeperHelperLocs); ++i) + { + if (GetData(m_aKeeperHelperLocs[i].uiType) == DONE) + { + if (Creature* pHelper = GetSingleCreatureFromStorage(m_aKeeperHelperLocs[i].uiEntry)) + { + if (uiData == FAIL) + { + pHelper->AI()->EnterEvadeMode(); + pHelper->CastSpell(pHelper, SPELL_KEEPER_ACTIVE, true); + } + else if (uiData == DONE) + { + pHelper->CastSpell(pHelper, SPELL_TELEPORT, true); + pHelper->ForcedDespawn(1000); + } + } + } + } + + // full reset only on fail + if (uiData == FAIL) + m_uiYoggResetTimer = 60000; + } + else if (uiData == IN_PROGRESS) + { + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_YOGG_ID); + SetSpecialAchievementCriteria(TYPE_ACHIEV_DRIVE_CRAZY, true); + } break; - // Celestial Planetarium + // Celestial Planetarium case TYPE_ALGALON: m_auiEncounter[uiType] = uiData; - //TODO: need to find the proper way to use these - DoUseDoorOrButton(GO_CELESTIAL_DOOR); - DoUseDoorOrButton(GO_UNIVERSE_FLOOR_CELESTIAL); + if (uiData != SPECIAL) + { + // environment gameobjects + DoUseDoorOrButton(GO_AZEROTH_GLOBE); + DoUseDoorOrButton(GO_UNIVERSE_FLOOR); + DoUseDoorOrButton(GO_UNIVERSE_FLOOR_COMBAT); + DoUseDoorOrButton(GO_CELESTIAL_DOOR_COMBAT); + } if (uiData == DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_GIFT_OF_OBSERVER_10 : GO_GIFT_OF_OBSERVER_25, 30*MINUTE); + { + DoUpdateWorldState(WORLD_STATE_TIMER, 0); + DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_GIFT_OF_OBSERVER_10 : GO_GIFT_OF_OBSERVER_25, 30 * MINUTE); + } + else if (uiData == FAIL) + { + // only despawn when time is over + if (GetData(TYPE_ALGALON_TIMER) == 0) + { + DoUpdateWorldState(WORLD_STATE_TIMER, 0); + if (Creature* pAlgalon = GetSingleCreatureFromStorage(NPC_ALGALON)) + pAlgalon->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pAlgalon, pAlgalon); + } + } + break; + case TYPE_ALGALON_TIMER: + m_auiEncounter[uiType] = uiData; + DoUpdateWorldState(WORLD_STATE_TIMER_COUNT, m_auiEncounter[uiType]); + break; + case TYPE_CHAMPION_FAILED: + m_auiEncounter[uiType] = uiData; break; - // Hard modes + // Hard modes (not saved) case TYPE_LEVIATHAN_HARD: - m_auiHardBoss[0] = uiData; // TODO: add extra loot - break; + m_auiHardBoss[0] = uiData; + return; case TYPE_XT002_HARD: - m_auiHardBoss[1] = uiData; // TODO: add extra loot - break; + m_auiHardBoss[1] = uiData; + return; case TYPE_HODIR_HARD: m_auiHardBoss[2] = uiData; - if (uiData == DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_RARE_WINTER_10 : GO_CACHE_OF_RARE_WINTER_25, 30*MINUTE); - break; + return; case TYPE_THORIM_HARD: m_auiHardBoss[3] = uiData; - if (uiData == DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_STORMS_10_H : GO_CACHE_OF_STORMS_25_H, 30*MINUTE); - break; + return; case TYPE_MIMIRON_HARD: m_auiHardBoss[4] = uiData; - if (uiData == DONE) - DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_CACHE_OF_INOV_10_H : GO_CACHE_OF_INOV_25_H, 30*MINUTE); - break; + return; + case TYPE_FREYA_HARD: + m_auiHardBoss[5] = uiData; + return; case TYPE_VEZAX_HARD: - m_auiHardBoss[5] = uiData; // TODO: add extra loot - break; + m_auiHardBoss[6] = uiData; + return; case TYPE_YOGGSARON_HARD: - m_auiHardBoss[6] = uiData; // TODO: add extra loot - break; + m_auiHardBoss[7] = uiData; + return; - // Ulduar keepers + // Ulduar keepers case TYPE_KEEPER_HODIR: + if (uiData == m_auiUlduarKeepers[0] || uiData != DONE) + return; + SpawnKeeperHelper(NPC_HODIR_HELPER); m_auiUlduarKeepers[0] = uiData; break; case TYPE_KEEPER_THORIM: + if (uiData == m_auiUlduarKeepers[1] || uiData != DONE) + return; + SpawnKeeperHelper(NPC_THORIM_HELPER); m_auiUlduarKeepers[1] = uiData; break; case TYPE_KEEPER_FREYA: + if (uiData == m_auiUlduarKeepers[2] || uiData != DONE) + return; + SpawnKeeperHelper(NPC_FREYA_HELPER); m_auiUlduarKeepers[2] = uiData; break; case TYPE_KEEPER_MIMIRON: + if (uiData == m_auiUlduarKeepers[3] || uiData != DONE) + return; + SpawnKeeperHelper(NPC_MIMIRON_HELPER); m_auiUlduarKeepers[3] = uiData; break; - } - DoOpenMadnessDoorIfCan(); + // Ulduar towers + case TYPE_TOWER_HODIR: + if (m_auiUlduarTowers[0] == uiData) + return; + if (uiData == FAIL) + DoUseDoorOrButton(GO_HODIR_CRYSTAL); + m_auiUlduarTowers[0] = uiData; + break; + case TYPE_TOWER_THORIM: + if (m_auiUlduarTowers[1] == uiData) + return; + if (uiData == FAIL) + DoUseDoorOrButton(GO_THORIM_CRYSTAL); + m_auiUlduarTowers[1] = uiData; + break; + case TYPE_TOWER_FREYA: + if (m_auiUlduarTowers[2] == uiData) + return; + if (uiData == FAIL) + DoUseDoorOrButton(GO_FREYA_CRYSTAL); + m_auiUlduarTowers[2] = uiData; + break; + case TYPE_TOWER_MIMIRON: + if (m_auiUlduarTowers[3] == uiData) + return; + if (uiData == FAIL) + DoUseDoorOrButton(GO_MIMIRON_CRYSTAL); + m_auiUlduarTowers[3] = uiData; + break; + + // Other types - not saved + case TYPE_LEVIATHAN_GAUNTLET: + m_uiGauntletStatus = uiData; + return; + } - if (uiData == DONE || uiData == FAIL) + if (uiData == DONE || uiData == FAIL || uiData == SPECIAL || uiType == TYPE_ALGALON_TIMER) { OUT_SAVE_INST_DATA; // Save all encounters, hard bosses, keepers and teleporters std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] << " " - << m_auiEncounter[12] << " " << m_auiEncounter[13] << " " << m_auiHardBoss[0] << " " - << m_auiHardBoss[1] << " " << m_auiHardBoss[2] << " " << m_auiHardBoss[2] << " " - << m_auiHardBoss[4] << " " << m_auiHardBoss[5] << " " << m_auiHardBoss[6] << " " - << m_auiUlduarKeepers[0] << " " << m_auiUlduarKeepers[1] << " " << m_auiUlduarKeepers[2] << " " << m_auiUlduarKeepers[3]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] << " " + << m_auiEncounter[12] << " " << m_auiEncounter[13] << " " << m_auiEncounter[14] << " " + << m_auiEncounter[15] << " " << m_auiUlduarKeepers[0] << " " << m_auiUlduarKeepers[1] << " " + << m_auiUlduarKeepers[2] << " " << m_auiUlduarKeepers[3] << " " << m_auiUlduarTowers[0] << " " + << m_auiUlduarTowers[1] << " " << m_auiUlduarTowers[2] << " " << m_auiUlduarTowers[3]; m_strInstData = saveStream.str(); @@ -453,24 +990,59 @@ void instance_ulduar::SetData(uint32 uiType, uint32 uiData) } } -// TODO: implement all hard mode loot here! -bool instance_ulduar::CheckConditionCriteriaMeet(Player const* pSource, uint32 uiMapId, uint32 uiInstanceConditionId) +bool instance_ulduar::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const { - if (uiMapId != instance->GetId()) - return false; - switch (uiInstanceConditionId) - { - case TYPE_XT002_HARD: - break; - } + { + case INSTANCE_CONDITION_ID_NORMAL_MODE: + case INSTANCE_CONDITION_ID_HARD_MODE: + case INSTANCE_CONDITION_ID_HARD_MODE_2: + case INSTANCE_CONDITION_ID_HARD_MODE_3: + case INSTANCE_CONDITION_ID_HARD_MODE_4: + { + if (!pConditionSource) + break; + + uint32 uiCondId = 0; + switch (pConditionSource->GetEntry()) + { + case NPC_LEVIATHAN: + uiCondId = GetData(TYPE_LEVIATHAN_HARD); + break; + case NPC_XT002: + if (GetData(TYPE_XT002_HARD) == DONE) + uiCondId = 1; + break; + case NPC_VEZAX: + if (GetData(TYPE_VEZAX_HARD) == DONE) + uiCondId = 1; + break; + case NPC_YOGGSARON: + uiCondId = 4 - GetData(TYPE_YOGGSARON_HARD); + break; + } + + return uiCondId == uiInstanceConditionId; + } + case INSTANCE_CONDITION_ID_ULDUAR: + { + if (!pConditionSource) + break; + + // handle vehicle spell clicks - are available only after the gauntlet was started by gossip or when Leviathan is active + return GetData(TYPE_LEVIATHAN_GAUNTLET) == IN_PROGRESS || GetData(TYPE_LEVIATHAN) == SPECIAL || GetData(TYPE_LEVIATHAN) == FAIL; + } + } + + script_error_log("instance_ulduar::CheckConditionCriteriaMeet called with unsupported Id %u. Called with param plr %s, src %s, condition source type %u", + uiInstanceConditionId, pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", pConditionSource ? pConditionSource->GetGuidStr().c_str() : "NULL", conditionSourceType); return false; } -uint32 instance_ulduar::GetData(uint32 uiType) +uint32 instance_ulduar::GetData(uint32 uiType) const { switch (uiType) - { + { case TYPE_LEVIATHAN: return m_auiEncounter[0]; case TYPE_IGNIS: @@ -499,8 +1071,12 @@ uint32 instance_ulduar::GetData(uint32 uiType) return m_auiEncounter[12]; case TYPE_ALGALON: return m_auiEncounter[13]; + case TYPE_ALGALON_TIMER: + return m_auiEncounter[14]; + case TYPE_CHAMPION_FAILED: + return m_auiEncounter[15]; - // Hard modes + // Hard modes case TYPE_LEVIATHAN_HARD: return m_auiHardBoss[0]; case TYPE_XT002_HARD: @@ -511,12 +1087,14 @@ uint32 instance_ulduar::GetData(uint32 uiType) return m_auiHardBoss[3]; case TYPE_MIMIRON_HARD: return m_auiHardBoss[4]; - case TYPE_VEZAX_HARD: + case TYPE_FREYA_HARD: return m_auiHardBoss[5]; - case TYPE_YOGGSARON_HARD: + case TYPE_VEZAX_HARD: return m_auiHardBoss[6]; + case TYPE_YOGGSARON_HARD: + return m_auiHardBoss[7]; - // Ulduar Keepers + // Ulduar Keepers case TYPE_KEEPER_HODIR: return m_auiUlduarKeepers[0]; case TYPE_KEEPER_THORIM: @@ -525,7 +1103,20 @@ uint32 instance_ulduar::GetData(uint32 uiType) return m_auiUlduarKeepers[2]; case TYPE_KEEPER_MIMIRON: return m_auiUlduarKeepers[3]; - } + + // Ulduar Towers + case TYPE_TOWER_HODIR: + return m_auiUlduarTowers[0]; + case TYPE_TOWER_THORIM: + return m_auiUlduarTowers[1]; + case TYPE_TOWER_FREYA: + return m_auiUlduarTowers[2]; + case TYPE_TOWER_MIMIRON: + return m_auiUlduarTowers[3]; + + case TYPE_LEVIATHAN_GAUNTLET: + return m_uiGauntletStatus; + } return 0; } @@ -537,23 +1128,139 @@ void instance_ulduar::SpawnFriendlyKeeper(uint32 uiWho) if (!pPlayer) return; - switch(uiWho) + switch (uiWho) { - case NPC_MIMIRON_IMAGE: pPlayer->SummonCreature(NPC_MIMIRON_IMAGE, m_aKeepersSpawnLocs[1].m_fX, m_aKeepersSpawnLocs[1].m_fY, m_aKeepersSpawnLocs[1].m_fZ, m_aKeepersSpawnLocs[1].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; - case NPC_HODIR_IMAGE: pPlayer->SummonCreature(NPC_HODIR_IMAGE, m_aKeepersSpawnLocs[2].m_fX, m_aKeepersSpawnLocs[2].m_fY, m_aKeepersSpawnLocs[2].m_fZ, m_aKeepersSpawnLocs[2].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; - case NPC_THORIM_IMAGE: pPlayer->SummonCreature(NPC_THORIM_IMAGE, m_aKeepersSpawnLocs[3].m_fX, m_aKeepersSpawnLocs[3].m_fY, m_aKeepersSpawnLocs[3].m_fZ, m_aKeepersSpawnLocs[3].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; - case NPC_FREYA_IMAGE: pPlayer->SummonCreature(NPC_FREYA_IMAGE, m_aKeepersSpawnLocs[0].m_fX, m_aKeepersSpawnLocs[0].m_fY, m_aKeepersSpawnLocs[0].m_fZ, m_aKeepersSpawnLocs[0].m_fO, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10000); break; + case NPC_KEEPER_MIMIRON: pPlayer->SummonCreature(uiWho, m_aKeepersSpawnLocs[1].fX, m_aKeepersSpawnLocs[1].fY, m_aKeepersSpawnLocs[1].fZ, m_aKeepersSpawnLocs[1].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true); break; + case NPC_KEEPER_HODIR: pPlayer->SummonCreature(uiWho, m_aKeepersSpawnLocs[2].fX, m_aKeepersSpawnLocs[2].fY, m_aKeepersSpawnLocs[2].fZ, m_aKeepersSpawnLocs[2].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true); break; + case NPC_KEEPER_THORIM: pPlayer->SummonCreature(uiWho, m_aKeepersSpawnLocs[3].fX, m_aKeepersSpawnLocs[3].fY, m_aKeepersSpawnLocs[3].fZ, m_aKeepersSpawnLocs[3].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true); break; + case NPC_KEEPER_FREYA: pPlayer->SummonCreature(uiWho, m_aKeepersSpawnLocs[0].fX, m_aKeepersSpawnLocs[0].fY, m_aKeepersSpawnLocs[0].fZ, m_aKeepersSpawnLocs[0].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true); break; + } +} + +// Spawn the keeper helpers for Yogg-Saron +void instance_ulduar::SpawnKeeperHelper(uint32 uiWho) +{ + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + switch (uiWho) + { + case NPC_MIMIRON_HELPER: + if (Creature* pKeeper = pPlayer->SummonCreature(uiWho, m_aKeeperHelperLocs[1].fX, m_aKeeperHelperLocs[1].fY, m_aKeeperHelperLocs[1].fZ, m_aKeeperHelperLocs[1].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true)) + { + DoScriptText(m_aKeeperHelperLocs[1].iText, pKeeper); + pKeeper->CastSpell(pKeeper, SPELL_KEEPER_ACTIVE, false); + } + break; + case NPC_HODIR_HELPER: + if (Creature* pKeeper = pPlayer->SummonCreature(uiWho, m_aKeeperHelperLocs[2].fX, m_aKeeperHelperLocs[2].fY, m_aKeeperHelperLocs[2].fZ, m_aKeeperHelperLocs[2].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true)) + { + DoScriptText(m_aKeeperHelperLocs[2].iText, pKeeper); + pKeeper->CastSpell(pKeeper, SPELL_KEEPER_ACTIVE, false); + } + break; + case NPC_THORIM_HELPER: + if (Creature* pKeeper = pPlayer->SummonCreature(uiWho, m_aKeeperHelperLocs[3].fX, m_aKeeperHelperLocs[3].fY, m_aKeeperHelperLocs[3].fZ, m_aKeeperHelperLocs[3].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true)) + { + DoScriptText(m_aKeeperHelperLocs[3].iText, pKeeper); + pKeeper->CastSpell(pKeeper, SPELL_KEEPER_ACTIVE, false); + } + break; + case NPC_FREYA_HELPER: + if (Creature* pKeeper = pPlayer->SummonCreature(uiWho, m_aKeeperHelperLocs[0].fX, m_aKeeperHelperLocs[0].fY, m_aKeeperHelperLocs[0].fZ, m_aKeeperHelperLocs[0].fO, TEMPSUMMON_CORPSE_DESPAWN, 0, true)) + { + DoScriptText(m_aKeeperHelperLocs[0].iText, pKeeper); + pKeeper->CastSpell(pKeeper, SPELL_KEEPER_ACTIVE, false); + } + break; + } +} + +void instance_ulduar::OnCreatureEnterCombat(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_RUNE_GIANT: + m_uiStairsSpawnTimer = 0; + break; } } void instance_ulduar::OnCreatureDeath(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_SANCTUM_SENTRY: if (GetData(TYPE_AURIAYA) == IN_PROGRESS) SetSpecialAchievementCriteria(TYPE_ACHIEV_CAT_LADY, false); break; + case NPC_ULDUAR_COLOSSUS: + { + if (m_sColossusGuidSet.find(pCreature->GetObjectGuid()) != m_sColossusGuidSet.end()) + m_sColossusGuidSet.erase(pCreature->GetObjectGuid()); + + // start pre Leviathan event + if (m_sColossusGuidSet.empty()) + { + StartNextDialogueText(SAY_PRE_LEVIATHAN_1); + SetData(TYPE_LEVIATHAN, SPECIAL); + SetData(TYPE_LEVIATHAN_GAUNTLET, DONE); + pCreature->SummonCreature(NPC_LEVIATHAN, afLeviathanSpawnPos[0], afLeviathanSpawnPos[1], afLeviathanSpawnPos[2], afLeviathanSpawnPos[3], TEMPSUMMON_DEAD_DESPAWN, 0, true); + } + } + break; + case NPC_DRUID_HORDE_N: + case NPC_DRUID_HORDE_H: + case NPC_SHAMAN_HORDE_N: + case NPC_SHAMAN_HORDE_H: + case NPC_MAGE_HORDE_N: + case NPC_MAGE_HORDE_H: + case NPC_PRIEST_HORDE_N: + case NPC_PRIEST_HORDE_H: + case NPC_DRUID_ALLIANCE_N: + case NPC_DRUID_ALLIANCE_H: + case NPC_SHAMAN_ALLIANCE_N: + case NPC_SHAMAN_ALLIANCE_H: + case NPC_MAGE_ALLIANCE_N: + case NPC_MAGE_ALLIANCE_H: + case NPC_PRIEST_ALLIANCE_N: + case NPC_PRIEST_ALLIANCE_H: + if (GetData(TYPE_HODIR) == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_COOL_FRIENDS, false); + break; + case NPC_JORMUNGAR_BEHEMOTH: + case NPC_SOLDIER_ALLIANCE: + case NPC_CAPTAIN_ALLIANCE: + case NPC_SOLDIER_HORDE: + case NPC_CAPTAIN_HORDE: + case NPC_DARK_RUNE_ACOLYTE: + ++m_uiSlayedArenaMobs; + + // start combat when all 4 faction soldiers, the Acolyte and the Jormungar are dead + if (m_uiSlayedArenaMobs == 6) + { + if (Creature* pThorim = GetSingleCreatureFromStorage(NPC_THORIM)) + pThorim->SetInCombatWithZone(); + } + break; + case NPC_RUNIC_COLOSSUS: + m_uiStairsSpawnTimer = 30000; + DoUseDoorOrButton(GO_RUNED_STONE_DOOR); + break; + case NPC_RUNE_GIANT: + DoUseDoorOrButton(GO_THORIM_STONE_DOOR); + break; + case NPC_SARONITE_ANIMUS: + if (Creature* pVezax = GetSingleCreatureFromStorage(NPC_VEZAX)) + { + if (pVezax->isAlive()) + { + pCreature->AI()->SendAIEvent(AI_EVENT_CUSTOM_C, pCreature, pVezax); + SetData(TYPE_VEZAX_HARD, DONE); + } + } + break; } } @@ -569,10 +1276,11 @@ void instance_ulduar::Load(const char* strIn) std::istringstream loadStream(strIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8] - >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11] >> m_auiEncounter[12] >> m_auiEncounter[13] - >> m_auiHardBoss[0] >> m_auiHardBoss[1] >> m_auiHardBoss[2] >> m_auiHardBoss[3] >> m_auiHardBoss[4] >> m_auiHardBoss[5] >> m_auiHardBoss[6] - >> m_auiUlduarKeepers[0] >> m_auiUlduarKeepers[1] >> m_auiUlduarKeepers[2] >> m_auiUlduarKeepers[3]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11] + >> m_auiEncounter[12] >> m_auiEncounter[13] >> m_auiEncounter[14] >> m_auiEncounter[15] + >> m_auiUlduarKeepers[0] >> m_auiUlduarKeepers[1] >> m_auiUlduarKeepers[2] >> m_auiUlduarKeepers[3] + >> m_auiUlduarTowers[0] >> m_auiUlduarTowers[1] >> m_auiUlduarTowers[2] >> m_auiUlduarTowers[3]; for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { @@ -589,13 +1297,16 @@ void instance_ulduar::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) m_abAchievCriteria[uiType] = bIsMet; } -bool instance_ulduar::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_ulduar::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { switch (uiCriteriaId) { case ACHIEV_CRIT_SARONITE_N: case ACHIEV_CRIT_SARONITE_H: return GetData(TYPE_VEZAX_HARD) == DONE; + case ACHIEV_CRIT_SHADOWDODGER_N: + case ACHIEV_CRIT_SHADOWDODGER_H: + return m_abAchievCriteria[TYPE_ACHIEV_SHADOWDODGER]; case ACHIEV_CRIT_CAT_LADY_N: case ACHIEV_CRIT_CAT_LADY_H: return m_abAchievCriteria[TYPE_ACHIEV_CAT_LADY]; @@ -622,17 +1333,331 @@ bool instance_ulduar::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player c case ACHIEV_CRIT_STUNNED_MOLG_H: if (GetData(TYPE_ASSEMBLY) == SPECIAL) return m_abAchievCriteria[TYPE_ACHIEV_STUNNED]; + case ACHIEV_CRIT_SHATTERED_N: + case ACHIEV_CRIT_SHATTERED_H: + return m_abAchievCriteria[TYPE_ACHIEV_SHATTERED]; + case ACHIEV_CRIT_HEARTBREAKER_N: + case ACHIEV_CRIT_HEARTBREAKER_H: + return GetData(TYPE_XT002_HARD) == DONE; + case ACHIEV_CRIT_QUICK_SHAVE_N: + case ACHIEV_CRIT_QUICK_SHAVE_H: + return m_abAchievCriteria[TYPE_ACHIEV_QUICK_SHAVE]; + case ACHIEV_CRIT_SHUTOUT_N: + case ACHIEV_CRIT_SHUTOUT_H: + return m_abAchievCriteria[TYPE_ACHIEV_SHUTOUT]; + case ACHIEV_CRIT_ORB_BOMB_N: + case ACHIEV_CRIT_ORB_BOMB_H: + return GetData(TYPE_LEVIATHAN_HARD) >= 1; + case ACHIEV_CRIT_ORB_DEV_N: + case ACHIEV_CRIT_ORB_DEV_H: + return GetData(TYPE_LEVIATHAN_HARD) >= 2; + case ACHIEV_CRIT_ORB_NUKED_N: + case ACHIEV_CRIT_ORB_NUKED_H: + return GetData(TYPE_LEVIATHAN_HARD) >= 3; + case ACHIEV_CRIT_ORBITUARY_N: + case ACHIEV_CRIT_ORBITUARY_H: + return GetData(TYPE_LEVIATHAN_HARD) == 4; + case ACHIEV_CRIT_NERF_ENG_N: + case ACHIEV_CRIT_NERF_ENG_H: + return m_abAchievCriteria[TYPE_ACHIEV_NERF_ENG]; + case ACHIEV_CRIT_RUBBLE_ROLL_N: + case ACHIEV_CRIT_RUBBLE_ROLL_H: + return m_abAchievCriteria[TYPE_ACHIEV_RUBBLE]; + case ACHIEV_CRIT_LOOKS_KILL_N: + case ACHIEV_CRIT_LOOKS_KILL_H: + return m_abAchievCriteria[TYPE_ACHIEV_LOOKS_KILL]; + case ACHIEV_CRIT_OPEN_ARMS_N: + case ACHIEV_CRIT_OPEN_ARMS_H: + return m_abAchievCriteria[TYPE_ACHIEV_OPEN_ARMS]; + case ACHIEV_CRIT_DISARMED_N: + case ACHIEV_CRIT_DISARMED_H: + return m_abAchievCriteria[TYPE_ACHIEV_DISARMED]; + case ACHIEV_CRIT_RARE_CACHE_N: + case ACHIEV_CRIT_RARE_CACHE_H: + return GetData(TYPE_HODIR_HARD) == DONE; + case ACHIEV_CRIT_CHEESE_N: + case ACHIEV_CRIT_CHEESE_H: + return m_abAchievCriteria[TYPE_ACHIEV_CHEESE_FREEZE]; + case ACHIEV_CRIT_COOL_FRIENDS_N: + case ACHIEV_CRIT_COOL_FRIENDS_H: + return m_abAchievCriteria[TYPE_ACHIEV_COOL_FRIENDS]; + case ACHIEV_CRIT_LOSE_ILLUSION_N: + case ACHIEV_CRIT_LOSE_ILLUSION_H: + return GetData(TYPE_THORIM_HARD) == DONE; + case ACHIEV_CRIT_LIGHTNING_N: + case ACHIEV_CRIT_LIGHTNING_H: + return m_abAchievCriteria[TYPE_ACHIEV_LIGHTNING]; + case ACHIEV_CRIT_BACK_NATURE_N: + case ACHIEV_CRIT_BACK_NATURE_H: + return m_abAchievCriteria[TYPE_ACHIEV_BACK_NATURE]; + case ACHIEV_CRIT_KNOCK_1_N: + case ACHIEV_CRIT_KNOCK_1_H: + return GetData(TYPE_FREYA_HARD) >= 1; + case ACHIEV_CRIT_KNOCK_2_N: + case ACHIEV_CRIT_KNOCK_2_H: + return GetData(TYPE_FREYA_HARD) >= 2; + case ACHIEV_CRIT_KNOCK_3_N: + case ACHIEV_CRIT_KNOCK_3_H: + return GetData(TYPE_FREYA_HARD) == 3; + case ACHIEV_CRIT_FIREFIGHTER_N: + case ACHIEV_CRIT_FIREFIGHTER_H: + return GetData(TYPE_MIMIRON_HARD) == DONE; + case ACHIEV_CRIT_THREE_LIGHTS_N: + case ACHIEV_CRIT_THREE_LIGHTS_H: + return GetData(TYPE_YOGGSARON_HARD) <= 3; + case ACHIEV_CRIT_TWO_LIGHTS_N: + case ACHIEV_CRIT_TWO_LIGHTS_H: + return GetData(TYPE_YOGGSARON_HARD) <= 2; + case ACHIEV_CRIT_ONE_LIGHT_N: + case ACHIEV_CRIT_ONE_LIGHT_H: + return GetData(TYPE_YOGGSARON_HARD) <= 1; + case ACHIEV_CRIT_ALONE_DARK_N: + case ACHIEV_CRIT_ALONE_DARK_H: + return GetData(TYPE_YOGGSARON_HARD) == 0; + case ACHIEV_CRIT_DRIVE_CRAZY_N: + case ACHIEV_CRIT_DRIVE_CRAZY_H: + return m_abAchievCriteria[TYPE_ACHIEV_DRIVE_CRAZY]; + // Champion / Conquerer of Ulduar + case ACHIEV_CRIT_CHAMP_LEVI: + case ACHIEV_CRIT_CHAMP_RAZOR: + case ACHIEV_CRIT_CHAMP_XT: + case ACHIEV_CRIT_CHAMP_IGNIS: + case ACHIEV_CRIT_CHAMP_MIMIRON: + case ACHIEV_CRIT_CHAMP_KOLO: + case ACHIEV_CRIT_CHAMP_VEZAX: + case ACHIEV_CRIT_CHAMP_YOGG: + case ACHIEV_CRIT_CHAMP_AURIAYA: + case ACHIEV_CRIT_CHAMP_THORIM: + case ACHIEV_CRIT_CHAMP_HODIR: + case ACHIEV_CRIT_CHAMP_FREYA: + case ACHIEV_CRIT_CHAMP_COUNCIL: + case ACHIEV_CRIT_CONQ_LEVI: + case ACHIEV_CRIT_CONQ_RAZOR: + case ACHIEV_CRIT_CONQ_XT: + case ACHIEV_CRIT_CONQ_IGNIS: + case ACHIEV_CRIT_CONQ_KOLO: + case ACHIEV_CRIT_CONQ_MIMIRON: + case ACHIEV_CRIT_CONQ_VEZAX: + case ACHIEV_CRIT_CONQ_AURIAYA: + case ACHIEV_CRIT_CONQ_YOGG: + case ACHIEV_CRIT_CONQ_THORIM: + case ACHIEV_CRIT_CONQ_FREYA: + case ACHIEV_CRIT_CONQ_COUNCIL: + case ACHIEV_CRIT_CONQ_HODIR: + { + // First, check if all bosses are killed (except the last encounter) + uint8 uiEncounterDone = 0; + for (uint8 i = 0; i < TYPE_YOGGSARON; ++i) + if (m_auiEncounter[i] == DONE) + ++uiEncounterDone; + + return uiEncounterDone >= 13 && GetData(TYPE_CHAMPION_FAILED) != DONE; + } default: return false; } } +// function which will handle the Flame Leviathan backup spawns +void instance_ulduar::DoCallLeviathanHelp() +{ + Creature* pLeviathan = GetSingleCreatureFromStorage(NPC_LEVIATHAN); + if (!pLeviathan) + return; + + for (uint8 i = 0; i < countof(afReinforcementsNormal); ++i) + pLeviathan->SummonCreature(afReinforcementsNormal[i].uiEntry, afReinforcementsNormal[i].fX, afReinforcementsNormal[i].fY, afReinforcementsNormal[i].fZ, afReinforcementsNormal[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0, true); + + if (!instance->IsRegularDifficulty()) + { + for (uint8 i = 0; i < countof(afReinforcementsHeroic); ++i) + pLeviathan->SummonCreature(afReinforcementsHeroic[i].uiEntry, afReinforcementsHeroic[i].fX, afReinforcementsHeroic[i].fY, afReinforcementsHeroic[i].fZ, afReinforcementsHeroic[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0, true); + } +} + +void instance_ulduar::DoProcessShatteredEvent() +{ + // If timer is already running set achiev criteria to true, else start the timer + if (m_uiShatterAchievTimer) + SetSpecialAchievementCriteria(TYPE_ACHIEV_SHATTERED, true); + else + m_uiShatterAchievTimer = 5000; +} + +void instance_ulduar::DoSpawnHodirNpcs(Player* pSummoner) +{ + if (GetData(TYPE_HODIR) != DONE) + { + for (uint8 i = 0; i < countof(afHodirHelpersNormal); ++i) + pSummoner->SummonCreature(pSummoner->GetTeam() == ALLIANCE ? afHodirHelpersNormal[i].uiAllyEntry : afHodirHelpersNormal[i].uiHordeEntry, afHodirHelpersNormal[i].fX, afHodirHelpersNormal[i].fY, afHodirHelpersNormal[i].fZ, afHodirHelpersNormal[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0, true); + + if (!instance->IsRegularDifficulty()) + { + for (uint8 i = 0; i < countof(afHodirHelpersHeroic); ++i) + pSummoner->SummonCreature(pSummoner->GetTeam() == ALLIANCE ? afHodirHelpersHeroic[i].uiAllyEntry : afHodirHelpersHeroic[i].uiHordeEntry, afHodirHelpersHeroic[i].fX, afHodirHelpersHeroic[i].fY, afHodirHelpersHeroic[i].fZ, afHodirHelpersHeroic[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0, true); + } + } +} + +void instance_ulduar::DoSpawnThorimNpcs(Player* pSummoner) +{ + if (GetData(TYPE_THORIM) != DONE) + { + for (uint8 i = 0; i < countof(afThorimSpawns); ++i) + pSummoner->SummonCreature(pSummoner->GetTeam() == ALLIANCE ? afThorimSpawns[i].uiAllyEntry : afThorimSpawns[i].uiHordeEntry, afThorimSpawns[i].fX, afThorimSpawns[i].fY, afThorimSpawns[i].fZ, afThorimSpawns[i].fO, TEMPSUMMON_DEAD_DESPAWN, 0, true); + } +} + +void instance_ulduar::JustDidDialogueStep(int32 iEntry) +{ + switch (iEntry) + { + case SAY_PRE_LEVIATHAN_1: + case SAY_PRE_LEVIATHAN_2: + case SAY_PRE_LEVIATHAN_3: + DoOrSimulateScriptTextForThisInstance(iEntry, NPC_BRONZEBEARD_RADIO); + break; + case NPC_LEVIATHAN: + // move the leviathan in the arena + if (Creature* pLeviathan = GetSingleCreatureFromStorage(NPC_LEVIATHAN)) + { + // the boss has increased speed for this move; handled as custom + float fSpeedRate = pLeviathan->GetSpeedRate(MOVE_RUN); + pLeviathan->SetWalk(false); + pLeviathan->SetSpeedRate(MOVE_RUN, 5); + pLeviathan->GetMotionMaster()->MovePoint(1, afLeviathanMovePos[0], afLeviathanMovePos[1], afLeviathanMovePos[2]); + pLeviathan->SetSpeedRate(MOVE_RUN, fSpeedRate); + + // modify respawn / home position to the center of arena + pLeviathan->SetRespawnCoord(afLeviathanMovePos[0], afLeviathanMovePos[1], afLeviathanMovePos[2], afLeviathanMovePos[3]); + } + + // Note: starting 4.x this gate is a GO 33 and it's destroyed at this point + DoUseDoorOrButton(GO_LEVIATHAN_GATE); + break; + } +} + +void instance_ulduar::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (GetData(TYPE_IGNIS) == IN_PROGRESS) + { + if (m_uiShatterAchievTimer) + { + // Just set the timer to 0 when it expires + if (m_uiShatterAchievTimer <= uiDiff) + m_uiShatterAchievTimer = 0; + else + m_uiShatterAchievTimer -= uiDiff; + } + } + + if (GetData(TYPE_ALGALON_TIMER)) + { + if (m_uiAlgalonTimer <= uiDiff) + { + --m_auiEncounter[TYPE_ALGALON_TIMER]; + SetData(TYPE_ALGALON_TIMER, m_auiEncounter[TYPE_ALGALON_TIMER]); + m_uiAlgalonTimer = MINUTE * IN_MILLISECONDS; + + if (m_auiEncounter[TYPE_ALGALON_TIMER] == 0) + SetData(TYPE_ALGALON, FAIL); + } + else + m_uiAlgalonTimer -= uiDiff; + } + + if (m_uiYoggResetTimer) + { + if (m_uiYoggResetTimer <= uiDiff) + { + // reset encounter + for (GuidList::const_iterator itr = m_lOminousCloudsGuids.begin(); itr != m_lOminousCloudsGuids.end(); ++itr) + { + if (Creature* pCloud = instance->GetCreature(*itr)) + pCloud->Respawn(); + } + + if (Creature* pVoice = GetSingleCreatureFromStorage(NPC_VOICE_OF_YOGG)) + pVoice->Respawn(); + if (Creature* pSara = GetSingleCreatureFromStorage(NPC_SARA)) + pSara->Respawn(); + if (Creature* pBrain = GetSingleCreatureFromStorage(NPC_YOGG_BRAIN)) + pBrain->Respawn(); + + m_uiYoggResetTimer = 0; + } + else + m_uiYoggResetTimer -= uiDiff; + } + + if (m_uiStairsSpawnTimer) + { + if (m_uiStairsSpawnTimer <= uiDiff) + { + // Note: this part involves a lot of guesswork + // These are the stairs npcs which are summoned before engaging the Rune Giant; both npcs have waypoint movement + if (Creature* pGiant = GetSingleCreatureFromStorage(NPC_RUNE_GIANT)) + { + if (urand(0, 1)) + pGiant->SummonCreature(NPC_HONOR_GUARD_STAIRS, 2101.2f, -434.135f, 438.331f, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + else + pGiant->SummonCreature(NPC_RUNE_ACOLYTE_STAIRS, 2100.41f, -446.712f, 438.331f, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + m_uiStairsSpawnTimer = urand(20000, 30000); + } + else + m_uiStairsSpawnTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_ulduar(Map* pMap) { return new instance_ulduar(pMap); } +bool ProcessEventId_event_ulduar(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (uiEventId == EVENT_ID_SPELL_SHATTER) + { + if (pSource->GetTypeId() == TYPEID_UNIT) + { + if (instance_ulduar* pInstance = (instance_ulduar*)((Creature*)pSource)->GetInstanceData()) + { + pInstance->DoProcessShatteredEvent(); + return true; + } + } + } + else if (uiEventId == EVENT_ID_SHUTDOWN) + { + if (pSource->GetTypeId() == TYPEID_UNIT) + { + if (instance_ulduar* pInstance = (instance_ulduar*)((Creature*)pSource)->GetInstanceData()) + { + pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_SHUTOUT, false); + return true; + } + } + } + else if (uiEventId == EVENT_ID_SCRAP_REPAIR) + { + if (pSource->GetTypeId() == TYPEID_UNIT) + { + if (instance_ulduar* pInstance = (instance_ulduar*)((Creature*)pSource)->GetInstanceData()) + { + pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_NERF_ENG, false); + return true; + } + } + } + + return false; +} + void AddSC_instance_ulduar() { Script* pNewScript; @@ -641,4 +1666,9 @@ void AddSC_instance_ulduar() pNewScript->Name = "instance_ulduar"; pNewScript->GetInstanceData = &GetInstanceData_instance_ulduar; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_ulduar"; + pNewScript->pProcessEventId = &ProcessEventId_event_ulduar; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/ulduar.cpp b/scripts/northrend/ulduar/ulduar/ulduar.cpp index d21f3996e..cb9e6c6a0 100644 --- a/scripts/northrend/ulduar/ulduar/ulduar.cpp +++ b/scripts/northrend/ulduar/ulduar/ulduar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,17 +16,37 @@ /* ScriptData SDName: ulduar -SD%Complete: 0% -SDComment: +SD%Complete: 70% +SDComment: Teleporters are hacked until solved in core SDCategory: Ulduar EndScriptData */ +/* ContentData +go_ulduar_teleporter +npc_brann_ulduar +npc_keeper_norgannon +event_go_ulduar_tower +npc_storm_tempered_keeper +npc_charged_sphere +npc_ulduar_keeper +EndContentData */ + #include "precompiled.h" #include "ulduar.h" /*##### -## Teleporters +## go_ulduar_teleporter #####*/ + +/* **** +* The teleporter spells cannot be used atm, because target-type TARGET_SCRIPT_COORDINATES, NO_TARGET is not yet suitable for needed targeting. (Current core-Design) +* All teleporters are GO with entry 194569 - on them are npcs of entry 32780 spawned. +* However for reload case we would need to be able to target these npcs of not yet loaded grids (currently impossible) +* And in general we would need some "good" way of selecting appropriate target-npcs for each spell, but sorting is nearly impossible, as there are > 50 of these npcs spawned in Ulduar + +* So -- TODO -- remove the TeleportTo Hacks when correct target selection for this spell is working. +*/ + enum TeleporterSpells { SPELL_TELE_EXPEDITION_BASE_CAMP = 64014, @@ -45,7 +65,7 @@ enum TeleporterGossipItems { GOSSIP_ITEM_TELE_BASE_CAMP = -3603000, GOSSIP_ITEM_TELE_FORMATION_GROUNDS = -3603001, - GOSSIP_ITEM_TELE_COLOSSAR_FORGE = -3603002, + GOSSIP_ITEM_TELE_COLOSSAL_FORGE = -3603002, GOSSIP_ITEM_TELE_SCRAPYARD = -3603003, GOSSIP_ITEM_TELE_ANTECHAMBER = -3603004, GOSSIP_ITEM_TELE_WALKWAY = -3603005, @@ -54,6 +74,563 @@ enum TeleporterGossipItems GOSSIP_ITEM_TELE_YOGG_SARON = -3603008, }; +bool GossipHello_go_ulduar_teleporter(Player* pPlayer, GameObject* pGo) +{ + instance_ulduar* pInstance = (instance_ulduar*)pPlayer->GetInstanceData(); + if (!pInstance) + return true; + + // Base camp + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_BASE_CAMP, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + + // Formation grounds + if (pInstance->GetData(TYPE_LEVIATHAN) != NOT_STARTED || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_FORMATION_GROUNDS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + // Colossal Forge + if (pInstance->GetData(TYPE_LEVIATHAN) == DONE || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_COLOSSAL_FORGE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + + // Scrapyard + if (pInstance->GetData(TYPE_XT002) != NOT_STARTED || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_SCRAPYARD, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + + // Antechamber + if (pInstance->GetData(TYPE_XT002) == DONE || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_ANTECHAMBER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + + // Shattered walkway + if (pInstance->GetData(TYPE_KOLOGARN) == DONE || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_WALKWAY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); + + // Conservatory of life + if (pInstance->GetData(TYPE_AURIAYA) == DONE || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_CONSERVATORY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); + + // Spark of imagination + if (pInstance->GetData(TYPE_MIMIRON) != NOT_STARTED || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_SPARK_IMAGINATION, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); + + // Prison of Yogg-Saron + if (pInstance->GetData(TYPE_VEZAX) == DONE || pPlayer->isGameMaster()) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELE_YOGG_SARON, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); + + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pGo->GetGOInfo()->GetGossipMenuId(), pGo), pGo->GetObjectGuid()); + + return true; +} + +bool GossipSelect_go_ulduar_teleporter(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction) +{ + instance_ulduar* pInstance = (instance_ulduar*)pPlayer->GetInstanceData(); + if (!pInstance) + return true; + + // Additional checks for the teleporters to prevent exploiting + // -- TODO -- HACK HERE, use spells when possible! + + // There needs to be displayed a msg when in Combat, it is likely that this is to be handled by core and spell can-cast check + // -- TODO -- Remove the combat check when spells are correctly working + if (pPlayer->isInCombat()) + return true; + + switch (uiAction) + { + // Basecamp + case GOSSIP_ACTION_INFO_DEF: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_EXPEDITION_BASE_CAMP, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, -706.122f, -92.6024f, 429.876f, 0); + break; + // Formation Grounds + case GOSSIP_ACTION_INFO_DEF + 1: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_FORMATION_GROUNDS, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 131.248f, -35.3802f, 409.804f, 0); + break; + // Colossal Forge + case GOSSIP_ACTION_INFO_DEF + 2: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_COLOSSAL_FORGE, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 553.233f, -12.3247f, 409.679f, 0); + break; + // Scrapyard + case GOSSIP_ACTION_INFO_DEF + 3: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_SCRAPYARD, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 926.292f, -11.4635f, 418.595f, 0); + break; + // Antechamber + case GOSSIP_ACTION_INFO_DEF + 4: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_ANTECHAMBER_OF_ULDUAR, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 1498.09f, -24.246f, 420.967f, 0); + break; + // Shattered walkway + case GOSSIP_ACTION_INFO_DEF + 5: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_SHATTERED_WALKWAY, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 1859.45f, -24.1f, 448.9f, 0); + break; + // Conservatory of life + case GOSSIP_ACTION_INFO_DEF + 6: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_CONSERVATORY_OF_LIFE, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 2086.27f, -24.3134f, 421.239f, 0); + break; + // Spark of imagination + case GOSSIP_ACTION_INFO_DEF + 7: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_SPARK_OF_IMAGINATION, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 2518.16f, 2569.03f, 412.299f, 0); + break; + // Prison of Yogg-Saron + case GOSSIP_ACTION_INFO_DEF + 8: + // pPlayer->CastSpell(pPlayer, SPELL_TELE_PRISON_OF_YOGG, true, NULL, NULL, pGo->GetObjectGuid()); + pPlayer->TeleportTo(603, 1854.82f, -11.56f, 334.175f, 4.71f); + break; + default: + return true; + } + + pPlayer->CLOSE_GOSSIP_MENU(); + return true; +} + +/*###### +## npc_brann_ulduar +######*/ + +enum +{ + GOSSIP_ITEM_BEGIN_ASSAULT = -3603012, + GOSSIP_TEXT_ID_BRANN = 14369, +}; + +bool GossipHello_npc_brann_ulduar(Player* pPlayer, Creature* pCreature) +{ + if (instance_ulduar* pInstance = (instance_ulduar*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_LEVIATHAN_GAUNTLET) == NOT_STARTED && pInstance->GetData(TYPE_LEVIATHAN) == NOT_STARTED) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BEGIN_ASSAULT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_BRANN, pCreature->GetObjectGuid()); + } + return true; +} + +bool GossipSelect_npc_brann_ulduar(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + if (instance_ulduar* pInstance = (instance_ulduar*)pCreature->GetInstanceData()) + { + // if encounter is started by Brann then hard mode is failed + pInstance->SetData(TYPE_TOWER_FREYA, FAIL); + pInstance->SetData(TYPE_TOWER_HODIR, FAIL); + pInstance->SetData(TYPE_TOWER_MIMIRON, FAIL); + pInstance->SetData(TYPE_TOWER_THORIM, FAIL); + + // set gauntlet in progress; rest of the event is done by DB scripts + pInstance->SetData(TYPE_LEVIATHAN_GAUNTLET, IN_PROGRESS); + pCreature->GetMotionMaster()->MoveWaypoint(); + } + + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## npc_keeper_norgannon +######*/ + +enum +{ + GOSSIP_ITEM_ACTIVATE_SYSTEMS = -3603010, + GOSSIP_ITEM_CONFIRMED = -3603011, + + GOSSIP_TEXT_ID_GREET = 14375, + GOSSIP_TEXT_ID_DEFENSES = 14496, + GOSSIP_TEXT_ID_ACTIVATED = 14497, +}; + +bool GossipHello_npc_keeper_norgannon(Player* pPlayer, Creature* pCreature) +{ + if (instance_ulduar* pInstance = (instance_ulduar*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_LEVIATHAN_GAUNTLET) == NOT_STARTED && pInstance->GetData(TYPE_LEVIATHAN) == NOT_STARTED && pInstance->GetData(TYPE_TOWER_HODIR) == NOT_STARTED && + pInstance->GetData(TYPE_TOWER_FREYA) == NOT_STARTED && pInstance->GetData(TYPE_TOWER_MIMIRON) == NOT_STARTED && pInstance->GetData(TYPE_TOWER_THORIM) == NOT_STARTED) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_ACTIVATE_SYSTEMS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_GREET, pCreature->GetObjectGuid()); + } + return true; +} + +bool GossipSelect_npc_keeper_norgannon(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_CONFIRMED, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_DEFENSES, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + if (instance_ulduar* pInstance = (instance_ulduar*)pCreature->GetInstanceData()) + { + // if hard mode is triggered all towers become active and encounter starts automatically + pInstance->SetData(TYPE_TOWER_FREYA, DONE); + pInstance->SetData(TYPE_TOWER_HODIR, DONE); + pInstance->SetData(TYPE_TOWER_MIMIRON, DONE); + pInstance->SetData(TYPE_TOWER_THORIM, DONE); + + // set gauntlet in progress and despawn the Lorekeeper; rest of the event is done by DB scripts + pInstance->SetData(TYPE_LEVIATHAN_GAUNTLET, IN_PROGRESS); + pCreature->ForcedDespawn(10000); + + if (Creature* pDellorah = pInstance->GetSingleCreatureFromStorage(NPC_EXPLORER_DELLORAH)) + pDellorah->GetMotionMaster()->MoveWaypoint(); + if (Creature* pBrann = pInstance->GetSingleCreatureFromStorage(NPC_BRANN_BRONZEBEARD)) + pBrann->GetMotionMaster()->MoveWaypoint(); + } + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_ACTIVATED, pCreature->GetObjectGuid()); + break; + } + + return true; +} + +/*###### +## event_go_ulduar_tower +######*/ + +bool ProcessEventId_event_go_ulduar_tower(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (pSource->GetTypeId() == TYPEID_GAMEOBJECT && ((GameObject*)pSource)->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) + { + instance_ulduar* pInstance = (instance_ulduar*)((GameObject*)pSource)->GetInstanceData(); + if (!pInstance) + return true; + + // Towers can be deactivated by destroying them. Notify instance data in case they get destroyed. + switch (uiEventId) + { + case EVENT_ID_TOWER_LIFE: + pInstance->SetData(TYPE_TOWER_FREYA, FAIL); + break; + case EVENT_ID_TOWER_FLAME: + pInstance->SetData(TYPE_TOWER_MIMIRON, FAIL); + break; + case EVENT_ID_TOWER_FROST: + pInstance->SetData(TYPE_TOWER_HODIR, FAIL); + break; + case EVENT_ID_TOWER_STORMS: + pInstance->SetData(TYPE_TOWER_THORIM, FAIL); + break; + default: + return false; + } + + // despawn all generators in range + std::list lGenerators; + GetCreatureListWithEntryInGrid(lGenerators, (GameObject*)pSource, NPC_GENERATOR_SMALL, 100.0f); + for (std::list::iterator itr = lGenerators.begin(); itr != lGenerators.end(); ++itr) + (*itr)->ForcedDespawn(); + + // allow further DB processing + return false; + } + + return false; +} + +/*###### +## npc_storm_tempered_keeper +######*/ + +enum +{ + SPELL_FORKED_LIGHTNING = 63541, + SPELL_SEPARATION_ANXIETY = 63539, // cast when a buddy is too far away + SPELL_VENGEFUL_SURGE = 63630, // cast when a buddy dies + SPELL_SUMMON_CHARGED_SPHERE = 63527, // summons npc 33715 + + SPELL_CHARGED_SPERE = 63537, // charged sphere spells + SPELL_SUPERCHARGED = 63528, + + NPC_TEMPERED_KEEPER_1 = 33699, + NPC_TEMPERED_KEEPER_2 = 33722, + NPC_CHARGED_SPHERE = 33715, // moves to buddy keeper location + + MAX_KEEPER_DISTANCE = 70, +}; + +struct npc_storm_tempered_keeperAI : public ScriptedAI +{ + npc_storm_tempered_keeperAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiCheckBuddyTimer; + uint32 m_uiLightningTimer; + uint32 m_uiSphereTimer; + + ObjectGuid m_buddyGuid; + + void Reset() override + { + m_uiCheckBuddyTimer = 1000; + m_uiLightningTimer = urand(5000, 10000); + m_uiSphereTimer = urand(10000, 30000); + } + + void Aggro(Unit* pWho) override + { + // initialize nearby buddy + if (Creature* pKeeper = GetClosestCreatureWithEntry(m_creature, m_creature->GetEntry() == NPC_TEMPERED_KEEPER_1 ? NPC_TEMPERED_KEEPER_2 : NPC_TEMPERED_KEEPER_1, 20)) + m_buddyGuid = pKeeper->GetObjectGuid(); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_CHARGED_SPHERE) + { + pSummoned->CastSpell(pSummoned, SPELL_CHARGED_SPERE, true); + + // move to buddy location and notify about buddy entry + if (Creature* pBuddy = m_creature->GetMap()->GetCreature(m_buddyGuid)) + { + pSummoned->GetMotionMaster()->MoveFollow(pBuddy, 0, 0); + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pSummoned, pBuddy->GetEntry()); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiCheckBuddyTimer) + { + if (m_uiCheckBuddyTimer <= uiDiff) + { + Creature* pBuddy = m_creature->GetMap()->GetCreature(m_buddyGuid); + if (!pBuddy) + { + script_error_log("npc_storm_tempered_keeper for %s couldn't find its buddy.", m_creature->GetGuidStr().c_str()); + m_uiCheckBuddyTimer = 0; + return; + } + + // check if buddy is withind distance or alive + if (!pBuddy->IsWithinDistInMap(m_creature, MAX_KEEPER_DISTANCE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_SEPARATION_ANXIETY) == CAST_OK) + m_uiCheckBuddyTimer = 5000; + } + else if (!pBuddy->isAlive()) + { + if (DoCastSpellIfCan(m_creature, SPELL_VENGEFUL_SURGE) == CAST_OK) + m_uiCheckBuddyTimer = 0; + } + else + m_uiCheckBuddyTimer = 1000; + } + else + m_uiCheckBuddyTimer -= uiDiff; + + // spawn a sphere only if the buddy is stil alive + if (m_uiSphereTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_CHARGED_SPHERE) == CAST_OK) + m_uiSphereTimer = urand(20000, 35000); + } + else + m_uiSphereTimer -= uiDiff; + } + + if (m_uiLightningTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FORKED_LIGHTNING) == CAST_OK) + m_uiLightningTimer = urand(10000, 15000); + } + else + m_uiLightningTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_storm_tempered_keeper(Creature* pCreature) +{ + return new npc_storm_tempered_keeperAI(pCreature); +} + +/*###### +## npc_charged_sphere +######*/ + +struct npc_charged_sphereAI : public ScriptedAI +{ + npc_charged_sphereAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + bool m_bIsCharged; + uint32 m_uiBuddyEntry; + + void Reset() override + { + m_bIsCharged = false; + m_uiBuddyEntry = 0; + } + + void MoveInLineOfSight(Unit* pWho) override + { + // cast supercharged if reached the buddy + if (!m_bIsCharged && pWho->GetEntry() == m_uiBuddyEntry && pWho->isAlive() && pWho->IsWithinDistInMap(m_creature, 5.0f)) + { + DoCastSpellIfCan(pWho, SPELL_SUPERCHARGED, CAST_TRIGGERED); + m_creature->ForcedDespawn(1000); + m_bIsCharged = true; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 uiMiscValue) override + { + // inity entry of the buddy keeper + if (eventType == AI_EVENT_CUSTOM_A) + m_uiBuddyEntry = uiMiscValue; + } + + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_charged_sphere(Creature* pCreature) +{ + return new npc_charged_sphereAI(pCreature); +} + +/*###### +## npc_ulduar_keeper +######*/ + +enum +{ + SAY_KEEPER_ACTIVE = -1603012, + + GOSSIP_ITEM_LEND_AID = -3603013, + GOSSIP_ITEM_KEEPER_CONFIRM = -3603014, + + GOSSIP_TEXT_ID_HODIR = 14326, + GOSSIP_TEXT_ID_FREYA = 14332, + GOSSIP_TEXT_ID_THORIM = 14333, + GOSSIP_TEXT_ID_MIMIRON = 14334, + GOSSIP_TEXT_ID_KEEPER_CONFIRM = 14325, + GOSSIP_TEXT_ID_YOGG_DEFEATED = 384, // ToDo: add the right text id here! +}; + +bool GossipHello_npc_ulduar_keeper(Player* pPlayer, Creature* pCreature) +{ + if (instance_ulduar* pInstance = (instance_ulduar*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_YOGGSARON) == DONE) + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_YOGG_DEFEATED, pCreature->GetObjectGuid()); + else + { + switch (pCreature->GetEntry()) + { + case NPC_KEEPER_HODIR: + if (pInstance->GetData(TYPE_KEEPER_HODIR) != DONE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_LEND_AID, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_HODIR, pCreature->GetObjectGuid()); + break; + case NPC_KEEPER_FREYA: + if (pInstance->GetData(TYPE_KEEPER_FREYA) != DONE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_LEND_AID, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_FREYA, pCreature->GetObjectGuid()); + break; + case NPC_KEEPER_THORIM: + if (pInstance->GetData(TYPE_KEEPER_THORIM) != DONE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_LEND_AID, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_THORIM, pCreature->GetObjectGuid()); + break; + case NPC_KEEPER_MIMIRON: + if (pInstance->GetData(TYPE_KEEPER_MIMIRON) != DONE) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_LEND_AID, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_MIMIRON, pCreature->GetObjectGuid()); + break; + } + } + } + return true; +} + +bool GossipSelect_npc_ulduar_keeper(Player* pPlayer, Creature* pCreature, uint32 /*sender*/, uint32 uiAction) +{ + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KEEPER_CONFIRM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_KEEPER_CONFIRM, pCreature->GetObjectGuid()); + break; + case GOSSIP_ACTION_INFO_DEF+2: + DoScriptText(SAY_KEEPER_ACTIVE, pCreature, pPlayer); + pPlayer->CLOSE_GOSSIP_MENU(); + + if (instance_ulduar* pInstance = (instance_ulduar*)pCreature->GetInstanceData()) + { + switch (pCreature->GetEntry()) + { + case NPC_KEEPER_HODIR: pInstance->SetData(TYPE_KEEPER_HODIR, DONE); break; + case NPC_KEEPER_FREYA: pInstance->SetData(TYPE_KEEPER_FREYA, DONE); break; + case NPC_KEEPER_THORIM: pInstance->SetData(TYPE_KEEPER_THORIM, DONE); break; + case NPC_KEEPER_MIMIRON: pInstance->SetData(TYPE_KEEPER_MIMIRON, DONE); break; + } + } + break; + } + + return true; +} + void AddSC_ulduar() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "go_ulduar_teleporter"; + pNewScript->pGossipHelloGO = &GossipHello_go_ulduar_teleporter; + pNewScript->pGossipSelectGO = &GossipSelect_go_ulduar_teleporter; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_brann_ulduar"; + pNewScript->pGossipHello = &GossipHello_npc_brann_ulduar; + pNewScript->pGossipSelect = &GossipSelect_npc_brann_ulduar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_keeper_norgannon"; + pNewScript->pGossipHello = &GossipHello_npc_keeper_norgannon; + pNewScript->pGossipSelect = &GossipSelect_npc_keeper_norgannon; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_go_ulduar_tower"; + pNewScript->pProcessEventId = &ProcessEventId_event_go_ulduar_tower; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_storm_tempered_keeper"; + pNewScript->GetAI = &GetAI_npc_storm_tempered_keeper; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_charged_sphere"; + pNewScript->GetAI = &GetAI_npc_charged_sphere; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ulduar_keeper"; + pNewScript->pGossipHello = &GossipHello_npc_ulduar_keeper; + pNewScript->pGossipSelect = &GossipSelect_npc_ulduar_keeper; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/ulduar/ulduar/ulduar.h b/scripts/northrend/ulduar/ulduar/ulduar.h index 493e5abb8..1d6f7891c 100644 --- a/scripts/northrend/ulduar/ulduar/ulduar.h +++ b/scripts/northrend/ulduar/ulduar/ulduar.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,8 +7,8 @@ enum { - MAX_ENCOUNTER = 14, - HARD_MODE_ENCOUNTER = 7, + MAX_ENCOUNTER = 16, + HARD_MODE_ENCOUNTER = 8, KEEPER_ENCOUNTER = 4, // Main boss types @@ -26,30 +26,69 @@ enum TYPE_VEZAX = 11, TYPE_YOGGSARON = 12, TYPE_ALGALON = 13, + TYPE_ALGALON_TIMER = 14, + TYPE_CHAMPION_FAILED = 15, // Achievements Champion / Conquerer of Ulduar, needs to be saved to database // Hard mode boss types // Used for hard mode bosses only - TYPE_LEVIATHAN_HARD = 14, - TYPE_XT002_HARD = 15, - TYPE_MIMIRON_HARD = 17, - TYPE_HODIR_HARD = 18, - TYPE_THORIM_HARD = 19, - TYPE_VEZAX_HARD = 21, - TYPE_YOGGSARON_HARD = 22, + TYPE_LEVIATHAN_HARD = 16, + TYPE_XT002_HARD = 17, + TYPE_MIMIRON_HARD = 18, + TYPE_HODIR_HARD = 19, + TYPE_THORIM_HARD = 20, + TYPE_FREYA_HARD = 21, + TYPE_VEZAX_HARD = 22, + TYPE_YOGGSARON_HARD = 23, // Keeper types // Used to store the keepers which will be used at yogg - TYPE_KEEPER_HODIR = 23, - TYPE_KEEPER_FREYA = 24, - TYPE_KEEPER_THORIM = 25, - TYPE_KEEPER_MIMIRON = 26, + TYPE_KEEPER_HODIR = 24, + TYPE_KEEPER_FREYA = 25, + TYPE_KEEPER_THORIM = 26, + TYPE_KEEPER_MIMIRON = 27, + + // Tower types + // Used to store the towers which will be used at Leviathan encounter + TYPE_TOWER_HODIR = 28, + TYPE_TOWER_FREYA = 29, + TYPE_TOWER_THORIM = 30, + TYPE_TOWER_MIMIRON = 31, + + // Other types - not saved + TYPE_LEVIATHAN_GAUNTLET = 32, // The siege of ulduar NPC_LEVIATHAN = 33113, - NPC_IGNIS = 33118, + // NPC_IGNIS = 33118, NPC_RAZORSCALE = 33186, - NPC_COMMANDER = 33210, NPC_XT002 = 33293, + NPC_HEART_DECONSTRUCTOR = 33329, + NPC_XT_TOY_PILE = 33337, // robot spawner npc for XT002 + + // Leviathan other npcs + NPC_ULDUAR_COLOSSUS = 33237, + NPC_BRONZEBEARD_RADIO = 34054, + NPC_EXPLORER_DELLORAH = 33701, + NPC_BRANN_BRONZEBEARD = 33579, + NPC_ORBITAL_SUPPORT = 34286, + // NPC_GENERATOR = 33571, // spawns iron dwarfs from Storm Beacons + NPC_GENERATOR_SMALL = 34159, // spawns iron dwarfs from hard mode towers + + // Leviathan reinforcements + // NPC_HIRED_ENGINEER = 33626, + // NPC_HIRED_DEMOLITIONIST = 33627, + // NPC_BATTLE_MAGE = 33662, + NPC_SALVAGED_SIEGE_ENGINE = 33060, + NPC_SALVAGED_CHOPPER = 33062, + NPC_SALVAGED_DEMOLISHER = 33109, + // NPC_LIQUID_PYRITE = 33189, + + // Razorscale helper npcs + NPC_EXPEDITION_COMMANDER = 33210, + NPC_EXPEDITION_ENGINEER = 33287, // npc used to repair the Harpoons + NPC_EXPEDITION_TRAPPER = 33259, // npc used in Razorscale grounding phase + NPC_EXPEDITION_DEFENDER = 33816, // used to fight Razorscale + NPC_RAZORSCALE_CONTROLLER = 33233, // harpoon shot trigger npc for phase // The antechamber of ulduar NPC_STEELBREAKER = 32867, @@ -58,50 +97,113 @@ enum NPC_KOLOGARN = 32930, NPC_RIGHT_ARM = 32934, NPC_LEFT_ARM = 32933, + NPC_RUBBLE_STALKER = 33809, // npc which spawns Rubble on Kologarn arms death NPC_AURIAYA = 33515, NPC_SANCTUM_SENTRY = 34014, NPC_FERAL_DEFENDER = 34035, + // Archivum + NPC_BRANN_ARCHIVUM = 33235, // npcs are spawned upon the Iron Council defeat; they handle specific quests + NPC_PROSPECTOR_DOREN = 33956, + NPC_PROSPECTOR_DOREN_H = 33957, + NPC_BRANN_ALGALON = 34064, // Brann entry summoned for the Algalon intro and epilogue event + // The keepers of ulduar NPC_MIMIRON = 33350, - NPC_LEVIATHAN_MK = 33432, - NPC_VX001 = 33651, - NPC_AERIAL_UNIT = 33670, NPC_HODIR = 32845, NPC_THORIM = 32865, - NPC_RUNIC_COLOSSUS = 32872, - NPC_RUNE_GIANT = 32873, - NPC_JORMUNGAR_BEHEMOTH = 32882, NPC_FREYA = 32906, + + // Freya elders NPC_ELDER_BRIGHTLEAF = 32915, NPC_ELDER_IRONBRACH = 32913, NPC_ELDER_STONEBARK = 32914, + NPC_FREYA_ACHIEV_TRIGGER = 33406, // Cast spell 65015 for achievs 2985 and 2984 + + // Hodir helpers + NPC_DRUID_HORDE_N = 32941, // Tor Greycloud + NPC_DRUID_HORDE_H = 33333, // Kar Greycloud + NPC_SHAMAN_HORDE_N = 32950, // Spiritwalker Yona + NPC_SHAMAN_HORDE_H = 33332, // Spiritwalker Tara + NPC_MAGE_HORDE_N = 32946, // Veesha Blazeweaver + NPC_MAGE_HORDE_H = 33331, // Amira Blazeweaver + NPC_PRIEST_HORDE_N = 32948, // Battle-Priest Eliza + NPC_PRIEST_HORDE_H = 33330, // Battle-Priest Gina + NPC_DRUID_ALLIANCE_N = 32901, // Ellie Nightfeather + NPC_DRUID_ALLIANCE_H = 33325, // Eivi Nightfeather + NPC_SHAMAN_ALLIANCE_N = 32900, // Elementalist Avuun + NPC_SHAMAN_ALLIANCE_H = 33328, // Elementalist Mahfuun + NPC_MAGE_ALLIANCE_N = 32893, // Missy Flamecuffs + NPC_MAGE_ALLIANCE_H = 33327, // Sissy Flamecuffs + NPC_PRIEST_ALLIANCE_N = 32897, // Field Medic Penny + NPC_PRIEST_ALLIANCE_H = 33326, // Field Medic Jessi + + // Thorim event npcs + NPC_RUNIC_COLOSSUS = 32872, + NPC_RUNE_GIANT = 32873, + NPC_SIF = 33196, + NPC_JORMUNGAR_BEHEMOTH = 32882, + NPC_DARK_RUNE_ACOLYTE = 32886, + NPC_SOLDIER_ALLIANCE = 32885, + NPC_CAPTAIN_ALLIANCE = 32908, + NPC_SOLDIER_HORDE = 32883, + NPC_CAPTAIN_HORDE = 32907, + NPC_THORIM_EVENT_BUNNY = 32892, + NPC_THUNDER_ORB = 33378, + NPC_THORIM_CONTROLLER = 32879, + NPC_THORIM_COMBAT_TRIGGER = 34055, + NPC_RIGHT_HAND_BUNNY = 33140, + NPC_LEFT_HAND_BUNNY = 33141, + NPC_HONOR_GUARD_STAIRS = 33125, // summoned mobs before the Rune Giant + NPC_RUNE_ACOLYTE_STAIRS = 32957, + + // Mimiron event npcs + NPC_LEVIATHAN_MK = 33432, + NPC_LEVIATHAN_MK_TURRET = 34071, + NPC_VX001 = 33651, + NPC_AERIAL_UNIT = 33670, + NPC_COMPUTER = 34143, + NPC_BOT_SUMMON_TRIGGER = 33856, + NPC_WORLD_TRIGGER_FLAMES = 21252, // The descent into madness NPC_VEZAX = 33271, NPC_SARONITE_ANIMUS = 33524, + NPC_VEZAX_BUNNY = 33500, NPC_YOGGSARON = 33288, NPC_SARA = 33134, NPC_YOGG_BRAIN = 33890, + NPC_VOICE_OF_YOGG = 33280, + NPC_OMINOUS_CLOUD = 33292, + NPC_GUARDIAN_OF_YOGG = 33136, + + // Yogg Saron illusions actors + NPC_YSERA = 33495, + NPC_NELTHARION = 33523, + NPC_MALYGOS = 33535, + NPC_ALEXSTRASZA = 33536, + NPC_GARONA = 33436, // cast spell 64063 on 33437 + NPC_KING_LLANE = 33437, + NPC_LICH_KING = 33441, // cast spell 63037 on 33442 + NPC_IMMOLATED_CHAMPION = 33442, + NPC_YOGGSARON_ILLUSION = 33552, // Celestial planetarium NPC_ALGALON = 32871, - // Keepers images - // They spawn in the central room after they are released from Yogg's enslavement - // You may talk to them and ask them to help you fight Yogg-Saron - NPC_THORIM_IMAGE = 33413, - NPC_MIMIRON_IMAGE = 33412, - NPC_HODIR_IMAGE = 33411, - NPC_FREYA_IMAGE = 33410, + // Keepers helpers spawned during Yogg Saron encounter + NPC_THORIM_HELPER = 33413, + NPC_MIMIRON_HELPER = 33412, + NPC_HODIR_HELPER = 33411, + NPC_FREYA_HELPER = 33410, - // Keepers used to fight Yogg-Saron + // Keepers spawned in the central hall after releaseed from Yogg's enslavement NPC_KEEPER_FREYA = 33241, NPC_KEEPER_HODIR = 33213, NPC_KEEPER_MIMIRON = 33244, NPC_KEEPER_THORIM = 33242, - MAX_SPECIAL_ACHIEV_CRITS = 6, + MAX_SPECIAL_ACHIEV_CRITS = 20, TYPE_ACHIEV_CAT_LADY = 0, TYPE_ACHIEV_NINE_LIVES = 1, @@ -109,6 +211,20 @@ enum TYPE_ACHIEV_BRUNDIR = 3, TYPE_ACHIEV_MOLGEIM = 4, TYPE_ACHIEV_STUNNED = 5, + TYPE_ACHIEV_SHATTERED = 6, + TYPE_ACHIEV_QUICK_SHAVE = 7, + TYPE_ACHIEV_SHUTOUT = 8, + TYPE_ACHIEV_NERF_ENG = 9, + TYPE_ACHIEV_RUBBLE = 10, + TYPE_ACHIEV_LOOKS_KILL = 11, + TYPE_ACHIEV_OPEN_ARMS = 12, + TYPE_ACHIEV_DISARMED = 13, + TYPE_ACHIEV_CHEESE_FREEZE = 14, + TYPE_ACHIEV_COOL_FRIENDS = 15, + TYPE_ACHIEV_LIGHTNING = 16, + TYPE_ACHIEV_BACK_NATURE = 17, + TYPE_ACHIEV_DRIVE_CRAZY = 18, + TYPE_ACHIEV_SHADOWDODGER = 19, // Loot chests // Kologarn @@ -140,24 +256,35 @@ enum // Doors and other Objects // The siege GO_SHIELD_WALL = 194416, // Gate before Leviathan - GO_LIGHTNING_FIELD = 194559, // Lightning gate after the Leviathan. It closes after the boss enters the arena + GO_LIGHTNING_DOOR = 194905, // Lightning gate after the Leviathan. It closes after the boss enters the arena GO_LEVIATHAN_GATE = 194630, // Gate after Leviathan -> this will be broken when the boss enters the arena GO_XT002_GATE = 194631, // Gate before Xt002 GO_BROKEN_HARPOON = 194565, // Broken harpoon from Razorscale + GO_HARPOON_GUN_1 = 194542, // usable harpoons - respawn when the broken one is repaired + GO_HARPOON_GUN_2 = 194541, + GO_HARPOON_GUN_3 = 194543, + GO_HARPOON_GUN_4 = 194519, + GO_FREYA_CRYSTAL = 194704, // crystals which can be active during Leviathan encounter if hard mode towers are active + GO_MIMIRON_CRYSTAL = 194705, + GO_THORIM_CRYSTAL = 194706, + GO_HODIR_CRYSTAL = 194707, // Antechamber GO_KOLOGARN_BRIDGE = 194232, - GO_SHATTERED_DOOR = 194553, // Door before kologarn + // GO_SHATTERED_DOOR = 194553, // Door before kologarn GO_IRON_ENTRANCE_DOOR = 194554, // Door before iron council GO_ARCHIVUM_DOOR = 194556, // Entrance door to the archivum - GO_ARCHIVUM_CONSOLE = 194555, // Used at some sort of cinematic - GO_UNIVERSE_FLOOR_ARCHIVUM = 194715, // Used for animation + // GO_ARCHIVUM_CONSOLE = 194555, // Used at some sort of cinematic + // GO_FLOOR_ARCHIVUM = 194715, // Used for animation // Planetarium GO_CELESTIAL_ACCES = 194628, // Acces console for 10 man mode GO_CELESTIAL_ACCES_H = 194752, // Acces console for 25 man mode - GO_CELESTIAL_DOOR = 194767, // Entrance door to the planetarium - GO_UNIVERSE_FLOOR_CELESTIAL = 194716, // For animation + GO_CELESTIAL_DOOR_1 = 194767, // Entrance doors to the planetarium + GO_CELESTIAL_DOOR_2 = 194911, + GO_CELESTIAL_DOOR_COMBAT = 194910, + GO_UNIVERSE_FLOOR = 194716, // For animation + GO_UNIVERSE_FLOOR_COMBAT = 194715, GO_AZEROTH_GLOBE = 194148, // For animation // The keepers @@ -166,7 +293,7 @@ enum GO_HODIR_ICE_WALL = 194441, GO_HODIR_ENTER = 194442, // Mimiron - G0_MIMIRON_BUTTON = 194739, // Used to start hard mode + GO_MIMIRON_BUTTON = 194739, // Used to start hard mode GO_MIMIRON_DOOR_1 = 194774, GO_MIMIRON_DOOR_2 = 194775, GO_MIMIRON_DOOR_3 = 194776, @@ -184,24 +311,54 @@ enum GO_DARK_IRON_PORTCULIS = 194560, // Door from the arena to the hallway GO_RUNED_STONE_DOOR = 194557, // Door after the runic colossus GO_THORIM_STONE_DOOR = 194558, // Door after the ancient rune giant - GO_LIGHTNING_DOOR = 194905, // Arena exit door + GO_LIGHTNING_FIELD = 194559, // Arena exit door GO_DOOR_LEVER = 194264, // In front of the door // Descent to madness GO_ANCIENT_GATE = 194255, // Door upstairs before vezax, opens when all keepers are freed GO_VEZAX_GATE = 194750, // Door after vezax GO_YOGG_GATE = 194773, // Yogg-Saron chamber door - GO_BRAIN_DOOR1 = 194635, // Brain chamber doors - GO_BRAIN_DOOR2 = 194636, - GO_BRAIN_DOOR3 = 194637, + GO_BRAIN_DOOR_CHAMBER = 194635, // Brain chamber doors + GO_BRAIN_DOOR_ICECROWN = 194636, + GO_BRAIN_DOOR_STORMWIND = 194637, + GO_FLEE_TO_SURFACE = 194625, // Brain chamber portals // World state used for algalon timer WORLD_STATE_TIMER = 4132, WORLD_STATE_TIMER_COUNT = 4131, + // common spells + SPELL_TELEPORT = 62940, + + // events + EVENT_ID_SHUTDOWN = 21605, + EVENT_ID_SCRAP_REPAIR = 21606, + EVENT_ID_SPELL_SHATTER = 21620, + EVENT_ID_TOWER_LIFE = 21030, // events checked when a tower is destroyed + EVENT_ID_TOWER_FLAME = 21033, + EVENT_ID_TOWER_FROST = 21032, + EVENT_ID_TOWER_STORMS = 21031, + + // area triggers + AREATRIGGER_ID_INTRO = 5388, // starts the intro dialogue + AREATRIGGER_ID_REPAIR_1 = 5369, // related to vehicle repair + AREATRIGGER_ID_REPAIR_2 = 5423, + // Achievement related + ACHIEV_START_IGNIS_ID = 20951, // Ignis timed achievs 2930, 2929 + ACHIEV_START_XT002_ID = 21027, // XT-002 timed achievs 2937, 2938 + ACHIEV_START_FREYA_ID = 21597, // Freya timed achievs 2980, 2981 + ACHIEV_START_YOGG_ID = 21001, // Yogg timed achievs 3012, 3013 + ACHIEV_START_COMING_WALLS = 33136, // Guardian of Yogg timed achievs 3014, 3017 + ACHIEV_START_DWARFAGEDDON = 65387, // Ulduar gauntlet timed achievs 3097, 3098; triggered by missing spell 65387 + ACHIEV_START_LUMBERJACKED = 21686, // Ulduar elder kill timed achievs 2979, 3118; triggered by missing spell 65296 + ACHIEV_START_NERF_BOTS = 65037, // XT-002 gauntlet timed achievs 2933, 2935; triggered by missing spell 65037 + ACHIEV_START_SUPERMASSIVE = 21697, // Black hole timed achievs 3003, 3002 + ACHIEV_CRIT_SARONITE_N = 10451, // General Vezax, achievs 3181, 3188 ACHIEV_CRIT_SARONITE_H = 10462, + ACHIEV_CRIT_SHADOWDODGER_N = 10173, // General Vezax, achievs 2996, 2997 + ACHIEV_CRIT_SHADOWDODGER_H = 10306, ACHIEV_CRIT_CAT_LADY_N = 10400, // Auriaya, achievs 3006, 3007 ACHIEV_CRIT_CAT_LADY_H = 10184, ACHIEV_CRIT_NINE_LIVES_N = 10399, // Auriaya, achievs 3076, 3077 @@ -218,42 +375,261 @@ enum ACHIEV_CRIT_STUNNED_BRUND_H = 10091, // Iron council, achiev 2948 ACHIEV_CRIT_STUNNED_STEEL_H = 10424, ACHIEV_CRIT_STUNNED_MOLG_H = 10425, + ACHIEV_CRIT_SHATTERED_N = 10068, // Ignis, achievs 2925, 2926 + ACHIEV_CRIT_SHATTERED_H = 10069, + ACHIEV_CRIT_HEARTBREAKER_N = 10221, // XT-002, achievs 3058, 3059 + ACHIEV_CRIT_HEARTBREAKER_H = 10220, + ACHIEV_CRIT_NERF_ENG_N = 10074, // XT-002, achievs 2931, 2932 + ACHIEV_CRIT_NERF_ENG_H = 10075, + ACHIEV_CRIT_NERF_GRAVITY_N = 10077, // XT-002, achievs 2934, 2936 + ACHIEV_CRIT_NERF_GRAVITY_H = 10079, + ACHIEV_CRIT_QUICK_SHAVE_N = 10062, // Razorscale, achievs 2919, 2921 + ACHIEV_CRIT_QUICK_SHAVE_H = 10063, + ACHIEV_CRIT_ORB_BOMB_N = 10056, // Flame Leviathan, achievs 2913, 2918 (one tower) + ACHIEV_CRIT_ORB_BOMB_H = 10061, + ACHIEV_CRIT_ORB_DEV_N = 10057, // Flame Leviathan, achievs 2914, 2916 (two towers) + ACHIEV_CRIT_ORB_DEV_H = 10059, + ACHIEV_CRIT_ORB_NUKED_N = 10058, // Flame Leviathan, achievs 2915, 2917 (three towers) + ACHIEV_CRIT_ORB_NUKED_H = 10060, + ACHIEV_CRIT_ORBITUARY_N = 10218, // Flame Leviathan, achievs 3056, 3057 (four towers) + ACHIEV_CRIT_ORBITUARY_H = 10219, + ACHIEV_CRIT_SHUTOUT_N = 10054, // Flame Leviathan, achievs 2911, 2913 + ACHIEV_CRIT_SHUTOUT_H = 10055, + ACHIEV_CRIT_UNBROKEN_N = 10044, // Flame Leviathan, achievs 2905, 2906 + ACHIEV_CRIT_UNBROKEN_H = 10045, + ACHIEV_CRIT_DISARMED_N = 10284, // Kologarn, achievs 2953, 2954 + ACHIEV_CRIT_DISARMED_H = 10722, + ACHIEV_CRIT_LOOKS_KILL_N = 10286, // Kologarn, achievs 2955, 2956 + ACHIEV_CRIT_LOOKS_KILL_H = 10099, + ACHIEV_CRIT_RUBBLE_ROLL_N = 10290, // Kologarn, achievs 2959, 2960 + ACHIEV_CRIT_RUBBLE_ROLL_H = 10133, + ACHIEV_CRIT_OPEN_ARMS_N = 10285, // Kologarn, achievs 2951, 2952 + ACHIEV_CRIT_OPEN_ARMS_H = 10095, + ACHIEV_CRIT_FEEDS_TEARS_N = 10568, // Algalon, achievs 3004, 3005 + ACHIEV_CRIT_FEEDS_TEARS_H = 10570, + ACHIEV_CRIT_CHEESE_N = 10259, // Hodir, achievs 2961, 2962 + ACHIEV_CRIT_CHEESE_H = 10261, + ACHIEV_CRIT_GETTING_COLD_N = 10247, // Hodir, achievs 2967, 2968 + ACHIEV_CRIT_GETTING_COLD_H = 10248, + ACHIEV_CRIT_COOL_FRIENDS_N = 10258, // Hodir, achievs 2963, 2965 + ACHIEV_CRIT_COOL_FRIENDS_H = 10260, + ACHIEV_CRIT_RARE_CACHE_N = 10452, // Hodir, achievs 3182, 3184 + ACHIEV_CRIT_RARE_CACHE_H = 10458, + ACHIEV_CRIT_LIGHTNING_N = 10305, // Thorim, achievs 2971, 2972 + ACHIEV_CRIT_LIGHTNING_H = 10309, + ACHIEV_CRIT_LOSE_ILLUSION_N = 10440, // Thorim, achievs 3176, 3183 + ACHIEV_CRIT_LOSE_ILLUSION_H = 10457, + ACHIEV_CRIT_BACK_NATURE_N = 10445, // Freya, achievs 2982, 2983 + ACHIEV_CRIT_BACK_NATURE_H = 10758, + ACHIEV_CRIT_KNOCK_1_N = 10447, // Freya, achievs 3177, 3185 + ACHIEV_CRIT_KNOCK_1_H = 10459, + ACHIEV_CRIT_KNOCK_2_N = 10448, // Freya, achievs 3178, 3186 + ACHIEV_CRIT_KNOCK_2_H = 10460, + ACHIEV_CRIT_KNOCK_3_N = 10449, // Freya, achievs 3179, 3187 + ACHIEV_CRIT_KNOCK_3_H = 10461, + ACHIEV_CRIT_FIREFIGHTER_N = 10450, // Mimiron, achievs 3180, 3189 + ACHIEV_CRIT_FIREFIGHTER_H = 10463, + ACHIEV_CRIT_THREE_LIGHTS_N = 10410, // Yogg-Saron, achievs 3157, 3161, + ACHIEV_CRIT_THREE_LIGHTS_H = 10414, + ACHIEV_CRIT_TWO_LIGHTS_N = 10338, // Yogg-Saron, achievs 3141, 3162 + ACHIEV_CRIT_TWO_LIGHTS_H = 10415, + ACHIEV_CRIT_ONE_LIGHT_N = 10409, // Yogg-Saron, achievs 3158, 3163 + ACHIEV_CRIT_ONE_LIGHT_H = 10416, + ACHIEV_CRIT_ALONE_DARK_N = 10412, // Yogg-Saron, achievs 3159, 3164 + ACHIEV_CRIT_ALONE_DARK_H = 10417, + ACHIEV_CRIT_DRIVE_CRAZY_N = 10185, // Yogg-Saron, achievs 3008, 3010 + ACHIEV_CRIT_DRIVE_CRAZY_H = 10296, + + // Champion / Conquerer of Ulduar, achievs 2903, 2904 + ACHIEV_CRIT_CHAMP_LEVI = 10042, + ACHIEV_CRIT_CHAMP_RAZOR = 10340, + ACHIEV_CRIT_CHAMP_XT = 10341, + ACHIEV_CRIT_CHAMP_IGNIS = 10342, + ACHIEV_CRIT_CHAMP_MIMIRON = 10347, + ACHIEV_CRIT_CHAMP_KOLO = 10348, + ACHIEV_CRIT_CHAMP_VEZAX = 10349, + ACHIEV_CRIT_CHAMP_YOGG = 10350, + ACHIEV_CRIT_CHAMP_AURIAYA = 10351, + ACHIEV_CRIT_CHAMP_THORIM = 10403, + ACHIEV_CRIT_CHAMP_HODIR = 10439, + ACHIEV_CRIT_CHAMP_FREYA = 10582, + ACHIEV_CRIT_CHAMP_COUNCIL = 10598, + + ACHIEV_CRIT_CONQ_LEVI = 10352, + ACHIEV_CRIT_CONQ_RAZOR = 10353, + ACHIEV_CRIT_CONQ_XT = 10354, + ACHIEV_CRIT_CONQ_IGNIS = 10355, + ACHIEV_CRIT_CONQ_KOLO = 10357, + ACHIEV_CRIT_CONQ_MIMIRON = 10361, + ACHIEV_CRIT_CONQ_VEZAX = 10362, + ACHIEV_CRIT_CONQ_AURIAYA = 10363, + ACHIEV_CRIT_CONQ_YOGG = 10364, + ACHIEV_CRIT_CONQ_THORIM = 10404, + ACHIEV_CRIT_CONQ_FREYA = 10583, + ACHIEV_CRIT_CONQ_COUNCIL = 10599, + ACHIEV_CRIT_CONQ_HODIR = 10719, }; -class MANGOS_DLL_DECL instance_ulduar : public ScriptedInstance +struct UlduarSpawn +{ + float fX, fY, fZ, fO; + uint32 uiEntry; +}; + +struct UlduarSpawnTwoSide +{ + float fX, fY, fZ, fO; + uint32 uiAllyEntry, uiHordeEntry; +}; + +// Note: coordinates are guessed, but pretty close to what they should be +// ToDo: spawn additional Engineers, Demolitionists, Mages and Liquid Pyrite near the columns +static const UlduarSpawn afReinforcementsNormal[] = +{ + {118.797f, -26.9963f, 409.80f, 3.14f, NPC_SALVAGED_SIEGE_ENGINE}, + {118.847f, -43.758f, 409.80f, 3.15f, NPC_SALVAGED_SIEGE_ENGINE}, + {116.602f, 8.464f, 409.80f, 3.10f, NPC_SALVAGED_CHOPPER}, + {116.859f, -4.199f, 409.80f, 3.12f, NPC_SALVAGED_CHOPPER}, + {122.479f, 25.093f, 410.60f, 3.10f, NPC_SALVAGED_DEMOLISHER}, + {123.022f, 39.671f, 409.80f, 3.10f, NPC_SALVAGED_DEMOLISHER}, +}; + +static const UlduarSpawn afReinforcementsHeroic[] = +{ + {106.359f, -35.269f, 409.80f, 3.12f, NPC_SALVAGED_SIEGE_ENGINE}, + {135.351f, -20.767f, 409.80f, 3.15f, NPC_SALVAGED_SIEGE_ENGINE}, + {135.408f, -50.178f, 409.80f, 3.12f, NPC_SALVAGED_SIEGE_ENGINE}, + {116.429f, 4.036f, 409.79f, 3.10f, NPC_SALVAGED_CHOPPER}, + {116.272f, -0.013f, 409.79f, 3.10f, NPC_SALVAGED_CHOPPER}, + {116.948f, -8.351f, 409.79f, 3.10f, NPC_SALVAGED_CHOPPER}, + {137.523f, 32.346f, 409.80f, 3.12f, NPC_SALVAGED_DEMOLISHER}, + {112.818f, 18.981f, 409.83f, 3.10f, NPC_SALVAGED_DEMOLISHER}, + {112.700f, 47.884f, 409.79f, 3.10f, NPC_SALVAGED_DEMOLISHER}, +}; + +static const UlduarSpawnTwoSide afHodirHelpersNormal[] = +{ + {1999.903f, -230.4966f, 432.7581f, 1.53589f, NPC_DRUID_ALLIANCE_N, NPC_DRUID_HORDE_N}, + {2010.058f, -243.4553f, 432.7672f, 1.361357f, NPC_SHAMAN_ALLIANCE_N, NPC_SHAMAN_HORDE_N}, + {2021.118f, -236.6482f, 432.7672f, 1.937315f, NPC_MAGE_ALLIANCE_N, NPC_MAGE_HORDE_N}, + {1983.751f, -243.3579f, 432.7672f, 1.570796f, NPC_PRIEST_ALLIANCE_N, NPC_PRIEST_HORDE_N}, +}; + +static const UlduarSpawnTwoSide afHodirHelpersHeroic[] = +{ + {2013.37f, -240.331f, 432.687f, 1.80463f, NPC_DRUID_ALLIANCE_H, NPC_DRUID_HORDE_H}, + {1983.89f, -240.369f, 432.687f, 1.37658f, NPC_SHAMAN_ALLIANCE_H, NPC_SHAMAN_HORDE_H}, + {2000.9f, -231.232f, 432.687f, 1.59846f, NPC_MAGE_ALLIANCE_H, NPC_MAGE_HORDE_H}, + {1997.88f, -239.394f, 432.687f, 1.4237f, NPC_PRIEST_ALLIANCE_H, NPC_PRIEST_HORDE_H}, +}; + +static const UlduarSpawnTwoSide afThorimSpawns[] = +{ + {2127.24f, -251.309f, 419.7935f, 5.899213f, NPC_SOLDIER_HORDE, NPC_SOLDIER_ALLIANCE}, + {2123.316f, -254.7708f, 419.7886f, 6.178465f, NPC_SOLDIER_HORDE, NPC_SOLDIER_ALLIANCE}, + {2120.431f, -259.0431f, 419.6813f, 6.122538f, NPC_SOLDIER_HORDE, NPC_SOLDIER_ALLIANCE}, + {2145.503f, -256.3357f, 419.7306f, 3.520873f, NPC_CAPTAIN_HORDE, NPC_CAPTAIN_ALLIANCE}, +}; + +// note: original spawn loc is 607.9199f, -12.90516f, 409.887f but we won't use it because it's too far and grid won't be loaded that far +static const float afLeviathanSpawnPos[4] = { 422.8898f, -13.32677f, 409.8839f, 3.12f }; +static const float afLeviathanMovePos[4] = { 296.5809f, -11.55668f, 409.8278f, 3.12f }; + +// spawn locations for Brann and Doren at the archivum +static const float afBrannArchivumSpawnPos[4] = { 1554.274f, 142.1644f, 427.273f, 3.61f }; +static const float afProspectorSpawnPos[4] = { 1556.469f, 143.5023f, 427.2918f, 4.04f }; + +// spawn location for Algalon in reload case +static const float afAlgalonMovePos[4] = {1632.668f, -302.7656f, 417.3211f, 1.53f}; + +class instance_ulduar : public ScriptedInstance, private DialogueHelper { public: instance_ulduar(Map* pMap); ~instance_ulduar() {} - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnPlayerEnter(Player* pPlayer) override; + void OnPlayerDeath(Player* pPlayer) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); - // Dummy, leave till correct solution for hardmode found - bool CheckConditionCriteriaMeet(Player const* pSource, uint32 uiMapId, uint32 uiInstanceConditionId); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const override; - void DoOpenMadnessDoorIfCan(); + void DoSpawnThorimNpcs(Player* pSummoner); + void DoProcessShatteredEvent(); - void SpawnFriendlyKeeper(uint32 uiWho); + ObjectGuid GetKoloRubbleStalker(bool bRightSide) { return bRightSide ? m_rightKoloStalkerGuid : m_leftKoloStalkerGuid; } + ObjectGuid GetVezaxBunnyGuid(bool bAnimus) { return bAnimus ? m_animusVezaxBunnyGuid : m_vaporVezaxBunnyGuid; } + + void GetDefenderGuids(GuidList& lDefenders) { lDefenders = m_lDefendersGuids; } + void GetEngineersGuids(GuidList& lEngineers) { lEngineers = m_lEngineersGuids; } + void GetTrappersGuids(GuidList& lTrappers) { lTrappers = m_lTrappersGuids; } + void GetHarpoonsGuids(GuidVector& vHarpoons) { vHarpoons = m_vBrokenHarpoonsGuids; } + void GetToyPileGuids(GuidVector& vToyPiles) { vToyPiles = m_vToyPileGuidVector; } + void GetThorimBunniesGuids(GuidList& lBunnies, bool bUpper) { lBunnies = bUpper ? m_lUpperBunniesGuids : m_lThorimBunniesGuids; } + void GetThunderOrbsGuids(GuidList& lOrbs) { lOrbs = m_lUpperThunderOrbsGuids; } + void GetSmashTargetsGuids(GuidList& lTargets, bool bLeft) { lTargets = bLeft ? m_lLeftHandBunniesGuids : m_lRightHandBunniesGuids; } + void GetOminousCloudGuids(GuidList& lClouds) { lClouds = m_lOminousCloudsGuids; } + + void Update(uint32 uiDiff); protected: + void JustDidDialogueStep(int32 iEntry) override; + void SpawnFriendlyKeeper(uint32 uiWho); + void SpawnKeeperHelper(uint32 uiWho); + void DoSpawnHodirNpcs(Player* pSummoner); + void DoOpenMadnessDoorIfCan(); + void DoCallLeviathanHelp(); + std::string m_strInstData; uint32 m_auiEncounter[MAX_ENCOUNTER]; uint32 m_auiHardBoss[HARD_MODE_ENCOUNTER]; uint32 m_auiUlduarKeepers[KEEPER_ENCOUNTER]; + uint32 m_auiUlduarTowers[KEEPER_ENCOUNTER]; bool m_abAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; + + bool m_bHelpersLoaded; + + uint32 m_uiAlgalonTimer; + uint32 m_uiYoggResetTimer; + uint32 m_uiShatterAchievTimer; + uint32 m_uiGauntletStatus; + uint32 m_uiStairsSpawnTimer; + uint8 m_uiSlayedArenaMobs; + + ObjectGuid m_leftKoloStalkerGuid; + ObjectGuid m_rightKoloStalkerGuid; + ObjectGuid m_animusVezaxBunnyGuid; + ObjectGuid m_vaporVezaxBunnyGuid; + + GuidVector m_vToyPileGuidVector; + GuidVector m_vBrokenHarpoonsGuids; + GuidList m_lEngineersGuids; + GuidList m_lTrappersGuids; + GuidList m_lDefendersGuids; + GuidList m_lHarpoonDummyGuids; + GuidList m_lRepairedHarpoonsGuids; + GuidList m_lThorimBunniesGuids; + GuidList m_lUpperBunniesGuids; + GuidList m_lUpperThunderOrbsGuids; + GuidList m_lLeftHandBunniesGuids; + GuidList m_lRightHandBunniesGuids; + GuidList m_lOminousCloudsGuids; + GuidSet m_sColossusGuidSet; }; #endif diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar.cpp index dd1af1e20..d8f0e5ae6 100644 --- a/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_keep/boss_ingvar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -40,7 +40,7 @@ enum NPC_THROW_DUMMY = 23997, // the axe, moving to target NPC_GROUND_VISUAL = 24012, // has SPELL_SCOURGE_RES_BUBBLE aura - //phase 1 + // phase 1 SPELL_CLEAVE = 42724, SPELL_SMASH = 42669, @@ -52,7 +52,7 @@ enum SPELL_STAGGERING_ROAR = 42708, SPELL_STAGGERING_ROAR_H = 59708, - //phase 2 + // phase 2 SPELL_DARK_SMASH_H = 42723, SPELL_DREADFUL_ROAR = 42729, @@ -65,7 +65,7 @@ enum SPELL_SHADOW_AXE_PROC = 42750, // triggers 42751 SPELL_SHADOW_AXE_PROC_H = 59719, // triggers 59720 - //ressurection sequenze + // ressurection sequenze SPELL_ASTRAL_TELEPORT = 34427, // aura cast by Annhylde on spawn SPELL_SUMMON_BANSHEE = 42912, // summons Annhylde and sets a glow aura SPELL_FEIGN_DEATH = 42795, @@ -82,7 +82,7 @@ enum ## boss_ingvar ######*/ -struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI +struct boss_ingvarAI : public ScriptedAI { boss_ingvarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -102,7 +102,7 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI uint32 m_uiStaggeringRoarTimer; uint32 m_uiEnrageTimer; - void Reset() + void Reset() override { m_bIsResurrected = false; m_bIsFakingDeath = false; @@ -113,7 +113,7 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI m_uiEnrageTimer = 30000; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { // don't yell for her if (pWho->GetEntry() == NPC_ANNHYLDE) @@ -121,9 +121,12 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI // ToDo: it shouldn't yell this aggro text after removing the feign death aura DoScriptText(SAY_AGGRO_FIRST, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_INGVAR, IN_PROGRESS); } - void DamageTaken(Unit* pDealer, uint32& uiDamage) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { if (m_bIsResurrected) return; @@ -148,7 +151,7 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI } } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_TRANSFORM) { @@ -160,7 +163,7 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -184,18 +187,29 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH_SECOND, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_INGVAR, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) DoScriptText(m_bIsResurrected ? SAY_KILL_SECOND : SAY_KILL_FIRST, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_INGVAR, FAIL); + + m_creature->UpdateEntry(NPC_INGVAR); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || m_bIsFakingDeath) return; @@ -241,7 +255,7 @@ struct MANGOS_DLL_DECL boss_ingvarAI : public ScriptedAI { if (m_uiCleaveTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode? SPELL_WOE_STRIKE : SPELL_WOE_STRIKE_H) == CAST_OK) + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_WOE_STRIKE : SPELL_WOE_STRIKE_H) == CAST_OK) m_uiCleaveTimer = urand(2500, 7000); } else @@ -288,7 +302,7 @@ CreatureAI* GetAI_boss_ingvar(Creature* pCreature) ## npc_annhylde ######*/ -struct MANGOS_DLL_DECL npc_annhyldeAI : public ScriptedAI +struct npc_annhyldeAI : public ScriptedAI { npc_annhyldeAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -301,17 +315,17 @@ struct MANGOS_DLL_DECL npc_annhyldeAI : public ScriptedAI uint32 m_uiResurrectTimer; uint8 m_uiResurrectPhase; - void Reset() + void Reset() override { m_uiResurrectTimer = 0; m_uiResurrectPhase = 0; } // No attacking - void MoveInLineOfSight(Unit*) {} - void AttackStart(Unit*) {} + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_ID_ANNHYLDE) return; @@ -320,7 +334,7 @@ struct MANGOS_DLL_DECL npc_annhyldeAI : public ScriptedAI m_uiResurrectTimer = 3000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiResurrectTimer) { diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp index cf0644e26..3be86c04a 100644 --- a/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_keep/boss_keleseth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -56,7 +56,7 @@ static float fAddPosition[4] = {163.5727f, 252.1900f, 42.8684f, 5.57052f}; ## mob_vrykul_skeleton ######*/ -struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI +struct mob_vrykul_skeletonAI : public ScriptedAI { mob_vrykul_skeletonAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -71,13 +71,13 @@ struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI uint32 m_uiCastTimer; uint32 m_uiReviveTimer; - void Reset() + void Reset() override { m_uiReviveTimer = 0; m_uiCastTimer = urand(5000, 10000); // taken out of thin air } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!pWho || m_uiReviveTimer) return; @@ -85,7 +85,7 @@ struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!pWho || m_uiReviveTimer) return; @@ -106,7 +106,7 @@ struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI m_uiReviveTimer = 0; } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (m_uiReviveTimer) { @@ -120,15 +120,15 @@ struct MANGOS_DLL_DECL mob_vrykul_skeletonAI : public ScriptedAI uiDamage = 0; m_uiReviveTimer = 6000; m_creature->SetHealth(0); - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnDeath(); m_creature->GetMotionMaster()->Clear(); m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); m_creature->SetStandState(UNIT_STAND_STATE_DEAD); return; - } + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -176,7 +176,7 @@ CreatureAI* GetAI_mob_vrykul_skeleton(Creature* pCreature) ## boss_keleseth ######*/ -struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI +struct boss_kelesethAI : public ScriptedAI { boss_kelesethAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -192,9 +192,9 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI uint32 m_uiSummonTimer; uint32 m_uiShadowboltTimer; - GUIDList m_lSummonedAddGuids; + GuidList m_lSummonedAddGuids; - void Reset() + void Reset() override { // timers need confirmation m_uiFrostTombTimer = 20000; @@ -204,7 +204,7 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI DespawnOrKillAdds(true); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, true)) { @@ -216,7 +216,7 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -226,13 +226,13 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI void SummonAdds() { - for (uint8 i=0; i<4; ++i) - m_creature->SummonCreature(NPC_VRYKUL_SKELETON, fAddPosition[0]+rand()%7, fAddPosition[1]+rand()%7, fAddPosition[2], fAddPosition[3], TEMPSUMMON_DEAD_DESPAWN, 0); + for (uint8 i = 0; i < 4; ++i) + m_creature->SummonCreature(NPC_VRYKUL_SKELETON, fAddPosition[0] + rand() % 7, fAddPosition[1] + rand() % 7, fAddPosition[2], fAddPosition[3], TEMPSUMMON_DEAD_DESPAWN, 0); } void DespawnOrKillAdds(bool bDespawn) { - for (GUIDList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); ++itr) + for (GuidList::const_iterator itr = m_lSummonedAddGuids.begin(); itr != m_lSummonedAddGuids.end(); ++itr) { if (Creature* pAdd = m_creature->GetMap()->GetCreature(*itr)) { @@ -249,7 +249,7 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI m_lSummonedAddGuids.clear(); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_VRYKUL_SKELETON) { @@ -261,7 +261,7 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI pSummoned->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, true); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -271,18 +271,18 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI DespawnOrKillAdds(false); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_KELESETH, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_KILL, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -310,7 +310,7 @@ struct MANGOS_DLL_DECL boss_kelesethAI : public ScriptedAI { if (Unit* pTombTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - //DoCastSpellIfCan(pTombTarget, SPELL_SUMMON_FROST_TOMB); + // DoCastSpellIfCan(pTombTarget, SPELL_SUMMON_FROST_TOMB); float fPosX, fPosY, fPosZ; pTombTarget->GetPosition(fPosX, fPosY, fPosZ); diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_and_dalronn.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_and_dalronn.cpp index 0e6d63ac6..fddc10025 100644 --- a/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_and_dalronn.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_keep/boss_skarvald_and_dalronn.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,14 +44,14 @@ enum NPC_DAL_GHOST = 27389, NPC_SKA_GHOST = 27390, - NPC_SKELETAL = 28878, //summoned guardian in heroic + NPC_SKELETAL = 28878, // summoned guardian in heroic - //skarvald + // skarvald SPELL_CHARGE = 43651, SPELL_STONE_STRIKE = 48583, SPELL_ENRAGE = 48193, - //dalronn + // dalronn SPELL_SHADOW_BOLT = 43649, SPELL_SHADOW_BOLT_H = 59575, @@ -74,7 +74,7 @@ Yell m_aYell[] = {SAY_DAL_DEATH, SAY_SKA_DAL_DIES_REPLY} }; -struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI +struct boss_s_and_d_dummyAI : public ScriptedAI { boss_s_and_d_dummyAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -95,9 +95,9 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI return m_pInstance->GetSingleCreatureFromStorage(m_creature->GetEntry() == NPC_DALRONN ? NPC_SKARVALD : NPC_DALRONN); } - void Reset() { } + void Reset() override { } - void JustReachedHome() + void JustReachedHome() override { if (Creature* pBuddy = GetBuddy()) { @@ -112,7 +112,7 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI } } - void EnterCombat(Unit* pWho) + void EnterCombat(Unit* pWho) override { if (!pWho) return; @@ -126,19 +126,19 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI Aggro(pWho); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // EventAI can probably handle ghosts if (pSummoned->GetEntry() == NPC_DAL_GHOST || pSummoned->GetEntry() == NPC_SKA_GHOST) m_ghostGuid = pSummoned->GetObjectGuid(); - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO,1); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1); if (m_creature->getVictim()) pSummoned->AI()->AttackStart(pTarget ? pTarget : m_creature->getVictim()); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (Creature* pBuddy = GetBuddy()) { @@ -166,7 +166,7 @@ struct MANGOS_DLL_DECL boss_s_and_d_dummyAI : public ScriptedAI ## boss_skarvald ######*/ -struct MANGOS_DLL_DECL boss_skarvaldAI : public boss_s_and_d_dummyAI +struct boss_skarvaldAI : public boss_s_and_d_dummyAI { boss_skarvaldAI(Creature* pCreature) : boss_s_and_d_dummyAI(pCreature) { Reset(); } @@ -175,7 +175,7 @@ struct MANGOS_DLL_DECL boss_skarvaldAI : public boss_s_and_d_dummyAI uint32 m_uiEnrageTimer; uint32 m_uiStoneStrikeTimer; - void Reset() + void Reset() override { m_uiYellDelayTimer = 0; m_uiChargeTimer = urand(2000, 6000); @@ -183,18 +183,18 @@ struct MANGOS_DLL_DECL boss_skarvaldAI : public boss_s_and_d_dummyAI m_uiStoneStrikeTimer = 8000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(m_aYell[0].m_iTextId, m_creature); m_uiYellDelayTimer = 5000; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_SKA_KILL, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -251,7 +251,7 @@ CreatureAI* GetAI_boss_skarvald(Creature* pCreature) ## boss_dalronn ######*/ -struct MANGOS_DLL_DECL boss_dalronnAI : public boss_s_and_d_dummyAI +struct boss_dalronnAI : public boss_s_and_d_dummyAI { boss_dalronnAI(Creature* pCreature) : boss_s_and_d_dummyAI(pCreature) { Reset(); } @@ -259,19 +259,19 @@ struct MANGOS_DLL_DECL boss_dalronnAI : public boss_s_and_d_dummyAI uint32 m_uiShadowBoltTimer; uint32 m_uiSkeletonTimer; - void Reset() + void Reset() override { m_uiDebilitateTimer = urand(5000, 10000); m_uiShadowBoltTimer = urand(2500, 6000); m_uiSkeletonTimer = urand(25000, 35000); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_DAL_KILL, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp index 62ad27f5b..e12c1883d 100644 --- a/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_keep/instance_utgarde_keep.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,7 +37,7 @@ void instance_utgarde_keep::Initialize() void instance_utgarde_keep::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_KELESETH: case NPC_SKARVALD: @@ -76,6 +76,13 @@ void instance_utgarde_keep::OnObjectCreate(GameObject* pGo) if (m_auiEncounter[TYPE_BELLOW_3] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; + case GO_PORTCULLIS_EXIT_1: + case GO_PORTCULLIS_EXIT_2: + if (m_auiEncounter[TYPE_INGVAR] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_PORTCULLIS_COMBAT: + break; default: return; @@ -91,7 +98,7 @@ void instance_utgarde_keep::OnCreatureDeath(Creature* pCreature) void instance_utgarde_keep::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_KELESETH: if (uiData == IN_PROGRESS) @@ -99,7 +106,17 @@ void instance_utgarde_keep::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; case TYPE_SKARVALD_DALRONN: + m_auiEncounter[uiType] = uiData; + break; case TYPE_INGVAR: + if (m_auiEncounter[uiType] == uiData) + return; + DoUseDoorOrButton(GO_PORTCULLIS_COMBAT); + if (uiData == DONE) + { + DoUseDoorOrButton(GO_PORTCULLIS_EXIT_1); + DoUseDoorOrButton(GO_PORTCULLIS_EXIT_2); + } m_auiEncounter[uiType] = uiData; break; case TYPE_BELLOW_1: @@ -128,7 +145,7 @@ void instance_utgarde_keep::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_utgarde_keep::GetData(uint32 uiType) +uint32 instance_utgarde_keep::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -149,7 +166,7 @@ void instance_utgarde_keep::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4] >> m_auiEncounter[5]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -158,7 +175,7 @@ void instance_utgarde_keep::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -bool instance_utgarde_keep::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_utgarde_keep::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { if (uiCriteriaId == ACHIEV_CRIT_ON_THE_ROCKS) return !m_bKelesethAchievFailed; diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp b/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp index f8d0753f8..8d3cf0c72 100644 --- a/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -41,7 +41,7 @@ enum MAX_FORGE = 3 }; -struct MANGOS_DLL_DECL mob_dragonflayer_forge_masterAI : public ScriptedAI +struct mob_dragonflayer_forge_masterAI : public ScriptedAI { mob_dragonflayer_forge_masterAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -57,20 +57,20 @@ struct MANGOS_DLL_DECL mob_dragonflayer_forge_masterAI : public ScriptedAI uint32 m_uiForgeEncounterId; uint32 m_uiBurningBrandTimer; - void Reset() + void Reset() override { m_uiBurningBrandTimer = 2000; } void SetMyForge() { - std::list lGOList; + std::list lGOList; uint32 uiGOBellow = 0; uint32 uiGOFire = 0; for (uint8 i = 0; i < MAX_FORGE; ++i) { - switch(i) + switch (i) { case 0: uiGOBellow = GO_BELLOW_1; break; case 1: uiGOBellow = GO_BELLOW_2; break; @@ -84,7 +84,7 @@ struct MANGOS_DLL_DECL mob_dragonflayer_forge_masterAI : public ScriptedAI if (!lGOList.empty()) { if (lGOList.size() != MAX_FORGE) - error_log("SD2: mob_dragonflayer_forge_master expected %u in lGOList, but does not match.", MAX_FORGE); + script_error_log("mob_dragonflayer_forge_master expected %u in lGOList, but does not match.", MAX_FORGE); lGOList.sort(ObjectDistanceOrder(m_creature)); @@ -93,7 +93,7 @@ struct MANGOS_DLL_DECL mob_dragonflayer_forge_masterAI : public ScriptedAI else if (lGOList.front()->getLootState() == GO_ACTIVATED) lGOList.front()->ResetDoorOrButton(); - switch(lGOList.front()->GetEntry()) + switch (lGOList.front()->GetEntry()) { case GO_BELLOW_1: uiGOFire = GO_FORGEFIRE_1; m_uiForgeEncounterId = TYPE_BELLOW_1; break; case GO_BELLOW_2: uiGOFire = GO_FORGEFIRE_2; m_uiForgeEncounterId = TYPE_BELLOW_2; break; @@ -110,23 +110,23 @@ struct MANGOS_DLL_DECL mob_dragonflayer_forge_masterAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { SetMyForge(); } - void JustReachedHome() + void JustReachedHome() override { SetMyForge(); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(m_uiForgeEncounterId, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h b/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h index 29a909eef..b89e9ee6a 100644 --- a/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h +++ b/scripts/northrend/utgarde_keep/utgarde_keep/utgarde_keep.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -29,30 +29,33 @@ enum GO_FORGEFIRE_1 = 186692, GO_FORGEFIRE_2 = 186693, GO_FORGEFIRE_3 = 186691, + GO_PORTCULLIS_COMBAT = 186612, + GO_PORTCULLIS_EXIT_1 = 186694, + GO_PORTCULLIS_EXIT_2 = 186756, ACHIEV_CRIT_ON_THE_ROCKS = 7231, }; -class MANGOS_DLL_DECL instance_utgarde_keep : public ScriptedInstance +class instance_utgarde_keep : public ScriptedInstance { public: instance_utgarde_keep(Map* pMap); ~instance_utgarde_keep() {} - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; protected: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp index b5a559ac6..126b59c4b 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_gortok.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Gortok -SD%Complete: 20% -SDComment: +SD%Complete: 90% +SDComment: Timers; The subbosses and Gortok should be activated on aura remove SDCategory: Utgarde Pinnacle EndScriptData */ @@ -46,7 +46,7 @@ enum ## boss_gortok ######*/ -struct MANGOS_DLL_DECL boss_gortokAI : public ScriptedAI +struct boss_gortokAI : public ScriptedAI { boss_gortokAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -58,21 +58,31 @@ struct MANGOS_DLL_DECL boss_gortokAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiRoarTimer; + uint32 m_uiImpaleTimer; + uint32 m_uiArcingSmashTimer; + + void Reset() override { + m_uiRoarTimer = 10000; + m_uiImpaleTimer = 15000; + m_uiArcingSmashTimer = urand(5000, 8000); + + // This needs to be reset in case the event fails + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -80,11 +90,44 @@ struct MANGOS_DLL_DECL boss_gortokAI : public ScriptedAI m_pInstance->SetData(TYPE_GORTOK, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_GORTOK, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiRoarTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WITHERING_ROAR : SPELL_WITHERING_ROAR_H) == CAST_OK) + m_uiRoarTimer = 10000; + } + else + m_uiRoarTimer -= uiDiff; + + if (m_uiImpaleTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_IMPALE : SPELL_IMPALE_H) == CAST_OK) + m_uiImpaleTimer = urand(8000, 15000); + } + } + else + m_uiImpaleTimer -= uiDiff; + + if (m_uiArcingSmashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCING_SMASH) == CAST_OK) + m_uiArcingSmashTimer = urand(5000, 13000); + } + else + m_uiArcingSmashTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -94,6 +137,63 @@ CreatureAI* GetAI_boss_gortok(Creature* pCreature) return new boss_gortokAI(pCreature); } +bool EffectDummyCreature_spell_awaken_gortok(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_AWAKEN_GORTOK && uiEffIndex == EFFECT_INDEX_0) + { + pCreatureTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pCreatureTarget->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + + // Start attacking the players + if (instance_pinnacle* pInstance = (instance_pinnacle*)pCreatureTarget->GetInstanceData()) + { + if (Unit* pStarter = pCreatureTarget->GetMap()->GetUnit(pInstance->GetGortokEventStarter())) + pCreatureTarget->AI()->AttackStart(pStarter); + } + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +bool EffectAuraDummy_spell_aura_dummy_awaken_subboss(const Aura* pAura, bool bApply) +{ + // Note: this should be handled on aura remove, but this can't be done because there are some core issues with areaeffect spells + if (pAura->GetId() == SPELL_AWAKEN_SUBBOSS && pAura->GetEffIndex() == EFFECT_INDEX_0 && bApply) + { + if (Creature* pTarget = (Creature*)pAura->GetTarget()) + { + pTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pTarget->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + + // Start attacking the players + if (instance_pinnacle* pInstance = (instance_pinnacle*)pTarget->GetInstanceData()) + { + if (Unit* pStarter = pTarget->GetMap()->GetUnit(pInstance->GetGortokEventStarter())) + pTarget->AI()->AttackStart(pStarter); + } + } + } + return true; +} + +bool ProcessEventId_event_spell_gortok_event(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (instance_pinnacle* pInstance = (instance_pinnacle*)((Creature*)pSource)->GetInstanceData()) + { + if (pInstance->GetData(TYPE_GORTOK) == IN_PROGRESS || pInstance->GetData(TYPE_GORTOK) == DONE) + return false; + + pInstance->SetData(TYPE_GORTOK, IN_PROGRESS); + pInstance->SetGortokEventStarter(pSource->GetObjectGuid()); + return true; + } + return false; +} + void AddSC_boss_gortok() { Script* pNewScript; @@ -101,5 +201,16 @@ void AddSC_boss_gortok() pNewScript = new Script; pNewScript->Name = "boss_gortok"; pNewScript->GetAI = &GetAI_boss_gortok; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_spell_awaken_gortok; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_gortok_subboss"; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_spell_aura_dummy_awaken_subboss; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_gortok_event"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_gortok_event; pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp index 63bb59401..1a7b7fca6 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_skadi.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Skadi -SD%Complete: 20% -SDComment: starts at trigger 4991 +SD%Complete: 80% +SDComment: The gauntlet movement needs to be random choosed for left and right. Event reset not implemented using the proper spell SDCategory: Utgarde Pinnacle EndScriptData */ @@ -38,60 +38,126 @@ enum SAY_DEATH = -1575028, SAY_DRAKE_DEATH = -1575029, EMOTE_HARPOON_RANGE = -1575030, + EMOTE_DEEP_BREATH = -1575041, + // phase 1 spells + SPELL_RIDE_VEHICLE = 61791, + SPELL_FREEZING_CLOUD_LEFT = 47590, + SPELL_FREEZING_CLOUD_RIGHT = 47592, + SPELL_SKADI_TELEPORT = 61790, // teleport when Grauf is killed + SPELL_GAUNTLET_PERIODIC = 47546, // what is this? Unknown use/effect, but probably related - cast by each player + SPELL_SUMMON_GAUNTLET_MOBS = 48630, // tick every 30 sec + SPELL_SUMMON_GAUNTLET_MOBS_H = 59275, // tick every 25 sec + SPELL_LAUNCH_HARPOON = 48642, // this spell hit drake to reduce HP (force triggered from 48641) + SPELL_CLOUD_AURA_LEFT = 47574, + SPELL_CLOUD_AURA_RIGHT = 47594, + SPELL_CLOUD_AURA_DAMAGE = 47579, + + // phase 2 spells SPELL_CRUSH = 50234, SPELL_CRUSH_H = 59330, - SPELL_WHIRLWIND = 50228, SPELL_WHIRLWIND_H = 59322, - SPELL_POISONED_SPEAR = 50255, SPELL_POISONED_SPEAR_H = 59331, - // casted with base of creature 22515 (World Trigger), so we must make sure - // to use the close one by the door leading further in to instance. - SPELL_SUMMON_GAUNTLET_MOBS = 48630, // tick every 30 sec - SPELL_SUMMON_GAUNTLET_MOBS_H = 59275, // tick every 25 sec + MAX_INTRO_MOBS = 13, - SPELL_GAUNTLET_PERIODIC = 47546, // what is this? Unknown use/effect, but probably related + PHASE_GAUNTLET = 1, + PHASE_NORMAL_COMBAT = 2, +}; - SPELL_LAUNCH_HARPOON = 48642, // this spell hit drake to reduce HP (force triggered from 48641) +struct GauntletIntroData +{ + uint32 uiCreatureId; + float fX, fY, fZ; +}; + +static const GauntletIntroData aSkadiIntroData[MAX_INTRO_MOBS] = +{ + {NPC_YMIRJAR_WITCH_DOCTOR, 478.31f, -511.049f, 104.7242f}, + {NPC_YMIRJAR_HARPOONER, 482.25f, -514.1273f, 104.7234f}, + {NPC_YMIRJAR_HARPOONER, 481.3883f, -507.1089f, 104.7241f}, + {NPC_YMIRJAR_WARRIOR, 458.5323f, -516.2537f, 104.617f}, + {NPC_YMIRJAR_WARRIOR, 429.4242f, -517.5624f, 104.8936f}, + {NPC_YMIRJAR_WARRIOR, 427.4026f, -510.7716f, 104.8802f}, + {NPC_YMIRJAR_WARRIOR, 458.5323f, -510.2537f, 104.617f}, + {NPC_YMIRJAR_WARRIOR, 397.036f, -515.158f, 104.725f}, // the rest are guesswork but follow the same pattern + {NPC_YMIRJAR_WARRIOR, 397.036f, -507.158f, 104.725f}, + {NPC_YMIRJAR_WARRIOR, 360.297f, -508.927f, 104.662f}, + {NPC_YMIRJAR_WARRIOR, 360.297f, -516.927f, 104.662f}, + {NPC_YMIRJAR_WARRIOR, 328.324f, -513.387f, 104.577f}, + {NPC_YMIRJAR_WARRIOR, 328.324f, -504.387f, 104.577f}, }; /*###### ## boss_skadi ######*/ -struct MANGOS_DLL_DECL boss_skadiAI : public ScriptedAI +struct boss_skadiAI : public ScriptedAI { boss_skadiAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_pinnacle*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } - ScriptedInstance* m_pInstance; + instance_pinnacle* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiCrush; + uint32 m_uiWhirlwind; + uint32 m_uiPoisonedSpear; + uint32 m_uiMountTimer; + uint8 m_uiPhase; + bool m_IntroMobs; + + void Reset() override + { + m_uiMountTimer = 0; + m_uiCrush = 15000; + m_uiWhirlwind = 23000; + m_uiPoisonedSpear = 10000; + m_uiPhase = PHASE_GAUNTLET; + m_IntroMobs = false; + + // Set immune during phase 1 + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, true); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + void AttackStart(Unit* pWho) override { + if (m_uiPhase == PHASE_GAUNTLET) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_uiPhase == PHASE_GAUNTLET) + return; + + ScriptedAI::MoveInLineOfSight(pWho); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SKADI, NOT_STARTED); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - DoScriptText(SAY_AGGRO, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_SKADI, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL_1, m_creature); break; case 1: DoScriptText(SAY_KILL_2, m_creature); break; @@ -99,7 +165,7 @@ struct MANGOS_DLL_DECL boss_skadiAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -107,11 +173,128 @@ struct MANGOS_DLL_DECL boss_skadiAI : public ScriptedAI m_pInstance->SetData(TYPE_SKADI, DONE); } - void UpdateAI(const uint32 uiDiff) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_SKADI_TELEPORT) + { + m_uiPhase = PHASE_NORMAL_COMBAT; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false); + } + } + + void JustSummoned(Creature* pSummon) override + { + // the intro mobs have predefined positions + if (m_IntroMobs) + return; + + // Move all the way to the entrance - the exact location is unk so use waypoint movement + switch (pSummon->GetEntry()) + { + case NPC_YMIRJAR_HARPOONER: + case NPC_YMIRJAR_WARRIOR: + case NPC_YMIRJAR_WITCH_DOCTOR: + pSummon->SetWalk(false); + pSummon->GetMotionMaster()->MoveWaypoint(); + break; + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + // called only for the intro mobs which are summoned directly + pSummoned->SetFacingTo(3.15f); + if (pSummoned->GetEntry() == NPC_YMIRJAR_WARRIOR) + pSummoned->HandleEmote(EMOTE_STATE_READY1H); + else + pSummoned->HandleEmote(EMOTE_STATE_READYTHROWN); + } + + void DoPrepareForGauntlet() { + DoScriptText(SAY_AGGRO, m_creature); + m_uiMountTimer = 3000; + + if (!m_pInstance) + return; + + // Prepare to periodic summon the mobs + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_pInstance->GetSkadiMobsTrigger())) + { + pTrigger->CastSpell(pTrigger, m_bIsRegularMode ? SPELL_SUMMON_GAUNTLET_MOBS : SPELL_SUMMON_GAUNTLET_MOBS_H, true, NULL, NULL, m_creature->GetObjectGuid()); + + // Spawn the intro mobs + m_IntroMobs = true; + for (uint8 i = 0; i < MAX_INTRO_MOBS; ++i) + { + if (Creature* pYmirjar = m_creature->SummonCreature(aSkadiIntroData[i].uiCreatureId, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pYmirjar->SetWalk(false); + pYmirjar->GetMotionMaster()->MovePoint(1, aSkadiIntroData[i].fX, aSkadiIntroData[i].fY, aSkadiIntroData[i].fZ); + } + } + + m_IntroMobs = false; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiMountTimer) + { + if (m_uiMountTimer <= uiDiff) + { + if (!m_pInstance) + return; + + if (Creature* pGrauf = m_pInstance->GetSingleCreatureFromStorage(NPC_GRAUF)) + { + if (DoCastSpellIfCan(pGrauf, SPELL_RIDE_VEHICLE) == CAST_OK) + { + // Maybe this flag should be set by the vehicle flags - requires research + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + m_uiMountTimer = 0; + } + } + } + else + m_uiMountTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiCrush < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_CRUSH : SPELL_CRUSH_H) == CAST_OK) + m_uiCrush = urand(10000, 15000); + } + else + m_uiCrush -= uiDiff; + + if (m_uiWhirlwind < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WHIRLWIND : SPELL_WHIRLWIND_H) == CAST_OK) + m_uiWhirlwind = 23000; + } + else + m_uiWhirlwind -= uiDiff; + + if (m_uiPoisonedSpear < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_POISONED_SPEAR : SPELL_POISONED_SPEAR_H) == CAST_OK) + m_uiPoisonedSpear = urand(10000, 15000); + } + } + else + m_uiPoisonedSpear -= uiDiff; + DoMeleeAttackIfReady(); } }; @@ -121,12 +304,223 @@ CreatureAI* GetAI_boss_skadi(Creature* pCreature) return new boss_skadiAI(pCreature); } -bool AreaTrigger_at_skadi(Player* pPlayer, AreaTriggerEntry const* pAt) +/*###### +## npc_grauf +######*/ + +struct npc_graufAI : public ScriptedAI +{ + npc_graufAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_pinnacle*)pCreature->GetInstanceData(); + SetCombatMovement(false); + Reset(); + } + + instance_pinnacle* m_pInstance; + + uint32 m_uiFlightDelayTimer; + + void Reset() override + { + m_uiFlightDelayTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustReachedHome() override + { + if (!m_pInstance) + return; + + // Handle the auras only when reached home in order to avoid vehicle complications + m_creature->RemoveAllAuras(); + + // Allow Skadi to evade + if (Creature* pSkadi = m_pInstance->GetSingleCreatureFromStorage(NPC_SKADI)) + pSkadi->AI()->EnterEvadeMode(); + + m_creature->SetLevitate(false); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + if (!m_pInstance) + return; + + if (pSpell->Id == SPELL_LAUNCH_HARPOON) + { + if (m_creature->GetHealth() < m_creature->GetMaxHealth() * 0.35f) + { + // Prepare phase 2 here, because the JustDied is called too late + if (Creature* pSkadi = m_pInstance->GetSingleCreatureFromStorage(NPC_SKADI)) + { + DoScriptText(SAY_DRAKE_DEATH, pSkadi); + // Exit vehicle before teleporting + m_creature->RemoveAllAuras(); + pSkadi->CastSpell(pSkadi, SPELL_SKADI_TELEPORT, true); + } + } + else if (urand(0, 1)) + { + if (Creature* pSkadi = m_pInstance->GetSingleCreatureFromStorage(NPC_SKADI)) + DoScriptText(urand(0, 1) ? SAY_DRAKE_HARPOON_1 : SAY_DRAKE_HARPOON_2, pSkadi); + } + + // Deal 35% damage on each harpoon hit + m_creature->DealDamage(m_creature, m_creature->GetMaxHealth() * 0.35f, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + // TODO: Temporary workaround - please remove when the boarding wrappers are implemented in core + else if (pSpell->Id == SPELL_RIDE_VEHICLE && pCaster->GetEntry() == NPC_SKADI) + m_uiFlightDelayTimer = 2000; + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != WAYPOINT_MOTION_TYPE || !m_pInstance) + return; + + // Note: On blizz the left and right sides are randomly choosen. + // However because of the lack of waypoint movement scripting we'll use them alternatively + // Another note: the pointId in script = pointId - 1 from DB + switch (uiPointId) + { + case 8: + case 21: + // TODO: choose the left / right patch random when core will support this + DoScriptText(EMOTE_HARPOON_RANGE, m_creature); + + break; + case 10: // left breath + if (DoCastSpellIfCan(m_creature, SPELL_FREEZING_CLOUD_LEFT) == CAST_OK) + { + DoHandleBreathYell(); + DoScriptText(EMOTE_DEEP_BREATH, m_creature); + } + + // Set the achiev as failed once we get to breath area + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_LOVE_SKADI, false); + break; + case 13: // left breath end + m_creature->RemoveAurasDueToSpell(SPELL_FREEZING_CLOUD_LEFT); + break; + case 23: // right breath + if (DoCastSpellIfCan(m_creature, SPELL_FREEZING_CLOUD_RIGHT) == CAST_OK) + { + DoHandleBreathYell(); + DoScriptText(EMOTE_DEEP_BREATH, m_creature); + } + + // Set the achiev as failed once we get to breath area + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_LOVE_SKADI, false); + break; + case 26: // right breath end + m_creature->RemoveAurasDueToSpell(SPELL_FREEZING_CLOUD_RIGHT); + break; + } + } + + void DoHandleBreathYell() + { + if (!m_pInstance || !roll_chance_i(25)) + return; + + // Yell on drake breath + if (Creature* pSkadi = m_pInstance->GetSingleCreatureFromStorage(NPC_SKADI)) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_DRAKEBREATH_1, pSkadi); break; + case 1: DoScriptText(SAY_DRAKEBREATH_2, pSkadi); break; + case 2: DoScriptText(SAY_DRAKEBREATH_3, pSkadi); break; + } + } + } + + // TODO: Enable the wrappers below, when they will be properly supported by the core + /* + void PassengerBoarded(Unit* pPassenger, uint8 uiSeat) override + { + if (pPassenger->GetEntry() == NPC_SKADI) + m_uiFlightDelayTimer = 2000; + } + */ + + void UpdateAI(const uint32 uiDiff) override + { + // Start the gauntlet flight + if (m_uiFlightDelayTimer) + { + if (m_uiFlightDelayTimer <= uiDiff) + { + m_creature->SetLevitate(true); + m_creature->SetWalk(false); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + m_creature->GetMotionMaster()->MoveWaypoint(); + m_uiFlightDelayTimer = 0; + } + else + m_uiFlightDelayTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_grauf(Creature* pCreature) +{ + return new npc_graufAI(pCreature); +} + +/*###### +## npc_flame_breath_trigger +######*/ + +bool EffectAuraDummy_npc_flame_breath_trigger(const Aura* pAura, bool bApply) +{ + if (pAura->GetEffIndex() != EFFECT_INDEX_0 || !bApply) + return true; + + Creature* pTarget = (Creature*)pAura->GetTarget(); + if (!pTarget) + return true; + + // apply auras based on creature position + if (pAura->GetId() == SPELL_CLOUD_AURA_LEFT) + { + if (pTarget->GetPositionY() > -511.0f) + pTarget->CastSpell(pTarget, SPELL_CLOUD_AURA_DAMAGE, true); + } + else if (pAura->GetId() == SPELL_CLOUD_AURA_RIGHT) + { + if (pTarget->GetPositionY() < -511.0f) + pTarget->CastSpell(pTarget, SPELL_CLOUD_AURA_DAMAGE, true); + } + return true; +} + +/*###### +## at_skadi +######*/ + +bool AreaTrigger_at_skadi(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { + if (pPlayer->isGameMaster()) + return false; + if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) { if (pInstance->GetData(TYPE_SKADI) == NOT_STARTED) + { pInstance->SetData(TYPE_SKADI, SPECIAL); + + // Start the gauntlet + if (Creature* pSkadi = pInstance->GetSingleCreatureFromStorage(NPC_SKADI)) + { + if (boss_skadiAI* pBossAI = dynamic_cast(pSkadi->AI())) + pBossAI->DoPrepareForGauntlet(); + } + } } return false; @@ -141,6 +535,16 @@ void AddSC_boss_skadi() pNewScript->GetAI = &GetAI_boss_skadi; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_grauf"; + pNewScript->GetAI = &GetAI_npc_grauf; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_flame_breath_trigger"; + pNewScript->pEffectAuraDummy = &EffectAuraDummy_npc_flame_breath_trigger; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "at_skadi"; pNewScript->pAreaTrigger = &AreaTrigger_at_skadi; diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp index 62308b0b4..2e6d77b1a 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_svala.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Svala -SD%Complete: 30% -SDComment: TODO: abilities. The way spells for intro works could use more research. +SD%Complete: 80% +SDComment: The way spells for intro work could use more research. SDCategory: Utgarde Pinnacle EndScriptData */ @@ -45,35 +45,46 @@ enum NPC_SVALA_SORROW = 26668, NPC_ARTHAS_IMAGE = 29280, + NPC_CHANNELER = 27281, + NPC_SCOURGE_HULK = 26555, // used to check the achiev SPELL_ARTHAS_VISUAL = 54134, - // don't know how these should work in relation to each other - SPELL_TRANSFORMING = 54205, - SPELL_TRANSFORMING_FLOATING = 54140, + SPELL_TRANSFORMING = 54205, // should also remove aura 54140 (script effect) + SPELL_TRANSFORMING_FLOATING = 54140, // triggers 54142 SPELL_TRANSFORMING_CHANNEL = 54142, - SPELL_RITUAL_OF_SWORD = 48276, - SPELL_CALL_FLAMES = 48258, + SPELL_RITUAL_OF_SWORD = 48276, // teleports the boss + SPELL_RITUAL_STRIKE = 48331, + SPELL_RITUAL_DISARM = 54159, + SPELL_CALL_FLAMES = 48258, // sends event 17841 - this makes npc 27273 cast 48246 SPELL_SINISTER_STRIKE = 15667, - SPELL_SINISTER_STRIKE_H = 59409 + SPELL_SINISTER_STRIKE_H = 59409, + + SPELL_SUMMON_CHANNELER_1 = 48271, + SPELL_SUMMON_CHANNELER_2 = 48274, + SPELL_SUMMON_CHANNELER_3 = 48275, + + // spells used by channelers + SPELL_PARALIZE = 48278, // should apply effect 48267 on target + SPELL_SHADOWS_IN_THE_DARK = 59407, }; /*###### ## boss_svala ######*/ -struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI +struct boss_svalaAI : public ScriptedAI { boss_svalaAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_pinnacle*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); m_bIsIntroDone = false; Reset(); } - ScriptedInstance* m_pInstance; + instance_pinnacle* m_pInstance; bool m_bIsRegularMode; Creature* pArthas; @@ -82,13 +93,25 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI uint32 m_uiIntroTimer; uint32 m_uiIntroCount; - void Reset() + uint32 m_uiSinisterStrikeTimer; + uint32 m_uiCallFlamesTimer; + uint32 m_uiRitualStrikeTimer; + bool m_bHasDoneRitual; + + ObjectGuid m_ritualTargetGuid; + + void Reset() override { pArthas = NULL; m_uiIntroTimer = 2500; m_uiIntroCount = 0; + m_uiSinisterStrikeTimer = 10000; + m_uiCallFlamesTimer = urand(10000, 20000); + m_uiRitualStrikeTimer = 0; + m_bHasDoneRitual = false; + if (m_creature->isAlive() && m_pInstance && m_pInstance->GetData(TYPE_SVALA) > IN_PROGRESS) { if (m_creature->GetEntry() != NPC_SVALA_SORROW) @@ -100,12 +123,15 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI } } - void JustReachedHome() + void JustReachedHome() override { DoMoveToPosition(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SVALA, FAIL); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bIsIntroDone) { @@ -126,13 +152,13 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { m_creature->SetLevitate(false); DoScriptText(SAY_AGGRO, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_ARTHAS_IMAGE) { @@ -140,28 +166,41 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI pArthas = pSummoned; pSummoned->SetFacingToObject(m_creature); } + else if (pSummoned->GetEntry() == NPC_CHANNELER) + { + if (!m_bIsRegularMode) + pSummoned->CastSpell(pSummoned, SPELL_SHADOWS_IN_THE_DARK, true); + + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_ritualTargetGuid)) + pSummoned->CastSpell(pTarget, SPELL_PARALIZE, true); + } } - void SummonedCreatureDespawn(Creature* pDespawned) + void SummonedCreatureDespawn(Creature* pDespawned) override { if (pDespawned->GetEntry() == NPC_ARTHAS_IMAGE) pArthas = NULL; } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_TRANSFORMING) { if (pArthas) pArthas->InterruptNonMeleeSpells(true); + m_creature->RemoveAurasDueToSpell(SPELL_TRANSFORMING_FLOATING); m_creature->UpdateEntry(NPC_SVALA_SORROW); } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { - switch(urand(0, 2)) + // set achiev to true if boss kills a hulk + if (pVictim->GetEntry() == NPC_SCOURGE_HULK && m_pInstance) + m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_INCREDIBLE_HULK, true); + + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -169,7 +208,7 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -186,7 +225,7 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI m_creature->GetMotionMaster()->MovePoint(0, fX, fY, fZ + 5.0f); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -199,7 +238,7 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI { m_uiIntroTimer = 10000; - switch(m_uiIntroCount) + switch (m_uiIntroCount) { case 0: DoScriptText(SAY_INTRO_1, m_creature); @@ -208,12 +247,12 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI DoScriptText(SAY_INTRO_2_ARTHAS, pArthas); break; case 2: + DoCastSpellIfCan(m_creature, SPELL_TRANSFORMING_FLOATING); pArthas->CastSpell(m_creature, SPELL_TRANSFORMING_CHANNEL, false); - m_creature->CastSpell(m_creature, SPELL_TRANSFORMING_FLOATING, false); DoMoveToPosition(); break; case 3: - m_creature->CastSpell(m_creature, SPELL_TRANSFORMING, false); + DoCastSpellIfCan(m_creature, SPELL_TRANSFORMING); DoScriptText(SAY_INTRO_3, m_creature); break; case 4: @@ -221,6 +260,8 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI break; case 5: DoScriptText(SAY_INTRO_5, m_creature); + break; + case 6: m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_bIsIntroDone = true; break; @@ -235,6 +276,62 @@ struct MANGOS_DLL_DECL boss_svalaAI : public ScriptedAI return; } + if (m_uiSinisterStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SINISTER_STRIKE : SPELL_SINISTER_STRIKE_H) == CAST_OK) + m_uiSinisterStrikeTimer = 10000; + } + else + m_uiSinisterStrikeTimer -= uiDiff; + + if (m_uiCallFlamesTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CALL_FLAMES) == CAST_OK) + m_uiCallFlamesTimer = urand(10000, 20000); + } + else + m_uiCallFlamesTimer -= uiDiff; + + if (m_uiRitualStrikeTimer) + { + if (m_uiRitualStrikeTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_RITUAL_STRIKE, CAST_INTERRUPT_PREVIOUS); + DoCastSpellIfCan(m_creature, SPELL_RITUAL_DISARM, CAST_TRIGGERED); + m_uiRitualStrikeTimer = 0; + } + else + m_uiRitualStrikeTimer -= uiDiff; + } + + // As from patch notes: Svala Sorrowgrave now casts Ritual of the Sword 1 time during the encounter, down from 3. + if (m_creature->GetHealthPercent() < 50.0f && !m_bHasDoneRitual) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_RITUAL_OF_SWORD, SELECT_FLAG_PLAYER)) + { + if (DoCastSpellIfCan(pTarget, SPELL_RITUAL_OF_SWORD) == CAST_OK) + { + m_ritualTargetGuid = pTarget->GetObjectGuid(); + + // summon channelers + DoCastSpellIfCan(m_creature, SPELL_SUMMON_CHANNELER_1, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_CHANNELER_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_CHANNELER_3, CAST_TRIGGERED); + + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_SACRIFICE_1, m_creature); break; + case 1: DoScriptText(SAY_SACRIFICE_2, m_creature); break; + case 2: DoScriptText(SAY_SACRIFICE_3, m_creature); break; + case 3: DoScriptText(SAY_SACRIFICE_4, m_creature); break; + } + + m_uiRitualStrikeTimer = 1000; + m_bHasDoneRitual = true; + } + } + } + DoMeleeAttackIfReady(); } }; @@ -244,8 +341,11 @@ CreatureAI* GetAI_boss_svala(Creature* pCreature) return new boss_svalaAI(pCreature); } -bool AreaTrigger_at_svala_intro(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_svala_intro(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { + if (pPlayer->isGameMaster()) + return false; + if (ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData()) { if (pInstance->GetData(TYPE_SVALA) == NOT_STARTED) diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp index 184ef396c..936623db4 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/boss_ymiron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss_Ymiron -SD%Complete: 20% -SDComment: +SD%Complete: 90% +SDComment: Timers SDCategory: Utgarde Pinnacle EndScriptData */ #include "precompiled.h" +#include "utgarde_pinnacle.h" enum { @@ -34,37 +35,144 @@ enum SAY_SLAY_2 = -1575037, SAY_SLAY_3 = -1575038, SAY_SLAY_4 = -1575039, - SAY_DEATH = -1575040 + SAY_DEATH = -1575040, + + SPELL_BANE = 48294, // sends script event 20651 when target is hit - set achiev to false + SPELL_BANE_H = 59301, + SPELL_DARK_SLASH = 48292, + SPELL_FETID_ROT = 48291, + SPELL_FETID_ROT_H = 59300, + SPELL_SCREAMS_OF_THE_DEAD = 51750, // knockback players to summon boat + // SPELL_CHOOSE_SPIRIT = 48306, // boss chooses spirit + + // blessings + SPELL_SPIRIT_BURST = 48529, // by Ranulf + SPELL_SPIRIT_BURST_H = 59305, + SPELL_SPIRIT_STRIKE = 48423, // by Haldor + SPELL_SPIRIT_STRIKE_H = 59304, + SPELL_SUMMON_SPIRIT_FOUNT = 48386, // by Bjorn + SPELL_SPIRIT_FOUNT_BEAM = 48385, // channeled beam on the spirit fount - triggers 48380 : 59320 on aura expire + SPELL_AVENGING_SPIRITS = 48590, // by Torgyn + + // visuals + SPELL_CHANNEL_YMIRON_SPIRIT = 48307, + SPELL_CHANNEL_SPIRIT_YMIRON = 48316, + SPELL_EMERGE_STATE = 56864, + SPELL_SPIRIT_DIES = 48596, // cast by a boat spirit + + // by summoned creatures + // SPELL_SPIRIT_VISUAL = 48593, // avenging spirit summon visual - handled in eventAI + // SPELL_WITHER_TRIGG = 48584, // aura for avenging spirits - triggers 48585 on melee - handled in eventAI + + // spirit transforms + SPELL_BJORN_TRANSFORM = 48308, + SPELL_HALDOR_TRANSFORM = 48311, + SPELL_RANULF_TRANSFORM = 48312, + SPELL_TORGYN_TRANSFORM = 48313, + + NPC_SPIRIT_FOUNT = 27339, + // NPC_AVENGING_SPIRIT = 27386, + // NPC_SPIRIT_SUMMONER = 27392, // summoned around the boss - triggers 48592 + + MAX_BOATS = 4, + + PHASE_NO_BOAT = 0, + PHASE_BJORN = 1, + PHASE_HALDOR = 2, + PHASE_RANULF = 3, + PHASE_TORGYN = 4 +}; + +struct BoatSpirits +{ + uint32 uiSpiritSpell, uiSpiritTarget; + int32 iYellId; + uint8 uiBoatPhase; +}; + +static const BoatSpirits aYmironBoatsSpirits[MAX_BOATS] = +{ + {SPELL_BJORN_TRANSFORM, NPC_BJORN, SAY_SUMMON_BJORN, PHASE_BJORN}, + {SPELL_HALDOR_TRANSFORM, NPC_HALDOR, SAY_SUMMON_HALDOR, PHASE_HALDOR}, + {SPELL_RANULF_TRANSFORM, NPC_RANULF, SAY_SUMMON_RANULF, PHASE_RANULF}, + {SPELL_TORGYN_TRANSFORM, NPC_TORGYN, SAY_SUMMON_TORGYN, PHASE_TORGYN} }; /*###### ## boss_ymiron ######*/ -struct MANGOS_DLL_DECL boss_ymironAI : public ScriptedAI +struct boss_ymironAI : public ScriptedAI { boss_ymironAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + + for (uint8 i = 0; i < MAX_BOATS; ++i) + m_vuiBoatPhases.push_back(i); + Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiFetidRotTimer; + uint32 m_uiBaneTimer; + uint32 m_uiDarkSlashTimer; + uint32 m_uiSpiritTransformTimer; + uint32 m_uiCombatResumeTimer; + uint8 m_uiPhase; + uint8 m_uiBoats; + float m_fHealthCheck; + + uint32 m_uiSpiritBurstTimer; + uint32 m_uiSpiritStrikeTimer; + uint32 m_uiSpiritFountTimer; + uint32 m_uiAvengingSpiritsTimer; + + bool m_bIsChannelingSpirit; + + ObjectGuid m_uiCurrentSpiritGuid; + + std::vector m_vuiBoatPhases; + + void Reset() override { + m_uiFetidRotTimer = urand(8000, 13000); + m_uiBaneTimer = urand(18000, 23000); + m_uiDarkSlashTimer = urand(28000, 33000); + m_uiSpiritTransformTimer = 0; + m_uiCombatResumeTimer = 0; + m_uiPhase = PHASE_NO_BOAT; + m_uiBoats = 0; + m_fHealthCheck = m_bIsRegularMode ? 33.3f : 20.0f; + + m_uiSpiritBurstTimer = 10000; + m_uiSpiritStrikeTimer = 10000; + m_uiSpiritFountTimer = 10000; + m_uiAvengingSpiritsTimer = 10000; + + m_bIsChannelingSpirit = false; + + m_uiCurrentSpiritGuid.Clear(); + + // Randomize spirit order + std::random_shuffle(m_vuiBoatPhases.begin(), m_vuiBoatPhases.end()); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_YMIRON, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -73,16 +181,222 @@ struct MANGOS_DLL_DECL boss_ymironAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + // Burn the last spirit + if (Creature* pSpirit = m_creature->GetMap()->GetCreature(m_uiCurrentSpiritGuid)) + { + pSpirit->InterruptNonMeleeSpells(false); + pSpirit->CastSpell(pSpirit, SPELL_SPIRIT_DIES, false); + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_YMIRON, DONE); + } + + void JustReachedHome() override + { + DoResetSpirits(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_YMIRON, FAIL); + } + + // Wrapper which handles the spirits reset + void DoResetSpirits() + { + if (!m_pInstance) + return; + + for (uint8 i = 0; i < MAX_BOATS; ++i) + { + if (Creature* pSpirit = m_pInstance->GetSingleCreatureFromStorage(aYmironBoatsSpirits[i].uiSpiritTarget)) + pSpirit->AI()->EnterEvadeMode(); + } + } + + void DoChannelSpiritYmiron() + { + if (Creature* pSpirit = m_creature->GetMap()->GetCreature(m_uiCurrentSpiritGuid)) + pSpirit->CastSpell(m_creature, SPELL_CHANNEL_SPIRIT_YMIRON, false); + + // Channeling is finished - resume combat + if (m_creature->getVictim()) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } + + SetCombatMovement(true); + m_bIsChannelingSpirit = false; + + m_uiPhase = aYmironBoatsSpirits[m_vuiBoatPhases[m_uiBoats]].uiBoatPhase; + ++m_uiBoats; + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SPIRIT_FOUNT) + DoCastSpellIfCan(pSummoned, SPELL_SPIRIT_FOUNT_BEAM, CAST_INTERRUPT_PREVIOUS); } - void UpdateAI(const uint32 uiDiff) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (Creature* pSpirit = m_creature->GetMap()->GetCreature(m_uiCurrentSpiritGuid)) + { + DoCastSpellIfCan(pSpirit, SPELL_CHANNEL_YMIRON_SPIRIT); + DoScriptText(aYmironBoatsSpirits[m_vuiBoatPhases[m_uiBoats]].iYellId, m_creature); + m_uiSpiritTransformTimer = 3000; + m_uiCombatResumeTimer = 6000; + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiSpiritTransformTimer) + { + if (m_uiSpiritTransformTimer <= uiDiff) + { + if (Creature* pSpirit = m_creature->GetMap()->GetCreature(m_uiCurrentSpiritGuid)) + { + pSpirit->CastSpell(pSpirit, aYmironBoatsSpirits[m_vuiBoatPhases[m_uiBoats]].uiSpiritSpell, true); + pSpirit->CastSpell(pSpirit, SPELL_EMERGE_STATE, true); + } + m_uiSpiritTransformTimer = 0; + } + else + m_uiSpiritTransformTimer -= uiDiff; + } + + if (m_uiCombatResumeTimer) + { + // This should be done on aura 48307 remove, but because of lack of core support, we'll handle it on normal timer + if (m_uiCombatResumeTimer <= uiDiff) + { + DoChannelSpiritYmiron(); + m_uiCombatResumeTimer = 0; + } + else + m_uiCombatResumeTimer -= uiDiff; + } + + // Don't attack while channeling on the boats + if (m_bIsChannelingSpirit) + return; + + if (m_uiBaneTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_BANE : SPELL_BANE_H) == CAST_OK) + m_uiBaneTimer = urand(20000, 25000); + } + else + m_uiBaneTimer -= uiDiff; + + if (m_uiFetidRotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FETID_ROT : SPELL_FETID_ROT_H) == CAST_OK) + m_uiFetidRotTimer = urand(10000, 15000); + } + else + m_uiFetidRotTimer -= uiDiff; + + if (m_uiDarkSlashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_SLASH) == CAST_OK) + m_uiDarkSlashTimer = urand(30000, 35000); + } + else + m_uiDarkSlashTimer -= uiDiff; + + // Check the spirit phases (also don't allow him to change phase if below 1%) + if (m_creature->GetHealthPercent() < 100 - m_fHealthCheck && m_creature->GetHealthPercent() > 1.0f) + { + // change phase + DoCastSpellIfCan(m_creature, SPELL_SCREAMS_OF_THE_DEAD, CAST_INTERRUPT_PREVIOUS); + + // make the current spirit die (burn) + if (Creature* pSpirit = m_creature->GetMap()->GetCreature(m_uiCurrentSpiritGuid)) + { + pSpirit->InterruptNonMeleeSpells(false); + pSpirit->CastSpell(pSpirit, SPELL_SPIRIT_DIES, false); + } + + // Get a close point to the spirits and move near them + if (m_pInstance) + { + if (Creature* pSpirit = m_pInstance->GetSingleCreatureFromStorage(aYmironBoatsSpirits[m_vuiBoatPhases[m_uiBoats]].uiSpiritTarget)) + { + float fX, fY, fZ; + m_uiCurrentSpiritGuid = pSpirit->GetObjectGuid(); + pSpirit->GetContactPoint(m_creature, fX, fY, fZ, INTERACTION_DISTANCE); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + } + + SetCombatMovement(false); + m_bIsChannelingSpirit = true; + m_fHealthCheck += m_bIsRegularMode ? 33.3f : 20.0f; + } + + switch (m_uiPhase) + { + case PHASE_BJORN: + + if (m_uiSpiritFountTimer) + { + if (m_uiSpiritFountTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SPIRIT_FOUNT) == CAST_OK) + m_uiSpiritFountTimer = 0; + } + else + m_uiSpiritFountTimer -= uiDiff; + } + + break; + case PHASE_HALDOR: + + if (m_uiSpiritStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_SPIRIT_STRIKE : SPELL_SPIRIT_STRIKE_H) == CAST_OK) + m_uiSpiritStrikeTimer = 5000; + } + else + m_uiSpiritStrikeTimer -= uiDiff; + + break; + case PHASE_RANULF: + + if (m_uiSpiritBurstTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SPIRIT_BURST : SPELL_SPIRIT_BURST_H) == CAST_OK) + m_uiSpiritBurstTimer = 10000; + } + else + m_uiSpiritBurstTimer -= uiDiff; + + break; + case PHASE_TORGYN: + + if (m_uiAvengingSpiritsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_AVENGING_SPIRITS) == CAST_OK) + m_uiAvengingSpiritsTimer = 15000; + } + else + m_uiAvengingSpiritsTimer -= uiDiff; + + break; + } + DoMeleeAttackIfReady(); } }; @@ -92,6 +406,19 @@ CreatureAI* GetAI_boss_ymiron(Creature* pCreature) return new boss_ymironAI(pCreature); } +bool ProcessEventId_event_achiev_kings_bane(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool /*bIsStart*/) +{ + if (instance_pinnacle* pInstance = (instance_pinnacle*)((Creature*)pSource)->GetInstanceData()) + { + if (pInstance->GetData(TYPE_YMIRON) != IN_PROGRESS) + return false; + + pInstance->SetData(TYPE_YMIRON, SPECIAL); + return true; + } + return false; +} + void AddSC_boss_ymiron() { Script* pNewScript; @@ -100,4 +427,9 @@ void AddSC_boss_ymiron() pNewScript->Name = "boss_ymiron"; pNewScript->GetAI = &GetAI_boss_ymiron; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_achiev_kings_bane"; + pNewScript->pProcessEventId = &ProcessEventId_event_achiev_kings_bane; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_utgarde_pinnacle.cpp b/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_utgarde_pinnacle.cpp index 2efeb0d25..aa7c6dd8d 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_utgarde_pinnacle.cpp +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/instance_utgarde_pinnacle.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: instance_pinnacle -SD%Complete: 25% +SD%Complete: 75% SDComment: SDCategory: Utgarde Pinnacle EndScriptData */ @@ -24,7 +24,9 @@ EndScriptData */ #include "precompiled.h" #include "utgarde_pinnacle.h" -instance_pinnacle::instance_pinnacle(Map* pMap) : ScriptedInstance(pMap) +instance_pinnacle::instance_pinnacle(Map* pMap) : ScriptedInstance(pMap), + m_uiGortokOrbTimer(0), + m_uiGortokOrbPhase(0) { Initialize(); } @@ -32,18 +34,57 @@ instance_pinnacle::instance_pinnacle(Map* pMap) : ScriptedInstance(pMap) void instance_pinnacle::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + + for (uint8 i = 0; i < MAX_SPECIAL_ACHIEV_CRITS; ++i) + m_abAchievCriteria[i] = false; +} + +void instance_pinnacle::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_FURBOLG: + case NPC_WORGEN: + case NPC_JORMUNGAR: + case NPC_RHINO: + case NPC_BJORN: + case NPC_HALDOR: + case NPC_RANULF: + case NPC_TORGYN: + case NPC_SKADI: + case NPC_GRAUF: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_WORLD_TRIGGER: + if (pCreature->GetPositionX() < 250.0f) + m_gortokEventTriggerGuid = pCreature->GetObjectGuid(); + else if (pCreature->GetPositionX() > 400.0f && pCreature->GetPositionX() < 500.0f) + m_skadiMobsTriggerGuid = pCreature->GetObjectGuid(); + break; + case NPC_YMIRJAR_HARPOONER: + case NPC_YMIRJAR_WARRIOR: + case NPC_YMIRJAR_WITCH_DOCTOR: + m_lskadiGauntletMobsList.push_back(pCreature->GetObjectGuid()); + break; + } } void instance_pinnacle::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_DOOR_SKADI: if (m_auiEncounter[TYPE_SKADI] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); - m_mGoEntryGuidStore[GO_DOOR_SKADI] = pGo->GetObjectGuid(); break; + case GO_DOOR_YMIRON: + if (m_auiEncounter[TYPE_YMIRON] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } void instance_pinnacle::SetData(uint32 uiType, uint32 uiData) @@ -51,22 +92,106 @@ void instance_pinnacle::SetData(uint32 uiType, uint32 uiData) switch (uiType) { case TYPE_SVALA: + if (uiData == IN_PROGRESS || uiData == FAIL) + SetSpecialAchievementCriteria(TYPE_ACHIEV_INCREDIBLE_HULK, false); m_auiEncounter[uiType] = uiData; break; case TYPE_GORTOK: + if (uiData == IN_PROGRESS) + { + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + { + pOrb->SetLevitate(true); + pOrb->CastSpell(pOrb, SPELL_ORB_VISUAL, true); + pOrb->GetMotionMaster()->MovePoint(0, aOrbPositions[0][0], aOrbPositions[0][1], aOrbPositions[0][2]); + + m_uiGortokOrbTimer = 2000; + } + } + else if (uiData == FAIL) + { + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + { + if (!pOrb->isAlive()) + pOrb->Respawn(); + else + pOrb->RemoveAllAuras(); + + // For some reasone the Orb doesn't evade automatically + pOrb->GetMotionMaster()->MoveTargetedHome(); + } + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + // Reset each miniboss + if (Creature* pTemp = GetSingleCreatureFromStorage(aGortokMiniBosses[i])) + { + if (!pTemp->isAlive()) + pTemp->Respawn(); + + pTemp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + + m_uiGortokOrbPhase = 0; + } m_auiEncounter[uiType] = uiData; break; case TYPE_SKADI: - if (uiData == DONE) - DoUseDoorOrButton(GO_DOOR_SKADI); + // Don't process the event twice + if (m_auiEncounter[uiType] == uiData) + return; + switch (uiData) + { + case DONE: + DoUseDoorOrButton(GO_DOOR_SKADI); + break; + case SPECIAL: + // Prepare achievements + SetSpecialAchievementCriteria(TYPE_ACHIEV_LOVE_SKADI, true); + DoStartTimedAchievement(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, ACHIEV_START_SKADI_ID); + + m_auiEncounter[uiType] = uiData; + return; + case FAIL: + // Handle Grauf evade - if event is in phase 1 + if (Creature* pGrauf = GetSingleCreatureFromStorage(NPC_GRAUF)) + pGrauf->AI()->EnterEvadeMode(); + + // no break; + case NOT_STARTED: + // Despawn all summons + for (GuidList::const_iterator itr = m_lskadiGauntletMobsList.begin(); itr != m_lskadiGauntletMobsList.end(); ++itr) + { + if (Creature* pYmirjar = instance->GetCreature(*itr)) + pYmirjar->ForcedDespawn(); + } + // Reset position + if (Creature* pGrauf = GetSingleCreatureFromStorage(NPC_GRAUF)) + pGrauf->GetMotionMaster()->MoveTargetedHome(); + + // no break; + case IN_PROGRESS: + + // Remove the summon aura on phase 2 or fail + if (Creature* pTrigger = instance->GetCreature(m_skadiMobsTriggerGuid)) + pTrigger->RemoveAllAuras(); + break; + } m_auiEncounter[uiType] = uiData; break; case TYPE_YMIRON: + if (uiData == DONE) + DoUseDoorOrButton(GO_DOOR_YMIRON); + else if (uiData == IN_PROGRESS) + SetSpecialAchievementCriteria(TYPE_ACHIEV_KINGS_BANE, true); + else if (uiData == SPECIAL) + SetSpecialAchievementCriteria(TYPE_ACHIEV_KINGS_BANE, false); m_auiEncounter[uiType] = uiData; break; default: - error_log("SD2: Instance Pinnacle: SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Pinnacle: SetData = %u for type %u does not exist/not implemented.", uiType, uiData); return; } @@ -85,7 +210,7 @@ void instance_pinnacle::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_pinnacle::GetData(uint32 uiType) +uint32 instance_pinnacle::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -106,7 +231,7 @@ void instance_pinnacle::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -115,6 +240,96 @@ void instance_pinnacle::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } +void instance_pinnacle::SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet) +{ + if (uiType < MAX_SPECIAL_ACHIEV_CRITS) + m_abAchievCriteria[uiType] = bIsMet; +} + +bool instance_pinnacle::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const +{ + switch (uiCriteriaId) + { + case ACHIEV_CRIT_INCREDIBLE_HULK: + return m_abAchievCriteria[TYPE_ACHIEV_INCREDIBLE_HULK]; + case ACHIEV_CRIT_GIRL_LOVES_SKADI: + return m_abAchievCriteria[TYPE_ACHIEV_LOVE_SKADI]; + case ACHIEV_CRIT_KINGS_BANE: + return m_abAchievCriteria[TYPE_ACHIEV_KINGS_BANE]; + + default: + return false; + } +} + +void instance_pinnacle::OnCreatureEvade(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_FURBOLG: + case NPC_WORGEN: + case NPC_JORMUNGAR: + case NPC_RHINO: + SetData(TYPE_GORTOK, FAIL); + break; + case NPC_YMIRJAR_WARRIOR: + case NPC_YMIRJAR_WITCH_DOCTOR: + case NPC_YMIRJAR_HARPOONER: + // Handle Skadi gauntlet reset. Used instead of using spell 49308 + SetData(TYPE_SKADI, FAIL); + break; + } +} + +void instance_pinnacle::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_FURBOLG: + case NPC_WORGEN: + case NPC_JORMUNGAR: + case NPC_RHINO: + m_uiGortokOrbTimer = 3000; + break; + } +} + +void instance_pinnacle::Update(uint32 const uiDiff) +{ + if (m_uiGortokOrbTimer) + { + if (m_uiGortokOrbTimer <= uiDiff) + { + if (!m_uiGortokOrbPhase) + { + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + pOrb->GetMotionMaster()->MovePoint(0, aOrbPositions[1][0], aOrbPositions[1][1], aOrbPositions[1][2]); + + m_uiGortokOrbTimer = 18000; + } + // Awaken Gortok if this is the last phase + else + { + uint8 uiMaxOrbPhase = instance->IsRegularDifficulty() ? 3 : 5; + uint32 uiSpellId = m_uiGortokOrbPhase == uiMaxOrbPhase ? SPELL_AWAKEN_GORTOK : SPELL_AWAKEN_SUBBOSS; + + if (Creature* pOrb = instance->GetCreature(m_gortokEventTriggerGuid)) + { + pOrb->CastSpell(pOrb, uiSpellId, false); + + if (m_uiGortokOrbPhase == uiMaxOrbPhase) + pOrb->ForcedDespawn(10000); + } + + m_uiGortokOrbTimer = 0; + } + ++m_uiGortokOrbPhase; + } + else + m_uiGortokOrbTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_pinnacle(Map* pMap) { return new instance_pinnacle(pMap); diff --git a/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h b/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h index 05b9e5284..2444aa1f1 100644 --- a/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h +++ b/scripts/northrend/utgarde_keep/utgarde_pinnacle/utgarde_pinnacle.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,39 +8,108 @@ enum { MAX_ENCOUNTER = 4, + MAX_SPECIAL_ACHIEV_CRITS = 3, TYPE_SVALA = 0, TYPE_GORTOK = 1, TYPE_SKADI = 2, TYPE_YMIRON = 3, + TYPE_ACHIEV_INCREDIBLE_HULK = 0, + TYPE_ACHIEV_LOVE_SKADI = 1, + TYPE_ACHIEV_KINGS_BANE = 2, + GO_STASIS_GENERATOR = 188593, GO_DOOR_SKADI = 192173, + GO_DOOR_YMIRON = 192174, + + NPC_WORLD_TRIGGER = 22515, + + NPC_GRAUF = 26893, + NPC_SKADI = 26693, + NPC_YMIRJAR_WARRIOR = 26690, + NPC_YMIRJAR_WITCH_DOCTOR = 26691, + NPC_YMIRJAR_HARPOONER = 26692, + // NPC_FLAME_BREATH_TRIGGER = 28351, // triggers the freezing cloud spell in script + // NPC_WORLD_TRIGGER_LARGE = 23472, // only one spawn in this instance - casts 49308 during the gauntlet event NPC_FURBOLG = 26684, NPC_WORGEN = 26683, NPC_JORMUNGAR = 26685, - NPC_RHINO = 26686 + NPC_RHINO = 26686, + + // Ymiron spirits + NPC_BJORN = 27303, // front right + NPC_HALDOR = 27307, // front left + NPC_RANULF = 27308, // back left + NPC_TORGYN = 27309, // back right + + ACHIEV_CRIT_INCREDIBLE_HULK = 7322, // Svala, achiev - 2043 + ACHIEV_CRIT_GIRL_LOVES_SKADI = 7595, // Skadi, achiev - 2156 + ACHIEV_CRIT_KINGS_BANE = 7598, // Ymiron, achiev - 2157 + + ACHIEV_START_SKADI_ID = 17726, // Starts Skadi timed achiev - 1873 + + // Gortok event spells + SPELL_ORB_VISUAL = 48044, + SPELL_AWAKEN_SUBBOSS = 47669, + SPELL_AWAKEN_GORTOK = 47670, + + // Skadi event spells + // The reset check spell is cast by npc 23472 every 7 seconds during the event + // If the spell doesn't hit any player then the event resets + // SPELL_GAUNTLET_RESET_CHECK = 49308, // for the moment we don't use this because of the lack of core support }; -class MANGOS_DLL_DECL instance_pinnacle : public ScriptedInstance +static const float aOrbPositions[2][3] = +{ + {238.6077f, -460.7103f, 112.5671f}, // Orb lift up + {279.26f, -452.1f, 110.0f}, // Orb center stop +}; + +static const uint32 aGortokMiniBosses[MAX_ENCOUNTER] = {NPC_WORGEN, NPC_FURBOLG, NPC_JORMUNGAR, NPC_RHINO}; + +class instance_pinnacle : public ScriptedInstance { public: instance_pinnacle(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; + + void OnCreatureEvade(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnObjectCreate(GameObject* pGo); + void SetSpecialAchievementCriteria(uint32 uiType, bool bIsMet); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetGortokEventStarter(ObjectGuid playerGuid) { m_gortokEventStarterGuid = playerGuid; } + ObjectGuid GetGortokEventStarter() { return m_gortokEventStarterGuid; } + ObjectGuid GetSkadiMobsTrigger() { return m_skadiMobsTriggerGuid; } - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; + bool m_abAchievCriteria[MAX_SPECIAL_ACHIEV_CRITS]; std::string m_strInstData; + + uint32 m_uiGortokOrbTimer; + uint8 m_uiGortokOrbPhase; + + ObjectGuid m_gortokEventTriggerGuid; + ObjectGuid m_gortokEventStarterGuid; + ObjectGuid m_skadiMobsTriggerGuid; + + GuidList m_lskadiGauntletMobsList; }; #endif diff --git a/scripts/northrend/vault_of_archavon/boss_archavon.cpp b/scripts/northrend/vault_of_archavon/boss_archavon.cpp index 1981760a3..0bad374a6 100644 --- a/scripts/northrend/vault_of_archavon/boss_archavon.cpp +++ b/scripts/northrend/vault_of_archavon/boss_archavon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/vault_of_archavon/boss_emalon.cpp b/scripts/northrend/vault_of_archavon/boss_emalon.cpp index b2256e7f8..fb7b78813 100644 --- a/scripts/northrend/vault_of_archavon/boss_emalon.cpp +++ b/scripts/northrend/vault_of_archavon/boss_emalon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/vault_of_archavon/boss_koralon.cpp b/scripts/northrend/vault_of_archavon/boss_koralon.cpp index bb85eaf7a..936b8b456 100644 --- a/scripts/northrend/vault_of_archavon/boss_koralon.cpp +++ b/scripts/northrend/vault_of_archavon/boss_koralon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/vault_of_archavon/boss_toravon.cpp b/scripts/northrend/vault_of_archavon/boss_toravon.cpp index 442df58f9..aec7d50ce 100644 --- a/scripts/northrend/vault_of_archavon/boss_toravon.cpp +++ b/scripts/northrend/vault_of_archavon/boss_toravon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp b/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp index 4aca719bf..384bd03d6 100644 --- a/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp +++ b/scripts/northrend/vault_of_archavon/instance_vault_of_archavon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/scripts/northrend/vault_of_archavon/vault_of_archavon.h b/scripts/northrend/vault_of_archavon/vault_of_archavon.h index 5871a49a1..1fc83fe24 100644 --- a/scripts/northrend/vault_of_archavon/vault_of_archavon.h +++ b/scripts/northrend/vault_of_archavon/vault_of_archavon.h @@ -1,3 +1,3 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/scripts/northrend/violet_hold/boss_erekem.cpp b/scripts/northrend/violet_hold/boss_erekem.cpp index d017f4e94..eb1ec4c86 100644 --- a/scripts/northrend/violet_hold/boss_erekem.cpp +++ b/scripts/northrend/violet_hold/boss_erekem.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_erekem -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 90 +SDComment: Timers may need adjustments SDCategory: Violet Hold EndScriptData */ @@ -30,11 +30,10 @@ enum SAY_ADD_DIE_1 = -1608013, SAY_ADD_DIE_2 = -1608014, SAY_DEATH = -1608018, - /* A few Sound IDs on SLAY, if there _is_ text related, fields -1608015 to -1608017 are free - ** 14222 - ** 14223 - ** 14224 - */ + // A few Sound IDs on SLAY, if there _is_ text related, fields -1608015 to -1608017 are free + SOUND_ID_SLAY_1 = 14222, + SOUND_ID_SLAY_2 = 14223, + SOUND_ID_SLAY_3 = 14224, SPELL_BLOODLUST = 54516, SPELL_BREAK_BONDS_H = 59463, @@ -52,7 +51,7 @@ enum SPELL_STRIKE = 14516 }; -struct MANGOS_DLL_DECL boss_erekemAI : public ScriptedAI +struct boss_erekemAI : public ScriptedAI { boss_erekemAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -65,25 +64,106 @@ struct MANGOS_DLL_DECL boss_erekemAI : public ScriptedAI instance_violet_hold* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiBreakBondsTimer; + uint32 m_uiChainHealTimer; + uint32 m_uiEarthShieldTimer; + uint32 m_uiEarthShockTimer; + uint32 m_uiSpecialSpellTimer; + uint8 m_uiGuardiansDead; + + void Reset() override { + m_uiSpecialSpellTimer = 0; + m_uiEarthShieldTimer = urand(2000, 3000); + m_uiEarthShockTimer = urand(4000, 9000); + m_uiChainHealTimer = urand(5000, 15000); + m_uiBreakBondsTimer = urand(25000, 30000); + m_uiGuardiansDead = 0; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void UpdateAI(const uint32 uiDiff) + void KilledUnit(Unit* /*pVictim*/) override + { + switch (urand(0, 2)) + { + case 0: DoPlaySoundToSet(m_creature, SOUND_ID_SLAY_1); break; + case 1: DoPlaySoundToSet(m_creature, SOUND_ID_SLAY_2); break; + case 2: DoPlaySoundToSet(m_creature, SOUND_ID_SLAY_3); break; + } + } + + void GuardianJustDied() + { + DoScriptText(!m_uiGuardiansDead ? SAY_ADD_DIE_1 : SAY_ADD_DIE_2, m_creature); + ++m_uiGuardiansDead; + + // cast bloodlust if both guards are dead + if (m_uiGuardiansDead == 2) + DoCastSpellIfCan(m_creature, SPELL_BLOODLUST, CAST_INTERRUPT_PREVIOUS); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiEarthShieldTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_EARTH_SHIELD : SPELL_EARTH_SHIELD_H, CAST_AURA_NOT_PRESENT) == CAST_OK) + m_uiEarthShieldTimer = urand(25000, 30000); + } + else + m_uiEarthShieldTimer -= uiDiff; + + if (m_uiEarthShockTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_EARTH_SHOCK) == CAST_OK) + m_uiEarthShockTimer = urand(8000, 13000); + } + } + else + m_uiEarthShockTimer -= uiDiff; + + if (m_uiChainHealTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CHAIN_HEAL : SPELL_CHAIN_HEAL_H) == CAST_OK) + m_uiChainHealTimer = urand(15000, 25000); + } + else + m_uiChainHealTimer -= uiDiff; + + // Cast Stormstrike only if both guards are down + if (m_uiSpecialSpellTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_uiGuardiansDead == 2 ? SPELL_STORMSTRIKE : SPELL_LIGHTNING_BOLT) == CAST_OK) + m_uiSpecialSpellTimer = urand(2000, 3000); + } + else + m_uiSpecialSpellTimer -= uiDiff; + + // Break bonds only on heroic + if (!m_bIsRegularMode) + { + if (m_uiBreakBondsTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BREAK_BONDS_H) == CAST_OK) + m_uiBreakBondsTimer = urand(25000, 30000); + } + else + m_uiBreakBondsTimer -= uiDiff; + } + DoMeleeAttackIfReady(); } }; @@ -93,6 +173,79 @@ CreatureAI* GetAI_boss_erekem(Creature* pCreature) return new boss_erekemAI(pCreature); } +struct npc_erekem_guardAI : public ScriptedAI +{ + npc_erekem_guardAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = ((instance_violet_hold*)pCreature->GetInstanceData()); + Reset(); + } + + instance_violet_hold* m_pInstance; + + uint32 m_uiGushingWoundTimer; + uint32 m_uiHowlingScreechTimer; + uint32 m_uiStrikeTimer; + + void Reset() override + { + m_uiGushingWoundTimer = urand(9000, 14000); + m_uiHowlingScreechTimer = urand(8000, 12000); + m_uiStrikeTimer = urand(5000, 7000); + } + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) + return; + + if (Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(TYPE_EREKEM) != DONE ? NPC_EREKEM : NPC_ARAKKOA)) + { + if (!pBoss->isAlive()) + return; + + ((boss_erekemAI*)pBoss->AI())->GuardianJustDied(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiGushingWoundTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GUSHING_WOUND) == CAST_OK) + m_uiGushingWoundTimer = urand(25000, 30000); + } + else + m_uiGushingWoundTimer -= uiDiff; + + if (m_uiHowlingScreechTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_HOWLING_SCREECH) == CAST_OK) + m_uiHowlingScreechTimer = urand(10000, 16000); + } + else + m_uiHowlingScreechTimer -= uiDiff; + + if (m_uiStrikeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRIKE) == CAST_OK) + m_uiStrikeTimer = urand(5000, 7000); + } + else + m_uiStrikeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_erekem_guard(Creature* pCreature) +{ + return new npc_erekem_guardAI(pCreature); +} + void AddSC_boss_erekem() { Script* pNewScript; @@ -101,4 +254,9 @@ void AddSC_boss_erekem() pNewScript->Name = "boss_erekem"; pNewScript->GetAI = &GetAI_boss_erekem; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_erekem_guard"; + pNewScript->GetAI = &GetAI_npc_erekem_guard; + pNewScript->RegisterSelf(); } diff --git a/scripts/northrend/violet_hold/boss_ichoron.cpp b/scripts/northrend/violet_hold/boss_ichoron.cpp index 2811509b3..7183b336b 100644 --- a/scripts/northrend/violet_hold/boss_ichoron.cpp +++ b/scripts/northrend/violet_hold/boss_ichoron.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_ichoron -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 50 +SDComment: Water Globule event NYI SDCategory: Violet Hold EndScriptData */ @@ -34,9 +34,32 @@ enum SAY_SLAY_3 = -1608024, SAY_ENRAGE = -1608025, SAY_DEATH = -1608026, + EMOTE_BUBBLE = -1608028, + + SPELL_SPLASH = 59516, + SPELL_DRAINED = 59820, + SPELL_FRENZY = 54312, + SPELL_FRENZY_H = 59522, + SPELL_PROTECTIVE_BUBBLE = 54306, + SPELL_WATER_BLAST = 54237, + SPELL_WATER_BLAST_H = 59520, + SPELL_WATER_BOLT_VOLLEY = 54241, + SPELL_WATER_BOLT_VOLLEY_H = 59521, + SPELL_WATER_GLOBULE = 54260, + + SPELL_WATER_GLOBULE_SPAWN_1 = 54258, + SPELL_WATER_GLOBULE_SPAWN_2 = 54264, + SPELL_WATER_GLOBULE_SPAWN_3 = 54265, + SPELL_WATER_GLOBULE_SPAWN_4 = 54266, + SPELL_WATER_GLOBULE_SPAWN_5 = 54267, + + SPELL_MERGE = 54269, // used by globules + SPELL_WATER_GLOBULE_TRANS = 54268, }; -struct MANGOS_DLL_DECL boss_ichoronAI : public ScriptedAI +static const uint32 aWaterGlobuleSpells[5] = {SPELL_WATER_GLOBULE_SPAWN_1, SPELL_WATER_GLOBULE_SPAWN_2, SPELL_WATER_GLOBULE_SPAWN_3, SPELL_WATER_GLOBULE_SPAWN_4, SPELL_WATER_GLOBULE_SPAWN_5}; + +struct boss_ichoronAI : public ScriptedAI { boss_ichoronAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -49,21 +72,30 @@ struct MANGOS_DLL_DECL boss_ichoronAI : public ScriptedAI instance_violet_hold* m_pInstance; bool m_bIsRegularMode; - void Reset() + uint32 m_uiWaterBoltVolleyTimer; + uint32 m_uiWaterBlastTimer; + bool m_bIsFrenzy; + + void Reset() override { + m_uiWaterBoltVolleyTimer = urand(10000, 12000); + m_uiWaterBlastTimer = 10000; + m_bIsFrenzy = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); + + DoCastSpellIfCan(m_creature, SPELL_PROTECTIVE_BUBBLE); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* pWho) + void KilledUnit(Unit* pWho) override { if (pWho->GetTypeId() != TYPEID_PLAYER) return; @@ -76,11 +108,39 @@ struct MANGOS_DLL_DECL boss_ichoronAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiWaterBlastTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_WATER_BLAST : SPELL_WATER_BLAST_H) == CAST_OK) + m_uiWaterBlastTimer = urand(8000, 14000); + } + } + else + m_uiWaterBlastTimer -= uiDiff; + + if (m_uiWaterBoltVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WATER_BOLT_VOLLEY : SPELL_WATER_BOLT_VOLLEY_H) == CAST_OK) + m_uiWaterBoltVolleyTimer = urand(7000, 12000); + } + else + m_uiWaterBoltVolleyTimer -= uiDiff; + + if (!m_bIsFrenzy && m_creature->GetHealthPercent() < 25.0f) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FRENZY : SPELL_FRENZY_H) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_bIsFrenzy = true; + } + } + DoMeleeAttackIfReady(); } }; diff --git a/scripts/northrend/violet_hold/instance_violet_hold.cpp b/scripts/northrend/violet_hold/instance_violet_hold.cpp index 2d83a08aa..3a3d64f42 100644 --- a/scripts/northrend/violet_hold/instance_violet_hold.cpp +++ b/scripts/northrend/violet_hold/instance_violet_hold.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Instance_Violet_Hold -SD%Complete: 50 -SDComment: "experimental" use of header/source object +SD%Complete: 75 +SDComment: Prison defense system requires more research SDCategory: Violet Hold EndScriptData */ @@ -31,7 +31,14 @@ instance_violet_hold::instance_violet_hold(Map* pMap) : ScriptedInstance(pMap), m_uiPortalId(0), m_uiPortalTimer(0), - m_uiMaxCountPortalLoc(0) + m_uiMaxCountPortalLoc(0), + + m_uiSealYellCount(0), + m_uiEventResetTimer(0), + + m_bIsVoidDance(false), + m_bIsDefenseless(false), + m_bIsDehydratation(false) { Initialize(); } @@ -39,13 +46,14 @@ instance_violet_hold::instance_violet_hold(Map* pMap) : ScriptedInstance(pMap), void instance_violet_hold::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - m_uiMaxCountPortalLoc = (sizeof(afPortalLocation)/sizeof(PortalData)) - 1; + m_uiMaxCountPortalLoc = countof(afPortalLocation) - 1; } void instance_violet_hold::ResetVariables() { m_uiWorldStateSealCount = 100; m_uiWorldStatePortalCount = 0; + m_uiSealYellCount = 0; } void instance_violet_hold::ResetAll() @@ -54,33 +62,65 @@ void instance_violet_hold::ResetAll() UpdateWorldState(false); CallGuards(true); SetIntroPortals(false); + // ToDo: reset the activation crystals when implemented for (std::vector::const_iterator itr = m_vRandomBosses.begin(); itr != m_vRandomBosses.end(); ++itr) { const BossInformation* pData = GetBossInformation((*itr)->uiEntry); if (pData && m_auiEncounter[pData->uiType] == DONE) { + // Despawn ghost boss if (Creature* pGhostBoss = GetSingleCreatureFromStorage(pData->uiGhostEntry)) + pGhostBoss->ForcedDespawn(); + + // Spawn new boss replacement + if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_SINCLARI_ALT)) + pSummoner->SummonCreature(pData->uiGhostEntry, (*itr)->fX, (*itr)->fY, (*itr)->fZ, (*itr)->fO, TEMPSUMMON_DEAD_DESPAWN, 0); + + // Replace Erekem guards + if (pData->uiType == TYPE_EREKEM) { - if (!pGhostBoss->isAlive()) - pGhostBoss->Respawn(); + // Despawn ghost guards + for (GuidList::const_iterator itr = m_lArakkoaGuardList.begin(); itr != m_lArakkoaGuardList.end(); ++itr) + { + if (Creature* pGhostGuard = instance->GetCreature(*itr)) + pGhostGuard->ForcedDespawn(); + } + + m_lArakkoaGuardList.clear(); + + // Spawn new guards replacement + float fX, fY, fZ, fO; + for (GuidList::const_iterator itr = m_lErekemGuardList.begin(); itr != m_lErekemGuardList.end(); ++itr) + { + if (Creature* pGuard = instance->GetCreature(*itr)) + { + // Don't allow alive original guards while the boss is dead + if (!pGuard->isDead()) + pGuard->ForcedDespawn(); + + // Spawn a ghost guard for each original guard + pGuard->GetRespawnCoord(fX, fY, fZ, &fO); + pGuard->SummonCreature(NPC_ARAKKOA_GUARD, fX, fY, fZ, fO, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } } - else if (Creature* pSummoner = GetSingleCreatureFromStorage(NPC_SINCLARI_ALT)) - pSummoner->SummonCreature(pData->uiGhostEntry, (*itr)->fX, (*itr)->fY, (*itr)->fZ, (*itr)->fO, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); + } - // Close Door if still open + // Close Door if still open + if (pData && (m_auiEncounter[pData->uiType] == DONE || m_auiEncounter[pData->uiType] == FAIL)) UpdateCellForBoss(pData->uiEntry, true); - } } } void instance_violet_hold::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_SINCLARI: case NPC_SINCLARI_ALT: case NPC_DOOR_SEAL: + case NPC_EVENT_CONTROLLER: break; case NPC_EREKEM: @@ -89,7 +129,7 @@ void instance_violet_hold::OnCreatureCreate(Creature* pCreature) case NPC_XEVOZZ: case NPC_LAVANTHOR: case NPC_ZURAMAT: - m_lRandomBossList.push_back(pCreature->GetEntry()); + m_vRandomBossList.push_back(pCreature->GetEntry()); break; case NPC_PORTAL_INTRO: @@ -98,6 +138,15 @@ void instance_violet_hold::OnCreatureCreate(Creature* pCreature) case NPC_HOLD_GUARD: m_lGuardsList.push_back(pCreature->GetObjectGuid()); return; + case NPC_EREKEM_GUARD: + m_lErekemGuardList.push_back(pCreature->GetObjectGuid()); + return; + case NPC_ARAKKOA_GUARD: + m_lArakkoaGuardList.push_back(pCreature->GetObjectGuid()); + return; + case NPC_ICHORON_SUMMON_TARGET: + m_lIchoronTargetsList.push_back(pCreature->GetObjectGuid()); + return; case NPC_ARAKKOA: case NPC_VOID_LORD: @@ -115,7 +164,7 @@ void instance_violet_hold::OnCreatureCreate(Creature* pCreature) void instance_violet_hold::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_CELL_LAVANTHOR: m_mBossToCellMap.insert(BossToCellMap::value_type(NPC_LAVANTHOR, pGo->GetObjectGuid())); @@ -157,14 +206,14 @@ void instance_violet_hold::UpdateCellForBoss(uint32 uiBossEntry, bool bForceClos if (itrCellLower == itrCellUpper) return; - for(BossToCellMap::const_iterator itr = itrCellLower; itr != itrCellUpper; ++itr) + for (BossToCellMap::const_iterator itr = itrCellLower; itr != itrCellUpper; ++itr) { if (!bForceClosing) DoUseDoorOrButton(itr->second); else { GameObject* pGo = instance->GetGameObject(itr->second); - if (pGo && pGo->GetGoType() == GAMEOBJECT_TYPE_DOOR && pGo->getLootState() == GO_ACTIVATED) + if (pGo && pGo->GetGoType() == GAMEOBJECT_TYPE_DOOR && pGo->GetGoState() == GO_STATE_ACTIVE) pGo->ResetDoorOrButton(); } } @@ -179,7 +228,7 @@ void instance_violet_hold::UpdateWorldState(bool bEnable) DoUpdateWorldState(WORLD_STATE_PORTALS, m_uiWorldStatePortalCount); } -void instance_violet_hold::OnPlayerEnter(Player* pPlayer) +void instance_violet_hold::OnPlayerEnter(Player* /*pPlayer*/) { UpdateWorldState(m_auiEncounter[TYPE_MAIN] == IN_PROGRESS ? true : false); @@ -192,7 +241,7 @@ void instance_violet_hold::OnPlayerEnter(Player* pPlayer) void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) { - debug_log("SD2: instance_violet_hold: SetData got type % u, data %u.", uiType, uiData); + debug_log("SD2: instance_violet_hold: SetData got type %u, data %u.", uiType, uiData); switch (uiType) { @@ -203,22 +252,28 @@ void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) if (m_auiEncounter[uiType] == DONE) return; - switch(uiData) + switch (uiData) { - case NOT_STARTED: - ResetAll(); - break; case IN_PROGRESS: + // ToDo: enable the prison defense system when implemented DoUseDoorOrButton(GO_PRISON_SEAL_DOOR); UpdateWorldState(); + m_bIsDefenseless = true; m_uiPortalId = urand(0, 2); m_uiPortalTimer = 15000; break; case FAIL: if (Creature* pSinclari = GetSingleCreatureFromStorage(NPC_SINCLARI)) - pSinclari->Respawn(); + pSinclari->DealDamage(pSinclari, pSinclari->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (Creature* pController = GetSingleCreatureFromStorage(NPC_EVENT_CONTROLLER)) + pController->AI()->EnterEvadeMode(); + // Reset the event (creature cleanup is handled in creature_linking) + DoUseDoorOrButton(GO_PRISON_SEAL_DOOR); // open instance door + ResetAll(); + m_uiEventResetTimer = 20000; // Timer may not be correct - 20 sec is default reset timer for blizz break; case DONE: + DoUseDoorOrButton(GO_PRISON_SEAL_DOOR); UpdateWorldState(false); break; case SPECIAL: @@ -229,6 +284,32 @@ void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) } case TYPE_SEAL: m_auiEncounter[uiType] = uiData; + if (uiData == SPECIAL) + { + --m_uiWorldStateSealCount; + DoUpdateWorldState(WORLD_STATE_SEAL, m_uiWorldStateSealCount); + + // Yell at 75%, 50% and 25% shield + if (m_uiWorldStateSealCount < 100 - 25 * m_uiSealYellCount) + { + if (Creature* pSinclari = GetSingleCreatureFromStorage(NPC_SINCLARI_ALT)) + { + // ToDo: I'm not sure if the last yell should be at 25% or at 5%. Needs research + ++m_uiSealYellCount; + DoScriptText(aSealWeakYell[m_uiSealYellCount - 1], pSinclari); + } + } + + // set achiev to failed + if (m_bIsDefenseless) + m_bIsDefenseless = false; + + if (!m_uiWorldStateSealCount) + { + SetData(TYPE_MAIN, FAIL); + SetData(TYPE_SEAL, NOT_STARTED); + } + } break; case TYPE_PORTAL: { @@ -238,7 +319,7 @@ void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) m_uiPortalTimer = 90000; break; case DONE: // portal done, set timer to 5 secs - m_uiPortalTimer = 5000; + m_uiPortalTimer = 3000; break; } m_auiEncounter[uiType] = uiData; @@ -254,10 +335,24 @@ void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) m_uiPortalTimer = 35000; if (m_auiEncounter[uiType] != DONE) // Keep the DONE-information stored m_auiEncounter[uiType] = uiData; + // Handle achievements if necessary + if (uiData == IN_PROGRESS) + { + if (uiType == TYPE_ZURAMAT) + m_bIsVoidDance = true; + else if (uiType == TYPE_ICHORON) + m_bIsDehydratation = true; + } + if (uiData == SPECIAL && uiType == TYPE_ICHORON) + m_bIsDehydratation = false; + if (uiData == FAIL) + SetData(TYPE_MAIN, FAIL); break; case TYPE_CYANIGOSA: if (uiData == DONE) SetData(TYPE_MAIN, DONE); + if (uiData == FAIL) + SetData(TYPE_MAIN, FAIL); m_auiEncounter[uiType] = uiData; break; default: @@ -270,9 +365,9 @@ void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " - << m_auiEncounter[9]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9]; m_strInstData = saveStream.str(); @@ -281,7 +376,7 @@ void instance_violet_hold::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_violet_hold::GetData(uint32 uiType) +uint32 instance_violet_hold::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -300,10 +395,10 @@ void instance_violet_hold::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -314,7 +409,7 @@ void instance_violet_hold::Load(const char* chrIn) void instance_violet_hold::SetIntroPortals(bool bDeactivate) { - for(GUIDList::const_iterator itr = m_lIntroPortalList.begin(); itr != m_lIntroPortalList.end(); ++itr) + for (GuidList::const_iterator itr = m_lIntroPortalList.begin(); itr != m_lIntroPortalList.end(); ++itr) { if (Creature* pPortal = instance->GetCreature(*itr)) { @@ -334,7 +429,7 @@ void instance_violet_hold::SpawnPortal() { uint32 uiPortalEntry = pData->pPortalType == PORTAL_TYPE_NORM ? NPC_PORTAL : NPC_PORTAL_ELITE; - pController->SummonCreature(uiPortalEntry, pData->fX, pData->fY, pData->fZ, pData->fOrient, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 1800*IN_MILLISECONDS); + pController->SummonCreature(uiPortalEntry, pData->fX, pData->fY, pData->fZ, pData->fOrient, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 1800 * IN_MILLISECONDS); } } } @@ -343,14 +438,14 @@ void instance_violet_hold::SetPortalId() { if (IsCurrentPortalForTrash()) { - int iTemp = rand()%(m_uiMaxCountPortalLoc - 1); + // Find another Trash portal position + uint8 uiTemp = m_uiPortalId + urand(1, m_uiMaxCountPortalLoc - 1); + // Decrease m_uiMaxCountPortalLoc so that the center position is skipped + uiTemp %= m_uiMaxCountPortalLoc - 1; - if (iTemp >= m_uiPortalId) - ++iTemp; + debug_log("SD2: instance_violet_hold: SetPortalId %u, old was id %u.", uiTemp, m_uiPortalId); - debug_log("SD2: instance_violet_hold: SetPortalId %i, old was id %u.", iTemp, m_uiPortalId); - - m_uiPortalId = iTemp; + m_uiPortalId = uiTemp; } else if (GetCurrentPortalNumber() == 18) { @@ -377,69 +472,47 @@ BossSpawn* instance_violet_hold::CreateBossSpawnByEntry(uint32 uiEntry) void instance_violet_hold::SetRandomBosses() { - if (m_vRandomBosses.empty()) - for (uint8 i = 0; i < MAX_MINIBOSSES; ++i) - { - if (m_auiEncounter[aBossInformation[i].uiType] == DONE) - m_vRandomBosses.push_back(CreateBossSpawnByEntry(aBossInformation[i].uiEntry)); - } - - if (m_vRandomBosses.size() >= 2) - return; - - while (m_lRandomBossList.size() > 2) + // Store bosses that are already done + for (uint8 i = 0; i < MAX_MINIBOSSES; ++i) { - uint32 uiPosition = urand(0, m_lRandomBossList.size() - 1); - - for(std::list::iterator itr = m_lRandomBossList.begin(); itr != m_lRandomBossList.end(); ++itr, --uiPosition) - { - if (!*itr) - continue; - - if (!uiPosition) - { - m_lRandomBossList.erase(itr); - break; - } - } + if (m_auiEncounter[aBossInformation[i].uiType] == DONE) + m_vRandomBosses.push_back(CreateBossSpawnByEntry(aBossInformation[i].uiEntry)); } - if (!m_vRandomBosses.empty()) + if (m_vRandomBosses.size() < 2) // Get some new random bosses { - for (std::list::const_iterator itr = m_lRandomBossList.begin(); itr != m_lRandomBossList.end(); ++itr) + std::random_shuffle(m_vRandomBossList.begin(), m_vRandomBossList.end()); + // two required, in case the first is already pushed to m_vRandomBosses + if (m_vRandomBossList.size() < 2) + script_error_log("instance_violet_hold, Mini Bosses are not properly spawned"); + else + m_vRandomBossList.resize(2); + + // Fill up some random bosses + for (std::vector::const_iterator itr = m_vRandomBossList.begin(); itr != m_vRandomBossList.end(); ++itr) { - if (m_vRandomBosses.at(0)->uiEntry != *itr) + if (m_vRandomBosses.empty() || m_vRandomBosses[0]->uiEntry != *itr) m_vRandomBosses.push_back(CreateBossSpawnByEntry(*itr)); } } - else - { - for (std::list::const_iterator itr = m_lRandomBossList.begin(); itr != m_lRandomBossList.end(); ++itr) - m_vRandomBosses.push_back(CreateBossSpawnByEntry(*itr)); - } - for (std::vector::const_iterator itr = m_vRandomBosses.begin(); itr != m_vRandomBosses.end(); ++itr) - debug_log("SD2: instance_violet_hold first random boss is entry %u", (*itr)->uiEntry); + for (uint8 i = 0; i < m_vRandomBosses.size(); ++i) + debug_log("SD2: instance_violet_hold random boss %u is entry %u", i, m_vRandomBosses[i]->uiEntry); } void instance_violet_hold::CallGuards(bool bRespawn) { - for(GUIDList::const_iterator itr = m_lGuardsList.begin(); itr != m_lGuardsList.end(); ++itr) + for (GuidList::const_iterator itr = m_lGuardsList.begin(); itr != m_lGuardsList.end(); ++itr) { if (Creature* pGuard = instance->GetCreature(*itr)) { if (bRespawn) - { pGuard->Respawn(); - } else if (pGuard->isAlive()) { - pGuard->AI()->EnterEvadeMode(); - - if (Creature* pSinclari = GetSingleCreatureFromStorage(NPC_SINCLARI)) - pGuard->GetMotionMaster()->MoveFollow(pSinclari, 0.0f, 0.0f); - - pGuard->ForcedDespawn(20000); + pGuard->SetWalk(false); + pGuard->GetMotionMaster()->MovePoint(0, fGuardExitLoc[0], fGuardExitLoc[1], fGuardExitLoc[2]); + pGuard->ForcedDespawn(6000); } } } @@ -461,21 +534,20 @@ void instance_violet_hold::ProcessActivationCrystal(Unit* pUser, bool bIsIntro) // else, kill (and despawn?) certain trash mobs. Also boss affected, but not killed. } -uint32 instance_violet_hold::GetRandomPortalEliteEntry() +bool instance_violet_hold::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* /*pSource*/, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { - return (urand(0, 1) ? NPC_PORTAL_GUARDIAN : NPC_PORTAL_KEEPER); -} - -uint32 instance_violet_hold::GetRandomMobForNormalPortal() -{ - switch(urand(1, 4)) + switch (uiCriteriaId) { - case 1: return NPC_AZURE_INVADER; - case 2: return NPC_MAGE_HUNTER; - case 3: return NPC_AZURE_SPELLBREAKER; - case 4: return NPC_AZURE_BINDER; + // ToDo: uncomment these when they are implemented + // case ACHIEV_CRIT_DEFENSELES: + // return m_bIsDefenseless; + // case ACHIEV_CRIT_DEHYDRATATION: + // return m_bIsDehydratation; + case ACHIEV_CRIT_VOID_DANCE: + return m_bIsVoidDance; + default: - return 0; + return false; } } @@ -510,6 +582,18 @@ void instance_violet_hold::OnCreatureEnterCombat(Creature* pCreature) case NPC_CYANIGOSA: SetData(TYPE_CYANIGOSA, IN_PROGRESS); break; + case NPC_AZURE_CAPTAIN: + case NPC_AZURE_RAIDER: + case NPC_AZURE_SORCEROR: + case NPC_AZURE_STALKER: + case NPC_AZURE_INVADER: + case NPC_MAGE_HUNTER: + case NPC_AZURE_SPELLBREAKER: + case NPC_AZURE_BINDER: + case NPC_AZURE_MAGE_SLAYER: + // Interrupt door seal casting (if necessary) + pCreature->InterruptNonMeleeSpells(false); + break; } } @@ -520,30 +604,52 @@ void instance_violet_hold::OnCreatureEvade(Creature* pCreature) case NPC_ZURAMAT: case NPC_VOID_LORD: SetData(TYPE_ZURAMAT, FAIL); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); break; case NPC_XEVOZZ: case NPC_ETHERAL: SetData(TYPE_XEVOZZ, FAIL); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); break; case NPC_LAVANTHOR: case NPC_LAVA_HOUND: SetData(TYPE_LAVANTHOR, FAIL); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); break; case NPC_MORAGG: case NPC_WATCHER: SetData(TYPE_MORAGG, FAIL); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); break; case NPC_EREKEM: case NPC_ARAKKOA: SetData(TYPE_EREKEM, FAIL); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + break; + case NPC_EREKEM_GUARD: + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); break; case NPC_ICHORON: case NPC_SWIRLING: SetData(TYPE_ICHORON, FAIL); + pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); break; case NPC_CYANIGOSA: SetData(TYPE_CYANIGOSA, FAIL); break; + case NPC_AZURE_CAPTAIN: + case NPC_AZURE_RAIDER: + case NPC_AZURE_SORCEROR: + case NPC_AZURE_STALKER: + case NPC_AZURE_INVADER: + case NPC_MAGE_HUNTER: + case NPC_AZURE_SPELLBREAKER: + case NPC_AZURE_BINDER: + case NPC_AZURE_MAGE_SLAYER: + // Allow them to finish off the door seal + pCreature->SetWalk(false); + pCreature->GetMotionMaster()->MovePoint(1, fSealAttackLoc[0], fSealAttackLoc[1], fSealAttackLoc[2]); + break; } } @@ -578,11 +684,28 @@ void instance_violet_hold::OnCreatureDeath(Creature* pCreature) case NPC_CYANIGOSA: SetData(TYPE_CYANIGOSA, DONE); break; + case NPC_VOID_SENTRY: + if (GetData(TYPE_ZURAMAT) == IN_PROGRESS) + m_bIsVoidDance = false; + break; } } void instance_violet_hold::Update(uint32 uiDiff) { + if (m_uiEventResetTimer) + { + if (m_uiEventResetTimer <= uiDiff) + { + if (Creature* pSinclari = GetSingleCreatureFromStorage(NPC_SINCLARI)) + pSinclari->Respawn(); + + m_uiEventResetTimer = 0; + } + else + m_uiEventResetTimer -= uiDiff; + } + if (m_auiEncounter[TYPE_MAIN] != IN_PROGRESS) return; @@ -631,7 +754,7 @@ instance_violet_hold::~instance_violet_hold() for (std::vector::const_iterator itr = m_vRandomBosses.begin(); itr != m_vRandomBosses.end(); ++itr) { if (*itr) - delete (*itr); + delete(*itr); } } diff --git a/scripts/northrend/violet_hold/violet_hold.cpp b/scripts/northrend/violet_hold/violet_hold.cpp index 913cd9ae8..2071874d6 100644 --- a/scripts/northrend/violet_hold/violet_hold.cpp +++ b/scripts/northrend/violet_hold/violet_hold.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Violet_Hold -SD%Complete: 40 -SDComment: +SD%Complete: 80 +SDComment: Intro event required more research and core support. SDCategory: Violet Hold EndScriptData */ @@ -25,6 +25,7 @@ EndScriptData */ go_activation_crystal npc_door_seal npc_sinclari +npc_prison_event_controller npc_teleportation_portal EndContentData */ @@ -48,15 +49,15 @@ bool GOUse_go_activation_crystal(Player* pPlayer, GameObject* pGo) ## npc_door_seal ######*/ -bool EffectDummyCreature_npc_door_seal(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_door_seal(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_DESTROY_DOOR_SEAL && uiEffIndex == EFFECT_INDEX_0) { if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreatureTarget->GetInstanceData()) pInstance->SetData(TYPE_SEAL, SPECIAL); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } @@ -71,15 +72,19 @@ enum { SAY_BEGIN = -1608000, SAY_LOCK_DOOR = -1608001, + SAY_VICTORY = -1608027, GOSSIP_ITEM_INTRO = -3608000, GOSSIP_ITEM_START = -3608001, + GOSSIP_ITEM_TELEPORT = -3608002, GOSSIP_TEXT_ID_INTRO = 13853, GOSSIP_TEXT_ID_START = 13854, + + SPELL_TELEPORT_INSIDE = 62138, // script effect - should trigger 62139 }; -struct MANGOS_DLL_DECL npc_sinclariAI : public npc_escortAI +struct npc_sinclariAI : public npc_escortAI { npc_sinclariAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -89,16 +94,19 @@ struct MANGOS_DLL_DECL npc_sinclariAI : public npc_escortAI instance_violet_hold* m_pInstance; - void Reset() + bool m_bIsEpilogue; + + void Reset() override { + m_bIsEpilogue = false; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { if (!m_pInstance) return; - switch(uiPointId) + switch (uiPointId) { case 0: m_pInstance->ProcessActivationCrystal(m_creature, true); @@ -110,18 +118,40 @@ struct MANGOS_DLL_DECL npc_sinclariAI : public npc_escortAI break; case 2: DoScriptText(SAY_LOCK_DOOR, m_creature); + m_creature->SetFacingTo(0.05f); + break; + case 3: m_pInstance->SetData(TYPE_MAIN, IN_PROGRESS); break; + case 4: + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + SetEscortPaused(true); + break; + case 5: + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + DoScriptText(SAY_VICTORY, m_creature); + SetEscortPaused(true); + break; } } - void JustRespawned() + void JustRespawned() override { if (m_pInstance && m_pInstance->GetData(TYPE_MAIN) != DONE) m_pInstance->SetData(TYPE_MAIN, NOT_STARTED); npc_escortAI::JustRespawned(); // Needed, to reset escort state, waypoints, etc } + + void UpdateEscortAI(const uint32 /*uiDiff*/) override + { + // Say outro after event is finished + if (m_pInstance && m_pInstance->GetData(TYPE_MAIN) == DONE && !m_bIsEpilogue) + { + SetEscortPaused(false); + m_bIsEpilogue = true; + } + } }; CreatureAI* GetAI_npc_sinclari(Creature* pCreature) @@ -131,20 +161,27 @@ CreatureAI* GetAI_npc_sinclari(Creature* pCreature) bool GossipHello_npc_sinclari(Player* pPlayer, Creature* pCreature) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INTRO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreature->GetInstanceData()) + { + if (pInstance->GetData(TYPE_MAIN) != IN_PROGRESS) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_INTRO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + else + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TELEPORT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + } + pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_INTRO, pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreature->GetInstanceData()) { if (pInstance->GetData(TYPE_MAIN) == NOT_STARTED) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_START, pCreature->GetObjectGuid()); } } @@ -152,7 +189,7 @@ bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSe pPlayer->CLOSE_GOSSIP_MENU(); } - if (uiAction == GOSSIP_ACTION_INFO_DEF+2) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 2) { if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreature->GetInstanceData()) { @@ -170,216 +207,373 @@ bool GossipSelect_npc_sinclari(Player* pPlayer, Creature* pCreature, uint32 uiSe pPlayer->CLOSE_GOSSIP_MENU(); } + if (uiAction == GOSSIP_ACTION_INFO_DEF + 3) + { + pCreature->CastSpell(pPlayer, SPELL_TELEPORT_INSIDE, true); + pPlayer->CLOSE_GOSSIP_MENU(); + } + return true; } /*###### -## npc_teleportation_portal +## npc_prison_event_controller ######*/ -struct MANGOS_DLL_DECL npc_teleportation_portalAI : public ScriptedAI +struct npc_prison_event_controllerAI : public ScriptedAI { - npc_teleportation_portalAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_prison_event_controllerAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (instance_violet_hold*)pCreature->GetInstanceData(); - m_uiMyPortalNumber = 0; Reset(); } instance_violet_hold* m_pInstance; - GUIDSet m_lMobSet; + GuidSet m_sTrashPackSet; - bool m_bNeedInvisible; - bool m_bIntro; - uint32 m_uiIntroTimer; - uint32 m_uiMyPortalNumber; + uint32 m_uiSaboteurTimer; + uint8 m_uiSaboteurPhase; + uint8 m_uiCurrentTrashPortalId; + + ObjectGuid m_currentSaboteurGuid; - void Reset() + void Reset() override { - m_bNeedInvisible = false; - m_bIntro = false; - m_uiIntroTimer = 10000; + m_uiCurrentTrashPortalId = 0; + m_uiSaboteurPhase = 0; + m_uiSaboteurTimer = 0; - if (m_pInstance) - m_uiMyPortalNumber = m_pInstance->GetCurrentPortalNumber(); + m_currentSaboteurGuid.Clear(); + m_sTrashPackSet.clear(); } - void DoSummon() + void DoSetCurrentTrashPortal(uint8 uiPortalId) { m_uiCurrentTrashPortalId = uiPortalId; } + + void JustSummoned(Creature* pSummoned) override { - if (m_creature->GetEntry() == NPC_PORTAL_INTRO) + switch (pSummoned->GetEntry()) { - //not made yet + case NPC_AZURE_CAPTAIN: + DoScriptText(EMOTE_DRAGONFLIGHT_PORTAL, pSummoned); + // no break + case NPC_AZURE_RAIDER: + case NPC_AZURE_SORCEROR: + case NPC_AZURE_STALKER: + m_sTrashPackSet.insert(pSummoned->GetObjectGuid()); + // no break + case NPC_AZURE_INVADER: + case NPC_MAGE_HUNTER: + case NPC_AZURE_SPELLBREAKER: + case NPC_AZURE_BINDER: + case NPC_AZURE_MAGE_SLAYER: + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, fSealAttackLoc[0], fSealAttackLoc[1], fSealAttackLoc[2]); + break; + case NPC_AZURE_SABOTEUR: + { + if (!m_pInstance) + return; + const BossInformation* pData = m_pInstance->GetBossInformation(); + if (pData) + { + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(pData->uiWayPointId, pData->fX, pData->fY, pData->fZ); + } + m_currentSaboteurGuid = pSummoned->GetObjectGuid(); + break; + } + } + } + + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override + { + if (uiMotionType != POINT_MOTION_TYPE && !uiPointId) return; + + if (pSummoned->GetEntry() == NPC_AZURE_SABOTEUR) + { + // Prepare to release the boss + m_uiSaboteurPhase = 0; + m_uiSaboteurTimer = 1000; + pSummoned->CastSpell(pSummoned, SPELL_SHIELD_DISRUPTION, false); } - else if (m_creature->GetEntry() == NPC_PORTAL) + // For other summons, cast destroy seal when they reach the door + else + pSummoned->CastSpell(pSummoned, SPELL_DESTROY_DOOR_SEAL, false); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - if (m_pInstance && m_pInstance->GetCurrentPortalNumber() == 18) - { - m_creature->SummonCreature(NPC_CYANIGOSA, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); - } - else + case NPC_AZURE_CAPTAIN: + case NPC_AZURE_RAIDER: + case NPC_AZURE_SORCEROR: + case NPC_AZURE_STALKER: { - m_creature->SummonCreature(m_pInstance->GetRandomPortalEliteEntry(), 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); - m_creature->CastSpell(m_creature, SPELL_PORTAL_PERIODIC, true); + if (m_sTrashPackSet.find(pSummoned->GetObjectGuid()) != m_sTrashPackSet.end()) + m_sTrashPackSet.erase(pSummoned->GetObjectGuid()); + + if (m_sTrashPackSet.empty()) + { + // no need if a new portal was made while this was in progress + if (m_uiCurrentTrashPortalId == m_pInstance->GetCurrentPortalNumber()) + m_pInstance->SetData(TYPE_PORTAL, DONE); + } + break; } } - else if (m_pInstance->IsCurrentPortalForTrash()) + } + + // Release a boss from a prison cell + void DoReleaseBoss() + { + if (!m_pInstance) + return; + + if (const BossInformation* pData = m_pInstance->GetBossInformation()) { - for(uint8 i = 0; i < 4; ++i) + if (Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(pData->uiType) != DONE ? pData->uiEntry : pData->uiGhostEntry)) { - uint32 uiSummonId = 0; + m_pInstance->UpdateCellForBoss(pData->uiEntry); + if (pData->iSayEntry) + DoScriptText(pData->iSayEntry, pBoss); + + pBoss->GetMotionMaster()->MovePoint(1, pData->fX, pData->fY, pData->fZ); + pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); - switch(i) + // Handle Erekem guards + if (pData->uiType == TYPE_EREKEM) { - case 0: uiSummonId = NPC_AZURE_CAPTAIN; break; - case 1: uiSummonId = NPC_AZURE_RAIDER; break; - case 2: uiSummonId = NPC_AZURE_SORCEROR; break; - case 3: uiSummonId = NPC_AZURE_STALKER; break; - } + GuidList lAddGuids; + if (m_pInstance) + m_pInstance->GetErekemGuardList(lAddGuids); - m_creature->SummonCreature(uiSummonId, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); + float fMoveX; + for (GuidList::const_iterator itr = lAddGuids.begin(); itr != lAddGuids.end(); ++itr) + { + if (Creature* pAdd = m_pInstance->instance->GetCreature(*itr)) + { + fMoveX = (pData->fX - pAdd->GetPositionX()) * .25; + pAdd->GetMotionMaster()->MovePoint(0, pData->fX - fMoveX, pData->fY, pData->fZ); + pAdd->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + } + } + } } - - m_bNeedInvisible = true; - } - else - { - m_creature->SummonCreature(NPC_AZURE_SABOTEUR, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); - m_bNeedInvisible = true; } } - void JustSummoned(Creature* pSummoned) + void UpdateAI(const uint32 uiDiff) override { - switch(pSummoned->GetEntry()) + if (m_uiSaboteurTimer) { - case NPC_PORTAL_GUARDIAN: - DoScriptText(EMOTE_GUARDIAN_PORTAL, pSummoned); - m_creature->CastSpell(pSummoned, SPELL_PORTAL_CHANNEL, false); - break; - case NPC_PORTAL_KEEPER: - DoScriptText(EMOTE_KEEPER_PORTAL, pSummoned); - m_creature->CastSpell(pSummoned, SPELL_PORTAL_CHANNEL, false); - break; - case NPC_AZURE_CAPTAIN: - DoScriptText(EMOTE_DRAGONFLIGHT_PORTAL, pSummoned); - m_lMobSet.insert(pSummoned->GetObjectGuid()); - break; - case NPC_AZURE_RAIDER: - case NPC_AZURE_SORCEROR: - case NPC_AZURE_STALKER: - m_lMobSet.insert(pSummoned->GetObjectGuid()); - return; - case NPC_AZURE_SABOTEUR: + if (m_uiSaboteurTimer <= uiDiff) { - if (!m_pInstance) + Creature* pSaboteur = m_creature->GetMap()->GetCreature(m_currentSaboteurGuid); + if (!pSaboteur) return; - const BossInformation* pData = m_pInstance->GetBossInformation(); - if (pData) - pSummoned->GetMotionMaster()->MovePoint(pData->uiWayPointId, pData->fX, pData->fY, pData->fZ); - return; + + switch (m_uiSaboteurPhase) + { + case 0: + pSaboteur->CastSpell(pSaboteur, SPELL_SHIELD_DISRUPTION, false); + m_uiSaboteurTimer = 1000; + break; + case 1: + pSaboteur->CastSpell(pSaboteur, SPELL_SHIELD_DISRUPTION, false); + m_uiSaboteurTimer = 1000; + break; + case 2: + DoReleaseBoss(); + pSaboteur->CastSpell(pSaboteur, SPELL_SIMPLE_TELEPORT, false); + pSaboteur->ForcedDespawn(1000); + m_uiSaboteurTimer = 0; + break; + } + ++m_uiSaboteurPhase; } - default: - return; + else + m_uiSaboteurTimer -= uiDiff; } + } +}; + +CreatureAI* GetAI_npc_prison_event_controller(Creature* pCreature) +{ + return new npc_prison_event_controllerAI(pCreature); +} + +/*###### +## npc_teleportation_portal +######*/ + +static const uint32 aTrashPortalNpcs[4] = {NPC_AZURE_CAPTAIN, NPC_AZURE_RAIDER, NPC_AZURE_SORCEROR, NPC_AZURE_STALKER}; + +struct npc_teleportation_portalAI : public ScriptedAI +{ + npc_teleportation_portalAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_violet_hold*)pCreature->GetInstanceData(); + m_uiMyPortalNumber = 0; + Reset(); + } + + instance_violet_hold* m_pInstance; + + bool m_bIntro; + uint32 m_uiMyPortalNumber; + uint32 m_uiCyanigosaMoveTimer; + + ObjectGuid m_cyanigosaGuid; + + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_PORTAL_PERIODIC); + + m_bIntro = true; + m_uiCyanigosaMoveTimer = 0; if (m_pInstance) - m_pInstance->SetData(TYPE_PORTAL, SPECIAL); + m_uiMyPortalNumber = m_pInstance->GetCurrentPortalNumber(); } - void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) + void DoSummon() { - if (uiMotionType != POINT_MOTION_TYPE && pSummoned->GetEntry() != NPC_AZURE_SABOTEUR) + if (!m_pInstance) return; - if (uiPointId == 1) + // Portal event used for intro + if (m_creature->GetEntry() == NPC_PORTAL_INTRO) { - pSummoned->CastSpell(pSummoned, SPELL_SHIELD_DISRUPTION, false); - if (m_pInstance) + // ToDo: uncomment this when the information and DB data is confirmed. Right now the mobs may overrun the guards after a few min of fightning + // m_creature->SummonCreature(m_pInstance->GetRandomMobForIntroPortal(), 0, 0, 0, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + return; + } + + // First summon tick + if (m_bIntro) + { + if (m_creature->GetEntry() == NPC_PORTAL) + { + // Summon a guardian keeper or Cyanigosa + if (m_uiMyPortalNumber == 18) + m_creature->SummonCreature(NPC_CYANIGOSA, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600 * IN_MILLISECONDS); + else + m_creature->SummonCreature(m_pInstance->GetRandomPortalEliteEntry(), 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600 * IN_MILLISECONDS); + } + else if (m_creature->GetEntry() == NPC_PORTAL_ELITE) { - if (const BossInformation* pData = m_pInstance->GetBossInformation()) + // Allow the event controller to summon the mobs, for better movement handling + Creature* pController = m_pInstance->GetSingleCreatureFromStorage(NPC_EVENT_CONTROLLER); + if (!pController) + return; + + // Summon a squad or a saboteur + if (m_pInstance->IsCurrentPortalForTrash()) { - if (Creature* pBoss = m_pInstance->GetSingleCreatureFromStorage(m_pInstance->GetData(pData->uiType) != DONE ? pData->uiEntry : pData->uiGhostEntry)) + float fX, fY, fZ; + for (uint8 i = 0; i < 4; ++i) { - m_pInstance->UpdateCellForBoss(pData->uiEntry); - if (pData->iSayEntry) - DoScriptText(pData->iSayEntry, pBoss); + uint32 uiSummonId = aTrashPortalNpcs[i]; - // TODO, adds for Erekem? Opening their Cells? Reset flags on FAIL? - pBoss->GetMotionMaster()->MovePoint(1, pData->fX, pData->fY, pData->fZ); - pBoss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + // Summon the trash pack around the portal + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 3.0f, M_PI_F / 2 * i); + pController->SummonCreature(uiSummonId, fX, fY, fZ, m_creature->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600 * IN_MILLISECONDS); } + + // If this is a trash portal, set the current number in the + if (npc_prison_event_controllerAI* pControllerAI = dynamic_cast(pController->AI())) + pControllerAI->DoSetCurrentTrashPortal(m_uiMyPortalNumber); } + else + pController->SummonCreature(NPC_AZURE_SABOTEUR, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 600 * IN_MILLISECONDS); + + m_creature->ForcedDespawn(5000); } + + // Set special data for all the portals, except the last one + if (m_pInstance && m_uiMyPortalNumber != 18) + m_pInstance->SetData(TYPE_PORTAL, SPECIAL); + + m_bIntro = false; + } + else + { + // Allow the normal mobs to be summoned by the event controller + if (Creature* pController = m_pInstance->GetSingleCreatureFromStorage(NPC_EVENT_CONTROLLER)) + pController->SummonCreature(m_pInstance->GetRandomMobForNormalPortal(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); } } - void SummonedCreatureJustDied(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { + case NPC_CYANIGOSA: + m_cyanigosaGuid = pSummoned->GetObjectGuid(); + m_uiCyanigosaMoveTimer = 5000; + m_creature->ForcedDespawn(5000); + break; case NPC_PORTAL_GUARDIAN: + DoScriptText(EMOTE_GUARDIAN_PORTAL, pSummoned); + DoCastSpellIfCan(pSummoned, SPELL_PORTAL_CHANNEL); + break; case NPC_PORTAL_KEEPER: + DoScriptText(EMOTE_KEEPER_PORTAL, pSummoned); + DoCastSpellIfCan(pSummoned, SPELL_PORTAL_CHANNEL); break; - case NPC_AZURE_CAPTAIN: - case NPC_AZURE_RAIDER: - case NPC_AZURE_SORCEROR: - case NPC_AZURE_STALKER: - { - m_lMobSet.erase(pSummoned->GetObjectGuid()); - - if (!m_lMobSet.empty()) - return; - + case NPC_AZURE_BINDER_INTRO: + case NPC_AZURE_INVADER_INTRO: + case NPC_AZURE_SPELLBREAKER_INTRO: + case NPC_AZURE_MAGE_SLAYER_INTRO: + // Move them to the entrance. They will attack the guards automatically + pSummoned->SetWalk(false); + pSummoned->GetMotionMaster()->MovePoint(1, fSealAttackLoc[0], fSealAttackLoc[1], fSealAttackLoc[2]); break; - } - default: - return; } + } - if (m_pInstance) + void SummonedCreatureJustDied(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) { - // no need if a new portal was made while this was in progress - if (m_uiMyPortalNumber == m_pInstance->GetCurrentPortalNumber()) - m_pInstance->SetData(TYPE_PORTAL, DONE); + case NPC_PORTAL_GUARDIAN: + case NPC_PORTAL_KEEPER: + m_creature->ForcedDespawn(3000); + // no need if a new portal was made while this was in progress + if (m_pInstance && m_uiMyPortalNumber == m_pInstance->GetCurrentPortalNumber()) + m_pInstance->SetData(TYPE_PORTAL, DONE); + break; } + } - m_creature->ForcedDespawn(); + void SummonedCreatureDespawn(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_PORTAL_GUARDIAN: + case NPC_PORTAL_KEEPER: + // Despawn in case of event reset + m_creature->ForcedDespawn(); + break; + } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_uiIntroTimer) + if (m_uiCyanigosaMoveTimer) { - if (m_uiIntroTimer <= uiDiff) + if (m_uiCyanigosaMoveTimer <= uiDiff) { - if (!m_pInstance) - { - m_creature->ForcedDespawn(); - return; - } + if (Creature* pCyanigosa = m_creature->GetMap()->GetCreature(m_cyanigosaGuid)) + pCyanigosa->GetMotionMaster()->MoveJump(afPortalLocation[8].fX, afPortalLocation[8].fY, afPortalLocation[8].fZ, pCyanigosa->GetSpeed(MOVE_RUN) * 2, 10.0f); - m_uiIntroTimer = 0; + m_uiCyanigosaMoveTimer = 0; } else - { - m_uiIntroTimer -= uiDiff; - return; - } - } - - if (!m_bIntro) - { - DoSummon(); - m_bIntro = true; - } - - if (m_bNeedInvisible) - { - // hack; find a better way - m_creature->SetVisibility(VISIBILITY_OFF); - m_bNeedInvisible = false; + m_uiCyanigosaMoveTimer -= uiDiff; } } }; @@ -389,15 +583,15 @@ CreatureAI* GetAI_npc_teleportation_portal(Creature* pCreature) return new npc_teleportation_portalAI(pCreature); } -bool EffectDummyCreature_npc_teleportation_portal(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_teleportation_portal(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - //always check spellid and effectindex + // always check spellid and effectindex if (uiSpellId == SPELL_PORTAL_PERIODIC && uiEffIndex == EFFECT_INDEX_0) { - if (instance_violet_hold* pInstance = (instance_violet_hold*)pCreatureTarget->GetInstanceData()) - pCreatureTarget->SummonCreature(pInstance->GetRandomMobForNormalPortal(), 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600*IN_MILLISECONDS); + if (npc_teleportation_portalAI* pPortalAI = dynamic_cast(pCreatureTarget->AI())) + pPortalAI->DoSummon(); - //always return true when we are handling this spell and effect + // always return true when we are handling this spell and effect return true; } @@ -425,6 +619,11 @@ void AddSC_violet_hold() pNewScript->pGossipSelect = &GossipSelect_npc_sinclari; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_prison_event_controller"; + pNewScript->GetAI = &GetAI_npc_prison_event_controller; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "npc_teleportation_portal"; pNewScript->GetAI = &GetAI_npc_teleportation_portal; diff --git a/scripts/northrend/violet_hold/violet_hold.h b/scripts/northrend/violet_hold/violet_hold.h index f68cdd380..6388081e1 100644 --- a/scripts/northrend/violet_hold/violet_hold.h +++ b/scripts/northrend/violet_hold/violet_hold.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -26,6 +26,7 @@ enum WORLD_STATE_PORTALS = 3810, GO_INTRO_CRYSTAL = 193615, + GO_PRISON_CRYSTAL = 193611, GO_PRISON_SEAL_DOOR = 191723, GO_CELL_LAVANTHOR = 191566, @@ -69,10 +70,13 @@ enum NPC_AZURE_RAIDER = 30668, NPC_AZURE_STALKER = 32191, + NPC_VOID_SENTRY = 29364, // Npc checked for Zuramat achiev + NPC_ICHORON_SUMMON_TARGET = 29326, // Npc which summons the Ichoron globules + // used for intro NPC_AZURE_BINDER_INTRO = 31007, NPC_AZURE_INVADER_INTRO = 31008, - NPC_AZURE_SPELLBREAKER_INTRO= 31009, + NPC_AZURE_SPELLBREAKER_INTRO = 31009, NPC_AZURE_MAGE_SLAYER_INTRO = 31010, NPC_AZURE_SABOTEUR = 31079, @@ -82,6 +86,7 @@ enum // 'Ghosts' for Killed mobs after Wipe NPC_ARAKKOA = 32226, + NPC_ARAKKOA_GUARD = 32228, NPC_VOID_LORD = 32230, NPC_ETHERAL = 32231, NPC_SWIRLING = 32234, @@ -90,11 +95,14 @@ enum SPELL_DEFENSE_SYSTEM_VISUAL = 57887, SPELL_DEFENSE_SYSTEM_SPAWN = 57886, + SPELL_LIGHTNING_INTRO = 60038, // intro kill spells, also related to spell 58152 + SPELL_ARCANE_LIGHTNING = 57930, // damage spells, related to spell 57912 SPELL_DESTROY_DOOR_SEAL = 58040, // spell periodic cast by misc SPELL_TELEPORTATION_PORTAL = 57687, // visual aura, but possibly not used? creature_template model for portals are same SPELL_SHIELD_DISRUPTION = 58291, // dummy when opening a cell + SPELL_SIMPLE_TELEPORT = 12980, // used after a cell has been opened - not sure if the id is correct SPELL_PORTAL_PERIODIC = 58008, // most likely the tick for each summon (tick each 15 seconds) SPELL_PORTAL_CHANNEL = 58012, // the blue "stream" between portal and guardian/keeper @@ -116,10 +124,21 @@ enum EMOTE_DRAGONFLIGHT_PORTAL = -1608006, EMOTE_KEEPER_PORTAL = -1608007, - MAX_NORMAL_PORTAL = 8 + MAX_NORMAL_PORTAL = 8, + + ACHIEV_CRIT_DEFENSELES = 6803, // event achiev - 1816 + ACHIEV_CRIT_DEHYDRATATION = 7320, // Ichoron achiev - 2041 + ACHIEV_CRIT_VOID_DANCE = 7587, // Zuramat achiev - 2153 }; static const float fDefenseSystemLoc[4] = {1888.146f, 803.382f, 58.604f, 3.072f}; +static const float fGuardExitLoc[3] = {1806.955f, 803.851f, 44.36f}; +static const float fSealAttackLoc[3] = {1858.027f, 804.11f, 44.008f}; + +static const uint32 aRandomPortalNpcs[5] = {NPC_AZURE_INVADER, NPC_MAGE_HUNTER, NPC_AZURE_SPELLBREAKER, NPC_AZURE_BINDER, NPC_AZURE_MAGE_SLAYER}; +static const uint32 aRandomIntroNpcs[4] = {NPC_AZURE_BINDER_INTRO, NPC_AZURE_INVADER_INTRO, NPC_AZURE_SPELLBREAKER_INTRO, NPC_AZURE_MAGE_SLAYER_INTRO}; + +static const int32 aSealWeakYell[3] = {SAY_SEAL_75, SAY_SEAL_50, SAY_SEAL_5}; enum ePortalType { @@ -134,17 +153,17 @@ struct PortalData float fX, fY, fZ, fOrient; }; -static const PortalData afPortalLocation[]= +static const PortalData afPortalLocation[] = { - {PORTAL_TYPE_NORM, 1936.07f, 803.198f, 53.3749f, 3.1241f}, //balcony - {PORTAL_TYPE_NORM, 1877.51f, 850.104f, 44.6599f, 4.7822f}, //erekem - {PORTAL_TYPE_NORM, 1890.64f, 753.471f, 48.7224f, 1.7104f}, //moragg - {PORTAL_TYPE_SQUAD, 1911.06f, 802.103f, 38.6465f, 2.8908f}, //below balcony - {PORTAL_TYPE_SQUAD, 1928.06f, 763.256f, 51.3167f, 2.3905f}, //bridge - {PORTAL_TYPE_SQUAD, 1924.26f, 847.661f, 47.1591f, 4.0202f}, //zuramat - {PORTAL_TYPE_NORM, 1914.16f, 832.527f, 38.6441f, 3.5160f}, //xevozz - {PORTAL_TYPE_NORM, 1857.30f, 764.145f, 38.6543f, 0.8339f}, //lavanthor - {PORTAL_TYPE_BOSS, 1890.73f, 803.309f, 38.4001f, 2.4139f}, //center + {PORTAL_TYPE_NORM, 1936.07f, 803.198f, 53.3749f, 3.1241f}, // balcony + {PORTAL_TYPE_NORM, 1877.51f, 850.104f, 44.6599f, 4.7822f}, // erekem + {PORTAL_TYPE_NORM, 1890.64f, 753.471f, 48.7224f, 1.7104f}, // moragg + {PORTAL_TYPE_SQUAD, 1911.06f, 802.103f, 38.6465f, 2.8908f}, // below balcony + {PORTAL_TYPE_SQUAD, 1928.06f, 763.256f, 51.3167f, 2.3905f}, // bridge + {PORTAL_TYPE_SQUAD, 1924.26f, 847.661f, 47.1591f, 4.0202f}, // zuramat + {PORTAL_TYPE_NORM, 1914.16f, 832.527f, 38.6441f, 3.5160f}, // xevozz + {PORTAL_TYPE_NORM, 1857.30f, 764.145f, 38.6543f, 0.8339f}, // lavanthor + {PORTAL_TYPE_BOSS, 1890.73f, 803.309f, 38.4001f, 2.4139f}, // center }; struct BossInformation @@ -170,35 +189,29 @@ static const BossInformation aBossInformation[] = {TYPE_MORAGG, NPC_MORAGG, NPC_WATCHER, 1, 1890.51f, 752.85f, 47.66f, 0} }; -class MANGOS_DLL_DECL instance_violet_hold : public ScriptedInstance +class instance_violet_hold : public ScriptedInstance { public: instance_violet_hold(Map* pMap); ~instance_violet_hold(); // Destructor used to free m_vRandomBosses - void Initialize(); - void ResetAll(); - void ResetVariables(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; void UpdateCellForBoss(uint32 uiBossEntry, bool bForceClosing = false); - void UpdateWorldState(bool bEnable = true); void SetIntroPortals(bool bDeactivate); - void SpawnPortal(); - - void SetPortalId(); void CallGuards(bool bRespawn); - uint32 GetRandomPortalEliteEntry(); - uint32 GetRandomMobForNormalPortal(); + uint32 GetRandomPortalEliteEntry() { return (urand(0, 1) ? NPC_PORTAL_GUARDIAN : NPC_PORTAL_KEEPER); } + uint32 GetRandomMobForNormalPortal() { return aRandomPortalNpcs[urand(0, 4)]; } + uint32 GetRandomMobForIntroPortal() { return aRandomIntroNpcs[urand(0, 3)]; } uint32 GetCurrentPortalNumber() { return m_uiWorldStatePortalCount; } - PortalData const* GetPortalData() { return &afPortalLocation[m_uiPortalId]; } BossInformation const* GetBossInformation(uint32 uiEntry = 0); bool IsCurrentPortalForTrash() @@ -209,35 +222,50 @@ class MANGOS_DLL_DECL instance_violet_hold : public ScriptedInstance return false; } - bool IsNextPortalForTrash() - { - if ((m_uiWorldStatePortalCount+1) % MAX_MINIBOSSES) - return true; - - return false; - } - void ProcessActivationCrystal(Unit* pUser, bool bIsIntro = false); - void SetRandomBosses(); + void GetErekemGuardList(GuidList& lGuardList) { lGuardList = GetData(TYPE_EREKEM) != DONE ? m_lErekemGuardList : m_lArakkoaGuardList; } + void GetIchoronTriggerList(GuidList& lList) { lList = m_lIchoronTargetsList; } - void OnPlayerEnter(Player* pPlayer); + void OnPlayerEnter(Player* pPlayer) override; - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - void Update(uint32 uiDiff); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; typedef std::multimap BossToCellMap; protected: + PortalData const* GetPortalData() { return &afPortalLocation[m_uiPortalId]; } + + void UpdateWorldState(bool bEnable = true); + + void SetRandomBosses(); + + void SpawnPortal(); + void SetPortalId(); + + void ResetAll(); + void ResetVariables(); + + bool IsNextPortalForTrash() + { + if ((m_uiWorldStatePortalCount + 1) % MAX_MINIBOSSES) + return true; + + return false; + } + BossSpawn* CreateBossSpawnByEntry(uint32 uiEntry); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; @@ -250,11 +278,21 @@ class MANGOS_DLL_DECL instance_violet_hold : public ScriptedInstance uint32 m_uiPortalTimer; uint32 m_uiMaxCountPortalLoc; + uint32 m_uiSealYellCount; + uint32 m_uiEventResetTimer; + + bool m_bIsVoidDance; + bool m_bIsDefenseless; + bool m_bIsDehydratation; + BossToCellMap m_mBossToCellMap; - GUIDList m_lIntroPortalList; - GUIDList m_lGuardsList; - std::list m_lRandomBossList; + GuidList m_lIntroPortalList; + GuidList m_lGuardsList; + GuidList m_lErekemGuardList; + GuidList m_lArakkoaGuardList; + GuidList m_lIchoronTargetsList; + std::vector m_vRandomBossList; std::vector m_vRandomBosses; }; diff --git a/scripts/northrend/zuldrak.cpp b/scripts/northrend/zuldrak.cpp index 3ca38d13c..6328b970c 100644 --- a/scripts/northrend/zuldrak.cpp +++ b/scripts/northrend/zuldrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,15 +17,18 @@ /* ScriptData SDName: Zuldrak SD%Complete: 100 -SDComment: Quest support: 12934. +SDComment: Quest support: 12652, 12934. SDCategory: Zuldrak EndScriptData */ /* ContentData npc_gurgthock +npc_ghoul_feeding_bunny +npc_decaying_ghoul EndContentData */ #include "precompiled.h" +#include "TemporarySummon.h" /*###### ## npc_gurgthock @@ -44,7 +47,7 @@ enum static float m_afSpawnLocation[] = {5768.71f, -2969.29f, 273.816f}; static uint32 m_auiBosses[] = {NPC_AZBARIN, NPC_DUKE_SINGEN, NPC_ERATHIUS, NPC_GARGORAL}; -struct MANGOS_DLL_DECL npc_gurgthockAI : public ScriptedAI +struct npc_gurgthockAI : public ScriptedAI { npc_gurgthockAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -55,15 +58,15 @@ struct MANGOS_DLL_DECL npc_gurgthockAI : public ScriptedAI m_playerGuid = pPlayer->GetObjectGuid(); } - void Reset() + void Reset() override { m_playerGuid.Clear(); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { uint32 uiEntry = pSummoned->GetEntry(); - for(uint8 i = 0; i < 4; ++i) + for (uint8 i = 0; i < 4; ++i) { if (uiEntry == m_auiBosses[i]) { @@ -81,7 +84,7 @@ bool QuestAccept_npc_gurgthock(Player* pPlayer, Creature* pCreature, const Quest { if (pQuest->GetQuestId() == QUEST_FROM_BEYOND) { - pCreature->SummonCreature(m_auiBosses[urand(0, 3)], m_afSpawnLocation[0], m_afSpawnLocation[1], m_afSpawnLocation[2], 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000); + pCreature->SummonCreature(m_auiBosses[urand(0, 3)], m_afSpawnLocation[0], m_afSpawnLocation[1], m_afSpawnLocation[2], 0.0f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 600000); if (npc_gurgthockAI* pGurthockAI = dynamic_cast(pCreature->AI())) pGurthockAI->SetPlayer(pPlayer); @@ -94,6 +97,181 @@ CreatureAI* GetAI_npc_gurgthock(Creature* pCreature) return new npc_gurgthockAI(pCreature); } +/*###### +## npc_ghoul_feeding_bunny +######*/ + +enum +{ + SPELL_ATTRACT_GHOUL = 52037, // script target on npc 28565 + SPELL_GHOUL_KILL_CREDIT = 52030, + // SPELL_GHOUL_KILL_CREDIT_EFFECT = 52038, // triggers 52039; purpose unk - same effect as 52030 but with different target + + NPC_DECAYING_GHOUL = 28565, +}; + +struct npc_ghoul_feeding_bunnyAI : public ScriptedAI +{ + npc_ghoul_feeding_bunnyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiAttractTimer; + + void Reset() override + { + m_uiAttractTimer = 1000; + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_DECAYING_GHOUL) + { + // Give kill credit to the summoner player + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + DoCastSpellIfCan(pSummoner, SPELL_GHOUL_KILL_CREDIT, CAST_TRIGGERED); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiAttractTimer) + { + if (m_uiAttractTimer <= uiDiff) + { + // try to target a nearby ghoul + if (DoCastSpellIfCan(m_creature, SPELL_ATTRACT_GHOUL) == CAST_OK) + m_uiAttractTimer = 0; + else + m_uiAttractTimer = 5000; + } + else + m_uiAttractTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_ghoul_feeding_bunny(Creature* pCreature) +{ + return new npc_ghoul_feeding_bunnyAI(pCreature); +} + +/*###### +## npc_decaying_ghoul +######*/ + +enum +{ + SPELL_BIRTH = 26047, + SPELL_FLESH_ROT = 28913, + + NPC_GHOUL_FEEDING_BUNNY = 28591, +}; + +struct npc_decaying_ghoulAI : public ScriptedAI +{ + npc_decaying_ghoulAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bSpawnAnim = false; + Reset(); + } + + uint32 m_uiFleshRotTimer; + bool m_bSpawnAnim; + ObjectGuid m_feedingBunnyGuid; + + void Reset() override + { + m_uiFleshRotTimer = urand(1000, 3000); + } + + void JustRespawned() override + { + DoCastSpellIfCan(m_creature, SPELL_BIRTH); + m_creature->HandleEmote(EMOTE_STATE_NONE); + m_feedingBunnyGuid.Clear(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // handle the animation and despawn + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->HandleEmote(EMOTE_STATE_EAT_NO_SHEATHE); + m_creature->ForcedDespawn(10000); + + // send AI event for the quest credit + if (Creature* pBunny = m_creature->GetMap()->GetCreature(m_feedingBunnyGuid)) + SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pBunny); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A && pInvoker->GetEntry() == NPC_GHOUL_FEEDING_BUNNY) + { + // check if the ghoul has already a feeding bunny set + if (m_feedingBunnyGuid) + return; + + // move the ghoul to the feeding target + float fX, fY, fZ; + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->Clear(); + pInvoker->GetContactPoint(m_creature, fX, fY, fZ); + + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + m_feedingBunnyGuid = pInvoker->GetObjectGuid(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // cast birth animation + if (!m_bSpawnAnim) + { + if (DoCastSpellIfCan(m_creature, SPELL_BIRTH) == CAST_OK) + m_bSpawnAnim = true; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiFleshRotTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLESH_ROT) == CAST_OK) + m_uiFleshRotTimer = urand(7000, 15000); + } + else + m_uiFleshRotTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_decaying_ghoul(Creature* pCreature) +{ + return new npc_decaying_ghoulAI(pCreature); +} + +bool EffectDummyCreature_npc_decaying_ghoul(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (uiSpellId == SPELL_ATTRACT_GHOUL && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_DECAYING_GHOUL) + { + if (pCaster->GetEntry() != NPC_GHOUL_FEEDING_BUNNY) + return true; + + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + return true; + } + + return false; +} + void AddSC_zuldrak() { Script* pNewScript; @@ -103,4 +281,15 @@ void AddSC_zuldrak() pNewScript->GetAI = &GetAI_npc_gurgthock; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_gurgthock; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ghoul_feeding_bunny"; + pNewScript->GetAI = &GetAI_npc_ghoul_feeding_bunny; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_decaying_ghoul"; + pNewScript->GetAI = &GetAI_npc_decaying_ghoul; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_decaying_ghoul; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp b/scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp index d4cdb0645..85d733734 100644 --- a/scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp +++ b/scripts/outland/auchindoun/auchenai_crypts/boss_exarch_maladaar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Exarch_Maladaar SD%Complete: 95 -SDComment: Most of event implemented, some adjustments to timers remain and possibly make some better code for switching his dark side in to better "images" of player. +SDComment: Most of event implemented, possibly make some better code for switching his dark side in to better "images" of player. SDCategory: Auchindoun, Auchenai Crypts EndScriptData */ @@ -31,6 +31,8 @@ EndContentData */ enum { + SPELL_STOLEN_SOUL_DISPEL = 33326, + SPELL_MOONFIRE = 37328, SPELL_FIREBALL = 37329, SPELL_MIND_FLAY = 37330, @@ -43,14 +45,16 @@ enum SPELL_PLAGUE_STRIKE = 58339 }; -struct MANGOS_DLL_DECL mob_stolen_soulAI : public ScriptedAI +struct mob_stolen_soulAI : public ScriptedAI { mob_stolen_soulAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint8 m_uiStolenClass; uint32 m_uiSpellTimer; - void Reset() + ObjectGuid m_targetGuid; + + void Reset() override { m_uiSpellTimer = 1000; } @@ -58,11 +62,17 @@ struct MANGOS_DLL_DECL mob_stolen_soulAI : public ScriptedAI void SetSoulInfo(Unit* pTarget) { m_uiStolenClass = pTarget->getClass(); + m_targetGuid = pTarget->GetObjectGuid(); m_creature->SetDisplayId(pTarget->GetDisplayId()); + } + void JustDied(Unit* /*pKiller*/) override + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_targetGuid)) + DoCastSpellIfCan(pTarget, SPELL_STOLEN_SOUL_DISPEL, CAST_TRIGGERED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -148,7 +158,7 @@ enum NPC_DORE = 19412 }; -struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI +struct boss_exarch_maladaarAI : public ScriptedAI { boss_exarch_maladaarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -165,20 +175,20 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI bool m_bHasTaunted; bool m_bHasSummonedAvatar; - void Reset() + void Reset() override { m_targetGuid.Clear(); - m_uiFearTimer = urand(15000, 20000); - m_uiRibbonOfSoulsTimer = 5000; - m_uiStolenSoulTimer = urand(25000, 35000); + m_uiFearTimer = urand(11000, 29000); + m_uiRibbonOfSoulsTimer = urand(4000, 8000); + m_uiStolenSoulTimer = urand(19000, 31000); m_bHasSummonedAvatar = false; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 150.0)) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 150.0f) && m_creature->IsWithinLOSInMap(pWho)) { DoScriptText(SAY_INTRO, m_creature); m_bHasTaunted = true; @@ -187,9 +197,9 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -197,26 +207,24 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_STOLEN_SOUL) { - //SPELL_STOLEN_SOUL_VISUAL has shapeshift effect, but not implemented feature in mangos for this spell. + // SPELL_STOLEN_SOUL_VISUAL has shapeshift effect, but not implemented feature in mangos for this spell. pSummoned->CastSpell(pSummoned, SPELL_STOLEN_SOUL_VISUAL, false); - pSummoned->setFaction(m_creature->getFaction()); if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_targetGuid)) { if (mob_stolen_soulAI* pSoulAI = dynamic_cast(pSummoned->AI())) - { pSoulAI->SetSoulInfo(pTarget); - pSoulAI->AttackStart(pTarget); - } + + pSummoned->AI()->AttackStart(pTarget); } } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -224,7 +232,7 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -232,35 +240,40 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI DoSpawnCreature(NPC_DORE, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 600000); } - void UpdateAI(const uint32 uiDiff) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_STOLEN_SOUL && pTarget->GetTypeId() == TYPEID_PLAYER) + DoSpawnCreature(NPC_STOLEN_SOUL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 10000); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!m_bHasSummonedAvatar && m_creature->GetHealthPercent() < 25.0f) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(true); - - DoScriptText(SAY_SUMMON, m_creature); - - DoCastSpellIfCan(m_creature, SPELL_SUMMON_AVATAR); - m_bHasSummonedAvatar = true; - m_uiStolenSoulTimer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_AVATAR) == CAST_OK) + { + DoScriptText(SAY_SUMMON, m_creature); + m_bHasSummonedAvatar = true; + m_uiStolenSoulTimer = urand(15000, 30000); + } } if (m_uiStolenSoulTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_STOLEN_SOUL, SELECT_FLAG_PLAYER)) { - DoScriptText(urand(0, 1) ? SAY_ROAR : SAY_SOUL_CLEAVE, m_creature); - - m_targetGuid = pTarget->GetObjectGuid(); + if (DoCastSpellIfCan(pTarget, SPELL_STOLEN_SOUL) == CAST_OK) + { + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_ROAR : SAY_SOUL_CLEAVE, m_creature); - DoCastSpellIfCan(pTarget, SPELL_STOLEN_SOUL, CAST_INTERRUPT_PREVIOUS); - DoSpawnCreature(NPC_STOLEN_SOUL, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); + m_targetGuid = pTarget->GetObjectGuid(); - m_uiStolenSoulTimer = urand(20000, 30000); + m_uiStolenSoulTimer = urand(35000, 67000); + } } } else @@ -269,17 +282,18 @@ struct MANGOS_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI if (m_uiRibbonOfSoulsTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_RIBBON_OF_SOULS); - - m_uiRibbonOfSoulsTimer = urand(5000, 25000); + { + if (DoCastSpellIfCan(pTarget, SPELL_RIBBON_OF_SOULS) == CAST_OK) + m_uiRibbonOfSoulsTimer = urand(4000, 18000); + } } else m_uiRibbonOfSoulsTimer -= uiDiff; if (m_uiFearTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SOUL_SCREAM); - m_uiFearTimer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_SOUL_SCREAM) == CAST_OK) + m_uiFearTimer = urand(13000, 30000); } else m_uiFearTimer -= uiDiff; @@ -293,45 +307,6 @@ CreatureAI* GetAI_boss_exarch_maladaar(Creature* pCreature) return new boss_exarch_maladaarAI(pCreature); } -enum -{ - SPELL_AV_MORTAL_STRIKE = 16856, - SPELL_AV_SUNDER_ARMOR = 16145 -}; - -struct MANGOS_DLL_DECL mob_avatar_of_martyredAI : public ScriptedAI -{ - mob_avatar_of_martyredAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() - { - m_uiMortalStrikeTimer = 10000; - } - - uint32 m_uiMortalStrikeTimer; - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiMortalStrikeTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_AV_MORTAL_STRIKE); - m_uiMortalStrikeTimer = urand(10000, 30000); - } - else - m_uiMortalStrikeTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_avatar_of_martyred(Creature* pCreature) -{ - return new mob_avatar_of_martyredAI(pCreature); -} - void AddSC_boss_exarch_maladaar() { Script* pNewScript; @@ -341,11 +316,6 @@ void AddSC_boss_exarch_maladaar() pNewScript->GetAI = &GetAI_boss_exarch_maladaar; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "mob_avatar_of_martyred"; - pNewScript->GetAI = &GetAI_mob_avatar_of_martyred; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "mob_stolen_soul"; pNewScript->GetAI = &GetAI_mob_stolen_soul; diff --git a/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp b/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp index 5f0fd6f68..b8d5ed918 100644 --- a/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp +++ b/scripts/outland/auchindoun/auchenai_crypts/boss_shirrak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_shirrak -SD%Complete: 90 -SDComment: Timers may need small adjustments +SD%Complete: 100 +SDComment: SDCategory: Auchindoun, Auchenai Crypts EndScriptData */ @@ -36,7 +36,7 @@ enum NPC_FOCUS_FIRE = 18374 }; -struct MANGOS_DLL_DECL boss_shirrakAI : public ScriptedAI +struct boss_shirrakAI : public ScriptedAI { boss_shirrakAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -54,24 +54,24 @@ struct MANGOS_DLL_DECL boss_shirrakAI : public ScriptedAI ObjectGuid m_focusTargetGuid; - void Reset() + void Reset() override { - m_uiCarnivorousBiteTimer = 10000; + m_uiCarnivorousBiteTimer = urand(4000, 7000); m_uiFocusFireTimer = 15000; - m_uiAttractMagicTimer = 25000; + m_uiAttractMagicTimer = urand(20000, 24000); m_uiFocusFireCount = 0; DoCastSpellIfCan(m_creature, SPELL_INHIBIT_MAGIC); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // The focus fire creature casts the focus fire visual if (pSummoned->GetEntry() == NPC_FOCUS_FIRE) pSummoned->CastSpell(pSummoned, SPELL_FOCUS_TARGET_VISUAL, true); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -79,7 +79,7 @@ struct MANGOS_DLL_DECL boss_shirrakAI : public ScriptedAI if (m_uiCarnivorousBiteTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_CARNIVOROUS_BITE : SPELL_CARNIVOROUS_BITE_H) == CAST_OK) - m_uiCarnivorousBiteTimer = urand(8000, 12000); + m_uiCarnivorousBiteTimer = urand(4000, 10000); } else m_uiCarnivorousBiteTimer -= uiDiff; @@ -87,7 +87,7 @@ struct MANGOS_DLL_DECL boss_shirrakAI : public ScriptedAI if (m_uiAttractMagicTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_ATTRACT_MAGIC) == CAST_OK) - m_uiAttractMagicTimer = urand(20000, 25000); + m_uiAttractMagicTimer = urand(25000, 38000); } else m_uiAttractMagicTimer -= uiDiff; diff --git a/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp b/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp index 23dbc68bc..2eebfcfde 100644 --- a/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp +++ b/scripts/outland/auchindoun/mana_tombs/boss_nexusprince_shaffar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_NexusPrince_Shaffar -SD%Complete: 80 -SDComment: Need more tuning of spell timers, it should not be as linear fight as current. Also should possibly find a better way to deal with his three initial beacons to make sure all aggro. +SD%Complete: 100 +SDComment: ToDo: move the Ethereal Beacon script to eventAI SDCategory: Auchindoun, Mana Tombs EndScriptData */ @@ -44,13 +44,11 @@ enum SPELL_FIREBALL = 32363, SPELL_FROSTNOVA = 32365, - SPELL_ETHEREAL_BEACON = 32371, // Summons NPC_BEACON - SPELL_ETHEREAL_BEACON_VISUAL = 32368, - - NPC_BEACON = 18431 + SPELL_ETHEREAL_BEACON = 32371, // Summons 18431 + // SPELL_ETHEREAL_BEACON_VISUAL = 32368, // included in creature_template_addon }; -struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI +struct boss_nexusprince_shaffarAI : public ScriptedAI { boss_nexusprince_shaffarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -66,18 +64,18 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI bool m_bHasTaunted; - void Reset() + void Reset() override { m_uiBlinkTimer = 30000; - m_uiBeaconTimer = 10000; - m_uiFireBallTimer = 8000; - m_uiFrostboltTimer = 4000; - m_uiFrostNovaTimer = 15000; + m_uiBeaconTimer = urand(12000, 15000); + m_uiFireBallTimer = urand(2000, 12000); + m_uiFrostboltTimer = urand(1000, 14000); + m_uiFrostNovaTimer = urand(18000, 25000); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 100.0f)) + if (!m_bHasTaunted && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 100.0f) && m_creature->IsWithinLOSInMap(pWho)) { DoScriptText(SAY_INTRO, m_creature); m_bHasTaunted = true; @@ -86,9 +84,9 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -96,28 +94,23 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (pSummoned->GetEntry() == NPC_BEACON) - { - pSummoned->CastSpell(pSummoned, SPELL_ETHEREAL_BEACON_VISUAL, false); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - pSummoned->AI()->AttackStart(pTarget); - } + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEAD, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -125,7 +118,7 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI if (m_uiFrostNovaTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_FROSTNOVA) == CAST_OK) - m_uiFrostNovaTimer = urand(17500, 25000); + m_uiFrostNovaTimer = urand(10000, 20000); } else m_uiFrostNovaTimer -= uiDiff; @@ -133,7 +126,7 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI if (m_uiFrostboltTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROSTBOLT) == CAST_OK) - m_uiFrostboltTimer = urand(4500, 6000); + m_uiFrostboltTimer = urand(3000, 8000); } else m_uiFrostboltTimer -= uiDiff; @@ -141,7 +134,7 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI if (m_uiFireBallTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL) == CAST_OK) - m_uiFireBallTimer = urand(4500, 6000); + m_uiFireBallTimer = urand(3000, 8000); } else m_uiFireBallTimer -= uiDiff; @@ -150,7 +143,7 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_BLINK) == CAST_OK) { - //expire movement, will prevent from running right back to victim after cast + // 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 (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) m_creature->GetMotionMaster()->MovementExpired(); @@ -165,10 +158,10 @@ struct MANGOS_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_ETHEREAL_BEACON) == CAST_OK) { - if (!urand(0,3)) + if (!urand(0, 3)) DoScriptText(SAY_SUMMON, m_creature); - m_uiBeaconTimer = 10000; + m_uiBeaconTimer = urand(45000, 75000); } } else @@ -183,75 +176,6 @@ CreatureAI* GetAI_boss_nexusprince_shaffar(Creature* pCreature) return new boss_nexusprince_shaffarAI(pCreature); } -enum -{ - SPELL_ARCANE_BOLT = 15254, - SPELL_ETHEREAL_APPRENTICE = 32372 // Summon 18430 -}; - -struct MANGOS_DLL_DECL mob_ethereal_beaconAI : public ScriptedAI -{ - mob_ethereal_beaconAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - - uint32 m_uiApprenticeTimer; - uint32 m_uiArcaneBoltTimer; - - void Reset() - { - m_uiApprenticeTimer = m_bIsRegularMode ? 20000 : 10000; - m_uiArcaneBoltTimer = 1000; - } - - void JustSummoned(Creature* pSummoned) - { - if (m_creature->getVictim()) - pSummoned->AI()->AttackStart(m_creature->getVictim()); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiArcaneBoltTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BOLT); - m_uiArcaneBoltTimer = urand(2000, 4500); - } - else - m_uiArcaneBoltTimer -= uiDiff; - - if (m_uiApprenticeTimer) - { - if (m_uiApprenticeTimer <= uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_ETHEREAL_APPRENTICE) == CAST_OK) - { - // despawn in 2 sec because of the spell visual - m_creature->ForcedDespawn(2000); - m_uiApprenticeTimer = 0; - } - } - else - m_uiApprenticeTimer -= uiDiff; - } - - //should they do meele? - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_ethereal_beacon(Creature* pCreature) -{ - return new mob_ethereal_beaconAI(pCreature); -} - void AddSC_boss_nexusprince_shaffar() { Script* pNewScript; @@ -260,9 +184,4 @@ void AddSC_boss_nexusprince_shaffar() pNewScript->Name = "boss_nexusprince_shaffar"; pNewScript->GetAI = &GetAI_boss_nexusprince_shaffar; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_ethereal_beacon"; - pNewScript->GetAI = &GetAI_mob_ethereal_beacon; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp b/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp index 1ee196ef8..5e8a27471 100644 --- a/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp +++ b/scripts/outland/auchindoun/mana_tombs/boss_pandemonius.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Pandemonius -SD%Complete: 75 -SDComment: Not known how void blast is done (amount of rapid cast seems to be related to players in party). All mobs remaining in surrounding area should aggro when engaged. +SD%Complete: 80 +SDComment: Not known how void blast is done (amount of rapid cast seems to be related to players in party). SDCategory: Auchindoun, Mana Tombs EndScriptData */ @@ -41,7 +41,7 @@ enum MAX_VOID_BLASTS = 5, }; -struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI +struct boss_pandemoniusAI : public ScriptedAI { boss_pandemoniusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -55,26 +55,26 @@ struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI uint32 m_uiDarkShellTimer; uint8 m_uiVoidBlastCounter; - void Reset() + void Reset() override { - m_uiVoidBlastTimer = urand(8000, 23000); - m_uiDarkShellTimer = 20000; + m_uiVoidBlastTimer = urand(15000, 20000); + m_uiDarkShellTimer = 15000; m_uiVoidBlastCounter = 0; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -82,7 +82,7 @@ struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -95,7 +95,7 @@ struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI // reset timer and counter when counter has reached the max limit if (m_uiVoidBlastCounter == MAX_VOID_BLASTS) { - m_uiVoidBlastTimer = urand(15000, 25000); + m_uiVoidBlastTimer = urand(25000, 30000); m_uiVoidBlastCounter = 0; } // cast the void blasts in a row until we reach the max limit @@ -116,7 +116,7 @@ struct MANGOS_DLL_DECL boss_pandemoniusAI : public ScriptedAI if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_DARK_SHELL : SPELL_DARK_SHELL_H) == CAST_OK) { DoScriptText(EMOTE_DARK_SHELL, m_creature); - m_uiDarkShellTimer = 20000; + m_uiDarkShellTimer = urand(25000, 30000); } } else diff --git a/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp b/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp index 83298feee..9c56767cc 100644 --- a/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp +++ b/scripts/outland/auchindoun/sethekk_halls/boss_anzu.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,221 @@ /* ScriptData SDName: boss_anzu -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 70 +SDComment: Intro event NYI. SDCategory: Auchindoun, Sethekk Halls EndScriptData */ #include "precompiled.h" +#include "sethekk_halls.h" + +enum +{ + SAY_BANISH = -1556018, + SAY_WHISPER_MAGIC_1 = -1556019, + SAY_WHISPER_MAGIC_2 = -1556021, + SAY_WHISPER_MAGIC_3 = -1556022, + EMOTE_BIRD_STONE = -1556020, + + SPELL_FLESH_RIP = 40199, + SPELL_SCREECH = 40184, + SPELL_SPELL_BOMB = 40303, + SPELL_CYCLONE = 40321, + SPELL_BANISH_SELF = 42354, + + NPC_BROOD_OF_ANZU = 23132, + + // Helper birds + NPC_HAWK_SPIRIT = 23134, // casts 40237 + NPC_FALCON_SPIRIT = 23135, // casts 40241 + NPC_EAGLE_SPIRIT = 23136, // casts 40240 + + MAX_BROODS = 5, +}; + +static const uint32 aSpiritsEntries[3] = {NPC_FALCON_SPIRIT, NPC_HAWK_SPIRIT, NPC_EAGLE_SPIRIT}; + +struct boss_anzuAI : public ScriptedAI +{ + boss_anzuAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_sethekk_halls*)pCreature->GetInstanceData(); + Reset(); + } + + instance_sethekk_halls* m_pInstance; + + uint32 m_uiFleshRipTimer; + uint32 m_uiScreechTimer; + uint32 m_uiSpellBombTimer; + uint32 m_uiCycloneTimer; + float m_fHealthCheck; + + GuidList m_lBirdsGuidList; + + void Reset() override + { + m_uiFleshRipTimer = urand(9000, 10000); + m_uiScreechTimer = 23000; + m_uiSpellBombTimer = 17000; + m_uiCycloneTimer = 5000; + m_fHealthCheck = 75.0f; + } + + void Aggro(Unit* /*pWho*/) override + { + // Note: this should be moved to the intro event when implemented! + DoSummonBirdHelpers(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ANZU, IN_PROGRESS); + } + + void JustDied(Unit* /*pKiller*/) override + { + DespawnBirdHelpers(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ANZU, DONE); + } + + void JustReachedHome() override + { + DespawnBirdHelpers(); + m_creature->ForcedDespawn(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ANZU, FAIL); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_BROOD_OF_ANZU) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + else + { + DoScriptText(EMOTE_BIRD_STONE, pSummoned); + m_lBirdsGuidList.push_back(pSummoned->GetObjectGuid()); + } + } + + void DoSummonBroodsOfAnzu() + { + if (!m_pInstance) + return; + + // Note: the birds should fly around the room for about 10 seconds before starting to attack the players + if (GameObject* pClaw = m_pInstance->GetSingleGameObjectFromStorage(GO_RAVENS_CLAW)) + { + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_BROODS; ++i) + { + m_creature->GetRandomPoint(pClaw->GetPositionX(), pClaw->GetPositionY(), pClaw->GetPositionZ(), 7.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_BROOD_OF_ANZU, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + } + } + } + + void DoSummonBirdHelpers() + { + float fX, fY, fZ, fAng; + for (uint8 i = 0; i < 3; ++i) + { + fAng = 2 * M_PI_F / 3 * i; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 15.0f, fAng); + m_creature->SummonCreature(aSpiritsEntries[i], fX, fY, fZ, fAng + M_PI_F, TEMPSUMMON_CORPSE_DESPAWN, 0); + } + } + + void DespawnBirdHelpers() + { + for (GuidList::const_iterator itr = m_lBirdsGuidList.begin(); itr != m_lBirdsGuidList.end(); ++itr) + { + if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) + pTemp->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + // Banish at 66% and 33%; Boss can still use spells while banished + if (m_creature->GetHealthPercent() < m_fHealthCheck) + { + if (DoCastSpellIfCan(m_creature, SPELL_BANISH_SELF) == CAST_OK) + { + DoScriptText(SAY_BANISH, m_creature); + DoSummonBroodsOfAnzu(); + m_fHealthCheck -= 40.0f; + } + } + + if (m_uiFleshRipTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLESH_RIP) == CAST_OK) + m_uiFleshRipTimer = urand(10000, 20000); + } + else + m_uiFleshRipTimer -= uiDiff; + + if (m_uiScreechTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SCREECH) == CAST_OK) + m_uiScreechTimer = urand(31000, 35000); + } + else + m_uiScreechTimer -= uiDiff; + + if (m_uiSpellBombTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SPELL_BOMB) == CAST_OK) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_WHISPER_MAGIC_1, m_creature, pTarget); break; + case 1: DoScriptText(SAY_WHISPER_MAGIC_2, m_creature, pTarget); break; + case 2: DoScriptText(SAY_WHISPER_MAGIC_3, m_creature, pTarget); break; + } + m_uiSpellBombTimer = urand(24000, 40000); + } + } + } + else + m_uiSpellBombTimer -= uiDiff; + + if (m_uiCycloneTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CYCLONE) == CAST_OK) + m_uiCycloneTimer = 21000; + } + } + else + m_uiCycloneTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_anzu(Creature* pCreature) +{ + return new boss_anzuAI(pCreature); +} void AddSC_boss_anzu() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_anzu"; + pNewScript->GetAI = &GetAI_boss_anzu; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp b/scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp index 8f6a72d0b..0569046c1 100644 --- a/scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp +++ b/scripts/outland/auchindoun/sethekk_halls/boss_darkweaver_syth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Darkweaver_Syth -SD%Complete: 85 -SDComment: Shock spells/times need more work. +SD%Complete: 100 +SDComment: SDCategory: Auchindoun, Sethekk Halls EndScriptData */ @@ -33,13 +33,17 @@ enum SAY_SLAY_2 = -1556005, SAY_DEATH = -1556006, - // TODO Heroic spells (shock, chain lightning) missing, unknown if IDs are correct - SPELL_FROST_SHOCK = 37865, - SPELL_FLAME_SHOCK = 34354, - SPELL_SHADOW_SHOCK = 30138, - SPELL_ARCANE_SHOCK = 37132, + SPELL_FROST_SHOCK = 12548, + SPELL_FROST_SHOCK_H = 21401, + SPELL_FLAME_SHOCK = 15039, + SPELL_FLAME_SHOCK_H = 15616, + SPELL_SHADOW_SHOCK = 33620, + SPELL_SHADOW_SHOCK_H = 38136, + SPELL_ARCANE_SHOCK = 33534, + SPELL_ARCANE_SHOCK_H = 38135, - SPELL_CHAIN_LIGHTNING = 39945, + SPELL_CHAIN_LIGHTNING = 15659, + SPELL_CHAIN_LIGHTNING_H = 15305, SPELL_SUMMON_SYTH_FIRE = 33537, // Spawns 19203 SPELL_SUMMON_SYTH_ARCANE = 33538, // Spawns 19205 @@ -51,18 +55,9 @@ enum NPC_FROST_ELEMENTAL = 19204, NPC_ARCANE_ELEMENTAL = 19205, NPC_SHADOW_ELEMENTAL = 19206, - - SPELL_FLAME_BUFFET = 33526, - SPELL_FLAME_BUFFET_H = 38141, - SPELL_ARCANE_BUFFET = 33527, - SPELL_ARCANE_BUFFET_H = 38138, - SPELL_FROST_BUFFET = 33528, - SPELL_FROST_BUFFET_H = 38142, - SPELL_SHADOW_BUFFET = 33529, - SPELL_SHADOW_BUFFET_H = 38143, }; -struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI +struct boss_darkweaver_sythAI : public ScriptedAI { boss_darkweaver_sythAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -79,20 +74,20 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI float m_fHpCheck; - void Reset() + void Reset() override { - m_uiFlameshockTimer = 2000; - m_uiArcaneshockTimer = 4000; - m_uiFrostshockTimer = 6000; - m_uiShadowshockTimer = 8000; - m_uiChainlightningTimer = 15000; + m_uiFlameshockTimer = 18000; + m_uiArcaneshockTimer = 19000; + m_uiFrostshockTimer = 18000; + m_uiShadowshockTimer = 17000; + m_uiChainlightningTimer = urand(6000, 9000); m_fHpCheck = 90.0f; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -100,12 +95,12 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -113,7 +108,7 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -143,13 +138,13 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI if (m_creature->IsNonMeleeSpellCasted(false)) m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_ARCANE, CAST_TRIGGERED); //front - DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_FIRE, CAST_TRIGGERED); //back - DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_FROST, CAST_TRIGGERED); //left - DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_SHADOW, CAST_TRIGGERED); //right + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_ARCANE, CAST_TRIGGERED); // front + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_FIRE, CAST_TRIGGERED); // back + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_FROST, CAST_TRIGGERED); // left + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SYTH_SHADOW, CAST_TRIGGERED); // right } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -165,8 +160,8 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pTarget, SPELL_FLAME_SHOCK) == CAST_OK) - m_uiFlameshockTimer = urand(10000, 15000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FLAME_SHOCK : SPELL_FLAME_SHOCK_H) == CAST_OK) + m_uiFlameshockTimer = m_bIsRegularMode ? urand(13000, 28000) : urand(11000, 20000); } } else @@ -176,8 +171,8 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pTarget, SPELL_ARCANE_SHOCK) == CAST_OK) - m_uiArcaneshockTimer = urand(10000, 15000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_ARCANE_SHOCK : SPELL_ARCANE_SHOCK_H) == CAST_OK) + m_uiArcaneshockTimer = m_bIsRegularMode ? urand(13000, 28000) : urand(11000, 20000); } } else @@ -187,8 +182,8 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pTarget, SPELL_FROST_SHOCK) == CAST_OK) - m_uiFrostshockTimer = urand(10000, 15000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FROST_SHOCK : SPELL_FROST_SHOCK_H) == CAST_OK) + m_uiFrostshockTimer = m_bIsRegularMode ? urand(13000, 28000) : urand(11000, 20000); } } else @@ -198,8 +193,8 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_SHOCK) == CAST_OK) - m_uiShadowshockTimer = urand(10000, 15000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_SHADOW_SHOCK : SPELL_SHADOW_SHOCK_H) == CAST_OK) + m_uiShadowshockTimer = m_bIsRegularMode ? urand(13000, 28000) : urand(11000, 20000); } } else @@ -209,8 +204,8 @@ struct MANGOS_DLL_DECL boss_darkweaver_sythAI : public ScriptedAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pTarget, SPELL_CHAIN_LIGHTNING) == CAST_OK) - m_uiChainlightningTimer = 25000; + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_CHAIN_LIGHTNING : SPELL_CHAIN_LIGHTNING_H) == CAST_OK) + m_uiChainlightningTimer = m_bIsRegularMode ? urand(14000, 26000) : urand(13000, 19000); } } else @@ -225,201 +220,6 @@ CreatureAI* GetAI_boss_darkweaver_syth(Creature* pCreature) return new boss_darkweaver_sythAI(pCreature); } -/* ELEMENTALS */ - -struct MANGOS_DLL_DECL mob_syth_fireAI : public ScriptedAI -{ - mob_syth_fireAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - uint32 flameshock_timer; - uint32 flamebuffet_timer; - - void Reset() - { - flameshock_timer = 2500; - flamebuffet_timer = 5000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (flameshock_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_FLAME_SHOCK); - - flameshock_timer = 5000; - }else flameshock_timer -= diff; - - if (flamebuffet_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_FLAME_BUFFET : SPELL_FLAME_BUFFET_H); - - flamebuffet_timer = 5000; - - }else flamebuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_fire(Creature* pCreature) -{ - return new mob_syth_fireAI(pCreature); -} - -struct MANGOS_DLL_DECL mob_syth_arcaneAI : public ScriptedAI -{ - mob_syth_arcaneAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - uint32 arcaneshock_timer; - uint32 arcanebuffet_timer; - - void Reset() - { - arcaneshock_timer = 2500; - arcanebuffet_timer = 5000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (arcaneshock_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_ARCANE_SHOCK); - - arcaneshock_timer = 5000; - }else arcaneshock_timer -= diff; - - if (arcanebuffet_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_ARCANE_BUFFET : SPELL_ARCANE_BUFFET_H); - - arcanebuffet_timer = 5000; - }else arcanebuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_arcane(Creature* pCreature) -{ - return new mob_syth_arcaneAI(pCreature); -} - -struct MANGOS_DLL_DECL mob_syth_frostAI : public ScriptedAI -{ - mob_syth_frostAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - uint32 frostshock_timer; - uint32 frostbuffet_timer; - - void Reset() - { - frostshock_timer = 2500; - frostbuffet_timer = 5000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (frostshock_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_FROST_SHOCK); - - frostshock_timer = 5000; - }else frostshock_timer -= diff; - - if (frostbuffet_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_FROST_BUFFET : SPELL_FROST_BUFFET_H); - - frostbuffet_timer = 5000; - }else frostbuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_frost(Creature* pCreature) -{ - return new mob_syth_frostAI(pCreature); -} - -struct MANGOS_DLL_DECL mob_syth_shadowAI : public ScriptedAI -{ - mob_syth_shadowAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - uint32 shadowshock_timer; - uint32 shadowbuffet_timer; - - void Reset() - { - shadowshock_timer = 2500; - shadowbuffet_timer = 5000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (shadowshock_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, SPELL_SHADOW_SHOCK); - - shadowshock_timer = 5000; - }else shadowshock_timer -= diff; - - if (shadowbuffet_timer < diff) - { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(target, m_bIsRegularMode ? SPELL_SHADOW_BUFFET : SPELL_SHADOW_BUFFET_H); - - shadowbuffet_timer = 5000; - }else shadowbuffet_timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_syth_shadow(Creature* pCreature) -{ - return new mob_syth_shadowAI(pCreature); -} - void AddSC_boss_darkweaver_syth() { Script* pNewScript; @@ -428,24 +228,4 @@ void AddSC_boss_darkweaver_syth() pNewScript->Name = "boss_darkweaver_syth"; pNewScript->GetAI = &GetAI_boss_darkweaver_syth; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_syth_fire"; - pNewScript->GetAI = &GetAI_mob_syth_fire; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_syth_arcane"; - pNewScript->GetAI = &GetAI_mob_syth_arcane; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_syth_frost"; - pNewScript->GetAI = &GetAI_mob_syth_frost; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_syth_shadow"; - pNewScript->GetAI = &GetAI_mob_syth_shadow; - pNewScript->RegisterSelf(); -} \ No newline at end of file +} diff --git a/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp b/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp index 9f50518df..649ecd8e0 100644 --- a/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp +++ b/scripts/outland/auchindoun/sethekk_halls/boss_talon_king_ikiss.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,7 +50,7 @@ enum SPELL_ARCANE_EXPLOSION_H = 40425, }; -struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI +struct boss_talon_king_ikissAI : public ScriptedAI { boss_talon_king_ikissAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -65,25 +65,27 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI uint32 m_uiArcaneVolleyTimer; uint32 m_uiSheepTimer; - uint32 m_uiBlinkTimer; uint32 m_uiSlowTimer; + uint8 m_uiBlinkPhase; + float m_fHealthCheck; bool m_bManaShield; bool m_bBlink; bool m_bIntro; - void Reset() + void Reset() override { - m_uiArcaneVolleyTimer = 5000; + m_uiArcaneVolleyTimer = urand(5000, 12000); m_uiSheepTimer = 8000; - m_uiBlinkTimer = 35000; - m_uiSlowTimer = urand(15000, 30000); + m_uiSlowTimer = urand(9000, 13000); + m_uiBlinkPhase = 0; + m_fHealthCheck = 80.0f; m_bBlink = false; m_bManaShield = false; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_creature->getVictim() && pWho->isTargetableForAttack() && (m_creature->IsHostileTo(pWho)) && pWho->isInAccessablePlaceFor(m_creature)) { @@ -97,9 +99,9 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -110,7 +112,7 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI m_pInstance->SetData(TYPE_IKISS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -118,18 +120,18 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI m_pInstance->SetData(TYPE_IKISS, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_IKISS, FAIL); } - void KilledUnit(Unit* pVctim) + void KilledUnit(Unit* /*pVctim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -148,7 +150,7 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI if (m_uiArcaneVolleyTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY_H) == CAST_OK) - m_uiArcaneVolleyTimer = urand(7000, 12000); + m_uiArcaneVolleyTimer = urand(8000, 12000); } else m_uiArcaneVolleyTimer -= uiDiff; @@ -163,7 +165,7 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI else m_uiSheepTimer -= uiDiff; - if (!m_bManaShield && m_creature->GetHealthPercent() < 20.0f) + if (!m_bManaShield && m_creature->GetHealthPercent() < 15.0f) { if (DoCastSpellIfCan(m_creature, SPELL_MANA_SHIELD) == CAST_OK) m_bManaShield = true; @@ -174,24 +176,30 @@ struct MANGOS_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI if (m_uiSlowTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SLOW_H) == CAST_OK) - m_uiSlowTimer = urand(15000, 30000); + m_uiSlowTimer = urand(15000, 24000); } else m_uiSlowTimer -= uiDiff; } - if (m_uiBlinkTimer < uiDiff) + if (m_creature->GetHealthPercent() < m_fHealthCheck) { - DoScriptText(EMOTE_ARCANE_EXP, m_creature); - if (DoCastSpellIfCan(m_creature, SPELL_BLINK, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { m_bBlink = true; - m_uiBlinkTimer = urand(35000, 40000); + DoScriptText(EMOTE_ARCANE_EXP, m_creature); + + // There is no relationship between the health percentages + switch (m_uiBlinkPhase) + { + case 0: m_fHealthCheck = 50.0f; break; + case 1: m_fHealthCheck = 25.0f; break; + case 2: m_fHealthCheck = 0.0f; break; + } + + ++m_uiBlinkPhase; } } - else - m_uiBlinkTimer -= uiDiff; if (!m_bBlink) DoMeleeAttackIfReady(); diff --git a/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp b/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp index 05e43c163..dcf68190a 100644 --- a/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp +++ b/scripts/outland/auchindoun/sethekk_halls/instance_sethekk_halls.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Instance - Sethekk Halls -SD%Complete: 50 -SDComment: Instance Data for Sethekk Halls instance +SD%Complete: 60 +SDComment: Summoning event for Anzu NYI SDCategory: Auchindoun, Sethekk Halls EndScriptData */ @@ -33,6 +33,12 @@ void instance_sethekk_halls::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_sethekk_halls::OnCreatureCreate(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_ANZU) + m_mNpcEntryGuidStore[NPC_ANZU] = pCreature->GetObjectGuid(); +} + void instance_sethekk_halls::OnObjectCreate(GameObject* pGo) { switch (pGo->GetEntry()) @@ -45,6 +51,8 @@ void instance_sethekk_halls::OnObjectCreate(GameObject* pGo) if (m_auiEncounter[TYPE_IKISS] == DONE) pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT | GO_FLAG_INTERACT_COND); break; + case GO_RAVENS_CLAW: + break; default: return; @@ -55,11 +63,19 @@ void instance_sethekk_halls::OnObjectCreate(GameObject* pGo) void instance_sethekk_halls::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_SYTH: + m_auiEncounter[uiType] = uiData; + break; case TYPE_ANZU: m_auiEncounter[uiType] = uiData; + // Respawn the Raven's Claw if event fails + if (uiData == FAIL) + { + if (GameObject* pClaw = GetSingleGameObjectFromStorage(GO_RAVENS_CLAW)) + pClaw->Respawn(); + } break; case TYPE_IKISS: if (uiData == DONE) @@ -87,7 +103,7 @@ void instance_sethekk_halls::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_sethekk_halls::GetData(uint32 uiType) +uint32 instance_sethekk_halls::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -108,7 +124,7 @@ void instance_sethekk_halls::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -117,7 +133,7 @@ void instance_sethekk_halls::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -bool instance_sethekk_halls::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) +bool instance_sethekk_halls::CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* /*pTarget*/, uint32 /*uiMiscValue1 = 0*/) const { if (uiCriteriaId != ACHIEV_CRITA_TURKEY_TIME) return false; @@ -134,6 +150,26 @@ InstanceData* GetInstanceData_instance_sethekk_halls(Map* pMap) return new instance_sethekk_halls(pMap); } +bool ProcessEventId_event_spell_summon_raven_god(uint32 /*uiEventId*/, Object* pSource, Object* /*pTarget*/, bool bIsStart) +{ + if (bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) + { + if (instance_sethekk_halls* pInstance = (instance_sethekk_halls*)((Player*)pSource)->GetInstanceData()) + { + // This should be checked by despawning the Raven Claw Go; However it's better to double check the condition + if (pInstance->GetData(TYPE_ANZU) == DONE || pInstance->GetData(TYPE_ANZU) == IN_PROGRESS) + return true; + + // Don't summon him twice + if (pInstance->GetSingleCreatureFromStorage(NPC_ANZU, true)) + return true; + + // ToDo: add more code here to handle the summoning event. For the moment it's handled in DB because of the missing info + } + } + return false; +} + void AddSC_instance_sethekk_halls() { Script* pNewScript; @@ -142,4 +178,9 @@ void AddSC_instance_sethekk_halls() pNewScript->Name = "instance_sethekk_halls"; pNewScript->GetInstanceData = &GetInstanceData_instance_sethekk_halls; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "event_spell_summon_raven_god"; + pNewScript->pProcessEventId = &ProcessEventId_event_spell_summon_raven_god; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h b/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h index 6245bb11f..33476f2c5 100644 --- a/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h +++ b/scripts/outland/auchindoun/sethekk_halls/sethekk_halls.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -13,8 +13,20 @@ enum TYPE_ANZU = 1, TYPE_IKISS = 2, + NPC_ANZU = 23035, + NPC_RAVEN_GOD_TARGET = 23057, + GO_IKISS_DOOR = 177203, GO_IKISS_CHEST = 187372, + GO_RAVENS_CLAW = 185554, + + SAY_ANZU_INTRO_1 = -1556016, + SAY_ANZU_INTRO_2 = -1556017, + + // possible spells used for Anzu summoning event + SPELL_PORTAL = 39952, + SPELL_SUMMONING_BEAMS = 39978, + SPELL_RED_LIGHTNING = 39990, ACHIEV_CRITA_TURKEY_TIME = 11142, ITEM_PILGRIMS_HAT = 46723, @@ -23,22 +35,24 @@ enum ITEM_PILGRIMS_ATTIRE = 46800, }; -class MANGOS_DLL_DECL instance_sethekk_halls : public ScriptedInstance +class instance_sethekk_halls : public ScriptedInstance { public: instance_sethekk_halls(Map* pMap); ~instance_sethekk_halls() {} - void Initialize(); - void OnObjectCreate(GameObject* pGo); + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/); + bool CheckAchievementCriteriaMeet(uint32 uiCriteriaId, Player const* pSource, Unit const* pTarget, uint32 uiMiscValue1 /* = 0*/) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp index cb5e1da22..8f9fb2613 100644 --- a/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp +++ b/scripts/outland/auchindoun/shadow_labyrinth/boss_ambassador_hellmaw.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,46 +39,42 @@ enum SPELL_ENRAGE = 34970 }; -struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI +struct boss_ambassador_hellmawAI : public ScriptedAI { boss_ambassador_hellmawAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_shadow_labyrinth*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); - - if (m_pInstance && m_creature->isAlive()) - { - if (m_pInstance->GetData(TYPE_OVERSEER) != DONE) - DoCastSpellIfCan(m_creature, SPELL_BANISH, CAST_TRIGGERED); - } } - ScriptedInstance* m_pInstance; + instance_shadow_labyrinth* m_pInstance; bool m_bIsRegularMode; + uint32 m_uiBanishTimer; uint32 m_uiCorrosiveAcidTimer; uint32 m_uiFearTimer; uint32 m_uiEnrageTimer; bool m_bIsEnraged; - void Reset() + void Reset() override { - m_uiCorrosiveAcidTimer = urand(5000, 10000); - m_uiFearTimer = urand(25000, 30000); - m_uiEnrageTimer = 3*MINUTE*IN_MILLISECONDS; + m_uiBanishTimer = 2000; + m_uiCorrosiveAcidTimer = urand(20000, 23000); + m_uiFearTimer = urand(20000, 26000); + m_uiEnrageTimer = 3 * MINUTE * IN_MILLISECONDS; m_bIsEnraged = false; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_HELLMAW, FAIL); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -89,12 +85,12 @@ struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI m_pInstance->SetData(TYPE_HELLMAW, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -102,15 +98,34 @@ struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI m_pInstance->SetData(TYPE_HELLMAW, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { + if (m_uiBanishTimer) + { + if (m_uiBanishTimer <= uiDiff) + { + if (!m_pInstance) + return; + + // Check for banish + if (m_pInstance->IsHellmawUnbanished()) + { + m_creature->RemoveAurasDueToSpell(SPELL_BANISH); + m_creature->GetMotionMaster()->MoveWaypoint(); + m_uiBanishTimer = 0; + } + } + else + m_uiBanishTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiCorrosiveAcidTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_CORROSIVE_ACID) == CAST_OK) - m_uiCorrosiveAcidTimer = urand(15000, 25000); + m_uiCorrosiveAcidTimer = urand(23000, 35000); } else m_uiCorrosiveAcidTimer -= uiDiff; @@ -118,7 +133,7 @@ struct MANGOS_DLL_DECL boss_ambassador_hellmawAI : public ScriptedAI if (m_uiFearTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) - m_uiFearTimer = urand(20000, 35000); + m_uiFearTimer = urand(20000, 38000); } else m_uiFearTimer -= uiDiff; diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp index f1c2a779e..f4d78e231 100644 --- a/scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp +++ b/scripts/outland/auchindoun/shadow_labyrinth/boss_blackheart_the_inciter.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Blackheart_the_Inciter -SD%Complete: 60 -SDComment: Incite Chaos needs further research and core support +SD%Complete: 90 +SDComment: Not all yells are implemented. SDCategory: Auchindoun, Shadow Labyrinth EndScriptData */ @@ -26,7 +26,7 @@ EndScriptData */ enum { - SPELL_INCITE_CHAOS = 33676, // triggers 33684 on party members - needs core support + SPELL_INCITE_CHAOS = 33676, // triggers 33684 on party members SPELL_CHARGE = 33709, SPELL_WAR_STOMP = 33707, @@ -53,7 +53,7 @@ enum SAY2_DEATH = -1555027, }; -struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI +struct boss_blackheart_the_inciterAI : public ScriptedAI { boss_blackheart_the_inciterAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -64,22 +64,26 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI ScriptedInstance* m_pInstance; uint32 m_uiInciteChaosTimer; + uint32 m_uiInciteChaosWaitTimer; uint32 m_uiChargeTimer; uint32 m_uiKnockbackTimer; - void Reset() + GuidVector m_vTargetsGuids; + + void Reset() override { + m_uiInciteChaosWaitTimer = 0; m_uiInciteChaosTimer = 15000; - m_uiChargeTimer = 5000; - m_uiKnockbackTimer = 15000; + m_uiChargeTimer = urand(30000, 37000); + m_uiKnockbackTimer = urand(10000, 14000); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -87,9 +91,9 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI m_pInstance->SetData(TYPE_INCITER, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -100,34 +104,70 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI m_pInstance->SetData(TYPE_INCITER, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { - if (m_pInstance) m_pInstance->SetData(TYPE_INCITER, FAIL); } - void UpdateAI(const uint32 uiDiff) + void EnterEvadeMode() override { + // if we are waiting for Incite chaos to expire don't evade + if (m_uiInciteChaosWaitTimer) + return; + + ScriptedAI::EnterEvadeMode(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiInciteChaosWaitTimer) + { + if (m_uiInciteChaosWaitTimer <= uiDiff) + { + // Restart attack on all targets + for (GuidVector::const_iterator itr = m_vTargetsGuids.begin(); itr != m_vTargetsGuids.end(); ++itr) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit(*itr)) + AttackStart(pTarget); + } + + m_creature->HandleEmote(EMOTE_STATE_NONE); + m_uiInciteChaosWaitTimer = 0; + } + else + m_uiInciteChaosWaitTimer -= uiDiff; + } + // Return since we have no pTarget if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // ToDo: this needs future core and script support - /*if (m_uiInciteChaosTimer < uiDiff) + if (m_uiInciteChaosTimer < uiDiff) { + // Store the threat list + m_vTargetsGuids.clear(); + m_creature->FillGuidsListFromThreatList(m_vTargetsGuids); + if (DoCastSpellIfCan(m_creature, SPELL_INCITE_CHAOS) == CAST_OK) - m_uiInciteChaosTimer = 40000; + { + m_creature->HandleEmote(EMOTE_STATE_LAUGH); + m_uiInciteChaosTimer = 55000; + m_uiInciteChaosWaitTimer = 16000; + return; + } } else - m_uiInciteChaosTimer -= uiDiff;*/ + m_uiInciteChaosTimer -= uiDiff; // Charge Timer if (m_uiChargeTimer < uiDiff) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget && DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) - m_uiChargeTimer = urand(15000, 25000); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_CHARGE, SELECT_FLAG_NOT_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) + m_uiChargeTimer = urand(30000, 43000); + } } else m_uiChargeTimer -= uiDiff; @@ -136,7 +176,7 @@ struct MANGOS_DLL_DECL boss_blackheart_the_inciterAI : public ScriptedAI if (m_uiKnockbackTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP) == CAST_OK) - m_uiKnockbackTimer = urand(18000, 24000); + m_uiKnockbackTimer = urand(15000, 30000); } else m_uiKnockbackTimer -= uiDiff; diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp index d811598da..edf231953 100644 --- a/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp +++ b/scripts/outland/auchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -67,17 +67,17 @@ struct SummonLocations // Summon locations for the void portals static const SummonLocations aVorpilLocation[MAX_PORTALS] = { - {-262.40f, -229.57f, 17.08f}, - {-260.35f, -297.56f, 17.08f}, - {-292.05f, -270.37f, 12.68f}, - {-301.64f, -255.97f, 12.68f} + { -262.40f, -229.57f, 17.08f}, + { -260.35f, -297.56f, 17.08f}, + { -292.05f, -270.37f, 12.68f}, + { -301.64f, -255.97f, 12.68f} }; -static const float aVorpilTeleportLoc[3] = {-253.06f, -264.02f, 17.08f}; +static const float aVorpilTeleportLoc[3] = { -253.06f, -264.02f, 17.08f}; static const uint32 aTravelerSummonSpells[5] = {SPELL_SUMMON_VOIDWALKER_A, SPELL_SUMMON_VOIDWALKER_B, SPELL_SUMMON_VOIDWALKER_C, SPELL_SUMMON_VOIDWALKER_D, SPELL_SUMMON_VOIDWALKER_E}; -struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI +struct boss_grandmaster_vorpilAI : public ScriptedAI { boss_grandmaster_vorpilAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -97,19 +97,19 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI uint32 m_uiBanishTimer; bool m_bHasDoneIntro; - void Reset() + void Reset() override { - m_uiShadowBoltVolleyTimer = urand(7000, 14000); - m_uiDrawShadowsTimer = 40000; + m_uiShadowBoltVolleyTimer = urand(13000, 19000); + m_uiDrawShadowsTimer = urand(38000, 44000); m_uiRainOfFireTimer = 0; m_uiVoidTravelerTimer = 5000; - m_uiBanishTimer = 25000; + m_uiBanishTimer = urand(12000, 16000); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - //not sure about right radius - if (!m_bHasDoneIntro && pWho->IsWithinDistInMap(m_creature, 50.0f) && pWho->IsWithinLOSInMap(m_creature)) + // not sure about right radius + if (!m_bHasDoneIntro && pWho->GetTypeId() == TYPEID_PLAYER && pWho->IsWithinDistInMap(m_creature, 50.0f) && pWho->IsWithinLOSInMap(m_creature)) { DoScriptText(SAY_INTRO, m_creature); m_bHasDoneIntro = true; @@ -118,9 +118,9 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -137,18 +137,18 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI m_pInstance->SetData(TYPE_VORPIL, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_VORPIL, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_VOID_TRAVELER) pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0.0f, 0.0f); @@ -157,7 +157,7 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI pSummoned->CastSpell(pSummoned, SPELL_VOID_PORTAL_VISUAL, true); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -172,23 +172,23 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI float fX, fY, fZ; - GUIDVector vGuids; + GuidVector vGuids; m_creature->FillGuidsListFromThreatList(vGuids); - for (GUIDVector::const_iterator itr = vGuids.begin();itr != vGuids.end(); ++itr) + for (GuidVector::const_iterator itr = vGuids.begin(); itr != vGuids.end(); ++itr) { Unit* pTarget = m_creature->GetMap()->GetUnit(*itr); if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) { - pTarget->GetRandomPoint(aVorpilTeleportLoc[0], aVorpilTeleportLoc[1], aVorpilTeleportLoc[2], 3.0f, fX, fY, fZ); - DoTeleportPlayer(pTarget, fX, fY, fZ, m_creature->GetAngle(m_creature->GetPositionX(), m_creature->GetPositionY())); + pTarget->GetRandomPoint(aVorpilTeleportLoc[0], aVorpilTeleportLoc[1], aVorpilTeleportLoc[2], 4.0f, fX, fY, fZ); + DoTeleportPlayer(pTarget, fX, fY, fZ, m_creature->GetAngle(fX, fY)); } } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -196,10 +196,15 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI { if (m_uiRainOfFireTimer <= uiDiff) { + SetCombatMovement(false, true); DoTeleportToPlatform(); - if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_RAIN_OF_FIRE : SPELL_RAIN_OF_FIRE_H) == CAST_OK) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_RAIN_OF_FIRE : SPELL_RAIN_OF_FIRE_H, CAST_INTERRUPT_PREVIOUS) == CAST_OK) m_uiRainOfFireTimer = 0; + + SetCombatMovement(true); + + return; // Nothing more todo after the players had been teleported } else m_uiRainOfFireTimer -= uiDiff; @@ -208,7 +213,7 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI if (m_uiShadowBoltVolleyTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_BOLT_VOLLEY) == CAST_OK) - m_uiShadowBoltVolleyTimer = urand(15000, 30000); + m_uiShadowBoltVolleyTimer = urand(10000, 26000); } else m_uiShadowBoltVolleyTimer -= uiDiff; @@ -217,7 +222,7 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_DRAW_SHADOWS) == CAST_OK) { - m_uiDrawShadowsTimer = 37000; + m_uiDrawShadowsTimer = urand(36000, 44000); m_uiRainOfFireTimer = 1000; } } @@ -242,7 +247,7 @@ struct MANGOS_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) { if (DoCastSpellIfCan(pTarget, SPELL_BANISH_H) == CAST_OK) - m_uiBanishTimer = 35000; + m_uiBanishTimer = urand(17000, 23000); } } else @@ -258,7 +263,7 @@ CreatureAI* GetAI_boss_grandmaster_vorpil(Creature* pCreature) return new boss_grandmaster_vorpilAI(pCreature); } -struct MANGOS_DLL_DECL npc_void_travelerAI : public ScriptedAI +struct npc_void_travelerAI : public ScriptedAI { npc_void_travelerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -271,13 +276,13 @@ struct MANGOS_DLL_DECL npc_void_travelerAI : public ScriptedAI uint32 m_uiDeathTimer; - void Reset() + void Reset() override { m_uiDeathTimer = 0; m_bHasExploded = false; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bHasExploded && pWho->GetEntry() == NPC_VORPIL && pWho->IsWithinDistInMap(m_creature, 3.0f)) { @@ -289,9 +294,9 @@ struct MANGOS_DLL_DECL npc_void_travelerAI : public ScriptedAI } } - void AttackStart(Unit* pWho) { } + void AttackStart(Unit* /*pWho*/) override { } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiDeathTimer) { diff --git a/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp b/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp index 66dc2a4ed..9b4117a86 100644 --- a/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp +++ b/scripts/outland/auchindoun/shadow_labyrinth/boss_murmur.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,30 +17,37 @@ /* ScriptData SDName: Boss_Murmur SD%Complete: 75 -SDComment: Database should have `RegenHealth`=0 to prevent regen. Also, his shockwave triggered after magnetic pull may be incorrect. Murmur's Touch does not work properly. +SDComment: Sonic Boom and Murmur's Touch require additional research and core support SDCategory: Auchindoun, Shadow Labyrinth EndScriptData */ #include "precompiled.h" #include "shadow_labyrinth.h" -#define EMOTE_SONIC_BOOM -1555036 - -#define SPELL_MAGNETIC_PULL 33689 -#define SPELL_SONIC_BOOM_PRE 33923 -#define SPELL_SONIC_BOOM_CAST 38795 -#define SPELL_MURMURS_TOUCH 33711 -#define SPELL_RESONANCE 33657 -#define SPELL_SHOCKWAVE 33686 - -#define SPELL_SONIC_SHOCK 38797 //Heroic Spell -#define SPELL_THUNDERING_STORM 39365 //Heroic Spell +enum +{ + EMOTE_SONIC_BOOM = -1555036, + + // Intro spells - used on npcs + SPELL_SUPPRESSION_BLAST = 33332, + SPELL_MURMURS_WRATH = 33331, + SPELL_MURMURS_WRATH_2 = 33329, + + SPELL_MAGNETIC_PULL = 33689, + SPELL_SONIC_BOOM = 33923, // dummy spell - triggers 33666 + SPELL_SONIC_BOOM_H = 38796, // dummy spell - triggers 38795 + SPELL_MURMURS_TOUCH = 33711, // on expire silences the party members using shockwave - 33686 - also related to spell 33760 + SPELL_MURMURS_TOUCH_H = 38794, + SPELL_RESONANCE = 33657, + + SPELL_SONIC_SHOCK = 38797, // Heroic Spell + SPELL_THUNDERING_STORM = 39365, // Heroic Spell +}; -struct MANGOS_DLL_DECL boss_murmurAI : public ScriptedAI +struct boss_murmurAI : public Scripted_NoMovementAI { - boss_murmurAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_murmurAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { - SetCombatMovement(false); m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); @@ -49,145 +56,100 @@ struct MANGOS_DLL_DECL boss_murmurAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 SonicBoom_Timer; - uint32 MurmursTouch_Timer; - uint32 Resonance_Timer; - uint32 MagneticPull_Timer; - uint32 SonicShock_Timer; - uint32 ThunderingStorm_Timer; - bool CanSonicBoom; - bool CanShockWave; - ObjectGuid m_playerTargetGuid; - - void Reset() - { - SonicBoom_Timer = 30000; - MurmursTouch_Timer = urand(8000, 20000); - Resonance_Timer = 5000; - MagneticPull_Timer = urand(15000, 30000); - SonicShock_Timer = urand(4000, 10000); - ThunderingStorm_Timer = 12000; //Casting directly after Sonic Boom. - CanSonicBoom = false; - CanShockWave = false; - m_playerTargetGuid.Clear(); - - //database should have `RegenHealth`=0 to prevent regen - uint32 hp = (m_creature->GetMaxHealth()*40)/100; - if (hp) - m_creature->SetHealth(hp); - } + uint32 m_uiSonicBoomTimer; + uint32 m_uiMurmursTouchTimer; + uint32 m_uiResonanceTimer; + uint32 m_uiMagneticPullTimer; + uint32 m_uiSonicShockTimer; + uint32 m_uiThunderingStormTimer; - void SonicBoomEffect() + void Reset() override { - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator itr = vGuids.begin();itr != vGuids.end(); ++itr) - { - Unit* target = m_creature->GetMap()->GetUnit(*itr); - - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - //Not do anything without aura, spell can be resisted! - if (target->HasAura(SPELL_SONIC_BOOM_CAST, EFFECT_INDEX_1) && m_creature->IsWithinDistInMap(target, 34.0f)) - { - //This will be wrong calculation. Also, comments suggest it must deal damage - target->SetHealth(uint32(target->GetMaxHealth() - target->GetMaxHealth() * 0.8)); - } - } - } + m_uiSonicBoomTimer = urand(21000, 35000); + m_uiMurmursTouchTimer = urand(9000, 18000); + m_uiResonanceTimer = urand(1000, 7000); + m_uiMagneticPullTimer = urand(15000, 25000); + m_uiSonicShockTimer = urand(5000, 15000); + m_uiThunderingStormTimer = urand(10000, 50000); + + // Boss has only 0.4 of max health + m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.4)); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //SonicBoom_Timer - if (SonicBoom_Timer < diff) + // SonicBoom_Timer + if (m_uiSonicBoomTimer < uiDiff) { - if (CanSonicBoom) - { - DoCastSpellIfCan(m_creature, SPELL_SONIC_BOOM_CAST, CAST_TRIGGERED); - SonicBoomEffect(); - - CanSonicBoom = false; - SonicBoom_Timer = 30000; - } - else + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SONIC_BOOM : SPELL_SONIC_BOOM_H) == CAST_OK) { DoScriptText(EMOTE_SONIC_BOOM, m_creature); - DoCastSpellIfCan(m_creature,SPELL_SONIC_BOOM_PRE); - CanSonicBoom = true; - SonicBoom_Timer = 5000; + m_uiSonicBoomTimer = urand(31000, 38000); } - }else SonicBoom_Timer -= diff; + } + else + m_uiSonicBoomTimer -= uiDiff; - //MurmursTouch_Timer - if (MurmursTouch_Timer < diff) - { - /*Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); - if (target) - DoCastSpellIfCan(target, SPELL_MURMURS_TOUCH);*/ - DoCastSpellIfCan(m_creature, SPELL_MURMURS_TOUCH); - MurmursTouch_Timer = urand(25000, 35000); - }else MurmursTouch_Timer -= diff; - - //Resonance_Timer - if (!CanSonicBoom && !m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + // MurmursTouch_Timer + if (m_uiMurmursTouchTimer < uiDiff) { - if (Resonance_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_RESONANCE); - Resonance_Timer = m_bIsRegularMode ? 5000 : 3000; - }else Resonance_Timer -= diff; + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_MURMURS_TOUCH : SPELL_MURMURS_TOUCH_H) == CAST_OK) + m_uiMurmursTouchTimer = m_bIsRegularMode ? urand(21000, 21000) : urand(29000, 40000); } + else + m_uiMurmursTouchTimer -= uiDiff; - if (!m_bIsRegularMode) + // Resonance_Timer - cast if no target is in range + if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) { - if (SonicShock_Timer < diff) + if (m_uiResonanceTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, SPELL_SONIC_SHOCK); - SonicShock_Timer = urand(8000, 12000); - }else SonicShock_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_RESONANCE) == CAST_OK) + m_uiResonanceTimer = urand(5000, 12000); + } + else + m_uiResonanceTimer -= uiDiff; + } - if (ThunderingStorm_Timer < diff) + // MagneticPull_Timer + if (m_uiMagneticPullTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MAGNETIC_PULL, SELECT_FLAG_PLAYER | SELECT_FLAG_NOT_IN_MELEE_RANGE)) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_THUNDERING_STORM); - ThunderingStorm_Timer = 12000; - }else ThunderingStorm_Timer -= diff; + if (DoCastSpellIfCan(pTarget, SPELL_MAGNETIC_PULL) == CAST_OK) + m_uiMagneticPullTimer = urand(21000, 30000); + } } + else + m_uiMagneticPullTimer -= uiDiff; - //MagneticPull_Timer - if (MagneticPull_Timer < diff) + if (!m_bIsRegularMode) { - if (!CanShockWave) + if (m_uiSonicShockTimer < uiDiff) { - if (Unit* pTemp = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MAGNETIC_PULL, SELECT_FLAG_PLAYER)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_SONIC_SHOCK, SELECT_FLAG_IN_MELEE_RANGE)) { - DoCastSpellIfCan(pTemp, SPELL_MAGNETIC_PULL); - m_playerTargetGuid = pTemp->GetObjectGuid(); - CanShockWave = true; + if (DoCastSpellIfCan(pTarget, SPELL_SONIC_SHOCK) == CAST_OK) + m_uiSonicShockTimer = urand(3000, 10000); } } else - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerTargetGuid)) - pPlayer->CastSpell(pPlayer, SPELL_SHOCKWAVE, true); + m_uiSonicShockTimer -= uiDiff; - MagneticPull_Timer = urand(15000, 30000); - CanShockWave = false; - m_playerTargetGuid.Clear(); + if (m_uiThunderingStormTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_THUNDERING_STORM) == CAST_OK) + m_uiThunderingStormTimer = urand(5000, 6000); } + else + m_uiThunderingStormTimer -= uiDiff; } - else - MagneticPull_Timer -= diff; - //no meele if preparing for sonic boom - if (!CanSonicBoom) - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(); } }; diff --git a/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp b/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp index 7b079ef26..2fba2c5e5 100644 --- a/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp +++ b/scripts/outland/auchindoun/shadow_labyrinth/instance_shadow_labyrinth.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,8 +31,7 @@ EndScriptData */ 4 - Murmur event */ -instance_shadow_labyrinth::instance_shadow_labyrinth(Map* pMap) : ScriptedInstance(pMap), - m_uiFelOverseerCount(0) +instance_shadow_labyrinth::instance_shadow_labyrinth(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } @@ -44,7 +43,7 @@ void instance_shadow_labyrinth::Initialize() void instance_shadow_labyrinth::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_REFECTORY_DOOR: if (m_auiEncounter[2] == DONE) @@ -64,74 +63,37 @@ void instance_shadow_labyrinth::OnObjectCreate(GameObject* pGo) void instance_shadow_labyrinth::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_VORPIL: case NPC_HELLMAW: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; - case NPC_FEL_OVERSEER: - ++m_uiFelOverseerCount; // TODO should actually only count alive ones - debug_log("SD2: Shadow Labyrinth: counting %u Fel Overseers.", m_uiFelOverseerCount); - break; } } void instance_shadow_labyrinth::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_HELLMAW: m_auiEncounter[0] = uiData; break; - case TYPE_OVERSEER: - if (uiData != DONE) - { - error_log("SD2: Shadow Labyrinth: TYPE_OVERSEER did not expect other data than DONE"); - return; - } - if (m_uiFelOverseerCount) - { - --m_uiFelOverseerCount; - - if (m_uiFelOverseerCount) - { - debug_log("SD2: Shadow Labyrinth: %u Fel Overseers left to kill.", m_uiFelOverseerCount); - - // Skip save call - return; - } - else - { - if (Creature* pHellmaw = GetSingleCreatureFromStorage(NPC_HELLMAW)) - { - // yell intro and remove banish aura - DoScriptText(SAY_HELLMAW_INTRO, pHellmaw); - if (pHellmaw->HasAura(SPELL_BANISH)) - pHellmaw->RemoveAurasDueToSpell(SPELL_BANISH); - } - - m_auiEncounter[1] = DONE; - debug_log("SD2: Shadow Labyrinth: TYPE_OVERSEER == DONE"); - } - } - break; - case TYPE_INCITER: if (uiData == DONE) DoUseDoorOrButton(GO_REFECTORY_DOOR); - m_auiEncounter[2] = uiData; + m_auiEncounter[1] = uiData; break; case TYPE_VORPIL: if (uiData == DONE) DoUseDoorOrButton(GO_SCREAMING_HALL_DOOR); - m_auiEncounter[3] = uiData; + m_auiEncounter[2] = uiData; break; case TYPE_MURMUR: - m_auiEncounter[4] = uiData; + m_auiEncounter[3] = uiData; break; } @@ -141,7 +103,7 @@ void instance_shadow_labyrinth::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " - << m_auiEncounter[2] << " " << m_auiEncounter[3] << " " << m_auiEncounter[4]; + << m_auiEncounter[2] << " " << m_auiEncounter[3]; m_strInstData = saveStream.str(); @@ -150,18 +112,52 @@ void instance_shadow_labyrinth::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_shadow_labyrinth::GetData(uint32 uiType) +uint32 instance_shadow_labyrinth::GetData(uint32 uiType) const { - switch(uiType) + switch (uiType) { case TYPE_HELLMAW: return m_auiEncounter[0]; - case TYPE_OVERSEER: return m_auiEncounter[1]; + case TYPE_INCITER: return m_auiEncounter[1]; + case TYPE_VORPIL: return m_auiEncounter[2]; + case TYPE_MURMUR: return m_auiEncounter[3]; default: return 0; } } +void instance_shadow_labyrinth::SetData64(uint32 uiData, uint64 uiGuid) +{ + // If Hellmaw already completed, just ignore + if (GetData(TYPE_HELLMAW) == DONE) + return; + + // Note: this is handled in Acid. The purpose is check which Cabal Ritualists is alive, in case of server reset + // The function is triggered by eventAI on generic timer + if (uiData == DATA_CABAL_RITUALIST) + m_sRitualistsAliveGUIDSet.insert(ObjectGuid(uiGuid)); +} + +void instance_shadow_labyrinth::OnCreatureDeath(Creature* pCreature) +{ + // unbanish Hellmaw when all Cabal Ritualists are dead + if (pCreature->GetEntry() == NPC_CABAL_RITUALIST) + { + m_sRitualistsAliveGUIDSet.erase(pCreature->GetObjectGuid()); + + if (m_sRitualistsAliveGUIDSet.empty()) + { + if (Creature* pHellmaw = GetSingleCreatureFromStorage(NPC_HELLMAW)) + { + // yell intro and remove banish aura + DoScriptText(SAY_HELLMAW_INTRO, pHellmaw); + pHellmaw->GetMotionMaster()->MoveWaypoint(); + pHellmaw->RemoveAurasDueToSpell(SPELL_BANISH); + } + } + } +} + void instance_shadow_labyrinth::Load(const char* chrIn) { if (!chrIn) @@ -173,7 +169,7 @@ void instance_shadow_labyrinth::Load(const char* chrIn) OUT_LOAD_INST_DATA(chrIn); std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] >> m_auiEncounter[4]; + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { diff --git a/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h b/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h index 435ee00f1..c86e91fea 100644 --- a/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h +++ b/scripts/outland/auchindoun/shadow_labyrinth/shadow_labyrinth.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,47 +7,55 @@ enum { - MAX_ENCOUNTER = 5, + MAX_ENCOUNTER = 4, TYPE_HELLMAW = 1, - TYPE_OVERSEER = 2, + // TYPE_OVERSEER = 2, // obsolete id used by acid TYPE_INCITER = 3, TYPE_VORPIL = 4, TYPE_MURMUR = 5, + DATA_CABAL_RITUALIST = 1, // DO NOT CHANGE! Used by Acid. - used to check the Cabal Ritualists alive + NPC_HELLMAW = 18731, NPC_VORPIL = 18732, - NPC_FEL_OVERSEER = 18796, + NPC_CABAL_RITUALIST = 18794, - GO_REFECTORY_DOOR = 183296, //door opened when blackheart the inciter dies - GO_SCREAMING_HALL_DOOR = 183295, //door opened when grandmaster vorpil dies + GO_REFECTORY_DOOR = 183296, // door opened when blackheart the inciter dies + GO_SCREAMING_HALL_DOOR = 183295, // door opened when grandmaster vorpil dies SAY_HELLMAW_INTRO = -1555000, - SPELL_BANISH = 30231, + SPELL_BANISH = 30231, // spell is handled in creature_template_addon; }; -class MANGOS_DLL_DECL instance_shadow_labyrinth : public ScriptedInstance +class instance_shadow_labyrinth : public ScriptedInstance { public: instance_shadow_labyrinth(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void SetData64(uint32 uiType, uint64 uiGuid) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + bool IsHellmawUnbanished() { return m_sRitualistsAliveGUIDSet.empty(); } private: uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; - uint32 m_uiFelOverseerCount; + GuidSet m_sRitualistsAliveGUIDSet; }; #endif diff --git a/scripts/outland/black_temple/black_temple.cpp b/scripts/outland/black_temple/black_temple.cpp index 3ee252500..95a47896f 100644 --- a/scripts/outland/black_temple/black_temple.cpp +++ b/scripts/outland/black_temple/black_temple.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -46,7 +46,7 @@ bool GossipHello_npc_spirit_of_olum(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_spirit_of_olum(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_spirit_of_olum(Player* pPlayer, Creature* /*pCreature*/, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) pPlayer->CLOSE_GOSSIP_MENU(); diff --git a/scripts/outland/black_temple/black_temple.h b/scripts/outland/black_temple/black_temple.h index 85d9d988d..2ab6aecc0 100644 --- a/scripts/outland/black_temple/black_temple.h +++ b/scripts/outland/black_temple/black_temple.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -23,6 +23,7 @@ enum // NPC_SUPREMUS = 22898, NPC_SHADE_OF_AKAMA = 22841, NPC_AKAMA_SHADE = 22990, + NPC_RELIQUARY_OF_SOULS = 22856, NPC_ILLIDARI_COUNCIL = 23426, NPC_COUNCIL_VOICE = 23499, NPC_LADY_MALANDE = 22951, @@ -30,11 +31,21 @@ enum NPC_GATHIOS = 22949, NPC_VERAS = 22952, NPC_AKAMA = 23089, + NPC_MAIEV_SHADOWSONG = 23197, NPC_ILLIDAN_STORMRAGE = 22917, + NPC_ASH_CHANNELER = 23421, + NPC_CREATURE_GENERATOR = 23210, + NPC_ILLIDAN_DOOR_TRIGGER = 23412, + NPC_GLAIVE_TARGET = 23448, + NPC_SPIRIT_OF_OLUM = 23411, + NPC_SPIRIT_OF_UDALO = 23410, + GO_NAJENTUS_GATE = 185483, GO_SUPREMUS_DOORS = 185882, GO_SHADE_OF_AKAMA = 185478, + GO_GOREFIEND_DOOR = 186153, + GO_GURTOGG_DOOR = 185892, GO_PRE_SHAHRAZ_DOOR = 185479, GO_POST_SHAHRAZ_DOOR = 185482, GO_PRE_COUNCIL_DOOR = 185481, @@ -44,33 +55,39 @@ enum GO_ILLIDAN_DOOR_L = 186262, }; -class MANGOS_DLL_DECL instance_black_temple : public ScriptedInstance +class instance_black_temple : public ScriptedInstance { public: instance_black_temple(Map* pMap); - void Initialize(); + void Initialize() override; + + bool IsEncounterInProgress() const override; - bool IsEncounterInProgress() const; + void OnPlayerEnter(Player* pPlayer) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - uint64 GetData64(uint32 uiData); + void GetChannelersGuidList(GuidList& lList) { lList = m_lChannelersGuidList; } + void GetGeneratorGuidVector(GuidVector& vVector) { vVector = m_vCreatureGeneratorGuidVector; } + void GetGlaiveTargetGuidVector(GuidVector& vVector) { vVector = m_vGlaiveTargetGuidVector; } - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: - bool CanPreMotherDoorOpen(); + void DoOpenPreMotherDoor(); + void DoSpawnAkamaIfCan(); uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; - ObjectGuid m_akamaGuid; // This is the Akama that starts the Illidan encounter. - ObjectGuid m_illidanStormrageGuid; + GuidList m_lChannelersGuidList; + GuidVector m_vCreatureGeneratorGuidVector; + GuidVector m_vGlaiveTargetGuidVector; }; #endif diff --git a/scripts/outland/black_temple/boss_bloodboil.cpp b/scripts/outland/black_temple/boss_bloodboil.cpp index 35d4b7ebb..3b82d9d63 100644 --- a/scripts/outland/black_temple/boss_bloodboil.cpp +++ b/scripts/outland/black_temple/boss_bloodboil.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,43 +16,57 @@ /* ScriptData SDName: Boss_Bloodboil -SD%Complete: 85 -SDComment: Bloodboil not working correctly +SD%Complete: 90 +SDComment: Timers may need adjustments. SDCategory: Black Temple EndScriptData */ #include "precompiled.h" #include "black_temple.h" -//Speech'n'Sound -#define SAY_AGGRO -1564029 -#define SAY_SLAY1 -1564030 -#define SAY_SLAY2 -1564031 -#define SAY_SPECIAL1 -1564032 -#define SAY_SPECIAL2 -1564033 -#define SAY_ENRAGE1 -1564034 -#define SAY_ENRAGE2 -1564035 -#define SAY_DEATH -1564036 - -//Spells -#define SPELL_ACID_GEYSER 40630 -#define SPELL_ACIDIC_WOUND 40481 -#define SPELL_ARCING_SMASH 40599 -#define SPELL_BLOODBOIL 42005 // This spell is AoE whereas it shouldn't be -#define SPELL_FEL_ACID 40508 -#define SPELL_FEL_RAGE_SELF 40594 -#define SPELL_FEL_RAGE_TARGET 40604 -#define SPELL_FEL_RAGE_2 40616 -#define SPELL_FEL_RAGE_3 41625 -#define SPELL_BEWILDERING_STRIKE 40491 -#define SPELL_EJECT1 40486 // 1000 Physical damage + knockback + script effect (should handle threat reduction I think) -#define SPELL_EJECT2 40597 // 1000 Physical damage + Stun (used in phase 2?) -#define SPELL_TAUNT_GURTOGG 40603 -#define SPELL_INSIGNIFIGANCE 40618 -#define SPELL_BERSERK 45078 -#define SPELL_ENRAGE 27680 - -struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI +enum +{ + // Speech'n'Sound + SAY_AGGRO = -1564029, + SAY_SLAY1 = -1564030, + SAY_SLAY2 = -1564031, + SAY_SPECIAL1 = -1564032, + SAY_SPECIAL2 = -1564033, + SAY_ENRAGE1 = -1564034, + SAY_ENRAGE2 = -1564035, + SAY_DEATH = -1564036, + + // Spells + // Phase 1 + SPELL_FEL_ACID_1 = 40508, + SPELL_ARCING_SMASH_1 = 40457, + SPELL_EJECT_1 = 40486, + SPELL_ACIDIC_WOUND = 40481, + SPELL_BLOODBOIL = 42005, + SPELL_BEWILDERING_STRIKE = 40491, + + // Phase 2 + SPELL_ACID_GEYSER = 40630, + SPELL_FEL_ACID_2 = 40595, + SPELL_ARCING_SMASH_2 = 40599, + SPELL_EJECT_2 = 40597, + SPELL_INSIGNIFIGANCE = 40618, + SPELL_FEL_RAGE = 40594, + SPELL_FEL_RAGE_PLAYER_1 = 40604, + SPELL_FEL_RAGE_PLAYER_2 = 40616, + SPELL_FEL_RAGE_PLAYER_3 = 41625, + SPELL_FEL_RAGE_4 = 40617, // spell not confirmed + SPELL_FEL_RAGE_5 = 46787, // spell not confirmed + SPELL_TAUNT_GURTOGG = 40603, + + // Other spells + SPELL_CHARGE = 40602, // spell not confirmed + SPELL_BERSERK = 27680, + + MAX_BLOODBOILS = 5, +}; + +struct boss_gurtogg_bloodboilAI : public ScriptedAI { boss_gurtogg_bloodboilAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -62,52 +76,42 @@ struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI ScriptedInstance* m_pInstance; - ObjectGuid m_targetGuid; - - float TargetThreat; - - uint32 BloodboilTimer; - uint32 BloodboilCount; - uint32 AcidGeyserTimer; - uint32 AcidicWoundTimer; - uint32 ArcingSmashTimer; - uint32 EnrageTimer; - uint32 FelAcidTimer; - uint32 EjectTimer; - uint32 BewilderingStrikeTimer; - uint32 PhaseChangeTimer; - uint32 m_uiEnrageTimer; + uint32 m_uiBloodboilTimer; + uint32 m_uiAcidGeyserTimer; + uint32 m_uiAcidicWoundTimer; + uint32 m_uiArcingSmashTimer; + uint32 m_uiFelAcidTimer; + uint32 m_uiEjectTimer; + uint32 m_uiStrikeTimer; + uint32 m_uiPhaseChangeTimer; + uint32 m_uiBerserkTimer; + uint8 m_uiBloodboilCount; - bool Phase1; + bool m_bIsPhase1; - void Reset() + void Reset() override { - m_targetGuid.Clear(); - - TargetThreat = 0; - - BloodboilTimer = 10000; - BloodboilCount = 0; - AcidGeyserTimer = 1000; - AcidicWoundTimer = 6000; - ArcingSmashTimer = 19000; - EnrageTimer = 600000; - FelAcidTimer = 25000; - EjectTimer = 10000; - BewilderingStrikeTimer = 15000; - PhaseChangeTimer = 60000; - m_uiEnrageTimer = 600000; - - Phase1 = true; + m_uiBloodboilTimer = 10000; + m_uiBloodboilCount = 0; + m_uiAcidGeyserTimer = 1000; + m_uiAcidicWoundTimer = 6000; + m_uiArcingSmashTimer = 19000; + m_uiFelAcidTimer = 25000; + m_uiEjectTimer = 10000; + m_uiStrikeTimer = 15000; + m_uiPhaseChangeTimer = MINUTE * IN_MILLISECONDS; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_bIsPhase1 = true; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_BLOODBOIL, NOT_STARTED); + m_pInstance->SetData(TYPE_BLOODBOIL, FAIL); } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -115,12 +119,12 @@ struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI m_pInstance->SetData(TYPE_BLOODBOIL, IN_PROGRESS); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_BLOODBOIL, DONE); @@ -128,203 +132,157 @@ struct MANGOS_DLL_DECL boss_gurtogg_bloodboilAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); } - // Note: This seems like a very complicated fix. The fix needs to be handled by the core, as implementation of limited-target AoE spells are still not limited. - void CastBloodboil() + void UpdateAI(const uint32 uiDiff) override { - // Get the Threat List - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - - // He doesn't have anyone in his threatlist, useless to continue - if (tList.empty()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - std::list targets; - - //store the threat list in a different container - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + if (m_uiArcingSmashTimer < uiDiff) { - Unit *target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - //only on alive players - if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); + if (DoCastSpellIfCan(m_creature, m_bIsPhase1 ? SPELL_ARCING_SMASH_1 : SPELL_ARCING_SMASH_2) == CAST_OK) + m_uiArcingSmashTimer = 10000; } + else + m_uiArcingSmashTimer -= uiDiff; - //Sort the list of players - targets.sort(ObjectDistanceOrderReversed(m_creature)); - //Resize so we only get top 5 - targets.resize(5); - - //Aura each player in the targets list with Bloodboil. Aura code copied+pasted from Aura command in Level3.cpp - /*SpellEntry const *spellInfo = GetSpellStore()->LookupEntry(SPELL_BLOODBOIL); - if (spellInfo) + if (m_uiFelAcidTimer < uiDiff) { - for(std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - Unit* target = *itr; - if (!target) return; - for(uint32 i = 0;i<3; ++i) - { - uint8 eff = spellInfo->Effect[i]; - if (eff>=TOTAL_SPELL_EFFECTS) - continue; - - Aura *Aur = new Aura(spellInfo, i, NULL, target); - target->AddAura(Aur); - } - } - }*/ - } - - void RevertThreatOnTarget(ObjectGuid guid) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(guid)) - { - if (m_creature->getThreatManager().getThreat(pPlayer)) - m_creature->getThreatManager().modifyThreatPercent(pPlayer, -100); - - if (TargetThreat) - m_creature->AddThreat(pPlayer, TargetThreat); + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsPhase1 ? SPELL_FEL_ACID_1 : SPELL_FEL_ACID_2) == CAST_OK) + m_uiFelAcidTimer = 25000; } - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; + else + m_uiFelAcidTimer -= uiDiff; - if (ArcingSmashTimer < diff) + // Phase 1 spells + if (m_bIsPhase1) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCING_SMASH); - ArcingSmashTimer = 10000; - }else ArcingSmashTimer -= diff; - - if (FelAcidTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEL_ACID); - FelAcidTimer = 25000; - }else FelAcidTimer -= diff; - - if (!m_creature->HasAura(SPELL_BERSERK, EFFECT_INDEX_0)) - { - if (EnrageTimer < diff) + if (m_uiStrikeTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) - DoScriptText(urand(0, 1) ? SAY_ENRAGE1 : SAY_ENRAGE2, m_creature); - }else EnrageTimer -= diff; - } - - if (Phase1) - { - if (BewilderingStrikeTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BEWILDERING_STRIKE); - float mt_threat = m_creature->getThreatManager().getThreat(m_creature->getVictim()); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1)) - m_creature->AddThreat(target, mt_threat); - - BewilderingStrikeTimer = 20000; - }else BewilderingStrikeTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BEWILDERING_STRIKE) == CAST_OK) + m_uiStrikeTimer = 20000; + } + else + m_uiStrikeTimer -= uiDiff; - if (EjectTimer < diff) + if (m_uiEjectTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_EJECT1); - m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -40); - EjectTimer = 15000; - }else EjectTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_EJECT_1) == CAST_OK) + { + // Script effect: reduce threat on main target + m_creature->getThreatManager().modifyThreatPercent(m_creature->getVictim(), -40); + m_uiEjectTimer = 15000; + } + } + else + m_uiEjectTimer -= uiDiff; - if (AcidicWoundTimer < diff) + if (m_uiAcidicWoundTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ACIDIC_WOUND); - AcidicWoundTimer = 10000; - }else AcidicWoundTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ACIDIC_WOUND) == CAST_OK) + m_uiAcidicWoundTimer = 10000; + } + else + m_uiAcidicWoundTimer -= uiDiff; - if (BloodboilTimer < diff) + if (m_uiBloodboilTimer) { - if (BloodboilCount < 5) // Only cast it five times. + if (m_uiBloodboilTimer <= uiDiff) { - //CastBloodboil(); // Causes issues on windows, so is commented out. - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLOODBOIL); - ++BloodboilCount; - BloodboilTimer = 10000*BloodboilCount; + if (DoCastSpellIfCan(m_creature, SPELL_BLOODBOIL) == CAST_OK) + { + ++m_uiBloodboilCount; + + // Allow only 5 Bloodboils per phase. + if (m_uiBloodboilCount == MAX_BLOODBOILS) + m_uiBloodboilTimer = 0; + else + m_uiBloodboilTimer = 10000; + } } - }else BloodboilTimer -= diff; + else + m_uiBloodboilTimer -= uiDiff; + } } - - if (!Phase1) + // Phase 2 spells + else { - if (AcidGeyserTimer < diff) + if (m_uiAcidGeyserTimer) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ACID_GEYSER); - AcidGeyserTimer = 30000; - }else AcidGeyserTimer -= diff; + if (m_uiAcidGeyserTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ACID_GEYSER) == CAST_OK) + m_uiAcidGeyserTimer = 0; + } + else + m_uiAcidGeyserTimer -= uiDiff; + } - if (EjectTimer < diff) + if (m_uiEjectTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_EJECT2); - EjectTimer = 15000; - }else EjectTimer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_EJECT_2) == CAST_OK) + m_uiEjectTimer = 15000; + } + else + m_uiEjectTimer -= uiDiff; } - if (PhaseChangeTimer < diff) + if (m_uiPhaseChangeTimer < uiDiff) { - if (Phase1) + if (m_bIsPhase1) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - Phase1 = false; - - TargetThreat = m_creature->getThreatManager().getThreat(target); - m_targetGuid = target->GetObjectGuid(); - target->CastSpell(m_creature, SPELL_TAUNT_GURTOGG, true); - - if (m_creature->getThreatManager().getThreat(target)) - m_creature->getThreatManager().modifyThreatPercent(target, -100); - - m_creature->AddThreat(target, 50000000.0f); - - // If VMaps are disabled, this spell can call the whole instance - DoCastSpellIfCan(m_creature, SPELL_INSIGNIFIGANCE, CAST_TRIGGERED); - DoCastSpellIfCan(target, SPELL_FEL_RAGE_TARGET, CAST_TRIGGERED); - DoCastSpellIfCan(target, SPELL_FEL_RAGE_2, CAST_TRIGGERED); - - /* These spells do not work, comment them out for now. - DoCastSpellIfCan(target, SPELL_FEL_RAGE_2, CAST_TRIGGERED); - DoCastSpellIfCan(target, SPELL_FEL_RAGE_3, CAST_TRIGGERED);*/ - - //Cast this without triggered so that it appears in combat logs and shows visual. - DoCastSpellIfCan(m_creature, SPELL_FEL_RAGE_SELF); - - DoScriptText(urand(0, 1) ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); - - AcidGeyserTimer = 1000; - PhaseChangeTimer = 30000; + // Buff self + if (DoCastSpellIfCan(m_creature, SPELL_FEL_RAGE) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); + + // Debuff player + DoCastSpellIfCan(pTarget, SPELL_FEL_RAGE_PLAYER_1, CAST_TRIGGERED); + DoCastSpellIfCan(pTarget, SPELL_FEL_RAGE_PLAYER_2, CAST_TRIGGERED); + DoCastSpellIfCan(pTarget, SPELL_FEL_RAGE_PLAYER_3, CAST_TRIGGERED); + // Allow player to taunt Gurtogg + pTarget->CastSpell(m_creature, SPELL_TAUNT_GURTOGG, true); + + // Don't allow others to generate threat + DoCastSpellIfCan(m_creature, SPELL_INSIGNIFIGANCE, CAST_TRIGGERED); + + // Reset timers + m_bIsPhase1 = false; + m_uiAcidGeyserTimer = 1000; + m_uiPhaseChangeTimer = 30000; + } } - }else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage + } + else { - if (m_targetGuid) - RevertThreatOnTarget(m_targetGuid); - - m_targetGuid.Clear(); - Phase1 = true; - BloodboilTimer = 10000; - BloodboilCount = 0; - AcidicWoundTimer += 2000; - ArcingSmashTimer += 2000; - FelAcidTimer += 2000; - EjectTimer += 2000; - PhaseChangeTimer = 60000; + // Reset timers + m_bIsPhase1 = true; + m_uiBloodboilTimer = 10000; + m_uiBloodboilCount = 0; + m_uiAcidicWoundTimer += 2000; + m_uiArcingSmashTimer += 2000; + m_uiFelAcidTimer += 2000; + m_uiEjectTimer += 2000; + m_uiPhaseChangeTimer = 60000; } - }else PhaseChangeTimer -= diff; + } + else + m_uiPhaseChangeTimer -= uiDiff; - //Enrage - if (m_uiEnrageTimer < diff) + if (m_uiBerserkTimer) { - DoCast(m_creature, SPELL_ENRAGE); - m_uiEnrageTimer = 60000; - }else m_uiEnrageTimer -= diff; + if (m_uiBerserkTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_ENRAGE1 : SAY_ENRAGE2, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; + } DoMeleeAttackIfReady(); } diff --git a/scripts/outland/black_temple/boss_illidan.cpp b/scripts/outland/black_temple/boss_illidan.cpp index 4c6f17da6..2a089460a 100644 --- a/scripts/outland/black_temple/boss_illidan.cpp +++ b/scripts/outland/black_temple/boss_illidan.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,2421 +17,1635 @@ /* ScriptData SDName: Boss_Illidan_Stormrage SD%Complete: 90 -SDComment: +SDComment: Movement during flight phase NYI. Some other fine details may need adjustments. SDCategory: Black Temple EndScriptData */ #include "precompiled.h" #include "black_temple.h" -#include "WorldPacket.h" - -/**** Creature Summon and Recognition IDs ****/ -enum CreatureEntry -{ - EMPTY = 0, - AKAMA = 22990, - ILLIDAN_STORMRAGE = 22917, - BLADE_OF_AZZINOTH = 22996, - FLAME_OF_AZZINOTH = 22997, - MAIEV_SHADOWSONG = 23197, - SHADOW_DEMON = 23375, - DEMON_FIRE = 23069, - FLAME_CRASH = 23336, - ILLIDAN_DOOR_TRIGGER = 23412, - SPIRIT_OF_OLUM = 23411, - SPIRIT_OF_UDALO = 23410, - ILLIDARI_ELITE = 23226, - PARASITIC_SHADOWFIEND = 23498, - CAGE_TRAP_TRIGGER = 23292, -}; - -/************* Quotes and Sounds ***********************/ -// Gossip for when a player clicks Akama -#define GOSSIP_ITEM "We are ready to face Illidan" - -enum -{ - SAY_CONVO_1 = -1564097, - SAY_CONVO_2 = -1564098, - SAY_CONVO_3 = -1564099, - SAY_CONVO_4 = -1564100, - SAY_CONVO_5 = -1564101, - SAY_CONVO_6 = -1564102, - SAY_CONVO_7 = -1564103, - SAY_CONVO_8 = -1564104, - SAY_CONVO_9 = -1564105, - SAY_CONVO_10 = -1564106, - SAY_CONVO_11 = -1564107, - SAY_CONVO_12 = -1564108, - SAY_CONVO_13 = -1564109, - SAY_CONVO_14 = -1564110, - SAY_CONVO_15 = -1564111, - - SAY_TAUNT_1 = -1564112, - SAY_TAUNT_2 = -1564113, - SAY_TAUNT_3 = -1564114, - SAY_TAUNT_4 = -1564115, - - SAY_MAIEV_TAUNT_1 = -1564116, - SAY_MAIEV_TAUNT_2 = -1564117, - SAY_MAIEV_TAUNT_3 = -1564118, - SAY_MAIEV_TAUNT_4 = -1564119, -}; - -//emote only defined if not related to textId (in database) -struct Yells -{ - int32 textId; - uint32 creature, timer, emote; - bool Talk; -}; - -static const Yells aConversation[]= -{ - {SAY_CONVO_1, ILLIDAN_STORMRAGE, 8000, 0, true}, - {0, ILLIDAN_STORMRAGE, 5000, 396, true}, - {SAY_CONVO_2, AKAMA, 7000, 0, true}, - {0, AKAMA, 5000, 66, true}, - {SAY_CONVO_3, ILLIDAN_STORMRAGE, 8000, 0, true}, - {SAY_CONVO_4, AKAMA, 3000, 0, true}, - {0, AKAMA, 2000, 15, true}, - {SAY_CONVO_5, ILLIDAN_STORMRAGE, 3000, 0, true}, - {0, EMPTY, 1000, 0, true}, - {0, EMPTY, 0, 0, false}, - {SAY_CONVO_6, ILLIDAN_STORMRAGE, 8000, 0, true}, - {SAY_CONVO_7, MAIEV_SHADOWSONG, 8000, 0, true}, - {SAY_CONVO_8, ILLIDAN_STORMRAGE, 7000, 0, true}, - {SAY_CONVO_9, MAIEV_SHADOWSONG, 8000, 0, true}, - {SAY_CONVO_10, ILLIDAN_STORMRAGE, 1000, 0, false}, - {SAY_CONVO_11, MAIEV_SHADOWSONG, 6000, 0, true}, - // Emote dead for now. Kill him later - {SAY_CONVO_12, ILLIDAN_STORMRAGE, 22000, 0, true}, - {SAY_CONVO_13, MAIEV_SHADOWSONG, 9000, 0, true}, - {SAY_CONVO_14, MAIEV_SHADOWSONG, 0, true}, - {SAY_CONVO_15, AKAMA, 8000, 0, true}, - {0, EMPTY, 1000, 0, false} -}; - -static const Yells aRandomTaunts[]= -{ - {SAY_TAUNT_1, ILLIDAN_STORMRAGE, 0, 0, false}, - {SAY_TAUNT_2, ILLIDAN_STORMRAGE, 0, 0, false}, - {SAY_TAUNT_3, ILLIDAN_STORMRAGE, 0, 0, false}, - {SAY_TAUNT_4, ILLIDAN_STORMRAGE, 0, 0, false} -}; - -static const Yells aMaievTaunts[]= -{ - {SAY_MAIEV_TAUNT_1, MAIEV_SHADOWSONG, 0, 0, false}, - {SAY_MAIEV_TAUNT_2, MAIEV_SHADOWSONG, 0, 0, false}, - {SAY_MAIEV_TAUNT_3, MAIEV_SHADOWSONG, 0, 0, false}, - {SAY_MAIEV_TAUNT_4, MAIEV_SHADOWSONG, 0, 0, false} -}; +#include "escort_ai.h" enum { - // Yells for/by Akama - SAY_AKAMA_BEWARE = -1564120, - SAY_AKAMA_MINION = -1564121, - SAY_AKAMA_LEAVE = -1564122, - - // Self explanatory - SAY_KILL1 = -1564123, - SAY_KILL2 = -1564124, - - // I think I'll fly now and let my subordinates take you on - SAY_TAKEOFF = -1564125, - SAY_SUMMONFLAMES = -1564126, - - // When casting Eye Blast. Demon Fire will be appear on places that he casts this - SAY_EYE_BLAST = -1564127, - - // kk, I go big, dark and demon on you. - SAY_MORPH = -1564128, + /************* Quotes and Sounds ***********************/ + // Intro yells and gossip + SAY_AKAMA_BEWARE = -1564120, + SAY_AKAMA_OPEN_DOOR_1 = -1564131, + SAY_AKAMA_OPEN_DOOR_2 = -1564132, + SAY_UDALO_OPEN_DOOR_3 = -1564133, + SAY_OLUM_OPEN_DOOR_4 = -1564134, + + // Gossip for when a player clicks Akama + GOSSIP_ITEM_PREPARE = -3564001, + GOSSIP_ITEM_START_EVENT = -3564002, + TEXT_ID_AKAMA_ILLIDAN_PREPARE = 10465, // ToDo: fix text id - this entry is wrong -> "The time has come to face Illidan, $N. Are you ready?" + TEXT_ID_AKAMA_ILLIDAN_START = 10835, + + // Event speech + SAY_ILLIDAN_SPEECH_1 = -1564097, + SAY_AKAMA_SPEECH_2 = -1564098, + SAY_ILLIDAN_SPEECH_3 = -1564099, + SAY_AKAMA_SPEECH_4 = -1564100, + SAY_ILLIDAN_SPEECH_5 = -1564101, // aggro + SAY_ILLIDAN_MINION = -1564121, + SAY_AKAMA_LEAVE = -1564122, + SAY_ILLIDAN_SPEECH_6 = -1564102, + SAY_MAIEV_SPEECH_7 = -1564103, + SAY_ILLIDAN_SPEECH_8 = -1564104, + SAY_MAIEV_SPEECH_9 = -1564105, + SAY_MAIEV_TRAP = -1564118, + + // Epilogue speech + SAY_MAIEV_EPILOGUE_1 = -1564107, + SAY_ILLIDAN_EPILOGUE_2 = -1564108, + SAY_MAIEV_EPILOGUE_3 = -1564109, + SAY_MAIEV_EPILOGUE_4 = -1564110, + SAY_AKAMA_EPILOGUE_5 = -1564111, + + // Combat yells + SAY_KILL1 = -1564123, + SAY_KILL2 = -1564124, + SAY_TAKEOFF = -1564125, + SAY_SUMMONFLAMES = -1564126, + SAY_EYE_BLAST = -1564127, + SAY_MORPH = -1564128, + SAY_FRENZY = -1564106, + SAY_BERSERK = -1564129, + + // Note: this yells may not be used. Need additional research + SAY_TAUNT_1 = -1564112, + SAY_TAUNT_2 = -1564113, + SAY_TAUNT_3 = -1564114, + SAY_TAUNT_4 = -1564115, + + SAY_MAIEV_TAUNT_1 = -1564116, + SAY_MAIEV_TAUNT_2 = -1564117, + SAY_MAIEV_TAUNT_3 = -1564119, - // I KILL! - SAY_ENRAGE = -1564129, /************** Spells *************/ // Normal Form - SPELL_SHEAR = 41032, // Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast - SPELL_FLAME_CRASH = 40832, // Summons an invis/unselect passive mob that has an uiAura of flame in a circle around him. - SPELL_DRAW_SOUL = 40904, // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect) - SPELL_PARASITIC_SHADOWFIEND = 41917, // DoT of 3k Shadow every 2 seconds. Lasts 10 seconds. (Script effect: Summon 2 parasites once the debuff has ticked off) - SPELL_SUMMON_PARASITICS = 41915, // Summons 2 Parasitic Shadowfiends on the target. It's supposed to be cast as soon as the Parasitic Shadowfiend debuff is gone, but the spells aren't linked :( - SPELL_AGONIZING_FLAMES = 40932, // 4k fire damage uiInitial to target and anyone w/i 5 yards. PHASE 3 ONLY - SPELL_ENRAGE = 40683, // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY + SPELL_SHEAR = 41032, // Reduces Max. Health by 60% for 7 seconds. Can stack 19 times. 1.5 second cast + SPELL_FLAME_CRASH = 40832, // Summons an invis/unselect passive mob that has an uiAura of flame in a circle around him. + SPELL_DRAW_SOUL = 40904, // 5k Shadow Damage in front of him. Heals Illidan for 100k health (script effect) + SPELL_PARASITIC_SHADOWFIEND = 41917, // DoT of 3k Shadow every 2 seconds. Lasts 10 seconds. (Script effect: Summon 2 parasites once the debuff has ticked off) + // SPELL_SUMMON_PARASITICS = 41915, // Summons 2 Parasitic Shadowfiends on the target. Handled in core. + SPELL_AGONIZING_FLAMES = 40834, // triggers 40932 + SPELL_FRENZY = 40683, // Increases damage by 50% and attack speed by 30%. 20 seconds, PHASE 5 ONLY + // Flying (Phase 2) - SPELL_THROW_GLAIVE = 39635, // Throws a glaive on the ground - SPELL_THROW_GLAIVE2 = 39849, // Animation for the above spell - SPELL_GLAIVE_RETURNS = 39873, // Glaive flies back to Illidan - SPELL_FIREBALL = 40598, // 2.5k-3.5k damage in 10 yard radius. 2 second cast time. - SPELL_DARK_BARRAGE = 40585, // 10 second channeled spell, 3k shadow damage per second. + SPELL_THROW_GLAIVE = 39635, // triggers 41466 - Throws the first glaive on the ground + SPELL_THROW_GLAIVE_VISUAL = 39849, // triggers 41466 - Throws the second glaive on the ground + SPELL_GLAIVE_RETURNS = 39873, // Glaive flies back to Illidan + SPELL_FIREBALL = 40598, // 2.5k-3.5k damage in 10 yard radius. 2 second cast time. + SPELL_DARK_BARRAGE = 40585, // 10 second channeled spell, 3k shadow damage per second. + SPELL_EYE_BLAST_DUMMY = 39908, // This does the blue beam channel - targets 23070 + // Demon Form - SPELL_DEMON_TRANSFORM_1 = 40511, // First uiPhase of animations for transforming into Dark Illidan (fall to ground) - SPELL_DEMON_TRANSFORM_2 = 40398, // Second uiPhase of animations (kneel) - SPELL_DEMON_TRANSFORM_3 = 40510, // Final uiPhase of animations (stand up and roar) - SPELL_DEMON_FORM = 40506, // Transforms into Demon Illidan. Has an Aura of Dread on him. - SPELL_SHADOW_BLAST = 41078, // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target. - SPELL_FLAME_BURST = 41126, // Hurls fire at entire raid for ~3.5k damage every 10 seconds. Resistable. (Does not work: Script effect) - SPELL_FLAME_BURST_EFFECT = 41131, // The actual damage. Handled by core (41126 triggers 41131) + SPELL_DEMON_TRANSFORM_1 = 40511, // start transform animation - spell sequence: 40398, 40506, 40510 - handled in core + SPELL_DEMON_TRANSFORM_2 = 40398, // Second uiPhase of animations (kneel) + SPELL_DEMON_TRANSFORM_3 = 40510, // Final uiPhase of animations (stand up and roar) + SPELL_DEMON_FORM = 40506, // Transforms into Demon Illidan. Has an Aura of Dread on him. + SPELL_SHADOW_BLAST = 41078, // 8k - 11k Shadow Damage. Targets highest threat. Has a splash effect, damaging anyone in 20 yards of the target. + SPELL_FLAME_BURST = 41126, // triggers 41131 + SPELL_SUMMON_SHADOW_DEMONS = 41117, // summons 23375 + // Other Illidan spells - SPELL_KNEEL = 39656, // Before beginning encounter, this is how he appears (talking to Wilson). - SPELL_SHADOW_PRISON = 40647, // Illidan casts this spell to immobilize entire raid when he summons Maiev. - SPELL_DEATH = 41220, // This spell doesn't do anything except stun Illidan and set him on his knees. - SPELL_BERSERK = 45078, // Damage increased by 500%, attack speed by 150% - - // Non-Illidan spells - SPELL_AKAMA_DOOR_CHANNEL = 41268, // Akama's channel spell on the door before the Temple Summit - SPELL_DEATHSWORN_DOOR_CHANNEL = 41269, // Olum and Udalo's channel spell on the door before the Temple Summit - SPELL_AKAMA_DOOR_FAIL = 41271, // Not sure where this is really used... - SPELL_HEALING_POTION = 40535, // Akama uses this to heal himself to full. - SPELL_AZZINOTH_CHANNEL = 39857, // Glaives cast it on Flames. Not sure if this is the right spell. - SPELL_SHADOW_DEMON_PASSIVE = 41079, // Adds the "shadowform" uiAura to Shadow Demons. - SPELL_CONSUME_SOUL = 41080, // Once the Shadow Demons reach their target, they use this to kill them - SPELL_PARALYZE = 41083, // Shadow Demons cast this on their target - SPELL_PURPLE_BEAM = 39123, // Purple Beam connecting Shadow Demon to their target - SPELL_CAGE_TRAP_DUMMY = 40761, // Put this in DB for cage trap GO. - SPELL_EYE_BLAST_TRIGGER = 40017, // This summons Demon Form every few seconds and deals ~20k damage in its radius - SPELL_EYE_BLAST = 39908, // This does the blue flamey animation. - SPELL_FLAME_CRASH_EFFECT = 40836, // Firey blue ring of circle that the other flame crash summons - SPELL_BLAZE_EFFECT = 40610, // Green flame on the ground, triggers damage (5k) every few seconds - SPELL_BLAZE_SUMMON = 40637, // Summons the Blaze creature - SPELL_DEMON_FIRE = 40029, // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it. - SPELL_CAGED = 40695, // Caged Trap triggers will cast this on Illidan if he is within 3 yards - SPELL_CAGE_TRAP_SUMMON = 40694, // Summons a Cage Trap GO (bugged) on the ground along with a Cage Trap Disturb Trigger mob (working) - SPELL_CAGE_TRAP_BEAM = 40713, // 8 Triggers on the ground in an octagon cast spells like this on Illidan 'caging him' - SPELL_FLAME_BLAST = 40631, // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage. - SPELL_CHARGE = 40602, // Flames of Azzinoth charges whoever is too far from them. They enrage after this. For simplicity, we'll use the same enrage as Illidan. - SPELL_TELEPORT_VISUAL = 41232, // Teleport visual for Maiev - SPELL_SHADOWFIEND_PASSIVE = 41913, // Passive uiAura for shadowfiends - - EQUIP_ID_MAIN_HAND = 32837, - EQUIP_ID_OFF_HAND = 32838, + SPELL_KNEEL_INTRO = 39656, // Before beginning encounter, this is how he appears (talking to Wilson). + SPELL_SUMMMON_MAIEV = 40403, // summons 23197 + SPELL_TELEPORT_MAIEV = 41221, + SPELL_SHADOW_PRISON = 40647, // Illidan casts this spell to immobilize entire raid when he summons Maiev. + SPELL_CAGE_TRAP = 40693, // Cast by Illidan on Maiev - teleports Maiev for the trap + SPELL_DEATH = 41220, // This spell doesn't do anything except stun Illidan and set him on his knees. + SPELL_BERSERK = 45078, // Damage increased by 500%, attack speed by 150% + + + /************** Non-Illidan Spells *************/ + // Akama + SPELL_AKAMA_DOOR_FAIL = 41271, // Akama's first door attempt + SPELL_AKAMA_DOOR_CHANNEL = 41268, // Akama's channel spell on the door before the Temple Summit + SPELL_DEATHSWORN_DOOR_CHANNEL = 41269, // Olum and Udalo's channel spell on the door before the Temple Summit + SPELL_HEALING_POTION = 40535, // Akama uses this to heal himself to full. + SPELL_CHAIN_LIGHTNING = 40536, + + // Maiev + SPELL_SHADOW_STRIKE = 40685, + SPELL_THROW_DAGGER = 41152, + SPELL_CAGE_TRAP_SUMMON = 40694, // summons npc 23304 and go 185916 + SPELL_TELEPORT_VISUAL = 41236, + + // Misc Summoned + SPELL_FLAME_CRASH_EFFECT = 40836, // Firey blue ring of circle that the other flame crash summons + SPELL_EYE_BLAST_TRIGGER = 40017, // This summons Demon Form every few seconds and deals ~20k damage in its radius + // SPELL_DEMON_FIRE = 40029, // Blue fire trail left by Eye Blast. Deals 2k per second if players stand on it. + SPELL_BLAZE_EFFECT = 40610, // Green flame on the ground, triggers damage (5k) every few seconds + + // Blade of Azzinoth + SPELL_RANGE_MARKER = 41997, // Dummy effect used by the Blade of Azzinoth to check the range of the Azzinoth flame - needs core support + SPELL_SUMMON_TEAR_AZZINOTH = 39855, // Summons 22997 + SPELL_AZZINOTH_CHANNEL = 39857, // Glaives cast it on Flames + + // Flame of Azzinoth + SPELL_FLAME_BLAST = 40631, // Flames of Azzinoth use this. Frontal cone AoE 7k-9k damage. + SPELL_CHARGE = 42003, // Flames of Azzinoth charges whoever is too far from them. They enrage after this + SPELL_UNCAGED_WRATH = 39869, + SPELL_BLAZE = 40637, // summons 23259 + + // Shadow Demon + SPELL_SHADOW_DEMON_PASSIVE = 41079, // Adds the "shadowform" uiAura to Shadow Demons. + SPELL_CONSUME_SOUL = 41080, // Once the Shadow Demons reach their target, they use this to kill them + SPELL_PARALYZE = 41083, // Shadow Demons cast this on their target + + // Cage spells + SPELL_CAGE_TRAP_PERIODIC = 40760, // purpose unk + SPELL_CAGE_TRAP_DUMMY = 40761, // purpose unk + SPELL_CAGED = 40695, // Caged Trap triggers will cast this on Illidan if he is within 3 yards + + + /************** Creature Summons **************/ + NPC_ILLIDARI_ELITE = 23226, // attacks Akama on the stairs + NPC_FLAME_CRASH = 23336, // has aura 40836 + // NPC_PARASITIC_SHADOWFIEND = 23498, // has aura 41913 (in c_t_a) + NPC_BLADE_OF_AZZINOTH = 22996, // has aura 41997 and summons 22997 on spawn + NPC_FLAME_OF_AZZINOTH = 22997, + NPC_ILLIDAN_TARGET = 23070, // the eye blast target - has aura 40017 + // NPC_DEMON_FIRE = 23069, // has aura 40029 (in EventAI) + NPC_BLAZE = 23259, // has aura 40610 + NPC_SHADOW_DEMON = 23375, + // NPC_CAGE_TRAP_DISTURB_TRIGGER = 23304, + + GO_CAGE_TRAP = 185916, + + /************** Others **************/ + EQUIP_ID_MAIN_HAND = 32837, + EQUIP_ID_OFF_HAND = 32838, + + MAX_ILLIDARI_ELITES = 10, + MAX_CAGE_SPELLS = 8, + MAX_FLAME_AZZINOTH = 2, + + DUMMY_EMOTE_ID_1 = 1, + DUMMY_EMOTE_ID_2 = 2, + DUMMY_EMOTE_ID_3 = 3, }; -// Other defines -#define CENTER_X 676.740f -#define CENTER_Y 305.297f -#define CENTER_Z 353.192f +static const uint32 aCagedSummonSpells[MAX_CAGE_SPELLS] = { 40696, 40697, 40698, 40699, 40700, 40701, 40702, 40703 }; +static const uint32 aCagedVisualSpells[MAX_CAGE_SPELLS] = { 40704, 40707, 40708, 40709, 40710, 40711, 40712, 40713 }; -/*** Phase Names ***/ -enum Phase +static const DialogueEntry aIntroDialogue[] = { - PHASE_NORMAL = 1, - PHASE_FLIGHT = 2, - PHASE_NORMAL_2 = 3, - PHASE_DEMON = 4, - PHASE_NORMAL_MAIEV = 5, - PHASE_DEMON_SEQUENCE = 6, - PHASE_NORMAL_FORM = 7, // Internal marker, for switching back to either NORMAL_2 or NORMAL_MAIEV + {SAY_AKAMA_OPEN_DOOR_1, NPC_AKAMA, 4000}, + {SPELL_AKAMA_DOOR_FAIL, 0, 9000}, + {SAY_AKAMA_OPEN_DOOR_2, NPC_AKAMA, 6000}, + {NPC_SPIRIT_OF_OLUM, 0, 2000}, + {SAY_UDALO_OPEN_DOOR_3, NPC_SPIRIT_OF_UDALO, 2000}, + {SAY_OLUM_OPEN_DOOR_4, NPC_SPIRIT_OF_OLUM, 4000}, + {SPELL_AKAMA_DOOR_CHANNEL, 0, 11000}, + {GO_ILLIDAN_GATE, 0, 4000}, + {NPC_SPIRIT_OF_UDALO, 0, 0}, + {0, 0, 0}, }; -struct Locations +static const DialogueEntry aEventDialogue[] = { - float x, y, z; - uint32 id; + // Akama intro + {NPC_AKAMA, 0, 1000}, + {SAY_ILLIDAN_SPEECH_1, NPC_ILLIDAN_STORMRAGE, 3000}, + {EMOTE_ONESHOT_QUESTION, 0, 3000}, + {DUMMY_EMOTE_ID_1, 0, 3000}, + {DUMMY_EMOTE_ID_2, 0, 3000}, + {SAY_AKAMA_SPEECH_2, NPC_AKAMA, 10000}, + {SAY_ILLIDAN_SPEECH_3, NPC_ILLIDAN_STORMRAGE, 3000}, + {DUMMY_EMOTE_ID_3, 0, 4000}, + {SAY_AKAMA_SPEECH_4, NPC_AKAMA, 4000}, + {EQUIP_ID_MAIN_HAND, 0, 1000}, + {SAY_ILLIDAN_SPEECH_5, NPC_ILLIDAN_STORMRAGE, 4000}, + {NPC_ILLIDAN_STORMRAGE, 0, 0}, + // Akama leaves fight + {SAY_ILLIDAN_MINION, NPC_ILLIDAN_STORMRAGE, 8000}, + {SAY_AKAMA_LEAVE, NPC_AKAMA, 0}, + // Maiev cutscene + {SAY_ILLIDAN_SPEECH_6, NPC_ILLIDAN_STORMRAGE, 7000}, + {SPELL_SUMMMON_MAIEV, 0, 1000}, + {SAY_MAIEV_SPEECH_7, NPC_MAIEV_SHADOWSONG, 2000}, + {EMOTE_ONESHOT_EXCLAMATION, 0, 6000}, + {SAY_ILLIDAN_SPEECH_8, NPC_ILLIDAN_STORMRAGE, 7000}, + {SAY_MAIEV_SPEECH_9, NPC_MAIEV_SHADOWSONG, 2000}, + {EMOTE_ONESHOT_YES, 0, 5000}, + {NPC_MAIEV_SHADOWSONG, 0, 0}, + {0, 0, 0}, }; -static const Locations aGlaivePosition[]= +static const DialogueEntry aEpilogueDialogue[] = { - {695.105f, 305.303f, 354.256f}, - {659.338f, 305.303f, 354.256f}, - {700.105f, 305.303f, 354.256f}, - {664.338f, 305.303f, 354.256f} + {SAY_MAIEV_EPILOGUE_1, NPC_MAIEV_SHADOWSONG, 6000}, + {SAY_ILLIDAN_EPILOGUE_2, NPC_ILLIDAN_STORMRAGE, 18000}, + {NPC_ILLIDAN_STORMRAGE, 0, 2000}, + {SAY_MAIEV_EPILOGUE_3, NPC_MAIEV_SHADOWSONG, 13000}, + {SAY_MAIEV_EPILOGUE_4, NPC_MAIEV_SHADOWSONG, 2000}, + {SPELL_TELEPORT_VISUAL, 0, 0}, + {0, 0, 0}, }; -static const Locations aEyeBlast[]= +/*** Phase Names ***/ +enum Phase { - {650.697f, 320.128f, 353.730f}, - {652.799f, 275.091f, 353.367f}, - {701.527f, 273.815f, 353.230f}, - {709.865f, 325.654f, 353.322f} + PHASE_AKAMA = 1, + PHASE_BLADES = 2, + PHASE_DUAL_NORMAL = 3, + PHASE_DUAL_DEMON = 4, + PHASE_MAIEV = 5, + PHASE_TRANSITION = 6, }; -static const Locations aAkamaWP[]= -{ - {770.01f, 304.50f, 312.29f}, // Bottom of the first stairs, at the doors - {780.66f, 304.50f, 319.74f}, // Top of the first stairs - {790.13f, 319.68f, 319.76f}, // Bottom of the second stairs (left from the entrance) - {787.17f, 347.38f, 341.42f}, // Top of the second stairs - {781.34f, 350.31f, 341.44f}, // Bottom of the third stairs - {762.60f, 361.06f, 353.60f}, // Top of the third stairs - {756.35f, 360.52f, 353.27f}, // Before the door-thingy - {743.82f, 342.21f, 353.00f}, // Somewhere further - {732.69f, 305.13f, 353.00f}, // In front of Illidan - {738.11f, 365.44f, 353.00f}, // in front of the door-thingy (the other one!) - {792.18f, 366.62f, 341.42f}, // Down the first flight of stairs - {796.84f, 304.89f, 319.76f}, // Down the second flight of stairs - {782.01f, 304.55f, 319.76f} // Final location - back at the uiInitial gates. This is where he will fight the minions! -}; -// 755.762, 304.0747, 312.1769 -- This is where Akama should be spawned -static const Locations aSpiritSpawns[]= +struct Locations { - {755.5426f, 309.9156f, 312.2129f, SPIRIT_OF_UDALO}, - {755.5426f, 298.7923f, 312.0834f, SPIRIT_OF_OLUM} + float fX, fY, fZ; }; -struct WayPoints +static const Locations aCenterLoc[] = { - WayPoints(uint32 _id, float _x, float _y, float _z) - { - id = _id; - x = _x; - y = _y; - z = _z; - } - uint32 id; - float x, y, z; + {705.012f, 305.721f, 354.723f}, // front location + {676.740f, 305.297f, 353.192f}, // center location }; -struct Animation // For the demon transformation +static const Locations aIllidariElitesPos[MAX_ILLIDARI_ELITES] = { - uint32 uiAura, uiUnAura, uiTimer, uiSize, uiDisplayId; - Phase uiPhase; - bool bEquip; + {743.9686f, 289.6447f, 311.1807f}, + {753.8425f, 286.562f, 310.9353f}, + {745.2552f, 322.1574f, 310.4596f}, + {745.3237f, 283.986f, 309.2765f}, + {750.0472f, 282.3274f, 309.4353f}, + {747.0576f, 326.4268f, 309.0688f}, + {751.0878f, 327.6505f, 309.4576f}, + {748.8422f, 288.062f, 310.9782f}, + {750.0322f, 323.6064f, 310.2757f}, + {754.0332f, 325.8136f, 310.3195f}, }; -static Animation DemonTransformation[]= +static const Locations aEyeBlastPos[] = { - {SPELL_DEMON_TRANSFORM_1, 0, 1300, 0, 0, PHASE_DEMON_SEQUENCE, true}, - {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, PHASE_DEMON_SEQUENCE, true}, - {SPELL_DEMON_FORM, 0, 3000, 1073741824, 21322, PHASE_DEMON_SEQUENCE, false}, - {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, PHASE_DEMON_SEQUENCE, false}, - {0, 0, 0, 0, 0, PHASE_DEMON, false}, - {SPELL_DEMON_TRANSFORM_1, 0, 1500, 0, 0, PHASE_DEMON_SEQUENCE, false}, - {SPELL_DEMON_TRANSFORM_2, SPELL_DEMON_TRANSFORM_1, 4000, 0, 0, PHASE_DEMON_SEQUENCE, false}, - {0, SPELL_DEMON_FORM, 3000, 1069547520, 21135, PHASE_DEMON_SEQUENCE, false}, - {SPELL_DEMON_TRANSFORM_3, SPELL_DEMON_TRANSFORM_2, 3500, 0, 0, PHASE_DEMON_SEQUENCE, true}, - {0, 0, 0, 0, 0, PHASE_NORMAL_FORM, true} + // spawn + {650.600f, 258.124f, 352.996f}, // back left + {651.867f, 353.212f, 352.996f}, // back right + {710.010f, 266.950f, 352.996f}, // front left + {711.003f, 343.562f, 352.996f}, // front right + // target - left + {742.212f, 338.333f, 352.996f}, // front right + {674.559f, 375.761f, 352.996f}, // back right + // target - right + {741.545f, 270.640f, 352.996f}, // front left + {671.943f, 235.718f, 352.996f}, // back left + // center back + {639.511f, 305.852f, 353.264f} }; -/**** Demon Fire will be used for Eye Blast. Illidan needs to have access to it's vars and functions, so we'll set it here ****/ -struct MANGOS_DLL_DECL demonfireAI : public ScriptedAI +/*###### +## boss_illidan_stormrage +######*/ + +struct boss_illidan_stormrageAI : public ScriptedAI, private DialogueHelper { - demonfireAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_illidan_stormrageAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aEventDialogue) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_black_temple*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); } - ScriptedInstance* m_pInstance; - - ObjectGuid m_illidanGuid; - - bool m_bIsTrigger; - - uint32 m_uiCheckTimer; - uint32 m_uiDemonFireTimer; - uint32 m_uiDespawnTimer; - - void Reset() - { - m_illidanGuid.Clear(); - - m_bIsTrigger = false; - - m_uiCheckTimer = 2000; - m_uiDemonFireTimer = 0; - m_uiDespawnTimer = 45000; - } - - void AttackStart(Unit* who) { } - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 uiDiff) - { - if (m_bIsTrigger) - return; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if (m_uiCheckTimer < uiDiff) - { - if (!m_illidanGuid && m_pInstance) - { - if (Creature* pIllidan = m_pInstance->instance->GetCreature(m_pInstance->GetGuid(NPC_ILLIDAN_STORMRAGE))) - { - m_illidanGuid = m_pInstance->GetGuid(NPC_ILLIDAN_STORMRAGE); - - if (!pIllidan->IsLevitating()) - m_creature->SetDeathState(JUST_DIED); - } - } - m_uiCheckTimer = 2000; - } - else - m_uiCheckTimer -= uiDiff; - - if (m_uiDemonFireTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_DEMON_FIRE); - m_uiDemonFireTimer = 30000; - } - else - m_uiDemonFireTimer -= uiDiff; + instance_black_temple* m_pInstance; - if (m_uiDespawnTimer < uiDiff) - m_creature->SetDeathState(JUST_DIED); - else - m_uiDespawnTimer -= uiDiff; - } -}; + Phase m_uiPhase; + uint32 m_uiBerserkTimer; -/******* Functions and vars for Akama's AI ******/ -struct MANGOS_DLL_DECL npc_akama_illidanAI : public ScriptedAI -{ - npc_akama_illidanAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - WayPointList.clear(); - Reset(); - } + bool m_bHasSummonedElites; + float m_fTargetMoveX, m_fTargetMoveY, m_fTargetMoveZ; - /* Instance Data */ - ScriptedInstance* m_pInstance; + uint32 m_uiShearTimer; + uint32 m_uiDrawSoulTimer; + uint32 m_uiFlameCrashTimer; + uint32 m_uiShadowFiendTimer; - /* Timers */ - uint32 m_uiChannelTimer; - uint32 m_uiTalkTimer; - uint32 m_uiWalkTimer; - uint32 m_uiSummonMinionTimer; + uint32 m_uiFireballTimer; + uint32 m_uiEyeBlastTimer; + uint32 m_uiDarkBarrageTimer; + uint32 m_uiSummonBladesTimer; // Animate summoning the Blades of Azzinoth in Phase 2 + uint32 m_uiCenterMoveTimer; + uint32 m_uiLandTimer; // This is used at the end of uiPhase 2 to signal Illidan landing after Flames are dead + uint8 m_uiLandStage; + uint8 m_uiFlameAzzinothKilled; - /* GUIDs */ - ObjectGuid m_illidanGuid; - ObjectGuid m_playerGuid; - ObjectGuid m_aSpiritGuids[2]; - ObjectGuid m_channelGuid; + uint32 m_uiAgonizingFlamesTimer; + uint32 m_uiTransformTimer; - bool m_bIsTalking; - bool m_bStartChanneling; - bool m_bDoorOpen; - bool m_bFightMinions; - bool m_bIsReturningToIllidan; - bool m_bIsWalking; - uint32 m_uiTalkCount; - uint32 m_uiChannelCount; + uint32 m_uiShadowBlastTimer; + uint32 m_uiFlameBurstTimer; + uint32 m_uiShadowDemonTimer; + Phase m_uiPrevPhase; // store the previous phase in transition - std::list WayPointList; - std::list::iterator WayPoint; + uint32 m_uiEnrageTimer; + uint32 m_uiTrapTimer; - void BeginEvent(ObjectGuid playerGuid); + GuidList m_lBladesGuidList; - void Reset() + void Reset() override { - if (m_pInstance) - { - m_pInstance->SetData(TYPE_ILLIDAN, NOT_STARTED); - GameObject* pGate = m_pInstance->GetSingleGameObjectFromStorage(GO_ILLIDAN_GATE); + m_uiPhase = PHASE_AKAMA; + m_uiBerserkTimer = 25 * MINUTE * IN_MILLISECONDS; - // close door if already open (when raid wipes or something) - if (pGate && !pGate->GetGoState()) - pGate->SetGoState(GO_STATE_READY); + m_bHasSummonedElites = false; - for(uint32 i = GO_ILLIDAN_DOOR_R; i <= GO_ILLIDAN_DOOR_L; ++i) - { - if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(i)) - pDoor->SetGoState(GO_STATE_ACTIVE); - } - } + m_uiShearTimer = urand(10000, 15000); + m_uiFlameCrashTimer = 30000; + m_uiShadowFiendTimer = 25000; + m_uiDrawSoulTimer = 35000; - m_illidanGuid.Clear(); - m_playerGuid.Clear(); - m_channelGuid.Clear(); - for(uint8 i = 0; i < 2; ++i) - m_aSpiritGuids[i].Clear(); + m_uiFlameAzzinothKilled = 0; + m_uiSummonBladesTimer = 0; + m_uiCenterMoveTimer = 0; + m_uiFireballTimer = 5000; + m_uiDarkBarrageTimer = 45000; + m_uiEyeBlastTimer = 15000; + m_uiLandTimer = 0; + m_uiLandStage = 0; - m_uiChannelTimer = 0; - m_uiChannelCount = 0; - m_uiSummonMinionTimer = 2000; + m_uiAgonizingFlamesTimer = 35000; + m_uiTransformTimer = 0; - m_uiWalkTimer = 0; - m_bIsWalking = false; + m_uiShadowBlastTimer = urand(1000, 2000); + m_uiFlameBurstTimer = 10000; + m_uiShadowDemonTimer = 30000; - m_uiTalkTimer = 0; - m_uiTalkCount = 0; + m_uiEnrageTimer = 40000; + m_uiTrapTimer = urand(30000, 40000); - KillAllElites(); + m_lBladesGuidList.clear(); - m_bIsReturningToIllidan = false; - m_bFightMinions = false; - m_bIsTalking = false; - m_bStartChanneling = false; - m_bDoorOpen = false; + // Reset boss + m_creature->SetLevitate(false); + SetCombatMovement(true); - // Database sometimes has strange values.. - m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->SetVisibility(VISIBILITY_ON); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); } - // Do not call reset in Akama's evade mode, as this will stop him from summoning minions after he kills the first bit - void EnterEvadeMode() + void GetAIInformation(ChatHandler& reader) override { - m_creature->RemoveAllAuras(); - m_creature->DeleteThreatList(); - m_creature->CombatStop(true); + reader.PSendSysMessage("Boss Illidan, current uiPhase = %u", m_uiPhase); } - void KillAllElites() + void Aggro(Unit* /*pWho*/) override { - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator itr = vGuids.begin();itr != vGuids.end(); ++itr) - { - Unit* pUnit = m_creature->GetMap()->GetUnit(*itr); - - if (pUnit && pUnit->GetTypeId() == TYPEID_UNIT && pUnit->GetEntry() == ILLIDARI_ELITE) - pUnit->SetDeathState(JUST_DIED); - } + if (m_pInstance) + m_pInstance->SetData(TYPE_ILLIDAN, IN_PROGRESS); } - void ReturnToIllidan() + // Do not attack using LoS function. The attack is triggered in script + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustReachedHome() override { - KillAllElites(); - m_bFightMinions = false; - m_bIsReturningToIllidan = true; - WayPoint = WayPointList.begin(); - m_creature->SetSpeedRate(MOVE_RUN, 2.0f); - m_creature->SetWalk(false); - m_bIsWalking = true; + if (m_pInstance) + m_pInstance->SetData(TYPE_ILLIDAN, FAIL); } - void AddWaypoint(uint32 id, float x, float y, float z) + void JustDied(Unit* /*pKiller*/) override { - WayPoints AWP(id, x, y, z); - WayPointList.push_back(AWP); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (m_pInstance) + m_pInstance->SetData(TYPE_ILLIDAN, DONE); } - void DamageTaken(Unit* pDealer, uint32& uiDamage) + void KilledUnit(Unit* pVictim) override { - if (uiDamage > m_creature->GetHealth() && (pDealer != m_creature)) - { - uiDamage = 0; - DoCastSpellIfCan(m_creature, SPELL_HEALING_POTION); - } + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); } - void BeginDoorEvent(Player* pPlayer) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { - // Requires Instance and this additional check to prevent exploits - if (!m_pInstance || m_pInstance->GetData(TYPE_COUNCIL) != DONE) + if (uiDamage < m_creature->GetHealth()) return; - debug_log("SD2: Akama - Door event initiated by player %s", pPlayer->GetObjectGuid().GetString().c_str()); - m_playerGuid = pPlayer->GetObjectGuid(); - - if (GameObject* pGate = m_pInstance->GetSingleGameObjectFromStorage(GO_ILLIDAN_GATE)) + // Make sure it won't die by accident + if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) { - float x,y,z; - pGate->GetPosition(x, y, z); - Creature* Channel = m_creature->SummonCreature(ILLIDAN_DOOR_TRIGGER, x, y, z+5, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); - if (Channel) - { - m_channelGuid = Channel->GetObjectGuid(); + uiDamage = 0; + return; + }; - // Invisible but spell visuals can still be seen. - Channel->SetDisplayId(11686); - Channel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + uiDamage = 0; + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); - float PosX, PosY, PosZ; - m_creature->GetPosition(PosX, PosY, PosZ); - for(uint8 i = 0; i < 2; ++i) - { - Creature* Spirit = m_creature->SummonCreature(aSpiritSpawns[i].id, aSpiritSpawns[i].x, aSpiritSpawns[i].y, aSpiritSpawns[i].z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000); - if (Spirit) - { - Spirit->SetVisibility(VISIBILITY_OFF); - m_aSpiritGuids[i] = Spirit->GetObjectGuid(); - } - } + DoCastSpellIfCan(m_creature, SPELL_DEATH, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_TELEPORT_MAIEV, CAST_TRIGGERED); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); - m_bStartChanneling = true; - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCastSpellIfCan(Channel, SPELL_AKAMA_DOOR_FAIL); - } + // Signal Maiev to start the outro dialogue + if (m_pInstance) + { + if (Creature* pMaiev = m_pInstance->GetSingleCreatureFromStorage(NPC_MAIEV_SHADOWSONG)) + pMaiev->AI()->KilledUnit(m_creature); } } - void MovementInform(uint32 type, uint32 id) + void JustDidDialogueStep(int32 iEntry) override { - if (type != POINT_MOTION_TYPE || !m_bIsWalking) - return; - - if (WayPoint->id != id) - return; - - switch(id) + switch (iEntry) { - case 6: - if (!m_bIsReturningToIllidan) + case NPC_AKAMA: + if (m_pInstance) + { + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA)) + m_creature->SetFacingToObject(pAkama); + } + m_creature->RemoveAurasDueToSpell(SPELL_KNEEL_INTRO); + break; + case EMOTE_ONESHOT_QUESTION: + case DUMMY_EMOTE_ID_1: + case DUMMY_EMOTE_ID_2: + case DUMMY_EMOTE_ID_3: + m_creature->HandleEmote(EMOTE_ONESHOT_QUESTION); + break; + case EQUIP_ID_MAIN_HAND: + SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE); + break; + case NPC_ILLIDAN_STORMRAGE: + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + m_creature->SetInCombatWithZone(); + if (m_pInstance) { - // open the doors that close the summit - for(uint32 i = GO_ILLIDAN_DOOR_R; i < GO_ILLIDAN_DOOR_L+1; ++i) + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA)) { - if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(i)) - pDoor->SetGoState(GO_STATE_ACTIVE); + pAkama->AI()->AttackStart(m_creature); + AttackStart(pAkama); } } break; - case 7: - if (m_bIsReturningToIllidan) + case SAY_AKAMA_LEAVE: + DoResetThreat(); + if (m_pInstance) { - m_bIsWalking = false; - if (m_illidanGuid) + // Remove Akama from threat list and allow him to fight the Illidari elites + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA)) { - Creature* Illidan = m_creature->GetMap()->GetCreature(m_illidanGuid); - if (Illidan) - { - float dx = Illidan->GetPositionX() + rand()%15; - float dy = Illidan->GetPositionY() + rand()%15; - m_creature->GetMotionMaster()->MovePoint(13, dx, dy, Illidan->GetPositionZ()); - m_creature->SetTargetGuid(Illidan->GetObjectGuid()); - } + pAkama->AI()->EnterEvadeMode(); + m_creature->getThreatManager().modifyThreatPercent(pAkama, -101); } } break; - case 8: - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - if (!m_bIsReturningToIllidan) + case SPELL_SUMMMON_MAIEV: + DoCastSpellIfCan(m_creature, SPELL_SUMMMON_MAIEV); + break; + case EMOTE_ONESHOT_EXCLAMATION: + if (m_pInstance) { - m_bIsWalking = false; - BeginEvent(m_playerGuid); + if (Creature* pMaiev = m_pInstance->GetSingleCreatureFromStorage(NPC_MAIEV_SHADOWSONG)) + pMaiev->HandleEmote(EMOTE_ONESHOT_EXCLAMATION); } break; - case 12: - m_bIsWalking = false; - m_bFightMinions = true; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + case EMOTE_ONESHOT_YES: + if (m_pInstance) + { + if (Creature* pMaiev = m_pInstance->GetSingleCreatureFromStorage(NPC_MAIEV_SHADOWSONG)) + pMaiev->HandleEmote(EMOTE_ONESHOT_YES); + } + break; + case NPC_MAIEV_SHADOWSONG: + // Resume combat and attack Maiev + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->SetTargetGuid(m_creature->getVictim()->GetObjectGuid()); + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + if (m_pInstance) + { + if (Creature* pMaiev = m_pInstance->GetSingleCreatureFromStorage(NPC_MAIEV_SHADOWSONG)) + pMaiev->AI()->AttackStart(m_creature); + } + m_uiPhase = PHASE_MAIEV; + m_uiTransformTimer = 60000; break; } + } - ++WayPoint; - m_uiWalkTimer = 200; + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_FLAME_CRASH: + pSummoned->CastSpell(pSummoned, SPELL_FLAME_CRASH_EFFECT, false); + break; + case NPC_BLADE_OF_AZZINOTH: + pSummoned->CastSpell(pSummoned, SPELL_RANGE_MARKER, true); + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_TEAR_AZZINOTH, true); + m_lBladesGuidList.push_back(pSummoned->GetObjectGuid()); + break; + case NPC_ILLIDAN_TARGET: + pSummoned->SetWalk(false); + pSummoned->CastSpell(pSummoned, SPELL_EYE_BLAST_TRIGGER, true); + pSummoned->GetMotionMaster()->MovePoint(0, m_fTargetMoveX, m_fTargetMoveY, m_fTargetMoveZ); + DoCastSpellIfCan(pSummoned, SPELL_EYE_BLAST_DUMMY, CAST_TRIGGERED); + break; + case NPC_SHADOW_DEMON: + pSummoned->CastSpell(pSummoned, SPELL_SHADOW_DEMON_PASSIVE, true); + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_PARALYZE, SELECT_FLAG_PLAYER)) + { + // Dummy attack function - used only to set the target + pSummoned->AI()->AttackStart(pTarget); + pSummoned->CastSpell(pTarget, SPELL_PARALYZE, true); + + // Move towards target (which is stunned) + float fX, fY, fZ; + pTarget->GetContactPoint(pSummoned, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + break; + case NPC_MAIEV_SHADOWSONG: + pSummoned->SetFacingToObject(m_creature); + m_creature->SetTargetGuid(pSummoned->GetObjectGuid()); + break; + } } - void DeleteFromThreatList() + // Wrapper to start the combat dialogue + void DoStartCombatEvent() { StartNextDialogueText(NPC_AKAMA); } + + // Wrapper to land Illidan when both flames are killed + void DoInformFlameKilled() { - // If we do not have Illidan's GUID, do not proceed - if (!m_illidanGuid) - return; + // Land Illidan if both Flames are killed + ++m_uiFlameAzzinothKilled; - // Create a pointer to Illidan - Creature* Illidan = m_creature->GetMap()->GetCreature(m_illidanGuid); + if (m_uiFlameAzzinothKilled == MAX_FLAME_AZZINOTH) + { + m_uiLandTimer = 5000; + m_uiPhase = PHASE_TRANSITION; + m_creature->InterruptNonMeleeSpells(false); + } + } - // No use to continue if Illidan does not exist - if (!Illidan) - return; + // Wrapper to handle the Eye Blast cast + bool DoCastEyeBlastIfCan() + { + if (m_creature->IsNonMeleeSpellCasted(false)) + return false; + + DoScriptText(SAY_EYE_BLAST, m_creature); - ThreatList const& tList = Illidan->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + // Set spawn and target loc + uint8 uiSpawnLoc = urand(0, 3); + uint8 uiTargetLoc = 0; + switch (uiSpawnLoc) { - // Loop through threatlist till our Guid is found in it. - if ((*itr)->getUnitGuid() == m_creature->GetObjectGuid()) - { - (*itr)->removeReference(); // Delete ourself from his threatlist. - break; // No need to continue anymore. - } + case 0: uiTargetLoc = urand(4, 5); break; + case 1: uiTargetLoc = urand(6, 7); break; + case 2: uiTargetLoc = urand(0, 1) ? 5 : 8; break; + case 3: uiTargetLoc = urand(7, 8); break; } - // Now we delete our threatlist to prevent attacking anyone for now - m_creature->DeleteThreatList(); - // Also we remove all auras, to prevent delayed damage - m_creature->RemoveAllAuras(); + m_fTargetMoveX = aEyeBlastPos[uiTargetLoc].fX; + m_fTargetMoveY = aEyeBlastPos[uiTargetLoc].fY; + m_fTargetMoveZ = aEyeBlastPos[uiTargetLoc].fZ; + m_creature->SummonCreature(NPC_ILLIDAN_TARGET, aEyeBlastPos[uiSpawnLoc].fX, aEyeBlastPos[uiSpawnLoc].fY, aEyeBlastPos[uiSpawnLoc].fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); + + return true; } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_pInstance) + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_illidanGuid) + // Make Akama evade combat at 85% + if (!m_bHasSummonedElites && m_creature->GetHealthPercent() < 85.0f) { - if (Creature* Illidan = m_creature->GetMap()->GetCreature(m_illidanGuid)) - { - if (Illidan->GetHealthPercent() < 85.0f && m_creature->isInCombat() && !m_bFightMinions) - { - if (m_uiTalkTimer < diff) - { - switch(m_uiTalkCount) - { - case 0: - DoScriptText(SAY_AKAMA_MINION, Illidan); - m_uiTalkTimer = 8000; - m_uiTalkCount = 1; - break; - case 1: - DoScriptText(SAY_AKAMA_LEAVE, m_creature); - m_uiTalkTimer = 3000; - m_uiTalkCount = 2; - break; - case 2: - m_bIsTalking = true; - m_uiTalkTimer = 2000; - m_creature->RemoveAllAuras(); - m_creature->CombatStop(true); - m_creature->AttackStop(); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_uiTalkCount = 3; - break; - case 3: - DeleteFromThreatList(); - m_bIsWalking = true; - WayPoint = WayPointList.begin(); - std::advance(WayPoint, 9); - m_creature->SetWalk(false); - break; - } - } - else - m_uiTalkTimer -= diff; - } - - if (Illidan->GetHealthPercent() < 4.0f && !m_bIsReturningToIllidan) - ReturnToIllidan(); - } + StartNextDialogueText(SAY_ILLIDAN_MINION); + m_bHasSummonedElites = true; } - else - m_illidanGuid = m_pInstance->GetGuid(NPC_ILLIDAN_STORMRAGE); - // Reset Encounter - if (m_pInstance->GetData(TYPE_ILLIDAN) == FAIL) + // Phase 1 to 2 transition + if (m_uiPhase == PHASE_AKAMA && m_creature->GetHealthPercent() < 65.0f) { - m_pInstance->SetData(TYPE_ILLIDAN, NOT_STARTED); - - m_creature->GetMotionMaster()->Clear(false); - Reset(); - // Get Akama Home - float fX, fY, fZ, fO; - m_creature->GetRespawnCoord(fX, fY, fZ, &fO); - m_creature->NearTeleportTo(fX, fY, fZ, fO); + DoScriptText(SAY_TAKEOFF, m_creature); + m_uiSummonBladesTimer = 10000; + m_uiCenterMoveTimer = 2000; + m_uiPhase = PHASE_BLADES; + m_creature->RemoveAllAuras(); + m_creature->SetLevitate(true); + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->HandleEmote(EMOTE_ONESHOT_LIFTOFF); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); return; } - if (m_bIsWalking && m_uiWalkTimer) + // Summon Maiev at 30% hp + if (m_uiPhase == PHASE_DUAL_NORMAL && m_creature->GetHealthPercent() <= 30.0f) { - if (m_uiWalkTimer <= diff) + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_PRISON, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - if (WayPoint == WayPointList.end()) - return; + StartNextDialogueText(SAY_ILLIDAN_SPEECH_6); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); - m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y,WayPoint->z); - m_uiWalkTimer = 0; - }else m_uiWalkTimer -= diff; + m_uiPhase = PHASE_TRANSITION; + m_uiTransformTimer = 0; + } + return; } - if (m_bStartChanneling) + if (m_uiBerserkTimer) { - if (m_uiChannelTimer < diff) + if (m_uiBerserkTimer <= uiDiff) { - switch(m_uiChannelCount) + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) { - case 3: - if (!m_bDoorOpen) - { - m_creature->InterruptNonMeleeSpells(true); - - for(uint8 i = 0; i < 2; ++i) - { - if (m_aSpiritGuids[i]) - { - Creature* Spirit = m_creature->GetMap()->GetCreature(m_aSpiritGuids[i]); - if (Spirit) - Spirit->InterruptNonMeleeSpells(true); - } - } - - if (GameObject* pGate = m_pInstance->GetSingleGameObjectFromStorage(GO_ILLIDAN_GATE)) - pGate->SetGoState(GO_STATE_ACTIVE); - - ++m_uiChannelCount; - m_uiChannelTimer = 5000; - } - break; - case 4: - m_creature->HandleEmote(EMOTE_ONESHOT_SALUTE); - m_uiChannelTimer = 2000; - ++m_uiChannelCount; - break; - case 5: - DoScriptText(SAY_AKAMA_BEWARE, m_creature); - if (m_channelGuid) - { - Creature* ChannelTarget = m_creature->GetMap()->GetCreature(m_channelGuid); - if (ChannelTarget) - ChannelTarget->SetDeathState(JUST_DIED); - m_channelGuid.Clear(); - } - for(uint8 i = 0; i < 2; ++i) - { - if (m_aSpiritGuids[i]) - { - Creature* Spirit = m_creature->GetMap()->GetCreature(m_aSpiritGuids[i]); - if (Spirit) - Spirit->SetDeathState(JUST_DIED); - } - } - m_uiChannelTimer = 6000; - ++m_uiChannelCount; - break; - case 6: - m_bStartChanneling = false; - if (WayPointList.empty()) - { - error_log("SD2: Akama has no waypoints to start with!"); - return; - } - - WayPoint = WayPointList.begin(); - m_creature->SetWalk(true); - m_creature->GetMotionMaster()->MovePoint(WayPoint->id, WayPoint->x, WayPoint->y, WayPoint->z); - m_bIsWalking = true; - break; - default: - if (m_channelGuid) - { - Creature* Channel = m_creature->GetMap()->GetCreature(m_channelGuid); - if (Channel) - { - m_creature->InterruptNonMeleeSpells(true); - - for(uint8 i = 0; i < 2; ++i) - { - if (m_aSpiritGuids[i]) - { - Creature* Spirit = m_creature->GetMap()->GetCreature(m_aSpiritGuids[i]); - if (Spirit) - { - Spirit->InterruptNonMeleeSpells(true); - if (m_uiChannelCount%2 == 0) - { - Spirit->CastSpell(Channel, SPELL_DEATHSWORN_DOOR_CHANNEL,false); - DoCastSpellIfCan(Channel, SPELL_AKAMA_DOOR_CHANNEL); - } - else - { - if (Spirit->GetVisibility() == VISIBILITY_OFF) - Spirit->SetVisibility(VISIBILITY_ON); - } - } - } - } - if (m_uiChannelCount < 3) - ++m_uiChannelCount; - m_uiChannelTimer = 10000; - } - } - break; + DoScriptText(SAY_BERSERK, m_creature); + m_uiBerserkTimer = 0; } } else - m_uiChannelTimer -= diff; + m_uiBerserkTimer -= uiDiff; } - if (m_bFightMinions) + switch (m_uiPhase) { - if (m_uiSummonMinionTimer < diff) - { - float x,y,z; - m_creature->GetPosition(x,y,z); - Creature* Elite = m_creature->SummonCreature(ILLIDARI_ELITE, x+rand()%10, y+rand()%10, z, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); - if (Elite) + case PHASE_MAIEV: + + // Phase 5 spell only + if (m_uiEnrageTimer < uiDiff) { - Elite->AI()->AttackStart(m_creature); - Elite->AddThreat(m_creature, 1000000.0f); - AttackStart(Elite); + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(SAY_FRENZY, m_creature); + m_uiEnrageTimer = 40000; + } } - m_uiSummonMinionTimer = urand(10000, 16000); - } - else - m_uiSummonMinionTimer -= diff; - } + else + m_uiEnrageTimer -= uiDiff; - // If we don't have a target, or is talking, or has run away, return - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiTrapTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CAGE_TRAP) == CAST_OK) + m_uiTrapTimer = urand(40000, 50000); + } + else + m_uiTrapTimer -= uiDiff; - DoMeleeAttackIfReady(); - } -}; + // no break; + case PHASE_DUAL_NORMAL: -/************************************** Illidan's AI ***************************************/ -struct MANGOS_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI -{ - boss_illidan_stormrageAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - /** Instance Data **/ - ScriptedInstance* m_pInstance; - - /** Generic **/ - bool m_bIsTalking; - bool m_bHasSummoned; - bool m_bRefaceVictim; - uint32 m_uiPhase; - uint32 m_uiGlobalTimer; - uint32 m_uiTalkCount; - uint32 m_uiDemonFormSequence; - - /** GUIDs **/ - ObjectGuid m_flameGuids[2]; - ObjectGuid m_glaiveGuids[2]; - ObjectGuid m_akamaGuid; - ObjectGuid m_maievGuid; - - /** Timers **/ - uint32 m_uiShearTimer; - uint32 m_uiDrawSoulTimer; - uint32 m_uiFlameCrashTimer; - uint32 m_uiParasiticShadowFiendTimer; - uint32 m_uiFireballTimer; - uint32 m_uiEyeBlastTimer; - uint32 m_uiDarkBarrageTimer; - uint32 m_uiSummonBladesTimer; // Animate summoning the Blades of Azzinoth in Phase 2 - uint32 m_uiSummonFlamesTimer; // Summon Flames of Azzinoth in Phase 2 - uint32 m_uiCheckFlamesTimer; // This is used to check the status of the Flames to see if we should begin entering Phase 3 or not. - uint32 m_uiRetrieveBladesTimer; // Animate retrieving the Blades of Azzinoth in Phase 2 -> 3 transition - uint32 m_uiLandTimer; // This is used at the end of uiPhase 2 to signal Illidan landing after Flames are dead - uint32 m_uiAgonizingFlamesTimer; - uint32 m_uiShadowBlastTimer; - uint32 m_uiFlameBurstTimer; - uint32 m_uiShadowDemonTimer; - uint32 m_uiTalkTimer; - uint32 m_uiTransformTimer; - uint32 m_uiEnrageTimer; - uint32 m_uiCageTimer; - uint32 m_uiLayTrapTimer; - uint32 m_uiAnimationTimer; - uint32 m_uiTauntTimer; // This is used for his random yells - uint32 m_uiFaceVictimTimer; - uint32 m_uiBerserkTimer; - - void Reset() - { - m_uiPhase = PHASE_NORMAL; - - m_bRefaceVictim = false; - m_bHasSummoned = false; - - m_uiFaceVictimTimer = 1000; - m_uiBerserkTimer = 1500000; - m_uiGlobalTimer = 0; - m_uiDemonFormSequence = 0; - - /** Normal Form **/ - m_uiShearTimer = urand(20000, 30000); // 20 to 30 seconds - m_uiFlameCrashTimer = 30000; // 30 seconds - m_uiParasiticShadowFiendTimer = 25000; // 25 seconds - m_uiDrawSoulTimer = 50000; // 50 seconds - - /** Phase 2 **/ - m_uiSummonBladesTimer = 10000; - m_uiSummonFlamesTimer = 20000; // Phase 2 timers may be incorrect - m_uiFireballTimer = 5000; - m_uiDarkBarrageTimer = 45000; - m_uiEyeBlastTimer = 30000; - m_uiCheckFlamesTimer = 5000; - m_uiRetrieveBladesTimer = 5000; - m_uiLandTimer = 0; - - /** Phase 3+ **/ - m_uiAgonizingFlamesTimer = 35000; // Phase 3+ timers may be incorrect - m_uiShadowBlastTimer = 3000; - m_uiFlameBurstTimer = 10000; - m_uiShadowDemonTimer = 30000; - m_uiTransformTimer = 90000; - m_uiEnrageTimer = 40000; - m_uiCageTimer = 30000; - m_uiLayTrapTimer = m_uiCageTimer + 2000; - m_uiAnimationTimer = 0; - - m_uiTauntTimer = 30000; // This timer may be off. - - m_creature->SetDisplayId(21135); - m_creature->InterruptNonMeleeSpells(false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - // Unequip warglaives if needed - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); - - m_creature->SetLevitate(false); - - m_bIsTalking = false; - - m_uiTalkCount = 0; - m_uiTalkTimer = 0; - - SetCombatMovement(false); // Start idle - } - - void GetAIInformation(ChatHandler& reader) - { - reader.PSendSysMessage("Boss Illidan, current uiPhase = %u, m_uiDemonFormSequence = %u", m_uiPhase, m_uiDemonFormSequence); - reader.PSendSysMessage("Boolean Vars: m_bIsTalking is %s, m_bHasSummoned is %s, m_bRefaceVictim is %s", m_bIsTalking ? "true" : "false", m_bHasSummoned ? "true" : "false", m_bRefaceVictim ? "true" : "false"); - reader.PSendSysMessage("Guids: Akama is %s, Maiev is %s", m_akamaGuid.GetString().c_str(), m_maievGuid.GetString().c_str()); - } - - void JustReachedHome() - { - // Check if Maiev are alive/existing. Despawn and clear Guid - if (Creature* Maiev = m_creature->GetMap()->GetCreature(m_maievGuid)) - Maiev->ForcedDespawn(); - m_maievGuid.Clear(); - - // Check if any flames/glaives are alive/existing. Kill if alive and clear Guids - for (uint8 i = 0; i < 2; ++i) - { - if (Creature* pFlame = m_creature->GetMap()->GetCreature(m_flameGuids[i])) - { - if (pFlame->isAlive()) - pFlame->SetDeathState(JUST_DIED); - - m_flameGuids[i].Clear(); - } - - if (Creature* pGlaive = m_creature->GetMap()->GetCreature(m_glaiveGuids[i])) - { - if (pGlaive->isAlive()) - pGlaive->SetDeathState(JUST_DIED); - - m_glaiveGuids[i].Clear(); - } - } - - if (Creature* pAkama = m_creature->GetMap()->GetCreature(m_akamaGuid)) - { - if (!pAkama->isAlive()) - pAkama->Respawn(); - - pAkama->AI()->EnterEvadeMode(); - } - - if (m_pInstance) - m_pInstance->SetData(TYPE_ILLIDAN, FAIL); - } - - void MoveInLineOfSight(Unit* pWho) - { - if (!pWho || m_creature->getVictim() || m_bIsTalking || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (pWho->isTargetableForAttack() && pWho->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(pWho)) - { - if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(pWho); - if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) - { - pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(pWho); - } - } - } - - void JustDied(Unit* pKiller) - { - m_bIsTalking = false; - m_uiTalkCount = 0; - m_uiTalkTimer = 0; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - if (!m_pInstance) - return; - - // Completed - m_pInstance->SetData(TYPE_ILLIDAN, DONE); - - for(uint32 i = GO_ILLIDAN_DOOR_R; i < GO_ILLIDAN_DOOR_L + 1; ++i) - { - // Open Doors - if (GameObject* pDoor = m_pInstance->GetSingleGameObjectFromStorage(i)) - pDoor->SetGoState(GO_STATE_ACTIVE); - } - - } - - void KilledUnit(Unit* pVictim) - { - if (pVictim == m_creature) - return; - - DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); - } - - void DamageTaken(Unit* pDealer, uint32& uiDamage) - { - if (uiDamage > m_creature->GetHealth()) // Don't let ourselves be slain before we do our death speech - { - uiDamage = 0; - m_creature->SetHealth(m_creature->GetMaxHealth()/100); - } - } - - void Cast(Unit* pVictim, uint32 uiSpellId, bool bTriggered = false) - { - if (!pVictim) - return; - - m_bRefaceVictim = true; - m_creature->SetTargetGuid(pVictim->GetObjectGuid()); - m_creature->CastSpell(pVictim, uiSpellId, bTriggered); - } - - /** This will handle the cast of eye blast **/ - void CastEyeBlast() - { - m_creature->InterruptNonMeleeSpells(false); - - m_uiDarkBarrageTimer += 10000; - - DoScriptText(SAY_EYE_BLAST, m_creature); - - uint32 uiInitial = urand(0, 3); - uint32 uiFinal = 0; - - if (uiInitial < 3) - uiFinal = uiInitial+1; - - float initial_X = aEyeBlast[uiInitial].x; - float initial_Y = aEyeBlast[uiInitial].y; - float initial_Z = aEyeBlast[uiInitial].z; - - float final_X = aEyeBlast[uiFinal].x; - float final_Y = aEyeBlast[uiFinal].y; - float final_Z = aEyeBlast[uiFinal].z; - - for(uint8 i = 0; i < 2; ++i) - { - if (Creature* pTrigger = m_creature->SummonCreature(DEMON_FIRE, initial_X, initial_Y, initial_Z, 0, TEMPSUMMON_TIMED_DESPAWN, 20000)) - { - if (demonfireAI* pTriggerAI = dynamic_cast(pTrigger->AI())) - pTriggerAI->m_bIsTrigger = true; - - pTrigger->GetMotionMaster()->MovePoint(0, final_X, final_Y, final_Z); - - if (!i) - pTrigger->CastSpell(pTrigger, SPELL_EYE_BLAST_TRIGGER, true); - else - { - pTrigger->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetTargetGuid(pTrigger->GetObjectGuid()); - DoCastSpellIfCan(pTrigger, SPELL_EYE_BLAST); - } - } - } - } - - // It's only cast on players that are greater than 15 yards away from Illidan. - //If no one is found, cast it on MT instead (since selecting someone in that 15 yard radius would cause the flames to hit the MT anyway). - void CastAgonizingFlames() - { - // We'll use a grid searcher that selects a player that is at a distance >15 yards - if (Player* pPlayer = GetPlayerAtMinimumRange(15.0f)) - DoCastSpellIfCan(pPlayer, SPELL_AGONIZING_FLAMES); - else - DoCastSpellIfCan(m_creature->getVictim(), SPELL_AGONIZING_FLAMES); - } - - void Talk(uint32 count) - { - if (!m_creature->isAlive()) - return; - - int32 text = 0; - - if (aConversation[count].textId) - text = aConversation[count].textId; - - m_uiTalkTimer = aConversation[count].timer; - uint32 emote = aConversation[count].emote; - m_bIsTalking = aConversation[count].Talk; - Creature* pCreature = NULL; - ObjectGuid Guid; - - if (aConversation[count].creature == ILLIDAN_STORMRAGE) - pCreature = m_creature; - else if (aConversation[count].creature == AKAMA) - { - if (!m_akamaGuid) - { - if (m_pInstance) - { - m_akamaGuid = m_pInstance->GetGuid(NPC_AKAMA); - if (!m_akamaGuid) - return; - Guid = m_akamaGuid; - } - } - else Guid = m_akamaGuid; - } - else if (aConversation[count].creature == MAIEV_SHADOWSONG) - { - if (!m_maievGuid) - return; - Guid = m_maievGuid; - } - else if (aConversation[count].creature == EMPTY) // This is just for special cases without speech/sounds/emotes. - return; - - if (Guid) // Now we check if we actually specified a GUID, if so: - // we grab a pointer to that creature - pCreature = m_creature->GetMap()->GetCreature(Guid); - - if (pCreature) - { - if (emote) - pCreature->HandleEmote(emote); // Make the creature do some animation - if (text) - DoScriptText(text, pCreature); // Have the creature yell out some text - } - } - - void Move(float X, float Y, float Z, Creature* pCreature) - { - pCreature->GetMotionMaster()->MovePoint(0, X, Y, Z); - } - - void HandleDemonTransformAnimation(uint32 uiSequenceCount) - { - m_uiAnimationTimer = DemonTransformation[uiSequenceCount].uiTimer; - - m_creature->InterruptNonMeleeSpells(false); - - if (DemonTransformation[uiSequenceCount].uiPhase != PHASE_NORMAL_FORM) - { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - } - - if (DemonTransformation[uiSequenceCount].uiUnAura) - m_creature->RemoveAurasDueToSpell(DemonTransformation[uiSequenceCount].uiUnAura); - - if (DemonTransformation[uiSequenceCount].uiAura) - DoCastSpellIfCan(m_creature, DemonTransformation[uiSequenceCount].uiAura, CAST_TRIGGERED); - - if (DemonTransformation[uiSequenceCount].uiDisplayId) - // It's morphin time! - m_creature->SetDisplayId(DemonTransformation[uiSequenceCount].uiDisplayId); - /*if (DemonTransformation[uiSequenceCount].uiSize) - m_creature->SetUInt32Value(OBJECT_FIELD_SCALE_X, DemonTransformation[uiSequenceCount].uiSize); // Let us grow! (or shrink)*/ - - if (DemonTransformation[uiSequenceCount].bEquip) - { - // Requip warglaives if needed - SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE); - } - else - { - // Unequip warglaives if needed - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); - } - - if (DemonTransformation[uiSequenceCount].uiPhase != PHASE_NORMAL_FORM) - m_uiPhase = DemonTransformation[uiSequenceCount].uiPhase; // Set uiPhase properly - else - { - // Refollow and attack our old victim - SetCombatMovement(true); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - - // Depending on whether we summoned Maiev, we switch to either uiPhase 5 or 3 - if (m_maievGuid) - m_uiPhase = PHASE_NORMAL_MAIEV; - else - m_uiPhase = PHASE_NORMAL_2; - } - - if (uiSequenceCount == 7) - { - DoResetThreat(); - m_creature->RemoveAurasDueToSpell(SPELL_DEMON_FORM); - } - else if (uiSequenceCount == 4) - { - DoResetThreat(); - if (!m_creature->HasAura(SPELL_DEMON_FORM, EFFECT_INDEX_0)) - DoCastSpellIfCan(m_creature, SPELL_DEMON_FORM, CAST_TRIGGERED); - } - } - - /** To reduce the amount of code in UpdateAI, we can seperate them into different functions and simply call them from UpdateAI **/ - void EnterPhase2() - { - DoScriptText(SAY_TAKEOFF, m_creature); - - m_uiSummonBladesTimer = 10000; // Summon Glaives when this decrements - m_uiSummonFlamesTimer = 20000; // Summon Flames when this decrements - m_uiGlobalTimer += 20000; - m_uiLandTimer = 0; - m_uiPhase = PHASE_FLIGHT; - m_creature->RemoveAllAuras(); - m_creature->SetTargetGuid(ObjectGuid()); - - // So players don't shoot us down - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - // We now hover! - m_creature->SetLevitate(true); - SetCombatMovement(false); - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MovePoint(0, CENTER_X, CENTER_Y, CENTER_Z); - for(uint8 i = 0; i < 2; ++i) - { - Creature* Glaive = m_creature->SummonCreature(BLADE_OF_AZZINOTH, aGlaivePosition[i].x, aGlaivePosition[i].y, aGlaivePosition[i].z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - if (Glaive) - { - m_glaiveGuids[i] = Glaive->GetObjectGuid(); // We need this to remove them later on - Glaive->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - Glaive->SetVisibility(VISIBILITY_OFF); - Glaive->setFaction(m_creature->getFaction()); - } - } - } - - void SummonBladesOfAzzinoth() - { - m_creature->GetMotionMaster()->Clear(false); - - m_uiLandTimer = 0; - m_uiRetrieveBladesTimer = 0; - - // Make it look like we're throwing the glaives on the ground - DoCastSpellIfCan(m_creature, SPELL_THROW_GLAIVE2); - - // We no longer wear the glaives! - // since they are now channeling the flames (or will be) - SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); - - for(uint8 i = 0; i < 2; ++i) - { - Creature* Glaive = NULL; - Glaive = m_creature->GetMap()->GetCreature(m_glaiveGuids[i]); - if (Glaive) - { - DoCastSpellIfCan(Glaive, SPELL_THROW_GLAIVE, CAST_TRIGGERED); - Glaive->SetVisibility(VISIBILITY_ON); - } - } - } - - void SummonFlamesOfAzzinoth() - { - DoScriptText(SAY_SUMMONFLAMES, m_creature); - - for(uint8 i = 0; i < 2; ++i) - { - Creature* Flame = NULL; - Creature* Glaive = NULL; - Glaive = m_creature->GetMap()->GetCreature(m_glaiveGuids[i]); - if (Glaive) - { - Flame = m_creature->SummonCreature(FLAME_OF_AZZINOTH, aGlaivePosition[i+2].x, aGlaivePosition[i+2].y, aGlaivePosition[i+2].z, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - if (Flame) + // Phase 3 and 5 spells + if (m_uiAgonizingFlamesTimer < uiDiff) { - // Just in case the database has it as a different faction - Flame->setFaction(m_creature->getFaction()); - - // Attack our target! - Flame->AI()->AttackStart(m_creature->getVictim()); - - // Record GUID in order to check if they're dead later on to move to the next uiPhase - m_flameGuids[i] = Flame->GetObjectGuid(); - - // Glaives do some random Beam type channel on it. - Glaive->CastSpell(Flame, SPELL_AZZINOTH_CHANNEL, true); - - if (m_creature->getVictim()) - Flame->AI()->AttackStart(m_creature->getVictim()); + if (DoCastSpellIfCan(m_creature, SPELL_AGONIZING_FLAMES) == CAST_OK) + m_uiAgonizingFlamesTimer = 60000; } else - { - error_log("SD2: Illidan Stormrage AI: Unable to summon Flame of Azzinoth (entry: 22997), please check your database"); - EnterEvadeMode(); - } - } - else - { - error_log("SD2: Illidan Stormrage AI: Unable to summon Blade of Azzinoth (entry: 22996), please check your database"); - } - } - DoResetThreat(); // And now reset our threatlist - m_bHasSummoned = true; - } - - void SummonMaiev() - { - m_uiTauntTimer += 4000; - m_uiGlobalTimer += 4000; - - m_creature->InterruptNonMeleeSpells(false); // Interrupt any of our spells - Creature* Maiev = NULL; // Summon Maiev near Illidan - Maiev = m_creature->SummonCreature(MAIEV_SHADOWSONG, m_creature->GetPositionX() + 10, m_creature->GetPositionY() + 5, m_creature->GetPositionZ()+2, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - if (Maiev) - { - SetCombatMovement(false); - m_creature->GetMotionMaster()->Clear(false); // Stop moving, it's rude to walk and talk! - m_creature->GetMotionMaster()->MoveIdle(); - // Just in case someone is unaffected by Shadow Prison - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCastSpellIfCan(m_creature, SPELL_SHADOW_PRISON, CAST_TRIGGERED); - m_uiTalkCount = 10; - m_bIsTalking = true; // We are now talking/ - Maiev->SetVisibility(VISIBILITY_OFF); // Leave her invisible until she has to talk - Maiev->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_maievGuid = Maiev->GetObjectGuid(); - } - else // If Maiev cannot be summoned, reset the encounter and post some errors to the console. - { - EnterEvadeMode(); - debug_log("SD2: Unable to summon Maiev Shadowsong and enter Phase 4. Resetting Encounter."); - error_log("SD2: Unable to summon Maiev Shadowsong (entry: 23197). Check your database to see if you have the proper SQL for Maiev Shadowsong (entry: 23197)"); - } - } - - void InitializeDeath() - { - m_creature->RemoveAllAuras(); - DoCastSpellIfCan(m_creature, SPELL_DEATH); // Animate his kneeling + stun him - // Don't let the players interrupt our talk! - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - SetCombatMovement(false); - m_creature->GetMotionMaster()->Clear(false); // No moving! - m_creature->GetMotionMaster()->MoveIdle(); - - if (m_maievGuid) - { - if (Creature* Maiev = m_creature->GetMap()->GetCreature(m_maievGuid)) - { - Maiev->CombatStop(true); // Maiev shouldn't do anything either. No point in her attacking us =] - Maiev->GetMotionMaster()->Clear(false); // Stop her from moving as well - Maiev->GetMotionMaster()->MoveIdle(); - - float distance = 10.0f; - float dx = m_creature->GetPositionX() + (distance*cos(m_creature->GetOrientation())); - float dy = m_creature->GetPositionY() + (distance*sin(m_creature->GetOrientation())); - - Maiev->NearTeleportTo(dx, dy, Maiev->GetPositionZ(), 0.0f); - - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - Maiev->SetTargetGuid(m_creature->GetObjectGuid()); - } - } - m_bIsTalking = true; - ++m_uiTalkCount; - } + m_uiAgonizingFlamesTimer -= uiDiff; - void UpdateAI(const uint32 uiDiff) - { - /*** This section will handle the conversations ***/ - if (m_bIsTalking) // Somewhat more efficient using a function rather than a long switch - { - if (m_uiTalkTimer < uiDiff) - { - switch(m_uiTalkCount) // This is only for specialized cases + if (m_uiTransformTimer < uiDiff) { - case 0: - // Time to stand up! - m_creature->RemoveAurasDueToSpell(SPELL_KNEEL); - break; - case 8: - // Equip our warglaives! - SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE); - // Hostile if we weren't before - m_creature->setFaction(14); - break; - case 9: - SetCombatMovement(true); - if (m_akamaGuid) - { - if (Creature* pAkama = m_creature->GetMap()->GetCreature(m_akamaGuid)) - { - // Start attacking Akama - AttackStart(pAkama); - - // Akama stop talk and start attack illidan - if (npc_akama_illidanAI* pAkamaAI = dynamic_cast(pAkama->AI())) - pAkamaAI->m_bIsTalking = false; + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_TRANSFORM_1) == CAST_OK) + { + DoScriptText(SAY_MORPH, m_creature); - pAkama->AI()->AttackStart(m_creature); - pAkama->AddThreat(m_creature, 1000000.0f); - } - } + m_uiPrevPhase = m_uiPhase; + m_uiPhase = PHASE_TRANSITION; + m_uiTransformTimer = 12500; + m_uiFlameBurstTimer = 10000; + m_uiShadowDemonTimer = 30000; - // We are now attackable! - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - debug_log("SD2: Black Temple: Illidan intro complete, players can attack Illidan."); - break; - case 11: - if (m_maievGuid) - { - Creature* Maiev = m_creature->GetMap()->GetCreature(m_maievGuid); - if (Maiev) - { - // Maiev is now visible - Maiev->SetVisibility(VISIBILITY_ON); - // onoz she looks like she teleported! - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - // Have her face us - Maiev->SetTargetGuid(m_creature->GetObjectGuid()); - // Face her, so it's not rude =P - m_creature->SetTargetGuid(Maiev->GetObjectGuid()); - } - } - break; - case 14: - if (Creature* pMaiev = m_creature->GetMap()->GetCreature(m_maievGuid)) - { - pMaiev->GetMotionMaster()->Clear(false); - pMaiev->GetMotionMaster()->MoveChase(m_creature); - // Have Maiev add a lot of threat on us so that players don't pull her off if they damage her via AOE - pMaiev->AddThreat(m_creature, 10000000.0f); - // Force Maiev to attack us. - pMaiev->AI()->AttackStart(m_creature); - pMaiev->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - SetCombatMovement(true); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_bIsTalking = false; - m_uiFaceVictimTimer = 2000; - m_bRefaceVictim = true; - break; - case 20: - // Kill ourself. - if (Creature* Maiev = m_creature->GetMap()->GetCreature(m_maievGuid)) - { - // Make Maiev leave - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - Maiev->SetDeathState(JUST_DIED); - } - m_bIsTalking = false; - if (m_creature->getVictim()) - m_creature->getVictim()->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE,SPELL_SCHOOL_MASK_NORMAL, NULL, false); - else - // Now we kill ourself - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - break; + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + } } + else + m_uiTransformTimer -= uiDiff; - // This function does most of the talking - Talk(m_uiTalkCount); - ++m_uiTalkCount; - } - else - m_uiTalkTimer -= uiDiff; - - // No further action while talking - return; - } - - // If we don't have a target, return. - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // If we are 'caged', then we shouldn't do anything such as cast spells or transform into Demon Form. - if (m_creature->HasAura(SPELL_CAGED, EFFECT_INDEX_0)) - { - // Just so that he doesn't immediately enrage after he stops being caged. - m_uiEnrageTimer = 40000; - m_uiCageTimer = 30000; - return; - } - - // Berserk Timer - flat 25 minutes - if (m_uiPhase != PHASE_DEMON_SEQUENCE && !m_creature->HasAura(SPELL_BERSERK, EFFECT_INDEX_0)) - { - if (m_uiBerserkTimer < uiDiff) - { - DoScriptText(SAY_ENRAGE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_TRIGGERED); - } - else - m_uiBerserkTimer -= uiDiff; - } - - if (m_bRefaceVictim) - { - if (m_uiFaceVictimTimer < uiDiff) - { - m_creature->SetTargetGuid(m_creature->getVictim()->GetObjectGuid()); - m_uiFaceVictimTimer = 1000; - m_bRefaceVictim = false; - } - else - m_uiFaceVictimTimer -= uiDiff; - } - - /** Signal to change to uiPhase 2 **/ - if (m_uiPhase == PHASE_NORMAL && m_creature->GetHealthPercent() < 65.0f) - { - EnterPhase2(); - return; - } - - /** Signal to summon Maiev at 30% health**/ - if (!m_maievGuid && !(m_uiPhase == PHASE_DEMON || m_uiPhase == PHASE_DEMON_SEQUENCE) && m_creature->GetHealthPercent() < 30.0f) - { - SummonMaiev(); - return; - } - - /** Time for the death speech **/ - if (!(m_uiPhase == PHASE_DEMON || m_uiPhase == PHASE_DEMON_SEQUENCE) && m_creature->GetHealthPercent() < 1.0f) - { - InitializeDeath(); - return; - } - - /***** Spells for Phase 1, 3 and 5 (Normal Form) ******/ - if (m_uiPhase == PHASE_NORMAL || m_uiPhase == PHASE_NORMAL_2 || m_uiPhase == PHASE_NORMAL_MAIEV) - { - if (m_uiTauntTimer < uiDiff) // His random taunt/yell uiTimer. - { - uint32 random = urand(0, 3); - int32 yell = aRandomTaunts[random].textId; - if (yell) - DoScriptText(yell, m_creature); - m_uiTauntTimer = 32000; - } - else - m_uiTauntTimer -= uiDiff; + // no break; + case PHASE_AKAMA: - // Global Timer so that spells do not overlap. - if (m_uiGlobalTimer < uiDiff) - { if (m_uiShearTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHEAR); - m_uiShearTimer = urand(25000, 40000); - m_uiGlobalTimer += 2000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHEAR) == CAST_OK) + m_uiShearTimer = urand(10000, 15000); } else m_uiShearTimer -= uiDiff; if (m_uiFlameCrashTimer < uiDiff) { - //It spawns multiple flames sometimes. Therefore, we'll do this manually. - //DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_CRASH); - m_creature->SummonCreature(FLAME_CRASH, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 40000); - m_uiFlameCrashTimer = 35000; - m_uiGlobalTimer += 2000; + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_CRASH) == CAST_OK) + m_uiFlameCrashTimer = urand(25000, 35000); } else m_uiFlameCrashTimer -= uiDiff; - if (m_uiParasiticShadowFiendTimer < uiDiff) + if (m_uiShadowFiendTimer < uiDiff) { - Unit* target = NULL; - target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1); - if (target && target->isAlive() && !target->HasAura(SPELL_PARASITIC_SHADOWFIEND, EFFECT_INDEX_0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_PARASITIC_SHADOWFIEND, SELECT_FLAG_PLAYER)) { - Cast(target, SPELL_PARASITIC_SHADOWFIEND); - m_uiParasiticShadowFiendTimer = 40000; + if (DoCastSpellIfCan(pTarget, SPELL_PARASITIC_SHADOWFIEND) == CAST_OK) + m_uiShadowFiendTimer = 40000; } } else - m_uiParasiticShadowFiendTimer -= uiDiff; + m_uiShadowFiendTimer -= uiDiff; if (m_uiDrawSoulTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DRAW_SOUL); - m_uiDrawSoulTimer = 55000; - m_uiGlobalTimer += 3000; + if (DoCastSpellIfCan(m_creature, SPELL_DRAW_SOUL) == CAST_OK) + m_uiDrawSoulTimer = 35000; } else m_uiDrawSoulTimer -= uiDiff; - } - else - m_uiGlobalTimer -= uiDiff; - DoMeleeAttackIfReady(); - } + DoMeleeAttackIfReady(); - /*** Phase 2 ***/ - if (m_uiPhase == PHASE_FLIGHT) - { - // Check if we have summoned or not. - if (!m_bHasSummoned) - { - if (m_uiSummonBladesTimer) + break; + case PHASE_BLADES: + + if (m_uiCenterMoveTimer) { - if (m_uiSummonBladesTimer <= uiDiff) + if (m_uiCenterMoveTimer <= uiDiff) { - SummonBladesOfAzzinoth(); - m_uiSummonBladesTimer = 0; + // The movement is not very clear - it may be possible that he is moving around the center during this phase + // ToDo: this requires additional resarch. For now bring him near home position + m_creature->GetMotionMaster()->MovePoint(0, aCenterLoc[0].fX, aCenterLoc[0].fY, aCenterLoc[0].fZ); + m_uiCenterMoveTimer = 0; } else - m_uiSummonBladesTimer -= uiDiff; + m_uiCenterMoveTimer -= uiDiff; } - if (m_uiSummonFlamesTimer < uiDiff) - { - SummonFlamesOfAzzinoth(); - } - else - m_uiSummonFlamesTimer -= uiDiff; - } - - if (!m_creature->GetMotionMaster()->empty() && (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)) - m_creature->GetMotionMaster()->Clear(false); - - if (m_bHasSummoned) - { - if (m_uiCheckFlamesTimer) + if (m_uiSummonBladesTimer) { - if (m_uiCheckFlamesTimer <= uiDiff) + if (m_uiSummonBladesTimer <= uiDiff) { - // Check if flames are dead or non-existant. If so, set GUID to 0. - for(uint8 i = 0; i < 2; ++i) + if (m_pInstance) { - if (m_flameGuids[i]) - { - Creature* pFlame = m_creature->GetMap()->GetCreature(m_flameGuids[i]); + // Need to provide explicit glaive targets + GuidVector vTargetsVect; + m_pInstance->GetGlaiveTargetGuidVector(vTargetsVect); + + Creature* pGlaive1 = m_creature->GetMap()->GetCreature(vTargetsVect[0]); + Creature* pGlaive2 = m_creature->GetMap()->GetCreature(vTargetsVect[1]); + if (!pGlaive1 || !pGlaive2) + return; - // If the flame dies, or somehow the pointer becomes invalid, reset Guid. - if (!pFlame || !pFlame->isAlive()) - m_flameGuids[i].Clear(); + // Summon both blades and remove them from equipment + if (DoCastSpellIfCan(pGlaive1, SPELL_THROW_GLAIVE_VISUAL) == CAST_OK) + { + DoCastSpellIfCan(pGlaive2, SPELL_THROW_GLAIVE, CAST_TRIGGERED); + SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + m_uiSummonBladesTimer = 0; } } - m_uiCheckFlamesTimer = 500; } else - m_uiCheckFlamesTimer -= uiDiff; + m_uiSummonBladesTimer -= uiDiff; + + // no other spells during takeoff + return; } - // If both flames are dead/non-existant, kill glaives and change to uiPhase 3. - if (!m_flameGuids[0] && !m_flameGuids[1] && m_uiCheckFlamesTimer) + if (m_uiFireballTimer < uiDiff) { - m_uiRetrieveBladesTimer = 5000; // Prepare for re-equipin! - m_uiCheckFlamesTimer = 0; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIREBALL) == CAST_OK) + m_uiFireballTimer = urand(2000, 3000); + } } + else + m_uiFireballTimer -= uiDiff; - if (m_uiRetrieveBladesTimer) + if (m_uiDarkBarrageTimer < uiDiff) { - if (m_uiRetrieveBladesTimer <= uiDiff) // Time to get back our glaives! + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - // Interrupt any spells we might be doing *cough* DArk Barrage *cough* - m_creature->InterruptNonMeleeSpells(false); - for(uint8 i = 0; i < 2; ++i) - { - if (Creature* pGlaive = m_creature->GetMap()->GetCreature(m_glaiveGuids[i])) - { - // Make it look like the Glaive flies back up to us - pGlaive->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, true); - // Despawn the Glaive - pGlaive->SetDeathState(JUST_DIED); - m_glaiveGuids[i].Clear(); - } - } - - // Re-bEquip our warblades! - SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE); - - // Prepare for landin'! - m_uiLandTimer = 5000; - m_uiRetrieveBladesTimer = 0; + if (DoCastSpellIfCan(pTarget, SPELL_DARK_BARRAGE) == CAST_OK) + m_uiDarkBarrageTimer = 45000; } - else - m_uiRetrieveBladesTimer -= uiDiff; } + else + m_uiDarkBarrageTimer -= uiDiff; - if (m_uiLandTimer) + if (m_uiEyeBlastTimer < uiDiff) { - // Time to land! - if (m_uiLandTimer <= uiDiff) + if (DoCastEyeBlastIfCan()) { - DoResetThreat(); + m_uiEyeBlastTimer = urand(35000, 45000); + m_uiFireballTimer = 15000; + } + } + else + m_uiEyeBlastTimer -= uiDiff; - // anndddd touchdown! - m_creature->HandleEmote(EMOTE_ONESHOT_LAND); - m_creature->SetLevitate(false); - m_uiPhase = PHASE_NORMAL_2; + break; + case PHASE_DUAL_DEMON: - // We should let the raid fight us =) - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->SetTargetGuid(m_creature->getVictim()->GetObjectGuid()); + // Handle phase transition at 30% + if (m_uiPrevPhase == PHASE_DUAL_NORMAL && m_creature->GetHealthPercent() <= 30.0f) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_TRANSFORM_1) == CAST_OK) + { + m_uiTransformTimer = 12500; + m_uiPhase = PHASE_TRANSITION; - // Chase our victim! SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } - else - m_uiLandTimer -= uiDiff; - - return; // Do not continue past this point if m_uiLandTimer is not 0 and we are in uiPhase 2. } - } - if (m_uiGlobalTimer < uiDiff) - { - if (m_uiFireballTimer < uiDiff) + if (m_uiTransformTimer < uiDiff) { - Cast(m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0), SPELL_FIREBALL); - m_uiFireballTimer = 5000; + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_TRANSFORM_1) == CAST_OK) + { + m_uiTransformTimer = 12500; + m_uiPhase = PHASE_TRANSITION; + + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + } } else - m_uiFireballTimer -= uiDiff; + m_uiTransformTimer -= uiDiff; - if (m_uiDarkBarrageTimer < uiDiff) + if (m_uiShadowDemonTimer < uiDiff) { - m_creature->InterruptNonMeleeSpells(false); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_DARK_BARRAGE); - - m_uiDarkBarrageTimer = 35000; - m_uiGlobalTimer += 9000; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SHADOW_DEMONS) == CAST_OK) + m_uiShadowDemonTimer = 60000; } else - m_uiDarkBarrageTimer -= uiDiff; + m_uiShadowDemonTimer -= uiDiff; - if (m_uiEyeBlastTimer < uiDiff) + if (m_uiShadowBlastTimer < uiDiff) { - CastEyeBlast(); - m_uiEyeBlastTimer = 30000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_BLAST) == CAST_OK) + m_uiShadowBlastTimer = urand(2000, 3000); + } } else - m_uiEyeBlastTimer -= uiDiff; - } - else - m_uiGlobalTimer -= uiDiff; - } + m_uiShadowBlastTimer -= uiDiff; - /** Phase 3,5 spells only**/ - if (m_uiPhase == PHASE_NORMAL_2 || m_uiPhase == PHASE_NORMAL_MAIEV) - { - if (m_uiGlobalTimer < uiDiff) - { - if (m_uiAgonizingFlamesTimer < uiDiff) + if (m_uiFlameBurstTimer < uiDiff) { - CastAgonizingFlames(); - m_uiAgonizingFlamesTimer = 60000; + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_BURST) == CAST_OK) + m_uiFlameBurstTimer = 20000; } else - m_uiAgonizingFlamesTimer -= uiDiff; - } - else - m_uiGlobalTimer -= uiDiff; - - if (m_uiTransformTimer < uiDiff) - { - float CurHealth = m_creature->GetHealthPercent(); - // Prevent Illidan from morphing if less than 32% or 5%, as this may cause issues with the uiPhase transition or death speech - if ((CurHealth < 32.0f && !m_maievGuid) || CurHealth < 5.0f) - return; - - m_uiPhase = PHASE_DEMON_SEQUENCE; // Transform sequence - m_uiDemonFormSequence = 0; - m_uiAnimationTimer = 0; - - DoScriptText(SAY_MORPH, m_creature); - - m_uiTransformTimer = 60000; - m_uiFlameBurstTimer = 10000; - m_uiShadowDemonTimer = 30000; - SetCombatMovement(false); - m_creature->GetMotionMaster()->Clear(false);// Stop moving - } - else - m_uiTransformTimer -= uiDiff; - } - - /** Phase 4 spells only (Demon Form) **/ - if (m_uiPhase == PHASE_DEMON) - { - // Stop moving if we are by clearing movement generators. - if (!m_creature->GetMotionMaster()->empty()) - m_creature->GetMotionMaster()->Clear(false); + m_uiFlameBurstTimer -= uiDiff; - if (m_uiTransformTimer < uiDiff) - { - m_uiPhase = PHASE_DEMON_SEQUENCE; - m_uiDemonFormSequence = 5; - m_uiAnimationTimer = 100; - m_uiTransformTimer = 60000; - } - else - m_uiTransformTimer -= uiDiff; + break; + case PHASE_TRANSITION: - if (m_uiShadowDemonTimer < uiDiff) - { - m_creature->InterruptNonMeleeSpells(false); - for (uint8 i = 0; i < 4; ++i) + if (m_uiLandTimer) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, uint32(0), SELECT_FLAG_PLAYER)) + if (m_uiLandTimer <= uiDiff) { - if (Creature* ShadowDemon = m_creature->SummonCreature(SHADOW_DEMON, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000)) + switch (m_uiLandStage) { - ShadowDemon->AddThreat(pTarget, 5000000.0f); - ShadowDemon->AI()->AttackStart(pTarget); - ShadowDemon->SetInCombatWithZone(); + case 0: + // Despawn the blades + for (GuidList::const_iterator itr = m_lBladesGuidList.begin(); itr != m_lBladesGuidList.end(); ++itr) + { + if (Creature* pBlade = m_creature->GetMap()->GetCreature(*itr)) + { + pBlade->CastSpell(m_creature, SPELL_GLAIVE_RETURNS, true); + pBlade->ForcedDespawn(500); + } + } + m_uiLandTimer = 5000; + break; + case 1: + // Set the equipment and land + SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_ID_OFF_HAND, EQUIP_NO_CHANGE); + + m_creature->SetLevitate(false); + m_creature->HandleEmote(EMOTE_ONESHOT_LAND); + m_uiLandTimer = 2000; + break; + case 2: + // Start phase 3 + DoResetThreat(); + m_uiPhase = PHASE_DUAL_NORMAL; + + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiTransformTimer = 64000; + m_uiLandTimer = 0; + break; } + ++m_uiLandStage; } + else + m_uiLandTimer -= uiDiff; } - m_uiShadowDemonTimer = 60000; - } - else - m_uiShadowDemonTimer -= uiDiff; - if (m_uiGlobalTimer < uiDiff) - { - if (m_uiShadowBlastTimer < uiDiff) + if (m_uiTransformTimer) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0); - if (target && target->isAlive()) + if (m_uiTransformTimer <= uiDiff) { - m_creature->SetTargetGuid(target->GetObjectGuid()); - DoCastSpellIfCan(target, SPELL_SHADOW_BLAST); - m_uiShadowBlastTimer = 4000; - m_uiGlobalTimer += 1500; + // Drop the transform time from the spell timers + if (m_creature->HasAura(SPELL_DEMON_FORM)) + { + DoResetThreat(); + m_uiPhase = PHASE_DUAL_DEMON; + m_uiShadowDemonTimer = 17000; + m_uiFlameBurstTimer = 7000; + m_uiTransformTimer = 47000; + } + else + { + m_uiPhase = m_uiPrevPhase; + m_uiEnrageTimer = 40000; + m_uiTransformTimer = 60000; + m_uiTrapTimer = urand(30000, 40000); + } } - if (!m_creature->HasAura(SPELL_DEMON_FORM, EFFECT_INDEX_0)) - DoCastSpellIfCan(m_creature, SPELL_DEMON_FORM, CAST_TRIGGERED); + else + m_uiTransformTimer -= uiDiff; } - else - m_uiShadowBlastTimer -= uiDiff; - if (m_uiFlameBurstTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAME_BURST); - m_uiFlameBurstTimer = 15000; - } - else - m_uiFlameBurstTimer -= uiDiff; - } - else - m_uiGlobalTimer -= uiDiff; + break; } + } +}; + +/*###### +## npc_akama_illidan +######*/ + +struct npc_akama_illidanAI : public npc_escortAI, private DialogueHelper +{ + npc_akama_illidanAI(Creature* pCreature) : npc_escortAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiSummonMinionTimer; + uint32 m_uiHealDelayTimer; + uint32 m_uiChainLightningTimer; + + bool m_bFightMinions; + bool m_bIsIntroFinished; + + void Reset() override + { + m_uiSummonMinionTimer = 2000; + m_uiHealDelayTimer = 0; + m_uiChainLightningTimer = urand(5000, 10000); - /** Phase 5 timers. Enrage spell **/ - if (m_uiPhase == PHASE_NORMAL_MAIEV) + if (!HasEscortState(STATE_ESCORT_ESCORTING)) { - if (m_uiEnrageTimer < uiDiff) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - m_uiEnrageTimer = 40000; - m_uiCageTimer = 30000; - m_uiTransformTimer += 10000; - } - else - m_uiEnrageTimer -= uiDiff; + m_bFightMinions = false; + m_bIsIntroFinished = false; + } + } - // We'll handle Cage Trap in Illidan's script for simplicity's sake - if (m_uiCageTimer < uiDiff) - { - if (m_maievGuid) + void MoveInLineOfSight(Unit* pWho) override + { + if (HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + // Star the event + if (pWho->GetTypeId() == TYPEID_PLAYER && pWho->IsWithinDistInMap(m_creature, 70.0f) && pWho->IsWithinLOSInMap(m_creature)) + Start(true); + } + + void AttackStart(Unit* pWho) override + { + // Don't attack Illidan again + if (m_bIsIntroFinished && pWho->GetEntry() == NPC_ILLIDAN_STORMRAGE) + return; + + npc_escortAI::AttackStart(pWho); + } + + void EnterEvadeMode() override + { + // Called first when evading from Illidan + if (!m_bIsIntroFinished) + { + SetEscortPaused(false); + m_bIsIntroFinished = true; + } + + // Go back to epilogue position + if (m_pInstance && m_pInstance->GetData(TYPE_ILLIDAN) == DONE) + { + SetEscortPaused(false); + m_bFightMinions = false; + } + + npc_escortAI::EnterEvadeMode(); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + SetEscortPaused(true); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + case 9: + SetEscortPaused(true); + if (m_pInstance) + { + if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_DOOR_TRIGGER)) + m_creature->SetFacingToObject(pTrigger); + } + StartNextDialogueText(SAY_AKAMA_OPEN_DOOR_1); + break; + case 16: + SetEscortPaused(true); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + if (m_pInstance) + { + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + m_creature->SetFacingToObject(pIllidan); + } + break; + case 17: + SetEscortPaused(true); + if (m_pInstance) + { + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + { + if (boss_illidan_stormrageAI* pIllidanAI = dynamic_cast(pIllidan->AI())) + pIllidanAI->DoStartCombatEvent(); + + m_creature->SetFacingToObject(pIllidan); + } + } + break; + case 24: + SetEscortPaused(true); + m_bFightMinions = true; + break; + case 30: + SetEscortPaused(true); + if (m_pInstance) { - Creature* Maiev = m_creature->GetMap()->GetCreature(m_maievGuid); - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); + // Move to a close point to Illidan + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + { + float fX, fY, fZ; + pIllidan->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(100, fX, fY, fZ); + } + } + break; + } + } - if (!Maiev || !target || (target->GetTypeId() != TYPEID_PLAYER)) - return; + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + npc_escortAI::MovementInform(uiMoveType, uiPointId); - float X, Y, Z; - target->GetPosition(X, Y, Z); - Maiev->GetMap()->CreatureRelocation(m_creature, X, Y, Z, Maiev->GetOrientation()); + if (uiMoveType != POINT_MOTION_TYPE || uiPointId != 100) + return; - // Make it look like she 'teleported' - Maiev->CastSpell(Maiev, SPELL_TELEPORT_VISUAL, true); - // summon the trap! - Maiev->CastSpell(Maiev, SPELL_CAGE_TRAP_SUMMON, false); - } - m_uiCageTimer = 15000; - } - else - m_uiCageTimer -= uiDiff; + // Do outro + if (m_pInstance) + { + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + m_creature->SetFacingToObject(pIllidan); } - if (m_uiPhase == PHASE_DEMON_SEQUENCE) // Demonic Transformation + DoScriptText(SAY_AKAMA_EPILOGUE_5, m_creature); + m_creature->ForcedDespawn(10000); + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) { - if (m_uiAnimationTimer < uiDiff) - { - HandleDemonTransformAnimation(m_uiDemonFormSequence); - ++m_uiDemonFormSequence; - } - else - m_uiAnimationTimer -= uiDiff; + case SPELL_AKAMA_DOOR_FAIL: + DoCastSpellIfCan(m_creature, SPELL_AKAMA_DOOR_FAIL); + break; + case NPC_SPIRIT_OF_OLUM: + m_creature->SummonCreature(NPC_SPIRIT_OF_OLUM, 751.64f, 297.22f, 312.21f, 6.03f, TEMPSUMMON_TIMED_DESPAWN, 25000); + m_creature->SummonCreature(NPC_SPIRIT_OF_UDALO, 751.47f, 311.01f, 312.19f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000); + break; + case SPELL_AKAMA_DOOR_CHANNEL: + DoCastSpellIfCan(m_creature, SPELL_AKAMA_DOOR_CHANNEL); + if (m_pInstance) + { + if (Creature* pOlum = m_pInstance->GetSingleCreatureFromStorage(NPC_SPIRIT_OF_OLUM)) + pOlum->CastSpell(pOlum, SPELL_DEATHSWORN_DOOR_CHANNEL, true); + if (Creature* pUdalo = m_pInstance->GetSingleCreatureFromStorage(NPC_SPIRIT_OF_UDALO)) + pUdalo->CastSpell(pUdalo, SPELL_DEATHSWORN_DOOR_CHANNEL, true); + } + break; + case GO_ILLIDAN_GATE: + if (m_pInstance) + m_pInstance->DoUseDoorOrButton(GO_ILLIDAN_GATE); + break; + case NPC_SPIRIT_OF_UDALO: + SetEscortPaused(false); + break; } } -}; - -/*********************** End of Illidan AI ******************************************/ -void npc_akama_illidanAI::BeginEvent(ObjectGuid playerGuid) -{ - debug_log("SD2: Akama - Illidan Introduction started. Illidan event properly begun."); - if (m_pInstance) + void JustSummoned(Creature* pSummoned) override { - m_illidanGuid = m_pInstance->GetGuid(NPC_ILLIDAN_STORMRAGE); - m_pInstance->SetData(TYPE_ILLIDAN, IN_PROGRESS); + switch (pSummoned->GetEntry()) + { + case NPC_ILLIDARI_ELITE: + pSummoned->AI()->AttackStart(m_creature); + break; + case NPC_SPIRIT_OF_OLUM: + case NPC_SPIRIT_OF_UDALO: + pSummoned->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + break; + } } - if (m_pInstance) + // Wrapper to handle event resume + void DoResumeEvent() { - m_pInstance->DoUseDoorOrButton(GO_ILLIDAN_DOOR_R); - m_pInstance->DoUseDoorOrButton(GO_ILLIDAN_DOOR_L); + SetEscortPaused(false); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - if (m_illidanGuid) + void UpdateEscortAI(const uint32 uiDiff) override { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DialogueUpdate(uiDiff); - if (Creature* pIllidan = m_creature->GetMap()->GetCreature(m_illidanGuid)) + if (m_bFightMinions) { - boss_illidan_stormrageAI* pIllidanAI = dynamic_cast(pIllidan->AI()); - - if (!pIllidanAI) - return; - - // Time for Illidan to stand up. - pIllidan->RemoveAurasDueToSpell(SPELL_KNEEL); - - // First line of Akama-Illidan convo - - pIllidanAI->m_uiTalkCount = 0; - - // Begin Talking - pIllidanAI->m_bIsTalking = true; - pIllidanAI->m_akamaGuid = m_creature->GetObjectGuid(); - - m_creature->SetTargetGuid(pIllidan->GetObjectGuid()); - pIllidan->SetTargetGuid(m_creature->GetObjectGuid()); - - m_bIsTalking = true; // Prevent Akama from starting to attack him - // Prevent players from talking again + if (m_uiSummonMinionTimer < uiDiff) + { + for (uint8 i = 0; i < MAX_ILLIDARI_ELITES; ++i) + m_creature->SummonCreature(NPC_ILLIDARI_ELITE, aIllidariElitesPos[i].fX, aIllidariElitesPos[i].fY, aIllidariElitesPos[i].fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiSummonMinionTimer = urand(35000, 50000); + } + else + m_uiSummonMinionTimer -= uiDiff; + } - pIllidan->GetMotionMaster()->Clear(false); - pIllidan->GetMotionMaster()->MoveIdle(); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); + if (m_uiHealDelayTimer) + { + if (m_uiHealDelayTimer <= uiDiff) + m_uiHealDelayTimer = 0; + else + m_uiHealDelayTimer -= uiDiff; + } - if (playerGuid) + if (m_bFightMinions) + { + if (m_uiChainLightningTimer < uiDiff) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(playerGuid)) - pIllidan->AddThreat(pPlayer, 100.0f); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiChainLightningTimer = urand(4000, 8000); } + else + m_uiChainLightningTimer -= uiDiff; } + + if (m_creature->GetHealthPercent() < 10.0f && !m_uiHealDelayTimer) + { + if (DoCastSpellIfCan(m_creature, SPELL_HEALING_POTION) == CAST_OK) + m_uiHealDelayTimer = 30000; + } + + DoMeleeAttackIfReady(); } -} +}; -bool GossipHello_npc_akama_at_illidan(Player* pPlayer, Creature* pCreature) +bool GossipHello_npc_akama_illidan(Player* pPlayer, Creature* pCreature) { - // TODO: Add gossip item only when Council is done? - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(10465, pCreature->GetObjectGuid()); + // Before climbing the stairs + if (pCreature->GetPositionZ() < 300.0f) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_PREPARE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_AKAMA_ILLIDAN_PREPARE, pCreature->GetObjectGuid()); + } + // Before starting combat + else + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_START_EVENT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_AKAMA_ILLIDAN_START, pCreature->GetObjectGuid()); + } return true; } -bool GossipSelect_npc_akama_at_illidan(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_akama_illidan(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF) // Time to begin the event + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1 || GOSSIP_ACTION_INFO_DEF + 2) { pPlayer->CLOSE_GOSSIP_MENU(); if (npc_akama_illidanAI* pAkamaAI = dynamic_cast(pCreature->AI())) - pAkamaAI->BeginDoorEvent(pPlayer); + pAkamaAI->DoResumeEvent(); } + return true; } -struct MANGOS_DLL_DECL boss_maievAI : public ScriptedAI +/*###### +## boss_maiev +######*/ + +struct boss_maievAI : public ScriptedAI, private DialogueHelper { - boss_maievAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_maievAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aEpilogueDialogue) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); }; + ScriptedInstance* m_pInstance; + uint32 m_uiTauntTimer; - ObjectGuid m_illidanGuid; + uint32 m_uiShadowStriketimer; + uint32 m_uiThrowDaggerTimer; - ScriptedInstance* m_pInstance; + bool m_bHasYelledTrap; - void Reset() + void Reset() override { - m_uiTauntTimer = 12000; + m_uiTauntTimer = urand(40000, 60000); + m_uiShadowStriketimer = urand(4000, 8000); + m_uiThrowDaggerTimer = urand(6000, 10000); + m_bHasYelledTrap = false; + + // Not sure if this is correct, but she seems to ignore all the shadow damage inflicted + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); + } + + void KilledUnit(Unit* pVictim) override + { + // Dummy function - used to start the epilogue + if (pVictim->GetEntry() == NPC_ILLIDAN_STORMRAGE) + StartNextDialogueText(SAY_MAIEV_EPILOGUE_1); + } + + // Custom evade - don't allow her to return to home position + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + m_creature->SetLootRecipient(NULL); + + Reset(); } - void UpdateAI(const uint32 diff) + // Attack only by script + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void JustDidDialogueStep(int32 iEntry) override { - if (!m_illidanGuid) + switch (iEntry) { - if (m_pInstance) - m_illidanGuid = m_pInstance->GetGuid(NPC_ILLIDAN_STORMRAGE); + case NPC_ILLIDAN_STORMRAGE: + if (m_pInstance) + { + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + pIllidan->DealDamage(pIllidan, pIllidan->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + } + break; + case SPELL_TELEPORT_VISUAL: + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT_VISUAL) == CAST_OK) + m_creature->ForcedDespawn(1000); + break; } - else - { - Creature* pIllidan = m_creature->GetMap()->GetCreature(m_illidanGuid); + } - if (!pIllidan || !pIllidan->isAlive() || pIllidan->IsInEvadeMode()) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_CAGE_TRAP) + { + // Yell only the first time + if (!m_bHasYelledTrap) { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + DoScriptText(SAY_MAIEV_TRAP, m_creature); + m_bHasYelledTrap = true; } - else if (pIllidan && pIllidan->GetHealthPercent() < 2.0f) - return; + DoCastSpellIfCan(m_creature, SPELL_CAGE_TRAP_SUMMON, CAST_TRIGGERED); } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); - // Return if we don't have a target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiTauntTimer < diff) + if (m_uiTauntTimer < uiDiff) { - uint32 random = urand(0, 3); - int32 text = aMaievTaunts[random].textId; + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_MAIEV_TAUNT_1, m_creature); break; + case 1: DoScriptText(SAY_MAIEV_TAUNT_2, m_creature); break; + case 2: DoScriptText(SAY_MAIEV_TAUNT_3, m_creature); break; + } + m_uiTauntTimer = urand(40000, 60000); + } + else + m_uiTauntTimer -= uiDiff; - DoScriptText(text, m_creature); + if (m_uiShadowStriketimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_STRIKE) == CAST_OK) + m_uiShadowStriketimer = urand(12000, 16000); + } + else + m_uiShadowStriketimer -= uiDiff; - m_uiTauntTimer = urand(22000, 42000); + if (m_uiThrowDaggerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_THROW_DAGGER) == CAST_OK) + m_uiThrowDaggerTimer = urand(6000, 10000); } else - m_uiTauntTimer -= diff; + m_uiThrowDaggerTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL cage_trap_triggerAI : public ScriptedAI -{ - cage_trap_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - ObjectGuid m_illidanGuid; - ObjectGuid m_cageTrapGuid; +/*###### +## npc_cage_trap_trigger +######*/ - uint32 m_uiDespawnTimer; +struct npc_cage_trap_triggerAI : public ScriptedAI +{ + npc_cage_trap_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } bool m_bActive; - bool m_bSummonedBeams; - void Reset() + void Reset() override { m_bActive = false; - m_bSummonedBeams = false; - - m_uiDespawnTimer = 0; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void MoveInLineOfSight(Unit *who) - { - if (!m_bActive) - return; - - if (who && (who->GetTypeId() != TYPEID_PLAYER)) - { - if (who->GetEntry() == ILLIDAN_STORMRAGE) // Check if who is Illidan - { - if (!m_illidanGuid && m_creature->IsWithinDistInMap(who, 3) && !who->HasAura(SPELL_CAGED, EFFECT_INDEX_0)) - { - m_illidanGuid = who->GetObjectGuid(); - who->CastSpell(who, SPELL_CAGED, true); - m_uiDespawnTimer = 5000; - - // Dispel his enrage - if (who->HasAura(SPELL_ENRAGE, EFFECT_INDEX_0)) - who->RemoveAurasDueToSpell(SPELL_ENRAGE); + void AttackStart(Unit* /*pWho*/) override { } - if (GameObject* pCageTrap = m_creature->GetMap()->GetGameObject(m_cageTrapGuid)) - pCageTrap->SetLootState(GO_JUST_DEACTIVATED); - } - } - } - } - - void UpdateAI(const uint32 diff) + void MoveInLineOfSight(Unit* pWho) override { - if (m_uiDespawnTimer) + if (!m_bActive && pWho->GetEntry() == NPC_ILLIDAN_STORMRAGE && m_creature->IsWithinDistInMap(pWho, 3.0f)) { - if (m_uiDespawnTimer <= diff) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - else m_uiDespawnTimer -= diff; - } + pWho->CastSpell(pWho, SPELL_CAGED, true); - //if (m_illidanGuid && !m_bSummonedBeams) - //{ - // if (Creature* pIllidan = m_creature->GetMap()->GetCreature(m_illidanGuid) - // { - // //TODO: Find proper spells and properly apply 'caged' Illidan effect - // } - //} - } -}; + // Cast the visual effects + for (uint8 i = 0; i < MAX_CAGE_SPELLS; ++i) + DoCastSpellIfCan(m_creature, aCagedSummonSpells[i], CAST_TRIGGERED); -bool GOUse_go_cage_trap(Player* pPlayer, GameObject* pGo) -{ - float x, y, z; - pPlayer->GetPosition(x, y, z); + for (uint8 i = 0; i < MAX_CAGE_SPELLS; ++i) + DoCastSpellIfCan(m_creature, aCagedVisualSpells[i], CAST_TRIGGERED); - // Grid search for nearest live creature of entry 23304 within 10 yards - Creature* pTrigger = GetClosestCreatureWithEntry(pGo, 23304, 10.0f); + if (GameObject* pCageTrap = GetClosestGameObjectWithEntry(m_creature, GO_CAGE_TRAP, 5.0f)) + pCageTrap->Use(m_creature); - if (!pTrigger) - { - error_log("SD2: Cage Trap- Unable to find trigger. This Cage Trap is now useless"); - return false; + m_bActive = true; + m_creature->ForcedDespawn(15000); + } } - if (cage_trap_triggerAI* pTriggerAI = dynamic_cast(pTrigger->AI())) - pTriggerAI->m_bActive = true; + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; - pGo->SetGoState(GO_STATE_ACTIVE); - return true; -} +/*###### +## npc_flame_of_azzinoth +######*/ -struct MANGOS_DLL_DECL flame_of_azzinothAI : public ScriptedAI +struct npc_flame_of_azzinothAI : public ScriptedAI { - flame_of_azzinothAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + npc_flame_of_azzinothAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint32 m_uiFlameBlastTimer; uint32 m_uiSummonBlazeTimer; uint32 m_uiChargeTimer; + uint32 m_uiWrathCheckTimer; - void Reset() + void Reset() override { - m_uiFlameBlastTimer = urand(15000, 30000); - m_uiSummonBlazeTimer = urand(10000, 30000); - m_uiChargeTimer = 5000; + m_uiFlameBlastTimer = 10000; + m_uiSummonBlazeTimer = 0; + m_uiChargeTimer = 5000; + m_uiWrathCheckTimer = 1000; } - void Charge() + void JustSummoned(Creature* pSummoned) override { - // Get the Threat List - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - - // He doesn't have anyone in his threatlist, useless to continue - if (tList.empty()) - return; - - std::list targets; - - //store the threat list in a different container - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - Unit *target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - //only on alive players - if (target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER) - targets.push_back(target); - } - - //Sort the list of players - targets.sort(ObjectDistanceOrderReversed(m_creature)); - //Resize so we only get the furthest target - targets.resize(1); - - Unit* target = (*targets.begin()); - if (target && (!m_creature->IsWithinDistInMap(target, 40))) - { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_TRIGGERED); - DoCastSpellIfCan(target, SPELL_CHARGE); - } + if (pSummoned->GetEntry() == NPC_BLAZE) + pSummoned->CastSpell(pSummoned, SPELL_BLAZE_EFFECT, false); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiFlameBlastTimer < diff) + if (m_uiFlameBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BLAST); - m_uiFlameBlastTimer = 30000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BLAST) == CAST_OK) + { + m_uiFlameBlastTimer = 10000; + m_uiSummonBlazeTimer = 3000; + } } else - m_uiFlameBlastTimer -= diff; + m_uiFlameBlastTimer -= uiDiff; - if (m_uiSummonBlazeTimer < diff) + if (m_uiSummonBlazeTimer) { - DoCastSpellIfCan(m_creature, SPELL_BLAZE_SUMMON); - m_uiSummonBlazeTimer = urand(30000, 50000); + if (m_uiSummonBlazeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLAZE) == CAST_OK) + m_uiSummonBlazeTimer = 0; + } + else + m_uiSummonBlazeTimer -= uiDiff; + } + + // Workaround for broken aura 41997; the creature should enrage if not within dist of 30 from summoner + // This should be done by checking if aura 41997 is removed from self, when getting out of range + if (m_uiWrathCheckTimer) + { + if (m_uiWrathCheckTimer <= uiDiff) + { + if (GetClosestCreatureWithEntry(m_creature, NPC_BLADE_OF_AZZINOTH, 30.0f)) + m_uiWrathCheckTimer = 1000; + else + { + if (DoCastSpellIfCan(m_creature, SPELL_UNCAGED_WRATH, CAST_TRIGGERED) == CAST_OK) + m_uiWrathCheckTimer = 0; + } + } + else + m_uiWrathCheckTimer -= uiDiff; } - else - m_uiSummonBlazeTimer -= diff; - if (m_uiChargeTimer < diff) + // Try to find a suitable target to charge + if (m_uiChargeTimer < uiDiff) { - Charge(); - m_uiChargeTimer = 5000; + std::vector suitableTargets; + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); + + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) + { + if (Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && !pTarget->IsWithinDist(m_creature, 30.0f)) + suitableTargets.push_back(pTarget); + } + } + + if (suitableTargets.empty()) + m_uiChargeTimer = 3000; + else + { + Unit* pTarget = suitableTargets[urand(0, suitableTargets.size() - 1)]; + + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) + m_uiChargeTimer = urand(5000, 10000); + } + } } else - m_uiChargeTimer -= diff; + m_uiChargeTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL shadow_demonAI : public ScriptedAI +/*###### +## npc_shadow_demon +######*/ + +struct npc_shadow_demonAI : public ScriptedAI { - shadow_demonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_shadow_demonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } ObjectGuid m_targetGuid; - void Reset() {} - - void JustDied(Unit *killer) - { - if (m_targetGuid) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_targetGuid)) - pPlayer->RemoveAurasDueToSpell(SPELL_PARALYZE); - } - } + void Reset() override {} - void UpdateAI(const uint32 diff) + void AttackStart(Unit* pWho) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - // Only cast the below on players. - if (m_creature->getVictim()->GetTypeId() != TYPEID_PLAYER) - return; - - if (!m_creature->getVictim()->HasAura(SPELL_PARALYZE, EFFECT_INDEX_0)) - { - m_targetGuid = m_creature->getVictim()->GetObjectGuid(); - m_creature->AddThreat(m_creature->getVictim(), 10000000.0f); - DoCastSpellIfCan(m_creature, SPELL_SHADOW_DEMON_PASSIVE, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PURPLE_BEAM, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PARALYZE, CAST_TRIGGERED); - } - // Kill our target if we're very close. - if (m_creature->IsWithinDistInMap(m_creature->getVictim(), 3)) - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONSUME_SOUL); + // Function used to set target only - the npc doesn't really attack + m_targetGuid = pWho->GetObjectGuid(); } -}; - -struct MANGOS_DLL_DECL flamecrashAI : public ScriptedAI -{ - flamecrashAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 m_uiFlameCrashTimer; - uint32 m_uiDespawnTimer; + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + void JustDied(Unit* /*pKiller*/) override { - m_uiFlameCrashTimer = urand(3000, 8000); - m_uiDespawnTimer = 60000; + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_targetGuid)) + pPlayer->RemoveAurasDueToSpell(SPELL_PARALYZE); } - void AttackStart(Unit *who) { } - - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 diff) + void MovementInform(uint32 uiMovementType, uint32 uiPointId) override { - if (m_uiFlameCrashTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_FLAME_CRASH_EFFECT); - m_uiFlameCrashTimer = 15000; - } - else - m_uiFlameCrashTimer -= diff; + if (uiMovementType != POINT_MOTION_TYPE || !uiPointId) + return; - if (m_uiDespawnTimer < diff) + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_targetGuid)) { - // So that players don't see the sparkly effect when we die. - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + if (DoCastSpellIfCan(pPlayer, SPELL_CONSUME_SOUL) == CAST_OK) + m_creature->ForcedDespawn(1000); } - else - m_uiDespawnTimer -= diff; } + + void UpdateAI(const uint32 /*uiDiff*/) override { } }; -/* ** TODO This code was unused for long time (not used in DB and pointless) - * ** Keep it temporarily as reference +/*###### +## npc_blade_of_azzinoth +######*/ -// Shadowfiends interact with Illidan, setting more targets in Illidan's hashmap -struct MANGOS_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI +struct npc_blade_of_azzinothAI : public ScriptedAI { - mob_parasitic_shadowfiendAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_blade_of_azzinothAI(Creature* pCreature) : ScriptedAI(pCreature) { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - void Reset() {} - - void DoMeleeAttackIfReady() - { - //If we are within range melee the target - if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) - { - //Make sure our attack is ready and we aren't currently casting - if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false)) - { - if (!m_creature->getVictim()->HasAura(SPELL_PARASITIC_SHADOWFIEND, EFFECT_INDEX_0)) - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PARASITIC_SHADOWFIEND, CAST_TRIGGERED); - - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - } - } - } -}; -*/ + ScriptedInstance* m_pInstance; -struct MANGOS_DLL_DECL blazeAI : public ScriptedAI -{ - blazeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + void Reset() override {} - uint32 m_uiBlazeTimer; - uint32 m_uiDespawnTimer; + // Do-Nothing-But-Stand-There + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void Reset() + void JustSummoned(Creature* pSummoned) override { - m_uiBlazeTimer = 2000; - m_uiDespawnTimer = 15000; + // Summon a Flame pear each blade + if (pSummoned->GetEntry() == NPC_FLAME_OF_AZZINOTH) + { + DoCastSpellIfCan(pSummoned, SPELL_AZZINOTH_CHANNEL, CAST_TRIGGERED); + pSummoned->SetInCombatWithZone(); + } } - void AttackStart(Unit* who) { } - - void MoveInLineOfSight(Unit *who){ } - - void UpdateAI(const uint32 diff) + void SummonedCreatureJustDied(Creature* pSummoned) override { - if (m_uiBlazeTimer < diff) + // Inform Illidan when a flame is killed + if (pSummoned->GetEntry() == NPC_FLAME_OF_AZZINOTH) { - DoCastSpellIfCan(m_creature, SPELL_BLAZE_EFFECT); - m_uiBlazeTimer = 15000; - } - else - m_uiBlazeTimer -= diff; + if (!m_pInstance) + return; - if (m_uiDespawnTimer < diff) - { - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + // For some reason it doesn't work with Spell Hit for SPELL_GLAIVE_RETURNS script effect, so we need to inform him manually + if (Creature* pIllidan = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDAN_STORMRAGE)) + { + if (boss_illidan_stormrageAI* pIllidanAI = dynamic_cast(pIllidan->AI())) + pIllidanAI->DoInformFlameKilled(); + } } - else - m_uiDespawnTimer -= diff; } -}; - -struct MANGOS_DLL_DECL blade_of_azzinothAI : public ScriptedAI -{ - blade_of_azzinothAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - void Reset() {} - - // Do-Nothing-But-Stand-There - void AttackStart(Unit* who) { } - void MoveInLineOfSight(Unit* who) { } + void UpdateAI(const uint32 /*uiDiff*/) override { } }; CreatureAI* GetAI_boss_illidan_stormrage(Creature* pCreature) @@ -2439,14 +1653,9 @@ CreatureAI* GetAI_boss_illidan_stormrage(Creature* pCreature) return new boss_illidan_stormrageAI(pCreature); } -CreatureAI* GetAI_npc_akama_at_illidan(Creature* pCreature) +CreatureAI* GetAI_npc_akama_illidan(Creature* pCreature) { - npc_akama_illidanAI* Akama_AI = new npc_akama_illidanAI(pCreature); - - for(uint8 i = 0; i < 13; ++i) - Akama_AI->AddWaypoint(i, aAkamaWP[i].x, aAkamaWP[i].y, aAkamaWP[i].z); - - return ((CreatureAI*)Akama_AI); + return new npc_akama_illidanAI(pCreature); } CreatureAI* GetAI_boss_maiev(Creature* pCreature) @@ -2456,45 +1665,23 @@ CreatureAI* GetAI_boss_maiev(Creature* pCreature) CreatureAI* GetAI_mob_flame_of_azzinoth(Creature* pCreature) { - return new flame_of_azzinothAI(pCreature); -} - -CreatureAI* GetAI_cage_trap_trigger(Creature* pCreature) -{ - return new cage_trap_triggerAI(pCreature); -} - -CreatureAI* GetAI_shadow_demon(Creature* pCreature) -{ - return new shadow_demonAI(pCreature); -} - -CreatureAI* GetAI_flamecrash(Creature* pCreature) -{ - return new flamecrashAI(pCreature); -} - -CreatureAI* GetAI_demonfire(Creature* pCreature) -{ - return new demonfireAI(pCreature); + return new npc_flame_of_azzinothAI(pCreature); } -CreatureAI* GetAI_blaze(Creature* pCreature) +CreatureAI* GetAI_npc_cage_trap_trigger(Creature* pCreature) { - return new blazeAI(pCreature); + return new npc_cage_trap_triggerAI(pCreature); } -CreatureAI* GetAI_blade_of_azzinoth(Creature* pCreature) +CreatureAI* GetAI_npc_shadow_demon(Creature* pCreature) { - return new blade_of_azzinothAI(pCreature); + return new npc_shadow_demonAI(pCreature); } -/* ** TODO dead code -CreatureAI* GetAI_parasitic_shadowfiend(Creature* pCreature) +CreatureAI* GetAI_npc_blade_of_azzinoth(Creature* pCreature) { - return new mob_parasitic_shadowfiendAI(pCreature); + return new npc_blade_of_azzinothAI(pCreature); } -*/ void AddSC_boss_illidan() { @@ -2507,9 +1694,9 @@ void AddSC_boss_illidan() pNewScript = new Script; pNewScript->Name = "npc_akama_illidan"; - pNewScript->GetAI = &GetAI_npc_akama_at_illidan; - pNewScript->pGossipHello = &GossipHello_npc_akama_at_illidan; - pNewScript->pGossipSelect = &GossipSelect_npc_akama_at_illidan; + pNewScript->GetAI = &GetAI_npc_akama_illidan; + pNewScript->pGossipHello = &GossipHello_npc_akama_illidan; + pNewScript->pGossipSelect = &GossipSelect_npc_akama_illidan; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -2524,43 +1711,16 @@ void AddSC_boss_illidan() pNewScript = new Script; pNewScript->Name = "mob_blade_of_azzinoth"; - pNewScript->GetAI = &GetAI_blade_of_azzinoth; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "gameobject_cage_trap"; - pNewScript->pGOUse = &GOUse_go_cage_trap; + pNewScript->GetAI = &GetAI_npc_blade_of_azzinoth; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "mob_cage_trap_trigger"; - pNewScript->GetAI = &GetAI_cage_trap_trigger; + pNewScript->GetAI = &GetAI_npc_cage_trap_trigger; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "mob_shadow_demon"; - pNewScript->GetAI = &GetAI_shadow_demon; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_flame_crash"; - pNewScript->GetAI = &GetAI_flamecrash; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_demon_fire"; - pNewScript->GetAI = &GetAI_demonfire; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_blaze"; - pNewScript->GetAI = &GetAI_blaze; - pNewScript->RegisterSelf(); - - /* ** TODO dead code - pNewScript = new Script; - pNewScript->Name = "mob_parasitic_shadowfiend"; - pNewScript->GetAI = &GetAI_parasitic_shadowfiend; + pNewScript->GetAI = &GetAI_npc_shadow_demon; pNewScript->RegisterSelf(); - */ } diff --git a/scripts/outland/black_temple/boss_mother_shahraz.cpp b/scripts/outland/black_temple/boss_mother_shahraz.cpp index cb93a835b..c5dd9ab98 100644 --- a/scripts/outland/black_temple/boss_mother_shahraz.cpp +++ b/scripts/outland/black_temple/boss_mother_shahraz.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,40 +17,41 @@ /* ScriptData SDName: Boss_Mother_Shahraz SD%Complete: 80 -SDComment: Saber Lash missing, Fatal Attraction slightly incorrect; need to damage only if affected players are within range of each other +SDComment: Saber Lash and Fatal Attraction need core support. Timers may need some tunning. SDCategory: Black Temple EndScriptData */ #include "precompiled.h" #include "black_temple.h" -//Speech'n'Sounds -#define SAY_TAUNT1 -1564018 -#define SAY_TAUNT2 -1564019 -#define SAY_TAUNT3 -1564020 -#define SAY_AGGRO -1564021 -#define SAY_SPELL1 -1564022 -#define SAY_SPELL2 -1564023 -#define SAY_SPELL3 -1564024 -#define SAY_SLAY1 -1564025 -#define SAY_SLAY2 -1564026 -#define SAY_ENRAGE -1564027 -#define SAY_DEATH -1564028 - -//Spells -#define SPELL_BEAM_SINISTER 40859 -#define SPELL_BEAM_VILE 40860 -#define SPELL_BEAM_WICKED 40861 -#define SPELL_BEAM_SINFUL 40827 -#define SPELL_ATTRACTION 40871 -#define SPELL_SILENCING_SHRIEK 40823 -#define SPELL_ENRAGE 23537 -#define SPELL_SABER_LASH 43267 -#define SPELL_SABER_LASH_IMM 43690 -#define SPELL_TELEPORT_VISUAL 40869 -#define SPELL_BERSERK 45078 - -uint32 PrismaticAuras[]= +enum +{ + // Speech'n'Sounds + SAY_TAUNT_1 = -1564018, + SAY_TAUNT_2 = -1564019, + SAY_TAUNT_3 = -1564020, + SAY_AGGRO = -1564021, + SAY_SPELL_1 = -1564022, + SAY_SPELL_2 = -1564023, + SAY_SPELL_3 = -1564024, + SAY_SLAY_1 = -1564025, + SAY_SLAY_2 = -1564026, + SAY_ENRAGE = -1564027, + SAY_DEATH = -1564028, + + // Spells + SPELL_SINFUL_PERIODIC = 40862, // periodic triggers 40827 + SPELL_SINISTER_PERIODIC = 40863, // periodic triggers 40859 + SPELL_VILE_PERIODIC = 40865, // periodic triggers 40860 + SPELL_WICKED_PERIODIC = 40866, // periodic triggers 40861 + SPELL_FATAL_ATTRACTION = 40869, // dummy, triggers 41001 + SPELL_SILENCING_SHRIEK = 40823, + SPELL_SABER_LASH_PROC = 40816, // procs 40810 and 43690 on melee damage + SPELL_FRENZY = 23537, + SPELL_BERSERK = 45078, +}; + +static const uint32 aPrismaticAuras[] = { 40880, // Shadow 40882, // Fire @@ -60,66 +61,44 @@ uint32 PrismaticAuras[]= 40897, // Holy }; -struct Locations -{ - float x,y,z; -}; +static const uint32 aPeriodicBeams[] = {SPELL_SINFUL_PERIODIC, SPELL_SINISTER_PERIODIC, SPELL_VILE_PERIODIC, SPELL_WICKED_PERIODIC}; -static Locations TeleportPoint[]= -{ - {959.996f, 212.576f, 193.843f}, - {932.537f, 231.813f, 193.838f}, - {958.675f, 254.767f, 193.822f}, - {946.955f, 201.316f, 192.535f}, - {944.294f, 149.676f, 197.551f}, - {930.548f, 284.888f, 193.367f}, - {965.997f, 278.398f, 195.777f} -}; - -struct MANGOS_DLL_DECL boss_shahrazAI : public ScriptedAI +struct boss_shahrazAI : public ScriptedAI { boss_shahrazAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_black_temple*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; + instance_black_temple* m_pInstance; - ObjectGuid m_targetGuid[3]; - uint32 BeamTimer; - uint32 BeamCount; - uint32 CurrentBeam; - uint32 PrismaticShieldTimer; - uint32 FatalAttractionTimer; - uint32 FatalAttractionExplodeTimer; - uint32 ShriekTimer; - uint32 RandomYellTimer; - uint32 EnrageTimer; - uint32 ExplosionCount; + uint32 m_uiBeamTimer; + uint32 m_uiPrismaticShieldTimer; + uint32 m_uiFatalAttractionTimer; + uint32 m_uiShriekTimer; + uint32 m_uiRandomYellTimer; + uint32 m_uiBerserkTimer; + uint8 m_uiCurrentBeam; - bool Enraged; + bool m_bIsEnraged; - void Reset() + void Reset() override { - for (uint8 i = 0; i < 3; ++i) - m_targetGuid[i].Clear(); - - BeamTimer = 60000; // Timers may be incorrect - BeamCount = 0; - CurrentBeam = 0; // 0 - Sinister, 1 - Vile, 2 - Wicked, 3 - Sinful - PrismaticShieldTimer = 0; - FatalAttractionTimer = 60000; - FatalAttractionExplodeTimer = 70000; - ShriekTimer = 30000; - RandomYellTimer = urand(70000, 110000); - EnrageTimer = 600000; - ExplosionCount = 0; - - Enraged = false; + m_uiBeamTimer = urand(5000, 10000); + m_uiCurrentBeam = urand(0, 3); + m_uiPrismaticShieldTimer = 0; + m_uiFatalAttractionTimer = 25000; + m_uiShriekTimer = 30000; + m_uiRandomYellTimer = urand(70000, 110000); + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_bIsEnraged = false; + + DoCastSpellIfCan(m_creature, SPELL_SABER_LASH_PROC); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SHAHRAZ, IN_PROGRESS); @@ -127,18 +106,18 @@ struct MANGOS_DLL_DECL boss_shahrazAI : public ScriptedAI DoScriptText(SAY_AGGRO, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_SHAHRAZ, NOT_STARTED); + m_pInstance->SetData(TYPE_SHAHRAZ, FAIL); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*pVictim*/) override { - DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); + DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SHAHRAZ, DONE); @@ -146,146 +125,94 @@ struct MANGOS_DLL_DECL boss_shahrazAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); } - void TeleportPlayers() - { - uint32 random = urand(0, 6); - float X = TeleportPoint[random].x; - float Y = TeleportPoint[random].y; - float Z = TeleportPoint[random].z; - - for(uint8 i = 0; i < 3; ++i) - { - Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (pUnit && pUnit->isAlive() && (pUnit->GetTypeId() == TYPEID_PLAYER)) - { - m_targetGuid[i] = pUnit->GetObjectGuid(); - pUnit->CastSpell(pUnit, SPELL_TELEPORT_VISUAL, true); - DoTeleportPlayer(pUnit, X, Y, Z, pUnit->GetOrientation()); - } - } - } - - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->GetHealthPercent() < 10.0f && !Enraged) + if (m_creature->GetHealthPercent() < 10.0f && !m_bIsEnraged) { - Enraged = true; - DoCastSpellIfCan(m_creature, SPELL_ENRAGE, CAST_TRIGGERED); - DoScriptText(SAY_ENRAGE, m_creature); + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_bIsEnraged = true; + } } - //Randomly cast one beam. - if (BeamTimer < diff) + // Randomly cast one beam. + if (m_uiBeamTimer < uiDiff) { - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (!target || !target->isAlive()) - return; - - BeamTimer = 9000; - - switch(CurrentBeam) + if (DoCastSpellIfCan(m_creature, aPeriodicBeams[m_uiCurrentBeam]) == CAST_OK) { - case 0: - DoCastSpellIfCan(target, SPELL_BEAM_SINISTER); - break; - case 1: - DoCastSpellIfCan(target, SPELL_BEAM_VILE); - break; - case 2: - DoCastSpellIfCan(target, SPELL_BEAM_WICKED); - break; - case 3: - DoCastSpellIfCan(target, SPELL_BEAM_SINFUL); - break; + uint8 uiNextBeam = (m_uiCurrentBeam + urand(1, 3)) % 4; + m_uiCurrentBeam = uiNextBeam; + m_uiBeamTimer = urand(10000, 13000); } - ++BeamCount; - uint32 Beam = CurrentBeam; - - if (BeamCount > 3) - while(CurrentBeam == Beam) - CurrentBeam = urand(0, 2); - - }else BeamTimer -= diff; + } + else + m_uiBeamTimer -= uiDiff; // Random Prismatic Shield every 15 seconds. - if (PrismaticShieldTimer < diff) - { - uint32 random = urand(0, 5); - if (PrismaticAuras[random]) - DoCastSpellIfCan(m_creature, PrismaticAuras[random]); - PrismaticShieldTimer = 15000; - }else PrismaticShieldTimer -= diff; - - // Select 3 random targets (can select same target more than once), teleport to a random location then make them cast explosions until they get away from each other. - if (FatalAttractionTimer < diff) + if (m_uiPrismaticShieldTimer < uiDiff) { - ExplosionCount = 0; - - TeleportPlayers(); - - DoScriptText(urand(0, 1) ? SAY_SPELL2 : SAY_SPELL3, m_creature); - - FatalAttractionExplodeTimer = 2000; - FatalAttractionTimer = urand(40000, 70000); - }else FatalAttractionTimer -= diff; + if (DoCastSpellIfCan(m_creature, aPrismaticAuras[urand(0, 5)]) == CAST_OK) + m_uiPrismaticShieldTimer = 15000; + } + else + m_uiPrismaticShieldTimer -= uiDiff; - if (FatalAttractionExplodeTimer < diff) + if (m_uiFatalAttractionTimer < uiDiff) { - // Just make them explode three times... they're supposed to keep exploding while they are in range, but it'll take too much code. I'll try to think of an efficient way for it later. - if (ExplosionCount < 3) + if (DoCastSpellIfCan(m_creature, SPELL_FATAL_ATTRACTION) == CAST_OK) { - for(uint8 i = 0; i < 3; ++i) + switch (urand(0, 2)) { - if (m_targetGuid[i]) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_targetGuid[i])) - pPlayer->CastSpell(pPlayer, SPELL_ATTRACTION, true); - - m_targetGuid[i].Clear(); - } + case 0: DoScriptText(SAY_SPELL_1, m_creature); break; + case 1: DoScriptText(SAY_SPELL_2, m_creature); break; + case 2: DoScriptText(SAY_SPELL_3, m_creature); break; } - - ++ExplosionCount; - FatalAttractionExplodeTimer = 1000; + m_uiFatalAttractionTimer = urand(30000, 40000); } - else - { - FatalAttractionExplodeTimer = FatalAttractionTimer + 2000; - ExplosionCount = 0; - } - }else FatalAttractionExplodeTimer -= diff; + } + else + m_uiFatalAttractionTimer -= uiDiff; - if (ShriekTimer < diff) + if (m_uiShriekTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SILENCING_SHRIEK); - ShriekTimer = 30000; - }else ShriekTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SILENCING_SHRIEK) == CAST_OK) + m_uiShriekTimer = 30000; + } + else + m_uiShriekTimer -= uiDiff; - //Enrage - if (!m_creature->HasAura(SPELL_BERSERK, EFFECT_INDEX_0)) + if (m_uiBerserkTimer) { - if (EnrageTimer < diff) + if (m_uiBerserkTimer <= uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - DoScriptText(SAY_ENRAGE, m_creature); - }else EnrageTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiBerserkTimer = 0; + } + } + else + m_uiBerserkTimer -= uiDiff; } - //Random taunts - if (RandomYellTimer < diff) + // Random taunts + if (m_uiRandomYellTimer < uiDiff) { - switch(urand(0, 2)) + switch (urand(0, 2)) { - case 0: DoScriptText(SAY_TAUNT1, m_creature); break; - case 1: DoScriptText(SAY_TAUNT2, m_creature); break; - case 2: DoScriptText(SAY_TAUNT3, m_creature); break; + case 0: DoScriptText(SAY_TAUNT_1, m_creature); break; + case 1: DoScriptText(SAY_TAUNT_2, m_creature); break; + case 2: DoScriptText(SAY_TAUNT_3, m_creature); break; } - RandomYellTimer = urand(60000, 150000); - }else RandomYellTimer -= diff; + m_uiRandomYellTimer = urand(60000, 150000); + } + else + m_uiRandomYellTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/outland/black_temple/boss_reliquary_of_souls.cpp b/scripts/outland/black_temple/boss_reliquary_of_souls.cpp index 396209101..aabef147e 100644 --- a/scripts/outland/black_temple/boss_reliquary_of_souls.cpp +++ b/scripts/outland/black_temple/boss_reliquary_of_souls.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,113 +24,90 @@ EndScriptData */ #include "precompiled.h" #include "black_temple.h" -//Sound'n'speech -//Suffering -#define SUFF_SAY_FREED -1564047 -#define SUFF_SAY_AGGRO -1564048 -#define SUFF_SAY_SLAY1 -1564049 -#define SUFF_SAY_SLAY2 -1564050 -#define SUFF_SAY_SLAY3 -1564051 -#define SUFF_SAY_RECAP -1564052 -#define SUFF_SAY_AFTER -1564053 -#define EMOTE_BOSS_GENERIC_ENRAGED -1000006 - -//Desire -#define DESI_SAY_FREED -1564055 -#define DESI_SAY_SLAY1 -1564056 -#define DESI_SAY_SLAY2 -1564057 -#define DESI_SAY_SLAY3 -1564058 -#define DESI_SAY_SPEC -1564059 -#define DESI_SAY_RECAP -1564060 -#define DESI_SAY_AFTER -1564061 - -//Anger -#define ANGER_SAY_FREED -1564062 -#define ANGER_SAY_FREED2 -1564063 -#define ANGER_SAY_SLAY1 -1564064 -#define ANGER_SAY_SLAY2 -1564065 -#define ANGER_SAY_SPEC -1564066 -#define ANGER_SAY_BEFORE -1564067 -#define ANGER_SAY_DEATH -1564068 - -//Spells -#define AURA_OF_SUFFERING 41292 -#define AURA_OF_SUFFERING_ARMOR 42017 -#define ESSENCE_OF_SUFFERING_PASSIVE 41296 -#define SPELL_ENRAGE 41305 -#define SPELL_SOUL_DRAIN 41303 -#define SPELL_FIXATE 41295 - -#define AURA_OF_DESIRE 41350 -#define SPELL_RUNE_SHIELD 41431 -#define SPELL_DEADEN 41410 -#define SPELL_SOUL_SHOCK 41426 - -#define AURA_OF_ANGER 41337 -#define SPELL_SELF_SEETHE 41364 -#define SPELL_ENEMY_SEETHE 41520 -#define SPELL_SOUL_SCREAM 41545 -#define SPELL_SPITE 41377 - -#define ENSLAVED_SOUL_PASSIVE 41535 -#define SPELL_SOUL_RELEASE 41542 -#define SPELL_RESTORE_MANA 32848 -#define SPELL_RESTORE_HEALTH 25329 - -#define CREATURE_ENSLAVED_SOUL 23469 - -struct ReliquaryPosition +enum { - float x,y; + // Sound'n'speech + // Suffering + SUFF_SAY_FREED = -1564047, + SUFF_SAY_AGGRO = -1564048, + SUFF_SAY_SLAY1 = -1564049, + SUFF_SAY_SLAY2 = -1564050, + SUFF_SAY_FRENZY = -1564051, + SUFF_SAY_RECAP = -1564052, + SUFF_SAY_AFTER = -1564053, + EMOTE_BOSS_GENERIC_ENRAGED = -1000006, + + // Desire + DESI_SAY_FREED = -1564055, + DESI_SAY_SLAY1 = -1564056, + DESI_SAY_SLAY2 = -1564057, + DESI_SAY_SLAY3 = -1564058, + DESI_SAY_SPEC = -1564059, + DESI_SAY_RECAP = -1564060, + DESI_SAY_AFTER = -1564061, + + // Anger + ANGER_SAY_FREED = -1564062, + ANGER_SAY_FREED2 = -1564063, + ANGER_SAY_SLAY1 = -1564064, + ANGER_SAY_SLAY2 = -1564065, + ANGER_SAY_SPEC = -1564066, + ANGER_SAY_BEFORE = -1564067, + ANGER_SAY_DEATH = -1564068, + + // Spells + // Suffering + SPELL_AURA_OF_SUFFERING = 41292, + SPELL_AURA_OF_SUFFERING_ARMOR = 42017, + SPELL_SUFFERING_PASSIVE = 41296, + SPELL_SUFFERING_PASSIVE_2 = 41623, + SPELL_FRENZY = 41305, + SPELL_SOUL_DRAIN = 41303, + + // Desire + SPELL_AURA_OF_DESIRE = 41350, + SPELL_RUNE_SHIELD = 41431, + SPELL_DEADEN = 41410, + SPELL_SPIRIT_SHOCK = 41426, + + // Anger + SPELL_AURA_OF_ANGER = 41337, + SPELL_SEETHE = 41364, + SPELL_SOUL_SCREAM = 41545, + SPELL_SPITE = 41376, // triggers 41377 after 2 seconds + + // Generic + SPELL_SUMMON_ESSENCE_SUFFERING = 41488, + SPELL_SUMMON_ESSENCE_DESIRE = 41493, + SPELL_SUMMON_ESSENCE_ANGER = 41496, + SPELL_SUMMON_ENSLAVED_SOUL = 41537, + + // Soul spells + SPELL_ENSLAVED_SOUL_PASSIVE = 41535, + SPELL_SOUL_RELEASE = 41542, + + // Summons + NPC_ESSENCE_SUFFERING = 23418, + NPC_ESSENCE_DESIRE = 23419, + NPC_ESSENCE_ANGER = 23420, + NPC_ENSLAVED_SOUL = 23469, + + // Phases + PHASE_0_NOT_BEGUN = 0, + PHASE_1_SUFFERING = 1, + PHASE_2_DESIRE = 2, + PHASE_3_ANGER = 3, + + MAX_ENSLAVED_SOULS = 36, }; -static ReliquaryPosition Coords[]= -{ - {450.4f, 212.3f}, - {542.1f, 212.3f}, - {542.1f, 168.3f}, - {542.1f, 137.4f}, - {450.4f, 137.4f}, - {450.4f, 168.3f} -}; +/*###### +## boss_reliquary_of_souls +######*/ -struct MANGOS_DLL_DECL npc_enslaved_soulAI : public ScriptedAI +struct boss_reliquary_of_soulsAI : public Scripted_NoMovementAI { - npc_enslaved_soulAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - ObjectGuid m_reliquaryGuid; - - void Reset() - { - m_reliquaryGuid.Clear(); - } - - void DamageTaken(Unit *done_by, uint32 &damage) - { - if (damage >= m_creature->GetHealth()) - { - if (done_by->GetTypeId() == TYPEID_PLAYER) - { - done_by->CastSpell(done_by, SPELL_RESTORE_HEALTH, true); - if (done_by->GetMaxPower(POWER_MANA) > 0) - { - if ((done_by->GetPower(POWER_MANA) / done_by->GetMaxPower(POWER_MANA)) < 70) - { - uint32 mana = done_by->GetPower(POWER_MANA) + (uint32)(done_by->GetMaxPower(POWER_MANA)*0.3); - done_by->SetPower(POWER_MANA, mana); - }else done_by->SetPower(POWER_MANA, done_by->GetMaxPower(POWER_MANA)); - } - } - DoCastSpellIfCan(done_by, SPELL_SOUL_RELEASE); - } - } - - void JustDied(Unit *killer); -}; - -struct MANGOS_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI -{ - boss_reliquary_of_soulsAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_reliquary_of_soulsAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -138,591 +115,359 @@ struct MANGOS_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI ScriptedInstance* m_pInstance; - ObjectGuid m_sufferingGuid; - ObjectGuid m_desireGuid; - ObjectGuid m_angerGuid; - - uint32 SoulDeathCount; - // 0 = Out of Combat, 1 = Not started, 2 = Suffering, 3 = Souls, 4 = Desire, 5 = Souls, 6 = Anger - uint32 Phase; - uint32 SummonEssenceTimer; - uint32 DespawnEssenceTimer; - uint32 SoulCount; - uint32 SummonSoulTimer; - uint32 AnimationTimer; + uint8 m_uiPhase; + uint8 m_uiSoulSummonedCount; + uint8 m_uiSoulDeathCount; - bool IsDead; - bool EndingPhase; + uint32 m_uiSummonEssenceTimer; + uint32 m_uiSummonSoulTimer; + uint32 m_uiAnimationTimer; + uint32 m_uiAnimResetTimer; - void Reset() + void Reset() override { - DespawnEssences(); + m_uiPhase = PHASE_0_NOT_BEGUN; + m_uiSoulDeathCount = 0; + m_uiSoulSummonedCount = 0; - SoulDeathCount = 0; - Phase = 0; - SummonEssenceTimer = 8000; - DespawnEssenceTimer = 2000; - SoulCount = 0; - SummonSoulTimer = 1000; - AnimationTimer = 8000; + m_uiSummonSoulTimer = 1000; + m_uiAnimationTimer = 0; + m_uiAnimResetTimer = 0; + m_uiSummonEssenceTimer = 0; - IsDead = false; - EndingPhase = false; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->HandleEmote(EMOTE_ONESHOT_NONE); - m_creature->GetMotionMaster()->Clear(false); + // Reset animation + m_creature->HandleEmote(EMOTE_STATE_NONE); } - void JustReachedHome() + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) - m_pInstance->SetData(TYPE_RELIQUIARY, NOT_STARTED); + m_pInstance->SetData(TYPE_RELIQUIARY, DONE); } - void DespawnEssences() + void JustReachedHome() override { - Creature* pEssence = NULL; - - if (m_sufferingGuid) - pEssence = m_creature->GetMap()->GetCreature(m_sufferingGuid); - else if (m_desireGuid) - pEssence = m_creature->GetMap()->GetCreature(m_desireGuid); - else if (m_angerGuid) - pEssence = m_creature->GetMap()->GetCreature(m_angerGuid); - - if (pEssence && pEssence->isAlive()) - pEssence->ForcedDespawn(); + if (m_pInstance) + m_pInstance->SetData(TYPE_RELIQUIARY, FAIL); } - void AttackStart(Unit* who) { } + void AttackStart(Unit* /*pWho*/) override { } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) + if (m_uiPhase == PHASE_0_NOT_BEGUN && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho)) { - float attackRadius = m_creature->GetAttackDistance(who); - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who)) - { - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - - if (m_creature->getThreatManager().getThreatList().empty()) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_RELIQUIARY, IN_PROGRESS); + // Start phase 1 + m_uiPhase = PHASE_1_SUFFERING; + m_uiSummonEssenceTimer = 7000; + m_uiAnimationTimer = 4000; - Phase = 1; + // Set the player in combat with the boss + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho); - // I R ANNNGRRRY! - m_creature->HandleEmote(EMOTE_STATE_READY2H); - SummonEssenceTimer = 8000; - AnimationTimer = 5100; - m_creature->AddThreat(who); - //m_creature->SetInCombatWith(who); // Don't know what is like retail - //who->SetInCombatWith(m_creature); - m_creature->SetInCombatWithZone(); // Same goes here, but setting to zone will prevent bug if the only player of threatList dies + // Start animation + m_creature->SetStandState(UNIT_STAND_STATE_STAND); - } - } + if (m_pInstance) + m_pInstance->SetData(TYPE_RELIQUIARY, IN_PROGRESS); } } - void SummonSoul() + void JustSummoned(Creature* pSummoned) override { - uint32 random = urand(0, 5); - float x = Coords[random].x; - float y = Coords[random].y; - - Creature* Soul = m_creature->SummonCreature(CREATURE_ENSLAVED_SOUL, x, y, m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); - Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (target && Soul) - { - if (npc_enslaved_soulAI* pSoulAI = dynamic_cast(Soul->AI())) - pSoulAI->m_reliquaryGuid = m_creature->GetObjectGuid(); - - Soul->CastSpell(Soul, ENSLAVED_SOUL_PASSIVE, true); - Soul->AddThreat(target); - ++SoulCount; + switch (pSummoned->GetEntry()) + { + case NPC_ESSENCE_SUFFERING: + DoScriptText(SUFF_SAY_FREED, pSummoned); + break; + case NPC_ESSENCE_DESIRE: + DoScriptText(DESI_SAY_FREED, pSummoned); + break; + case NPC_ESSENCE_ANGER: + DoScriptText(ANGER_SAY_FREED, pSummoned); + break; } - } - void MergeThreatList(Creature* target) - { - if (!target) - return; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - if (Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) - { - m_creature->AddThreat(pUnit); // This is so that we make sure the unit is in Reliquary's threat list before we reset the unit's threat. - m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); - float threat = target->getThreatManager().getThreat(pUnit); - m_creature->AddThreat(pUnit, threat); // This makes it so that the unit has the same amount of threat in Reliquary's threatlist as in the target creature's (One of the Essences). - } - } + // All summons are set in combat + pSummoned->SetInCombatWithZone(); } - void JustDied(Unit* killer) + void SummonedCreatureJustDied(Creature* pSummoned) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_RELIQUIARY, DONE); + // Self kill when the Essence of Anger is killed + if (pSummoned->GetEntry() == NPC_ESSENCE_ANGER) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } - void UpdateAI(const uint32 diff) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMoveType, uint32 uiPointId) override { - if (!Phase) + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) return; - // Reset if event is begun and we don't have a threatlist - if (Phase && m_creature->getThreatManager().getThreatList().empty()) - EnterEvadeMode(); - - if (Phase == 1) - { - if (AnimationTimer < diff) - { - // Release the cube - m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - AnimationTimer = 8300; - }else AnimationTimer -= diff; - - if (SummonEssenceTimer < diff) - { - // Ribs: open - m_creature->HandleEmote(EMOTE_STATE_SUBMERGED); + // Switch to next phase when the essence gets back + switch (pSummoned->GetEntry()) + { + case NPC_ESSENCE_SUFFERING: + DoScriptText(SUFF_SAY_AFTER, pSummoned); + m_uiPhase = PHASE_2_DESIRE;; + break; + case NPC_ESSENCE_DESIRE: + DoScriptText(DESI_SAY_AFTER, pSummoned); + m_uiPhase = PHASE_3_ANGER; + break; + } - Creature* EssenceSuffering = m_creature->SummonCreature(23418, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); + // Despawn and set animation + pSummoned->ForcedDespawn(); - if (EssenceSuffering) - { - DoScriptText(SUFF_SAY_FREED, EssenceSuffering); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0)) - { - EssenceSuffering->AddThreat(target); - EssenceSuffering->AI()->AttackStart(target); - } + m_uiSoulDeathCount = 0; + m_uiSoulSummonedCount = 0; + m_uiAnimResetTimer = 2000; + // Reset animation + m_creature->HandleEmote(EMOTE_ONESHOT_EMERGE); + } - m_sufferingGuid = EssenceSuffering->GetObjectGuid(); - } + // Wrapper to count the dead spirits + void DoNotifySouldDead() + { + ++m_uiSoulDeathCount; - EndingPhase = false; - Phase = 2; - }else SummonEssenceTimer -= diff; + // Prepare to summon the essence + if (m_uiSoulDeathCount == MAX_ENSLAVED_SOULS) + { + m_uiSummonEssenceTimer = 7000; + m_uiAnimationTimer = 4000; } + } - if (Phase == 2) + void UpdateAI(const uint32 uiDiff) override + { + // Animation for opening the Reliquary + if (m_uiAnimationTimer) { - if (m_sufferingGuid) + if (m_uiAnimationTimer <= uiDiff) { - Creature* EssenceSuffering = m_creature->GetMap()->GetCreature(m_sufferingGuid); - - if (!EssenceSuffering || (!EssenceSuffering->isAlive())) - EnterEvadeMode(); - - if (!EndingPhase) - { - if (EssenceSuffering) - { - if (EssenceSuffering->GetHealthPercent() < 10.0f) - { - DoScriptText(SUFF_SAY_RECAP, EssenceSuffering); - MergeThreatList(EssenceSuffering); - EssenceSuffering->RemoveAllAuras(); - EssenceSuffering->DeleteThreatList(); - EssenceSuffering->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); - EssenceSuffering->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DespawnEssenceTimer = 4000; - AnimationTimer = 2200; - EndingPhase = true; - } - } - } - - if ((EndingPhase) && (EssenceSuffering) && (EssenceSuffering->isAlive())) - { - if (AnimationTimer < diff) - { - // Return - EssenceSuffering->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (DespawnEssenceTimer < diff) - { - DoScriptText(SUFF_SAY_AFTER, EssenceSuffering); - - EssenceSuffering->DeleteThreatList(); - EssenceSuffering->SetDisplayId(11686); - EssenceSuffering->setFaction(35); - m_creature->HandleEmote(EMOTE_ONESHOT_NONE); - SummonEssenceTimer = 20000; //60000; - AnimationTimer = 18200; //58100; - SoulDeathCount = 0; - SoulCount = 0; - SummonSoulTimer = 1000; - EndingPhase = false; - Phase = 3; - m_sufferingGuid.Clear(); - }else DespawnEssenceTimer -= diff; - } + m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); + m_uiAnimationTimer = 0; } + else + m_uiAnimationTimer -= uiDiff; } - if (Phase == 3) + // Animation for reset Reliquary + if (m_uiAnimResetTimer) { - if (SoulCount < 36) + if (m_uiAnimResetTimer <= uiDiff) { - if (SummonSoulTimer < diff) - { - SummonSoul(); - SummonSoulTimer = 500; - }else SummonSoulTimer -= diff; - } - - if (SoulDeathCount >= SoulCount) - { - if (AnimationTimer < diff) - { - // Release the cube - m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (SummonEssenceTimer < diff) - { - // Ribs: open - m_creature->HandleEmote(EMOTE_STATE_SUBMERGED); - - Creature* EssenceDesire = m_creature->SummonCreature(23419, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 10000); - - if (EssenceDesire) - { - DoScriptText(DESI_SAY_FREED, EssenceDesire); - - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - EssenceDesire->AddThreat(target); - EssenceDesire->AI()->AttackStart(target); - } - - m_desireGuid = EssenceDesire->GetObjectGuid(); - SoulDeathCount = 0; - } - - Phase = 4; - }else SummonEssenceTimer -= diff; + // Reset animation + m_creature->HandleEmote(EMOTE_STATE_NONE); + m_uiAnimResetTimer = 0; } + else + m_uiAnimResetTimer -= uiDiff; } - if (Phase == 4) + // Summon the Essence on timer + if (m_uiSummonEssenceTimer) { - if (m_desireGuid) + if (m_uiSummonEssenceTimer <= uiDiff) { - Creature* EssenceDesire = m_creature->GetMap()->GetCreature(m_desireGuid); - - if (!EssenceDesire || !EssenceDesire->isAlive()) - EnterEvadeMode(); - - if (!EndingPhase && EssenceDesire) + uint32 uiSpellId = 0; + switch (m_uiPhase) { - if (EssenceDesire->GetHealthPercent() < 10.0f) - { - MergeThreatList(EssenceDesire); - EssenceDesire->GetMotionMaster()->MoveFollow(m_creature,0.0f,0.0f); - EssenceDesire->RemoveAllAuras(); - EssenceDesire->DeleteThreatList(); - - DoScriptText(DESI_SAY_RECAP, EssenceDesire); - - EssenceDesire->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DespawnEssenceTimer = 4000; - AnimationTimer = 2200; - EndingPhase = true; - } + case PHASE_1_SUFFERING: uiSpellId = SPELL_SUMMON_ESSENCE_SUFFERING; break; + case PHASE_2_DESIRE: uiSpellId = SPELL_SUMMON_ESSENCE_DESIRE; break; + case PHASE_3_ANGER: uiSpellId = SPELL_SUMMON_ESSENCE_ANGER; break; } - if (EndingPhase && EssenceDesire) + if (DoCastSpellIfCan(m_creature, uiSpellId) == CAST_OK) { - if (EssenceDesire->isAlive()) - { - if (AnimationTimer < diff) - { - // Return - EssenceDesire->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (DespawnEssenceTimer < diff) - { - EssenceDesire->DeleteThreatList(); - EssenceDesire->setFaction(35); - - DoScriptText(DESI_SAY_AFTER, EssenceDesire); - - EssenceDesire->SetDisplayId(11686); - m_creature->HandleEmote(EMOTE_ONESHOT_NONE); - SummonEssenceTimer = 20000; - AnimationTimer = 18200; - SoulDeathCount = 0; - SoulCount = 0; - SummonSoulTimer = 1000; - EndingPhase = false; - Phase = 5; - m_desireGuid.Clear(); - }else DespawnEssenceTimer -= diff; - } + m_creature->HandleEmote(EMOTE_STATE_SUBMERGED); + m_uiSummonEssenceTimer = 0; } } + else + m_uiSummonEssenceTimer -= uiDiff; } - if (Phase == 5) + // Summon Enslaved souls between the essence + switch (m_uiPhase) { - if (SoulCount < 36) - { - if (SummonSoulTimer < diff) - { - SummonSoul(); - SummonSoulTimer = 500; - }else SummonSoulTimer -= diff; - } + case PHASE_2_DESIRE: + case PHASE_3_ANGER: - if (SoulDeathCount >= SoulCount) - { - if (AnimationTimer < diff) + if (m_uiSoulSummonedCount < MAX_ENSLAVED_SOULS) { - // Release the cube - m_creature->HandleEmote(EMOTE_ONESHOT_SUBMERGE); - AnimationTimer = 10000; - }else AnimationTimer -= diff; - - if (SummonEssenceTimer < diff) - { - // Ribs: open - m_creature->HandleEmote(EMOTE_STATE_SUBMERGED); - - Creature* EssenceAnger = m_creature->SummonCreature(23420, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 1.57f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); - - if (EssenceAnger) + if (m_uiSummonSoulTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0)) + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_ENSLAVED_SOUL) == CAST_OK) { - EssenceAnger->AddThreat(target); - EssenceAnger->AI()->AttackStart(target); + ++m_uiSoulSummonedCount; + m_uiSummonSoulTimer = 500; } - - m_angerGuid = EssenceAnger->GetObjectGuid(); - DoScriptText(ANGER_SAY_FREED, EssenceAnger); - SoulDeathCount = 0; - } - - Phase = 6; - }else SummonEssenceTimer -= diff; - } - } - - if (Phase == 6) - { - if (m_angerGuid) - { - Creature* EssenceAnger = m_creature->GetMap()->GetCreature(m_angerGuid); - - if (!EssenceAnger) - EnterEvadeMode(); - - if (m_creature->isAlive() && EssenceAnger) - { - if (!EssenceAnger->isAlive()) - { - m_angerGuid.Clear(); - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } + else + m_uiSummonSoulTimer -= uiDiff; } - } + + break; } } }; -struct MANGOS_DLL_DECL boss_essence_of_sufferingAI : public ScriptedAI -{ - boss_essence_of_sufferingAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} +/*###### +## essence_base_AI +######*/ - ObjectGuid m_statAuraGuid; // TODO currently unused - bug? +struct essence_base_AI : public ScriptedAI +{ + essence_base_AI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsPhaseFinished = false; + } - uint32 AggroYellTimer; - uint32 FixateTimer; - uint32 EnrageTimer; - uint32 SoulDrainTimer; + ScriptedInstance* m_pInstance; - void Reset() - { - m_statAuraGuid.Clear(); + bool m_bIsPhaseFinished; - AggroYellTimer = 5000; - FixateTimer = 5000; - EnrageTimer = 30000; - SoulDrainTimer = 150000; - } + virtual void OnPhaseFinished() {} - void DamageTaken(Unit *done_by, uint32 &damage) + void JustReachedHome() override { - if ((damage >= m_creature->GetHealth()) && (done_by != m_creature)) + // Reset encounter and despawn Essence + if (m_pInstance) { - damage = 0; - // 10% of total health, signalling time to return - m_creature->SetHealth(m_creature->GetMaxHealth()/10); - if (m_statAuraGuid) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_statAuraGuid)) - pPlayer->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); - } + if (Creature* pReliquary = m_pInstance->GetSingleCreatureFromStorage(NPC_RELIQUARY_OF_SOULS)) + pReliquary->AI()->EnterEvadeMode(); } - } - void Aggro(Unit* pWho) - { - DoCastSpellIfCan(pWho, AURA_OF_SUFFERING, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, ESSENCE_OF_SUFFERING_PASSIVE, CAST_TRIGGERED); + m_creature->ForcedDespawn(); } - void KilledUnit(Unit *victim) + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override { - switch(urand(0, 2)) + if (uiDamage < m_creature->GetHealth()) + return; + + // Prevent glitch if in fake death + if (m_bIsPhaseFinished) { - case 0: DoScriptText(SUFF_SAY_SLAY1, m_creature); break; - case 1: DoScriptText(SUFF_SAY_SLAY2, m_creature); break; - case 2: DoScriptText(SUFF_SAY_SLAY3, m_creature); break; + uiDamage = 0; + return; } - } - void JustDied(Unit* killer) - { + uiDamage = 0; + + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(0); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + + if (!m_pInstance) + return; + + // Move to home position + if (Creature* pReliquary = m_pInstance->GetSingleCreatureFromStorage(NPC_RELIQUARY_OF_SOULS)) + m_creature->GetMotionMaster()->MovePoint(1, pReliquary->GetPositionX(), pReliquary->GetPositionY(), pReliquary->GetPositionZ()); + + m_bIsPhaseFinished = true; + + OnPhaseFinished(); } +}; - void CastFixate() - { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - if (tList.empty()) - return; // No point continuing if empty threatlist. +/*###### +## boss_essence_of_suffering +######*/ - std::list targets; +struct boss_essence_of_sufferingAI : public essence_base_AI +{ + boss_essence_of_sufferingAI(Creature* pCreature) : essence_base_AI(pCreature) { Reset(); } - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) - { - Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); + uint32 m_uiEnrageTimer; + uint32 m_uiSoulDrainTimer; - // Only alive players - if (pUnit && pUnit->isAlive() && pUnit->GetTypeId() == TYPEID_PLAYER) - targets.push_back(pUnit); - } + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_AURA_OF_SUFFERING, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUFFERING_PASSIVE, CAST_TRIGGERED); - if (targets.empty()) - return; // No targets added for some reason. No point continuing. + m_uiEnrageTimer = 45000; + m_uiSoulDrainTimer = 20000; + } - targets.sort(ObjectDistanceOrder(m_creature)); // Sort players by distance. - targets.resize(1); // Only need closest target. - Unit* target = targets.front(); // Get the first target. + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SUFF_SAY_SLAY1 : SUFF_SAY_SLAY2, m_creature); + } - // Add threat equivalent to threat on victim. - m_creature->AddThreat(target, m_creature->getThreatManager().getThreat(m_creature->getVictim())); - DoCastSpellIfCan(target, SPELL_FIXATE); + void OnPhaseFinished() + { + DoScriptText(SUFF_SAY_RECAP, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->GetHealthPercent() <= 10.0f) + if (m_uiEnrageTimer < uiDiff) { - if (m_statAuraGuid) + if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_statAuraGuid)) - pPlayer->RemoveAurasDueToSpell(AURA_OF_SUFFERING_ARMOR); + DoScriptText(EMOTE_BOSS_GENERIC_ENRAGED, m_creature); + DoScriptText(SUFF_SAY_FRENZY, m_creature); + m_uiEnrageTimer = 45000; } } + else + m_uiEnrageTimer -= uiDiff; - if (m_creature->GetHealthPercent() <= 10.0f) - { - if (m_creature->getVictim()) - m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack. - return; - } - - // Prevent overlapping yells - if (AggroYellTimer) + if (m_uiSoulDrainTimer < uiDiff) { - if (AggroYellTimer <= diff) - { - DoScriptText(SUFF_SAY_AGGRO, m_creature); - AggroYellTimer = 0; - }else AggroYellTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SOUL_DRAIN) == CAST_OK) + m_uiSoulDrainTimer = urand(45000, 60000); } - - //Supposed to be cast on nearest target - if (FixateTimer < diff) - { - CastFixate(); - FixateTimer = 5000; - }else FixateTimer -= diff; - - if (EnrageTimer < diff) - { - if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) - { - DoScriptText(EMOTE_BOSS_GENERIC_ENRAGED, m_creature); - EnrageTimer = 60000; - } - }else EnrageTimer -= diff; - - if (SoulDrainTimer < diff) - { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, SPELL_SOUL_DRAIN); - SoulDrainTimer = 60000; - }else SoulDrainTimer -= diff; + else + m_uiSoulDrainTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL boss_essence_of_desireAI : public ScriptedAI + +/*###### +## boss_essence_of_desire +######*/ + +struct boss_essence_of_desireAI : public essence_base_AI { - boss_essence_of_desireAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} + boss_essence_of_desireAI(Creature* pCreature) : essence_base_AI(pCreature) { Reset(); } - uint32 AggroYellTimer; - uint32 RuneShieldTimer; - uint32 DeadenTimer; - uint32 SoulShockTimer; + uint32 m_uiRuneShieldTimer; + uint32 m_uiDeadenTimer; + uint32 m_uiSoulShockTimer; - void Reset() + void Reset() override { - AggroYellTimer = 5000; - RuneShieldTimer = 60000; - DeadenTimer = 15000; - SoulShockTimer = 40000; - } + m_uiRuneShieldTimer = urand(10000, 15000); + m_uiDeadenTimer = 15000; + m_uiSoulShockTimer = urand(5000, 10000); - void DamageTaken(Unit *done_by, uint32 &damage) - { - if ((damage >= m_creature->GetHealth()) && (done_by != m_creature)) - { - damage = 0; - // 10% of total health, signalling time to return - m_creature->SetHealth(m_creature->GetMaxHealth()/10); - } - else - { - if (done_by && (done_by->GetTypeId() == TYPEID_PLAYER) && done_by->isAlive()) - done_by->DealDamage(done_by, damage/2, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } + DoCastSpellIfCan(m_creature, SPELL_AURA_OF_DESIRE); } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(DESI_SAY_SLAY1, m_creature); break; case 1: DoScriptText(DESI_SAY_SLAY2, m_creature); break; @@ -730,192 +475,186 @@ struct MANGOS_DLL_DECL boss_essence_of_desireAI : public ScriptedAI } } - void MoveInLineOfSight(Unit *who) + void OnPhaseFinished() { - if (!who || m_creature->getVictim()) - return; - - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) - { - float attackRadius = m_creature->GetAttackDistance(who); - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who)) - { - if (!m_creature->isInCombat()) - { - DoCastSpellIfCan(who, AURA_OF_DESIRE); - } - - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - } + DoScriptText(DESI_SAY_RECAP, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_creature->GetHealthPercent() <= 10.0f) + if (m_uiRuneShieldTimer < uiDiff) { - if (m_creature->getVictim()) - m_creature->DeleteThreatList(); // Delete our threatlist if below 10% as we should no longer attack. - return; + if (DoCastSpellIfCan(m_creature, SPELL_RUNE_SHIELD) == CAST_OK) + m_uiRuneShieldTimer = 15000; } + else + m_uiRuneShieldTimer -= uiDiff; - if (RuneShieldTimer < diff) - { - DoCastSpellIfCan(m_creature, SPELL_RUNE_SHIELD); - RuneShieldTimer = 60000; - }else RuneShieldTimer -= diff; - - if (DeadenTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEADEN); - DeadenTimer = urand(30000, 60000); - }else DeadenTimer -= diff; - - if (SoulShockTimer < diff) + if (m_uiDeadenTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_SHOCK); - SoulShockTimer = 40000; - - if (urand(0, 1)) + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEADEN) == CAST_OK) + { DoScriptText(DESI_SAY_SPEC, m_creature); + m_uiDeadenTimer = 30000; + } + } + else + m_uiDeadenTimer -= uiDiff; - }else SoulShockTimer -= diff; + if (m_uiSoulShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SPIRIT_SHOCK) == CAST_OK) + m_uiSoulShockTimer = urand(5000, 10000); + } + else + m_uiSoulShockTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL boss_essence_of_angerAI : public ScriptedAI -{ - boss_essence_of_angerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - ObjectGuid m_aggroTargetGuid; +/*###### +## boss_essence_of_anger +######*/ - uint32 AggroYellTimer; - uint32 CheckTankTimer; - uint32 SoulScreamTimer; - uint32 SpiteTimer; - - bool CheckedAggro; - - void Reset() +struct boss_essence_of_angerAI : public ScriptedAI +{ + boss_essence_of_angerAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_aggroTargetGuid.Clear(); + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } - AggroYellTimer = 5000; - CheckTankTimer = 5000; - SoulScreamTimer = 10000; - SpiteTimer = 30000; + ScriptedInstance* m_pInstance; - CheckedAggro = false; - } + uint32 m_uiSeetheTimer; + uint32 m_uiSoulScreamTimer; + uint32 m_uiSpiteTimer; - void Aggro(Unit* pWho) + void Reset() override { - DoCastSpellIfCan(m_creature->getVictim(), AURA_OF_ANGER, CAST_TRIGGERED); + m_uiSeetheTimer = 5000; + m_uiSoulScreamTimer = 10000; + m_uiSpiteTimer = 20000; + + DoCastSpellIfCan(m_creature, SPELL_AURA_OF_ANGER); } - void MoveInLineOfSight(Unit *who) + void KilledUnit(Unit* /*pVictim*/) override { - if (!who || m_creature->getVictim()) - return; - - if (who->isTargetableForAttack() && who->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(who)) - { - float attackRadius = m_creature->GetAttackDistance(who); - if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who)) - { - if (!m_creature->isInCombat()) - { - DoCastSpellIfCan(who, AURA_OF_ANGER); - } - - who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } - } + DoScriptText(urand(0, 1) ? ANGER_SAY_SLAY1 : ANGER_SAY_SLAY2, m_creature); } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(ANGER_SAY_DEATH, m_creature); } - void KilledUnit(Unit *victim) + void JustReachedHome() override { - DoScriptText(urand(0, 1) ? ANGER_SAY_SLAY1 : ANGER_SAY_SLAY2, m_creature); + // Reset encounter and despawn Essence + if (m_pInstance) + { + if (Creature* pReliquary = m_pInstance->GetSingleCreatureFromStorage(NPC_RELIQUARY_OF_SOULS)) + pReliquary->AI()->EnterEvadeMode(); + } + + m_creature->ForcedDespawn(); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!CheckedAggro) + if (m_uiSeetheTimer < uiDiff) { - m_aggroTargetGuid = m_creature->getVictim()->GetObjectGuid(); - CheckedAggro = true; + if (DoCastSpellIfCan(m_creature, SPELL_SEETHE) == CAST_OK) + m_uiSeetheTimer = urand(20000, 30000); } + else + m_uiSeetheTimer -= uiDiff; - if (AggroYellTimer) + if (m_uiSoulScreamTimer < uiDiff) { - if (AggroYellTimer <= diff) - { - DoScriptText(ANGER_SAY_FREED2, m_creature); - AggroYellTimer = 0; - }else AggroYellTimer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SOUL_SCREAM) == CAST_OK) + m_uiSoulScreamTimer = 10000; } + else + m_uiSoulScreamTimer -= uiDiff; - if (CheckTankTimer < diff) + if (m_uiSpiteTimer < uiDiff) { - if (m_creature->getVictim()->GetObjectGuid() != m_aggroTargetGuid) + if (DoCastSpellIfCan(m_creature, SPELL_SPITE) == CAST_OK) { DoScriptText(ANGER_SAY_BEFORE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_SELF_SEETHE); - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENEMY_SEETHE, CAST_TRIGGERED); - m_aggroTargetGuid = m_creature->getVictim()->GetObjectGuid(); + m_uiSpiteTimer = 20000; } - CheckTankTimer = 2000; - }else CheckTankTimer -= diff; + } + else + m_uiSpiteTimer -= uiDiff; - if (SoulScreamTimer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOUL_SCREAM); - SoulScreamTimer = 10000; - }else SoulScreamTimer -= diff; + DoMeleeAttackIfReady(); + } +}; + +/*###### +## npc_enslaved_soul +######*/ + +struct npc_enslaved_soulAI : public ScriptedAI +{ + npc_enslaved_soulAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; - if (SpiteTimer < diff) + void Reset() override + { + DoCastSpellIfCan(m_creature, SPELL_ENSLAVED_SOUL_PASSIVE); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_SOUL_RELEASE, CAST_TRIGGERED); + + // Notify the main boss about the spirit death. Needs to be done here, because the spirit is summoned with triggered spell + if (m_pInstance) { - for(uint8 i = 0; i < 4; ++i) + if (Creature* pReliquary = m_pInstance->GetSingleCreatureFromStorage(NPC_RELIQUARY_OF_SOULS)) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(target, SPELL_SPITE); + if (boss_reliquary_of_soulsAI* pBossAI = dynamic_cast(pReliquary->AI())) + pBossAI->DoNotifySouldDead(); } - - SpiteTimer = 30000; - DoScriptText(ANGER_SAY_SPEC, m_creature); - }else SpiteTimer -= diff; - - DoMeleeAttackIfReady(); + } } -}; -void npc_enslaved_soulAI::JustDied(Unit *killer) -{ - if (m_reliquaryGuid) + void JustReachedHome() override { - if (Creature* pReliquary = m_creature->GetMap()->GetCreature(m_reliquaryGuid)) + // Reset encounter and despawn the spirit + if (m_pInstance) { - if (boss_reliquary_of_soulsAI* pReliqAI = dynamic_cast(pReliquary->AI())) - pReliqAI->SoulDeathCount++; + if (Creature* pReliquary = m_pInstance->GetSingleCreatureFromStorage(NPC_RELIQUARY_OF_SOULS)) + pReliquary->AI()->EnterEvadeMode(); } + + m_creature->ForcedDespawn(); } -} + + void UpdateAI(const uint32 /*uiDiff*/) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; CreatureAI* GetAI_boss_reliquary_of_souls(Creature* pCreature) { diff --git a/scripts/outland/black_temple/boss_shade_of_akama.cpp b/scripts/outland/black_temple/boss_shade_of_akama.cpp index b59c9cbf5..d3ade518a 100644 --- a/scripts/outland/black_temple/boss_shade_of_akama.cpp +++ b/scripts/outland/black_temple/boss_shade_of_akama.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,665 +16,473 @@ /* ScriptData SDName: Boss_Shade_of_Akama -SD%Complete: 85 -SDComment: Seems to be complete. Some little details/cosmetics left (see next comment section). +SD%Complete: 90 +SDComment: Some adjustments may be required once the Shade Soul Channel stacking is fixed in core. Epilogue positions need more work. SDCategory: Black Temple EndScriptData */ -/* ToDo: -(1) After start event Akama should walk a bit towards Shade of Akama, then stop (between the two pillars) and begin to channel. -(2) Some minor changes to post event (after killing Shade of Akama): -(2.1) After Shade of Akama is dead Akama should roar in direction to the door (he must turn around if he reached the stage). -(2.2) Positioning of broken NPCs. -(3) The channelers are casting their spell somestimes even if they are daed (move out of view distance and then move in - they are dead but they channel - maybe some clientspecific issue?). -(4) Unbanish Shade of Akama if a ashtongue sorcerer is spawned but not reached Shade of Akama and channels his spell? -(5) Unsure: If sourcer channels the banish spell, shade should be banished again? -*/ - #include "precompiled.h" #include "black_temple.h" enum { - GOSSIP_ITEM_START_ENCOUNTER = -3564000, - TEXT_ID_AKAMA = 907, - + // yells SAY_DEATH = -1564013, SAY_LOW_HEALTH = -1564014, // Ending cinematic text - SAY_FREE = -1564015, + SAY_FREE_1 = -1564130, + SAY_FREE_2 = -1564015, SAY_BROKEN_FREE_01 = -1564016, SAY_BROKEN_FREE_02 = -1564017, - SPELL_VERTEX_SHADE_BLACK = 39833, - SPELL_SHADE_SOUL_CHANNEL = 40401, - SPELL_DESTRUCTIVE_POISON = 40874, - SPELL_LIGHTNING_BOLT = 42024, - SPELL_AKAMA_SOUL_CHANNEL = 40447, - SPELL_AKAMA_SOUL_RETRIEVE = 40902, + // gossip + GOSSIP_ITEM_START_ENCOUNTER = -3564000, + TEXT_ID_AKAMA = 10866, - NPC_ASH_CHANNELER = 23421, + // Akama spells + SPELL_STEALTH = 34189, + SPELL_DESTRUCTIVE_POISON = 40874, + SPELL_CHAIN_LIGHTNING = 39945, // old spell was 42024 -> probably wrong + SPELL_AKAMA_SOUL_CHANNEL = 40447, // channeled during the event + SPELL_AKAMA_SOUL_RETRIEVE = 40902, // used for the epilogue + + // Other spells + SPELL_SUMMON_DEFENDER = 40474, + SPELL_SUMMON_SORCERER = 40476, + // SPELL_VERTEX_SHADE_BLACK = 39833, // used by the shade - in c_t_a + SPELL_SHADE_SOUL_CHANNEL = 40401, // channel spell, used to banish the shade + SPELL_SUMMON_SHADE_TRIGGER = 40955, + + // npcs NPC_ASH_SORCERER = 23215, NPC_ASH_DEFENDER = 23216, - NPC_ASH_BROKEN = 23319, NPC_ASH_ELEMENTAL = 23523, NPC_ASH_ROGUE = 23318, NPC_ASH_SPIRITBIND = 23524, + NPC_ASH_BROKEN = 23319, + + // akama's phases + PHASE_CHANNEL = 1, + PHASE_COMBAT = 2, + PHASE_EPILOGUE = 3, - //akama's phases (used as point id's) - //PHASE_CHANNEL = 1, - //PHASE_BELOW_PLATFORM = 2, - //PHASE_ON_PLATFORM = 3 + MAX_CHANNELERS = 6, }; -static const uint32 auiRandSpawnEntry[]= +static const uint32 auiRandSpawnEntry[] = { NPC_ASH_ELEMENTAL, NPC_ASH_ROGUE, NPC_ASH_SPIRITBIND }; -static const float LOC_RAND_TO_CENTER_X = 482.793182f; -static const float LOC_RAND_TO_CENTER_Y = 401.270172f; -static const float LOC_RAND_TO_CENTER_Z = 112.783928f; - -static const float LOC_PLATFORM_Z = 118.537f; -static const float LOC_LOW_Z = 112.784f; - -struct Location +static const DialogueEntry aOutroDialogue[] = { - float m_fX, m_fY, m_fZ, m_fO; + {SPELL_AKAMA_SOUL_RETRIEVE, 0, 18000}, + {EMOTE_ONESHOT_ROAR, 0, 2000}, + {SAY_FREE_1, NPC_AKAMA_SHADE, 5000}, + {SAY_FREE_2, NPC_AKAMA_SHADE, 20000}, + {SAY_BROKEN_FREE_01, 0, 2000}, + {EMOTE_STATE_KNEEL, 0, 5000}, + {SAY_BROKEN_FREE_02, 0, 0}, + {0, 0, 0}, }; -static const Location afSpawnLoc[]= +struct Location { - {498.652740f, 461.728119f, LOC_LOW_Z, 0.0f}, - {498.505003f, 339.619324f, LOC_LOW_Z, 0.0f} + float m_fX, m_fY, m_fZ; }; -static const Location afAkamaWP[]= +static const Location afAkamaWP[] = { - //{516.885193, 400.836060, LOC_LOW_Z_SPAWN, 0.0}, //not used yet, he moves to here before start channel - {482.352448f, 401.162720f, LOC_LOW_Z, 0.0f}, - {469.597443f, 402.264404f, LOC_PLATFORM_Z, 0.0f} + {516.885193f, 400.836060f, 112.784f}, + {469.597443f, 402.264404f, 118.537f} }; -static const Location afBrokenSpawnLoc[]= +static const Location afBrokenSpawnLoc[] = { - {541.375916f, 401.439575f, LOC_LOW_Z, M_PI_F}, // The place where Akama channels - {534.130005f, 352.394531f, LOC_LOW_Z, 2.164150f}, // Behind a 'pillar' which is behind the east alcove - {499.621185f, 341.534729f, LOC_LOW_Z, 1.652856f}, // East Alcove - {499.151093f, 461.036438f, LOC_LOW_Z, 4.770888f} // West Alcove + {541.375916f, 401.439575f, 112.784f}, // The place where Akama channels + {534.130005f, 352.394531f, 112.784f}, // Behind a 'pillar' which is behind the east alcove }; -static const Location afBrokenWP[]= -{ - {492.491638f, 400.744690f, LOC_LOW_Z, 3.122336f}, - {494.335724f, 382.221771f, LOC_LOW_Z, 2.676230f}, - {489.555939f, 373.507202f, LOC_LOW_Z, 2.416263f}, - {491.136353f, 427.868774f, LOC_LOW_Z, 3.519748f} -}; +/*###### +## npc_akama +######*/ -struct MANGOS_DLL_DECL boss_shade_of_akamaAI : public ScriptedAI +struct npc_akamaAI : public ScriptedAI, private DialogueHelper { - boss_shade_of_akamaAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_akamaAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aOutroDialogue) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_black_temple*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); } - ScriptedInstance* m_pInstance; - - GUIDList m_lChannelersGUIDList; - GUIDList m_lSorcerersGUIDList; + instance_black_temple* m_pInstance; - uint32 m_uiDeathChannelerCount; + uint8 m_uiPhase; - uint32 m_uiReduceHealthTimer; - uint32 m_uiSummonTimer; - uint32 m_uiResetTimer; - uint32 m_uiDefenderTimer; // They are on a flat 15 second timer, independant of the other summon creature timer. + uint32 m_uiDestructivePoisonTimer; + uint32 m_uiLightningBoltTimer; - bool m_bIsBanished; - bool m_bHasKilledAkama; + uint32 m_uiSummonPackTimer; + uint32 m_uiSummonDefenderTimer; + uint32 m_uiSummonSorcererTimer; - void Reset() - { - m_uiDeathChannelerCount = 0; + uint8 m_uiChannelersDead; - m_uiSummonTimer = 10000; - m_uiReduceHealthTimer = 0; - m_uiResetTimer = 60000; - m_uiDefenderTimer = 15000; + GuidList m_lBrokenGUIDList; + GuidList m_lSorcerersGUIDList; - m_bIsBanished = true; - m_bHasKilledAkama = false; + bool m_bHasYelledOnce; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + void Reset() override + { + SetCombatMovement(false); - m_creature->HandleEmote(EMOTE_STATE_STUN); - } + m_uiPhase = 0; - void AttackStart(Unit* pWho) - { - if (!pWho || m_bIsBanished) - return; + m_uiDestructivePoisonTimer = 15000; + m_uiLightningBoltTimer = 10000; - ScriptedAI::AttackStart(pWho); - } + m_uiSummonPackTimer = 5000; + m_uiSummonDefenderTimer = 10000; + m_uiSummonSorcererTimer = 10000; - void MoveInLineOfSight(Unit* pWho) - { - if (m_bIsBanished) - return; + m_uiChannelersDead = 0; - ScriptedAI::MoveInLineOfSight(pWho); - } + m_bHasYelledOnce = false; - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_SHADE, NOT_STARTED); + m_lBrokenGUIDList.clear(); + m_lSorcerersGUIDList.clear(); - RespawnChannelersIfDeadOrEvade(); + DoCastSpellIfCan(m_creature, SPELL_STEALTH); + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - // If guid is set, will remove it from list of sorcerer - void IncrementDeathCount(ObjectGuid uiGuid = ObjectGuid()) + void AttackedBy(Unit* pAttacker) override { - debug_log("SD2: Increasing Death Count for Shade of Akama encounter"); - ++m_uiDeathChannelerCount; - - if (uiGuid) + // When the Shade starts to attack Akama, switch to melee phase + if (m_uiPhase == PHASE_CHANNEL && pAttacker->GetEntry() == NPC_SHADE_OF_AKAMA) { - if (m_lSorcerersGUIDList.empty()) - error_log("SD2: boss_shade_of_akamaAI attempt to remove guid %s from Sorcerers list but list is already empty", uiGuid.GetString().c_str()); - else - m_lSorcerersGUIDList.remove(uiGuid); + m_creature->InterruptNonMeleeSpells(false); + AttackStart(pAttacker); + m_uiPhase = PHASE_COMBAT; + + // despawn all sorcerers at this point + for (GuidList::const_iterator itr = m_lSorcerersGUIDList.begin(); itr != m_lSorcerersGUIDList.end(); ++itr) + { + if (Creature* pSorcerer = m_creature->GetMap()->GetCreature(*itr)) + pSorcerer->ForcedDespawn(); + } } } - void SummonCreature() + void KilledUnit(Unit* pVictim) override { - uint32 uiRand = urand(0, countof(afSpawnLoc) - 1); - - // max of 6 sorcerers can be summoned at one time! - if (!urand(0, 2) && (m_uiDeathChannelerCount > 0) && (m_lSorcerersGUIDList.size() < 7)) + // Note: this is called from the Shade, Channeler and Sorcerer script + // If the function is changed in the future, please review this. + switch (pVictim->GetEntry()) { - if (Creature* pSorcerer = m_creature->SummonCreature(NPC_ASH_SORCERER, - afSpawnLoc[uiRand].m_fX, afSpawnLoc[uiRand].m_fY, afSpawnLoc[uiRand].m_fZ, afSpawnLoc[uiRand].m_fO, - TEMPSUMMON_DEAD_DESPAWN, 0)) - { - pSorcerer->SetWalk(false); - pSorcerer->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); - pSorcerer->SetTargetGuid(m_creature->GetObjectGuid()); + case NPC_SHADE_OF_AKAMA: + m_uiPhase = PHASE_EPILOGUE; - m_lSorcerersGUIDList.push_back(pSorcerer->GetObjectGuid()); + m_creature->GetMotionMaster()->MovePoint(PHASE_EPILOGUE, afAkamaWP[1].m_fX, afAkamaWP[1].m_fY, afAkamaWP[1].m_fZ); + break; + case NPC_ASH_SORCERER: + // Decrease the sorcerer counter + m_lSorcerersGUIDList.remove(pVictim->GetObjectGuid()); + break; + case NPC_ASH_CHANNELER: - --m_uiDeathChannelerCount; - } - } - else - { - for (uint8 i = 0; i < countof(auiRandSpawnEntry); ++i) - { - if (Creature* pSpawn = m_creature->SummonCreature(auiRandSpawnEntry[i], - afSpawnLoc[uiRand].m_fX, afSpawnLoc[uiRand].m_fY, afSpawnLoc[uiRand].m_fZ, afSpawnLoc[uiRand].m_fO, - TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000)) + ++m_uiChannelersDead; + + // Move the shade to Akama when all channelers are dead + // Note: the boss should be already slowly moving, but this isn't possible because of the missing stack for the speed debuff + if (m_uiChannelersDead == MAX_CHANNELERS) { - pSpawn->SetWalk(false); - pSpawn->GetMotionMaster()->MovePoint(0, LOC_RAND_TO_CENTER_X, LOC_RAND_TO_CENTER_Y, LOC_RAND_TO_CENTER_Z); + if (m_pInstance) + { + if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + { + float fX, fY, fZ; + m_creature->GetContactPoint(pShade, fX, fY, fZ); + pShade->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + } } - } + break; } } - void DespawnSorceres() + void JustDied(Unit* /*pKiller*/) override { - for (GUIDList::const_iterator itr = m_lSorcerersGUIDList.begin(); itr != m_lSorcerersGUIDList.end(); ++itr) + DoScriptText(SAY_DEATH, m_creature); + m_creature->SetCorpseDelay(30); + + if (m_pInstance) { - if (Creature* pSorcerer = m_creature->GetMap()->GetCreature(*itr)) - { - if (pSorcerer->isAlive()) - pSorcerer->ForcedDespawn(); - } + // Reset the shade + if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + pShade->AI()->EnterEvadeMode(); } } - void RespawnChannelersIfDeadOrEvade() + void CorpseRemoved(uint32& uiRespawnDelay) override { - for (GUIDList::const_iterator itr = m_lChannelersGUIDList.begin(); itr != m_lChannelersGUIDList.end(); ++itr) - { - if (Creature* pChanneler = m_creature->GetMap()->GetCreature(*itr)) - { - if (!pChanneler->isAlive()) - pChanneler->Respawn(); - else - pChanneler->AI()->EnterEvadeMode(); - } - } + // Resapwn after 5 min + uiRespawnDelay = 5 * MINUTE; } - void PrepareChannelers() + void JustSummoned(Creature* pSummoned) override { - std::list lChannelerList; - GetCreatureListWithEntryInGrid(lChannelerList,m_creature, NPC_ASH_CHANNELER, 50.0f); - - if (!lChannelerList.empty()) + switch (pSummoned->GetEntry()) { - //clear this, we want a clean start - m_lChannelersGUIDList.clear(); + case NPC_ASH_SORCERER: + { + pSummoned->SetWalk(false); + m_lSorcerersGUIDList.push_back(pSummoned->GetObjectGuid()); - for (std::list::iterator itr = lChannelerList.begin(); itr != lChannelerList.end(); ++itr) + float fX, fY, fZ; + if (m_pInstance) + { + if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + { + pShade->GetNearPoint(pShade, fX, fY, fZ, 0, 20.0f, pShade->GetAngle(pSummoned)); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + } + break; + } + case NPC_ASH_BROKEN: { - m_lChannelersGUIDList.push_back((*itr)->GetObjectGuid()); + float fX, fY, fZ; + m_lBrokenGUIDList.push_back(pSummoned->GetObjectGuid()); - (*itr)->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 30.0f, m_creature->GetAngle(pSummoned)); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + break; } + case NPC_ASH_DEFENDER: + pSummoned->AI()->AttackStart(m_creature); + break; + default: + pSummoned->SetInCombatWithZone(); + break; } - else - error_log("SD2: boss_shade_of_akamaAI unable to find any channelers."); } - void KilledUnit(Unit* pVictim) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - if (pVictim->GetEntry() == NPC_AKAMA) - EnterEvadeMode(); - } - - void JustDied(Unit* pKiller) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_SHADE, DONE); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->isInCombat()) + if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) return; - if (m_bIsBanished) + switch (uiPointId) { - // Akama is set in the threatlist so when we reset, we make sure that he is not included in our check - if (m_creature->getThreatManager().getThreatList().size() < 2) - ScriptedAI::EnterEvadeMode(); - - if (m_uiDefenderTimer < uiDiff) - { - uint32 uiRand = urand(0, countof(afSpawnLoc) - 1); - - if (Creature* pDefender = m_creature->SummonCreature(NPC_ASH_DEFENDER, - afSpawnLoc[uiRand].m_fX, afSpawnLoc[uiRand].m_fY, afSpawnLoc[uiRand].m_fZ, afSpawnLoc[uiRand].m_fO, - TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 25000)) + case PHASE_CHANNEL: + if (DoCastSpellIfCan(m_creature, SPELL_AKAMA_SOUL_CHANNEL) == CAST_OK) { - if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) - pDefender->AI()->AttackStart(pAkama); - } + m_uiPhase = PHASE_CHANNEL; - m_uiDefenderTimer = 15000; - } - else - m_uiDefenderTimer -= uiDiff; + GuidList m_lChannelersList; + m_pInstance->GetChannelersGuidList(m_lChannelersList); - if (m_uiSummonTimer < uiDiff) - { - SummonCreature(); - m_uiSummonTimer = 35000; - } - else - m_uiSummonTimer -= uiDiff; - - if (m_uiDeathChannelerCount >= 6) - { - if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) - { - if (pAkama && pAkama->isAlive()) + for (GuidList::const_iterator itr = m_lChannelersList.begin(); itr != m_lChannelersList.end(); ++itr) { - m_bIsBanished = false; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - // Shade should move to Akama, not the other way around - AttackStart(pAkama); - - // Crazy amount of threat - m_creature->AddThreat(pAkama, 10000000.0f); - pAkama->AddThreat(m_creature, 10000000.0f); + if (Creature* pChanneler = m_creature->GetMap()->GetCreature(*itr)) + pChanneler->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } } - } + break; + case PHASE_EPILOGUE: + // Start epilogue here + if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + m_creature->SetFacingToObject(pShade); + + StartNextDialogueText(SPELL_AKAMA_SOUL_RETRIEVE); + break; } - else // No longer banished, let's fight Akama now + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) { - if (m_uiReduceHealthTimer < uiDiff) - { - if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) + case SPELL_AKAMA_SOUL_RETRIEVE: + DoCastSpellIfCan(m_creature, SPELL_AKAMA_SOUL_RETRIEVE); + break; + case EMOTE_ONESHOT_ROAR: + m_creature->HandleEmote(EMOTE_ONESHOT_ROAR); + break; + case SAY_FREE_1: + DoSummonBrokenAshtongue(); + break; + case SAY_BROKEN_FREE_01: + if (Creature* pBroken = GetClosestCreatureWithEntry(m_creature, NPC_ASH_BROKEN, 35.0f)) + DoScriptText(SAY_BROKEN_FREE_01, pBroken); + break; + case EMOTE_STATE_KNEEL: + for (GuidList::const_iterator itr = m_lBrokenGUIDList.begin(); itr != m_lBrokenGUIDList.end(); ++itr) { - if (pAkama->isAlive()) - { - // 10 % less health every few seconds. - m_creature->DealDamage(pAkama, pAkama->GetMaxHealth()/10, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - m_uiReduceHealthTimer = 12000; - } - else - { - m_bHasKilledAkama = true; // Akama is dead, we stop fighting and disappear - EnterEvadeMode(); - return; - } + if (Creature* pBroken = m_creature->GetMap()->GetCreature(*itr)) + pBroken->HandleEmote(EMOTE_STATE_KNEEL); } - } - else - m_uiReduceHealthTimer -= uiDiff; - - if (m_bHasKilledAkama) - { - if (m_uiResetTimer < uiDiff) + break; + case SAY_BROKEN_FREE_02: + for (GuidList::const_iterator itr = m_lBrokenGUIDList.begin(); itr != m_lBrokenGUIDList.end(); ++itr) { - EnterEvadeMode(); // Reset a little while after killing Akama - return; + if (Creature* pBroken = m_creature->GetMap()->GetCreature(*itr)) + DoScriptText(SAY_BROKEN_FREE_02, pBroken); } - else - m_uiResetTimer -= uiDiff; - } - - DoMeleeAttackIfReady(); + break; } } -}; -struct MANGOS_DLL_DECL npc_akamaAI : public ScriptedAI -{ - npc_akamaAI(Creature* pCreature) : ScriptedAI(pCreature) + // Wrapper to start the Akama event + void DoStartEvent() { - m_bIsShadeDead = false; - m_bCanStartCombat = false; - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; + if (m_pInstance) + m_pInstance->SetData(TYPE_SHADE, IN_PROGRESS); - uint32 m_uiDestructivePoisonTimer; - uint32 m_uiLightningBoltTimer; - uint32 m_uiCheckTimer; - uint32 m_uiCastSoulRetrieveTimer; - uint32 m_uiSoulRetrieveTimer; - uint32 m_uiSummonBrokenTimer; - uint32 m_uiEndingTalkCount; - uint32 m_uiWayPointId; - uint32 m_uiBrokenSummonIndex; - - GUIDList m_lBrokenGUIDList; - - bool m_bIsEventBegun; - bool m_bIsShadeDead; - bool m_bCanStartCombat; - bool m_bHasYelledOnce; + m_creature->RemoveAurasDueToSpell(SPELL_STEALTH); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->GetMotionMaster()->MovePoint(PHASE_CHANNEL, afAkamaWP[0].m_fX, afAkamaWP[0].m_fY, afAkamaWP[0].m_fZ); + } - void Reset() + // Wrapper to summon ashtongue mobs + void DoSummonAshtongue(uint32 uiSpellId = 0) { - SetCombatMovement(false); - - m_uiDestructivePoisonTimer = 15000; - m_uiLightningBoltTimer = 10000; - m_uiCheckTimer = 2000; - m_uiCastSoulRetrieveTimer = 0; - m_uiSoulRetrieveTimer = 0; - m_uiSummonBrokenTimer = 0; - m_uiEndingTalkCount = 0; - m_uiWayPointId = 0; - m_uiBrokenSummonIndex = 0; - - m_lBrokenGUIDList.clear(); + if (!m_pInstance) + return; - m_bIsEventBegun = false; - m_bHasYelledOnce = false; + GuidVector vGeneratorsVect; + m_pInstance->GetGeneratorGuidVector(vGeneratorsVect); + Creature* pGenerator = m_creature->GetMap()->GetCreature(vGeneratorsVect[urand(0, 1)]); + if (!pGenerator) + return; - m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + // Summon mobs by spell + if (uiSpellId) + pGenerator->CastSpell(pGenerator, uiSpellId, true, NULL, NULL, m_creature->GetObjectGuid()); + // Summon ashtongue pack + else + { + float fX, fY, fZ; + for (uint8 i = 0; i < countof(auiRandSpawnEntry); ++i) + { + pGenerator->GetRandomPoint(pGenerator->GetPositionX(), pGenerator->GetPositionY(), pGenerator->GetPositionZ(), 5.0f, fX, fY, fZ); + m_creature->SummonCreature(auiRandSpawnEntry[i], fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } } - void BeginEvent() + // Wrapper to summon the npcs for the epilogue + void DoSummonBrokenAshtongue() { if (!m_pInstance) return; - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) - { - if (boss_shade_of_akamaAI* pShadeAI = dynamic_cast(pShade->AI())) - pShadeAI->PrepareChannelers(); - - // Prevent players from trying to restart event - m_pInstance->SetData(TYPE_SHADE, IN_PROGRESS); - - m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - pShade->AddThreat(m_creature, 1000000.0f); - pShade->SetInCombatWith(m_creature); - m_creature->SetInCombatWith(pShade); - - pShade->HandleEmote(EMOTE_STATE_NONE); - pShade->SetTargetGuid(m_creature->GetObjectGuid()); + float fX, fY, fZ; - pShade->SetInCombatWithZone(); + // Spawn 4 Broken in the center and behind the column + for (uint8 i = 0; i < countof(afBrokenSpawnLoc); ++i) + { + for (uint8 j = 0; j < 4; ++j) + { + fX = afBrokenSpawnLoc[i].m_fX; + fY = afBrokenSpawnLoc[i].m_fY + (j * 7); + fZ = afBrokenSpawnLoc[i].m_fZ; - m_bIsEventBegun = true; + m_creature->SummonCreature(NPC_ASH_BROKEN, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 10 * MINUTE * IN_MILLISECONDS); + } } - } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) - { - if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) - return; + GuidVector vGeneratorsVect; + m_pInstance->GetGeneratorGuidVector(vGeneratorsVect); - switch(uiPointId) + // Spawn 4 Broken at each generator + for (uint8 i = 0; i < vGeneratorsVect.size(); ++i) { - case 0: - ++m_uiWayPointId; - break; - case 1: - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + if (Creature* pGenerator = m_creature->GetMap()->GetCreature(vGeneratorsVect[i])) + { + for (uint8 j = 0; j < 4; ++j) { - DoCastSpellIfCan(pShade, SPELL_AKAMA_SOUL_RETRIEVE); - m_uiEndingTalkCount = 0; - m_uiSoulRetrieveTimer = 16000; + pGenerator->GetRandomPoint(pGenerator->GetPositionX(), pGenerator->GetPositionY(), pGenerator->GetPositionZ(), 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_ASH_BROKEN, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 10 * MINUTE * IN_MILLISECONDS); } - break; + } } } - void JustDied(Unit* pKiller) - { - DoScriptText(SAY_DEATH, m_creature); - } - - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_bIsEventBegun || !m_pInstance) - return; - - if (!m_bCanStartCombat) + switch (m_uiPhase) { - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) - { - if (!pShade->isAlive()) + case PHASE_CHANNEL: + + if (m_uiSummonDefenderTimer < uiDiff) { - EnterEvadeMode(); - return; + DoSummonAshtongue(SPELL_SUMMON_DEFENDER); + m_uiSummonDefenderTimer = 15000; } + else + m_uiSummonDefenderTimer -= uiDiff; - if (boss_shade_of_akamaAI* pShadeAI = dynamic_cast(pShade->AI())) + if (m_lSorcerersGUIDList.size() <= m_uiChannelersDead) { - if (pShadeAI->m_bIsBanished) + if (m_uiSummonSorcererTimer < uiDiff) { - if (m_uiCastSoulRetrieveTimer < uiDiff) - { - DoCastSpellIfCan(pShade, SPELL_AKAMA_SOUL_CHANNEL); - m_uiCastSoulRetrieveTimer = 500; - } - else - m_uiCastSoulRetrieveTimer -= uiDiff; + DoSummonAshtongue(SPELL_SUMMON_SORCERER); + m_uiSummonSorcererTimer = urand(20000, 30000); } else - { - m_creature->InterruptNonMeleeSpells(false); - m_bCanStartCombat = true; - } + m_uiSummonSorcererTimer -= uiDiff; } - } - } - if (m_bIsShadeDead && (m_uiWayPointId == 1)) - { - m_creature->GetMotionMaster()->MovePoint(m_uiWayPointId, afAkamaWP[1].m_fX, afAkamaWP[1].m_fY, afAkamaWP[1].m_fZ); - ++m_uiWayPointId; - } - - if (!m_bIsShadeDead && m_bCanStartCombat) - { - if (m_uiCheckTimer < uiDiff) - { - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + if (m_uiSummonPackTimer < uiDiff) { - if (!pShade->isAlive()) - { - m_bIsShadeDead = true; - m_uiWayPointId = 0; - m_creature->SetWalk(true); - m_creature->GetMotionMaster()->MovePoint(m_uiWayPointId, afAkamaWP[0].m_fX, afAkamaWP[0].m_fY, afAkamaWP[0].m_fZ); - } + DoSummonAshtongue(); + m_uiSummonPackTimer = 35000; } - m_uiCheckTimer = 5000; - } - else - m_uiCheckTimer -= uiDiff; - } - - if (m_uiSummonBrokenTimer && m_uiBrokenSummonIndex < countof(afBrokenSpawnLoc)) - { - if (m_uiSummonBrokenTimer <= uiDiff) - { - for (uint8 i = 0; i < 4; ++i) - { - float x = afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fX + (i*5); - float y = afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fY + (1*5); - float z = afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fZ; - float o = afBrokenSpawnLoc[m_uiBrokenSummonIndex].m_fO; + else + m_uiSummonPackTimer -= uiDiff; - if (Creature* pBroken = m_creature->SummonCreature(NPC_ASH_BROKEN, x, y, z, o, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 360000)) - { - float wx = afBrokenWP[m_uiBrokenSummonIndex].m_fX + (i*5); - float wy = afBrokenWP[m_uiBrokenSummonIndex].m_fY + (i*5); - float wz = afBrokenWP[m_uiBrokenSummonIndex].m_fZ; + break; + case PHASE_COMBAT: - pBroken->GetMotionMaster()->MovePoint(0, wx, wy, wz); - pBroken->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - m_lBrokenGUIDList.push_back(pBroken->GetObjectGuid()); - } + if (!m_bHasYelledOnce && m_creature->GetHealthPercent() < 15.0f) + { + DoScriptText(SAY_LOW_HEALTH, m_creature); + m_bHasYelledOnce = true; } - ++m_uiBrokenSummonIndex; - m_uiSummonBrokenTimer = 1000; - } - else - m_uiSummonBrokenTimer -= uiDiff; - } - - if (m_uiSoulRetrieveTimer) - { - if (m_uiSoulRetrieveTimer <= uiDiff) - { - switch(m_uiEndingTalkCount) + if (m_uiDestructivePoisonTimer < uiDiff) { - case 0: - m_creature->HandleEmote(EMOTE_ONESHOT_ROAR); - ++m_uiEndingTalkCount; - m_uiSoulRetrieveTimer = 2000; - m_uiSummonBrokenTimer = 1; - break; - case 1: - DoScriptText(SAY_FREE, m_creature); - ++m_uiEndingTalkCount; - m_uiSoulRetrieveTimer = 25000; - break; - case 2: - if (!m_lBrokenGUIDList.empty()) - { - bool bYelled = false; - - for (GUIDList::const_iterator itr = m_lBrokenGUIDList.begin(); itr != m_lBrokenGUIDList.end(); ++itr) - { - if (Creature* pBroken = m_creature->GetMap()->GetCreature(*itr)) - { - if (!bYelled) - { - DoScriptText(SAY_BROKEN_FREE_01, pBroken); - bYelled = true; - } - - pBroken->HandleEmote(EMOTE_ONESHOT_KNEEL); - } - } - } - ++m_uiEndingTalkCount; - m_uiSoulRetrieveTimer = 1500; - break; - case 3: - for (GUIDList::const_iterator itr = m_lBrokenGUIDList.begin(); itr != m_lBrokenGUIDList.end(); ++itr) - { - // This is the incorrect spell, but can't seem to find the right one. - if (Creature* pBroken = m_creature->GetMap()->GetCreature(*itr)) - pBroken->CastSpell(pBroken, 39656, true); - } - ++m_uiEndingTalkCount; - m_uiSoulRetrieveTimer = 5000; - break; - case 4: - for (GUIDList::const_iterator itr = m_lBrokenGUIDList.begin(); itr != m_lBrokenGUIDList.end(); ++itr) - { - if (Creature* pBroken = m_creature->GetMap()->GetCreature(*itr)) - DoScriptText(SAY_BROKEN_FREE_02, pBroken); - } - m_uiSoulRetrieveTimer = 0; - break; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DESTRUCTIVE_POISON) == CAST_OK) + m_uiDestructivePoisonTimer = 15000; } - } - else - m_uiSoulRetrieveTimer -= uiDiff; - } - - if (!m_creature->getVictim() || !m_creature->SelectHostileTarget()) - return; - - if (!m_bHasYelledOnce && m_creature->GetHealthPercent() < 15.0f) - { - DoScriptText(SAY_LOW_HEALTH, m_creature); - m_bHasYelledOnce = true; - } + else + m_uiDestructivePoisonTimer -= uiDiff; - if (m_uiDestructivePoisonTimer < uiDiff) - { - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) - { - if (pShade->isAlive()) - DoCastSpellIfCan(pShade, SPELL_DESTRUCTIVE_POISON); - } + if (m_uiLightningBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiLightningBoltTimer = 10000; + } + else + m_uiLightningBoltTimer -= uiDiff; - m_uiDestructivePoisonTimer = 15000; - } - else - m_uiDestructivePoisonTimer -= uiDiff; + DoMeleeAttackIfReady(); - if (m_uiLightningBoltTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); - m_uiLightningBoltTimer = 10000; + break; + case PHASE_EPILOGUE: + DialogueUpdate(uiDiff); + break; } - else - m_uiLightningBoltTimer -= uiDiff; - - DoMeleeAttackIfReady(); } }; @@ -690,22 +498,26 @@ bool GossipHello_npc_akama(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_akama(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_akama(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) //Fight time + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) // Fight time { pPlayer->CLOSE_GOSSIP_MENU(); if (npc_akamaAI* pAkamaAI = dynamic_cast(pCreature->AI())) - pAkamaAI->BeginEvent(); + pAkamaAI->DoStartEvent(); } return true; } -struct MANGOS_DLL_DECL mob_ashtongue_channelerAI : public ScriptedAI +/*###### +## boss_shade_of_akama +######*/ + +struct boss_shade_of_akamaAI : public ScriptedAI { - mob_ashtongue_channelerAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_shade_of_akamaAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -713,55 +525,73 @@ struct MANGOS_DLL_DECL mob_ashtongue_channelerAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Reset() + void Reset() override + { + SetCombatMovement(false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SHADE, FAIL); + } + + void KilledUnit(Unit* pVictim) override + { + if (pVictim->GetEntry() == NPC_AKAMA) + EnterEvadeMode(); + } + + void JustDied(Unit* /*pKiller*/) override { + DoCastSpellIfCan(m_creature, SPELL_SUMMON_SHADE_TRIGGER, CAST_TRIGGERED); + if (m_pInstance) { - //self-resurrect if encounter not done and we are dead - if (!m_creature->isAlive() && m_pInstance->GetData(TYPE_SHADE) != DONE) - m_creature->Respawn(); + m_pInstance->SetData(TYPE_SHADE, DONE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // Inform Akama that the Shade is dead + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) + pAkama->AI()->KilledUnit(m_creature); } } - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - - void JustDied(Unit* pKiller) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - if (!m_pInstance) + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId || !m_pInstance) return; - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + // Set in combat with Akama + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) { - if (pShade->isAlive()) - { - if (boss_shade_of_akamaAI* pShadeAI = dynamic_cast(pShade->AI())) - pShadeAI->IncrementDeathCount(); - else - error_log("SD2: mob_ashtongue_channelerAI dead but unable to increment DeathCount for Shade of Akama."); - } + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + // Shade should move to Akama, not the other way around + AttackStart(pAkama); + + // Crazy amount of threat + m_creature->AddThreat(pAkama, 10000000.0f); + pAkama->AddThreat(m_creature, 10000000.0f); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 /*uiDiff*/) override { - if (!m_creature->isAlive()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //start channel (not nice way to start channeling) - if (!m_creature->IsNonMeleeSpellCasted(false) && !m_creature->getVictim() && m_pInstance) - { - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) - m_creature->CastSpell(pShade, SPELL_SHADE_SOUL_CHANNEL, false); - } + DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI +/*###### +## mob_ashtongue_channeler +######*/ + +struct mob_ashtongue_channelerAI : public ScriptedAI { - mob_ashtongue_sorcererAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_ashtongue_channelerAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); @@ -769,70 +599,96 @@ struct MANGOS_DLL_DECL mob_ashtongue_sorcererAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiCheckTimer; - bool m_bStartBanishing; + uint32 m_uiBanishTimer; - void Reset() + void Reset() override { - m_uiCheckTimer = 5000; - m_bStartBanishing = false; - } + m_uiBanishTimer = 5000; - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (!m_pInstance) return; - if (Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA)) + // Inform Akama that one channeler is dead + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) + pAkama->AI()->KilledUnit(m_creature); + } + + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiBanishTimer) { - if (pShade->isAlive()) + if (m_uiBanishTimer <= uiDiff) { - if (boss_shade_of_akamaAI* pShadeAI = dynamic_cast(pShade->AI())) - pShadeAI->IncrementDeathCount(m_creature->GetObjectGuid()); - else - error_log("SD2: mob_ashtongue_sorcererAI dead but unable to increment DeathCount for Shade of Akama."); + if (DoCastSpellIfCan(m_creature, SPELL_SHADE_SOUL_CHANNEL)) + m_uiBanishTimer = 0; } + else + m_uiBanishTimer -= uiDiff; } } +}; - void UpdateAI(const uint32 uiDiff) +/*###### +## mob_ashtongue_sorcerer +######*/ + +struct mob_ashtongue_sorcererAI : public ScriptedAI +{ + mob_ashtongue_sorcererAI(Creature* pCreature) : ScriptedAI(pCreature) { - if (m_bStartBanishing || !m_pInstance) + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + void Reset() override {} + + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + + void JustDied(Unit* /*pKiller*/) override + { + if (!m_pInstance) return; - if (m_uiCheckTimer < uiDiff) - { - Creature* pShade = m_pInstance->GetSingleCreatureFromStorage(NPC_SHADE_OF_AKAMA); + // Inform Akama that one sorcerer is dead + if (Creature* pAkama = m_pInstance->GetSingleCreatureFromStorage(NPC_AKAMA_SHADE)) + pAkama->AI()->KilledUnit(m_creature); + } - if (pShade && pShade->isAlive() && m_creature->isAlive()) - { - if (m_creature->IsWithinDist(pShade, 20.0f, false)) - { - m_creature->GetMotionMaster()->Clear(false); - m_creature->GetMotionMaster()->MoveIdle(); + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; - if (DoCastSpellIfCan(pShade, SPELL_SHADE_SOUL_CHANNEL) == CAST_OK) - m_bStartBanishing = true; - } - } - m_uiCheckTimer = 2000; + // Channel on the Shade when reached the calculated point + if (DoCastSpellIfCan(m_creature, SPELL_SHADE_SOUL_CHANNEL) == CAST_OK) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); } - else - m_uiCheckTimer -= uiDiff; } + + void UpdateAI(const uint32 /*uiDiff*/) override {} }; -CreatureAI* GetAI_boss_shade_of_akama(Creature* pCreature) +CreatureAI* GetAI_npc_akama_shade(Creature* pCreature) { - return new boss_shade_of_akamaAI(pCreature); + return new npc_akamaAI(pCreature); } -CreatureAI* GetAI_npc_akama_shade(Creature* pCreature) +CreatureAI* GetAI_boss_shade_of_akama(Creature* pCreature) { - return new npc_akamaAI(pCreature); + return new boss_shade_of_akamaAI(pCreature); } CreatureAI* GetAI_mob_ashtongue_channeler(Creature* pCreature) @@ -849,11 +705,6 @@ void AddSC_boss_shade_of_akama() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "boss_shade_of_akama"; - pNewScript->GetAI = &GetAI_boss_shade_of_akama; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_akama_shade"; pNewScript->GetAI = &GetAI_npc_akama_shade; @@ -861,6 +712,11 @@ void AddSC_boss_shade_of_akama() pNewScript->pGossipSelect = &GossipSelect_npc_akama; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "boss_shade_of_akama"; + pNewScript->GetAI = &GetAI_boss_shade_of_akama; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "mob_ashtongue_channeler"; pNewScript->GetAI = &GetAI_mob_ashtongue_channeler; diff --git a/scripts/outland/black_temple/boss_supremus.cpp b/scripts/outland/black_temple/boss_supremus.cpp index 6a4f1d426..daff991ca 100644 --- a/scripts/outland/black_temple/boss_supremus.cpp +++ b/scripts/outland/black_temple/boss_supremus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Supremus SD%Complete: 90 -SDComment: Fixating the target is hacky, unknown if other speed-changes happen, remove AI for trigger mobs in next step +SDComment: Unknown if other speed-changes happen, remove AI for trigger mobs in next step SDCategory: Black Temple EndScriptData */ @@ -60,28 +60,28 @@ const float RANGE_MOLTEN_PUNCH = 40.0; */ // TODO Remove this 'script' when combat movement can be proper prevented from core-side -struct MANGOS_DLL_DECL molten_flameAI : public Scripted_NoMovementAI +struct molten_flameAI : public Scripted_NoMovementAI { molten_flameAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - void Reset() {} - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - void UpdateAI(const uint32 uiDiff) {} + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} }; // TODO Remove this 'script' when combat movement can be proper prevented from core-side -struct MANGOS_DLL_DECL npc_volcanoAI : public Scripted_NoMovementAI +struct npc_volcanoAI : public Scripted_NoMovementAI { npc_volcanoAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - void Reset() {} - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - void UpdateAI(const uint32 uiDiff) {} + void Reset() override {} + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + void UpdateAI(const uint32 /*uiDiff*/) override {} }; -struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI +struct boss_supremusAI : public ScriptedAI { boss_supremusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -99,50 +99,46 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI uint32 m_uiBerserkTimer; uint32 m_uiMoltenPunchTimer; - ObjectGuid m_lastGazeTargetGuid; - bool m_bTankPhase; - GUIDList m_lSummonedGUIDs; + GuidList m_lSummonedGUIDs; - void Reset() + void Reset() override { m_uiHatefulStrikeTimer = 5000; m_uiSummonFlameTimer = 20000; m_uiPhaseSwitchTimer = 60000; m_uiMoltenPunchTimer = 8000; - m_uiBerserkTimer = 15*MINUTE*IN_MILLISECONDS; - - m_lastGazeTargetGuid.Clear(); + m_uiBerserkTimer = 15 * MINUTE * IN_MILLISECONDS; m_bTankPhase = true; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_SUPREMUS, NOT_STARTED); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SUPREMUS, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_SUPREMUS, DONE); - for (GUIDList::const_iterator itr = m_lSummonedGUIDs.begin(); itr != m_lSummonedGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lSummonedGUIDs.begin(); itr != m_lSummonedGUIDs.end(); ++itr) { if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) pSummoned->ForcedDespawn(); } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_STALKER) { @@ -185,13 +181,14 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI return pTarget; } - void KilledUnit(Unit* pKilled) + void KilledUnit(Unit* pKilled) override { - if (!m_bTankPhase && pKilled->GetObjectGuid() == m_lastGazeTargetGuid) + // The current target is the fixated target - repick a new one + if (!m_bTankPhase && pKilled == m_creature->getVictim()) m_uiSwitchTargetTimer = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -222,6 +219,7 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI { m_bTankPhase = true; m_creature->RemoveAurasDueToSpell(SPELL_SLOW_SELF); + m_creature->FixateTarget(NULL); } else { @@ -232,8 +230,7 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_SLOW_SELF, CAST_INTERRUPT_PREVIOUS); } - m_uiPhaseSwitchTimer = MINUTE*IN_MILLISECONDS; - DoResetThreat(); + m_uiPhaseSwitchTimer = MINUTE * IN_MILLISECONDS; } else m_uiPhaseSwitchTimer -= uiDiff; @@ -257,12 +254,9 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoResetThreat(); - // This way to simulate some fixating is to be considered a hack - m_creature->AddThreat(pTarget, 5000000.0f); + m_creature->FixateTarget(pTarget); DoScriptText(EMOTE_NEW_TARGET, m_creature); m_uiSwitchTargetTimer = 10000; - m_lastGazeTargetGuid = pTarget->GetObjectGuid(); } } else @@ -283,7 +277,7 @@ struct MANGOS_DLL_DECL boss_supremusAI : public ScriptedAI if (m_uiMoltenPunchTimer < uiDiff) { - if (m_creature->GetCombatDistance(m_creature->getVictim()) < RANGE_MOLTEN_PUNCH) + if (m_creature->GetCombatDistance(m_creature->getVictim(), false) < RANGE_MOLTEN_PUNCH) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHARGE); DoScriptText(EMOTE_PUNCH_GROUND, m_creature); diff --git a/scripts/outland/black_temple/boss_teron_gorefiend.cpp b/scripts/outland/black_temple/boss_teron_gorefiend.cpp index 900ecc048..241b399ee 100644 --- a/scripts/outland/black_temple/boss_teron_gorefiend.cpp +++ b/scripts/outland/black_temple/boss_teron_gorefiend.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,7 @@ EndScriptData */ enum { - //Speech'n'sound + // Speech'n'sound SAY_INTRO = -1564037, SAY_AGGRO = -1564038, SAY_SLAY1 = -1564039, @@ -38,167 +38,35 @@ enum SAY_ENRAGE = -1564045, SAY_DEATH = -1564046, - //Spells - SPELL_INCINERATE = 40239, - SPELL_CRUSHING_SHADOWS = 40243, - SPELL_SHADOWBOLT = 40185, - SPELL_PASSIVE_SHADOWFORM = 40326, - SPELL_SHADOW_OF_DEATH = 40251, - SPELL_BERSERK = 45078, - - SPELL_ATROPHY = 40327, // Shadowy Constructs use this when they get within melee range of a player - - NPC_DOOM_BLOSSOM = 23123, - NPC_SHADOWY_CONSTRUCT = 23111 -}; - -struct MANGOS_DLL_DECL mob_doom_blossomAI : public ScriptedAI -{ - mob_doom_blossomAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - uint32 m_uiCheckTeronTimer; - uint32 m_uiShadowBoltTimer; - ObjectGuid m_teronGuid; - - void Reset() - { - m_uiCheckTeronTimer = 5000; - m_uiShadowBoltTimer = 12000; - } - - void AttackStart(Unit* pWho) { } - void MoveInLineOfSight(Unit* pWho) { } - - void UpdateAI(const uint32 uiDiff) - { - if (m_uiCheckTeronTimer < uiDiff) - { - if (m_teronGuid) - { - m_creature->SetInCombatWithZone(); - - Creature* pTeron = m_creature->GetMap()->GetCreature(m_teronGuid); - if (pTeron && (!pTeron->isAlive() || pTeron->IsInEvadeMode())) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } - else - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - m_uiCheckTeronTimer = 5000; - } - else - m_uiCheckTeronTimer -= uiDiff; - - if (!m_creature->getVictim() || !m_creature->SelectHostileTarget()) - return; - - if (m_uiShadowBoltTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_SHADOWBOLT); - - m_uiShadowBoltTimer = 10000; - } - else - m_uiShadowBoltTimer -= uiDiff; - } - - void SetTeronGUID(ObjectGuid guid){ m_teronGuid = guid; } -}; - -struct MANGOS_DLL_DECL mob_shadowy_constructAI : public ScriptedAI -{ - mob_shadowy_constructAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - ObjectGuid m_ghostGuid; - ObjectGuid m_teronGuid; // TODO unused, possible bug? - - uint32 m_uiCheckPlayerTimer; - uint32 m_uiCheckTeronTimer; - - void Reset() - { - m_ghostGuid.Clear(); - - m_uiCheckPlayerTimer = 2000; - m_uiCheckTeronTimer = 5000; - } - - void MoveInLineOfSight(Unit* pWho) - { - if (!pWho || !pWho->isAlive() || pWho->GetObjectGuid() == m_ghostGuid) - return; - - ScriptedAI::MoveInLineOfSight(pWho); - } - -/* Comment it out for now. NOTE TO FUTURE DEV: UNCOMMENT THIS OUT ONLY AFTER MIND CONTROL IS IMPLEMENTED - void DamageTaken(Unit* done_by, uint32 &damage) - { - if (done_by->GetObjectGuid() != m_ghostGuid) - damage = 0; // Only the ghost can deal damage. - } - */ - - void CheckPlayers() - { - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - if (tList.empty()) - return; // No threat list. Don't continue. - - std::list lTargets; - - for (ThreatList::const_iterator itr = tList.begin(); itr != tList.end(); ++itr) - { - Unit* pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - if (pUnit && pUnit->isAlive()) - lTargets.push_back(pUnit); - } - - lTargets.sort(ObjectDistanceOrder(m_creature)); - Unit* pTarget = lTargets.front(); - if (pTarget && m_creature->IsWithinDistInMap(pTarget, m_creature->GetAttackDistance(pTarget))) - { - DoCastSpellIfCan(pTarget, SPELL_ATROPHY); - m_creature->AI()->AttackStart(pTarget); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (m_uiCheckPlayerTimer < uiDiff) - { - CheckPlayers(); - m_uiCheckPlayerTimer = 3000; - } - else - m_uiCheckPlayerTimer -= uiDiff; - - if (m_uiCheckTeronTimer < uiDiff) - { - Creature* pTeron = m_creature->GetMap()->GetCreature(m_teronGuid); - if (!pTeron || !pTeron->isAlive() || pTeron->IsInEvadeMode()) - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - m_uiCheckTeronTimer = 5000; - } - else - m_uiCheckTeronTimer -= uiDiff; - } + // Spells - boss spells + SPELL_INCINERATE = 40239, + SPELL_CRUSHING_SHADOWS = 40243, + SPELL_SHADOW_OF_DEATH = 40251, + SPELL_BERSERK = 45078, + SPELL_SUMMON_DOOM_BLOSSOM = 40188, + SPELL_SUMMON_SKELETON_1 = 40270, + SPELL_SUMMON_SKELETON_2 = 41948, + SPELL_SUMMON_SKELETON_3 = 41949, + SPELL_SUMMON_SKELETON_4 = 41950, + SPELL_SUMMON_SPIRIT = 40266, + SPELL_DESTROY_SPIRIT = 41626, // purpose unk + SPELL_DESTROY_ALL_SPIRITS = 44659, // purpose unk + + // Spells - other + // SPELL_ATROPHY = 40327, // Shadowy Constructs use this when they get within melee range of a player + SPELL_SHADOWY_CONSTRUCT = 40326, + + // NPC_DOOM_BLOSSOM = 23123, // scripted in eventAI + NPC_SHADOWY_CONSTRUCT = 23111, // scripted in eventAI + // NPC_VENGEFUL_SPIRIT = 23109, // npc controlled by the dead player }; -struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI +struct boss_teron_gorefiendAI : public ScriptedAI { boss_teron_gorefiendAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIntroDone = false; Reset(); } @@ -206,71 +74,55 @@ struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI uint32 m_uiIncinerateTimer; uint32 m_uiSummonDoomBlossomTimer; - uint32 m_uiEnrageTimer; + uint32 m_uiBerserkTimer; uint32 m_uiCrushingShadowsTimer; uint32 m_uiShadowOfDeathTimer; - uint32 m_uiSummonShadowsTimer; - uint32 m_uiRandomYellTimer; - uint32 m_uiAggroTimer; - - ObjectGuid m_aggroTargetGuid; - ObjectGuid m_ghostGuid; // Player that gets killed by Shadow of Death and gets turned into a ghost - bool m_bIntro; + bool m_bIntroDone; - void Reset() + void Reset() override { - m_uiIncinerateTimer = urand(20000, 30000); - m_uiSummonDoomBlossomTimer = 12000; - m_uiEnrageTimer = MINUTE*10*IN_MILLISECONDS; - m_uiCrushingShadowsTimer = 22000; - m_uiSummonShadowsTimer = 60000; - m_uiRandomYellTimer = 50000; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // Start off unattackable so that the intro is done properly - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - m_uiAggroTimer = 20000; - m_aggroTargetGuid.Clear(); - m_bIntro = false; + m_uiIncinerateTimer = urand(20000, 30000); + m_uiSummonDoomBlossomTimer = urand(5000, 10000); + m_uiShadowOfDeathTimer = 10000; + m_uiCrushingShadowsTimer = 22000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_GOREFIEND, NOT_STARTED); + m_pInstance->SetData(TYPE_GOREFIEND, FAIL); } - void MoveInLineOfSight(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (m_pInstance && m_pInstance->GetData(TYPE_GOREFIEND)!= IN_PROGRESS && !m_bIntro && pWho->GetTypeId() == TYPEID_PLAYER && pWho->isTargetableForAttack() && - m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) - { - if (m_creature->IsWithinDistInMap(pWho, VISIBLE_RANGE) && m_creature->IsWithinLOSInMap(pWho)) - { - m_pInstance->SetData(TYPE_GOREFIEND, IN_PROGRESS); - - m_creature->GetMotionMaster()->Clear(false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoScriptText(SAY_AGGRO, m_creature); - DoScriptText(SAY_INTRO, m_creature); + if (m_pInstance) + m_pInstance->SetData(TYPE_GOREFIEND, IN_PROGRESS); + } - m_creature->HandleEmote(EMOTE_STATE_TALK); - m_aggroTargetGuid = pWho->GetObjectGuid(); - m_bIntro = true; - } + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bIntroDone && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 60.0f)) + { + DoScriptText(SAY_INTRO, m_creature); + m_bIntroDone = true; } ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_GOREFIEND, DONE); @@ -278,139 +130,25 @@ struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); } - float CalculateRandomLocation(float fLoc, uint32 uiRadius) - { - return fLoc + urand(0, 1) ? -rand()%uiRadius : rand()%uiRadius; - } - - void SetThreatList(Creature* pCreature) - { - if (!pCreature) - return; - - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) - { - Unit* pUnit = m_creature->GetMap()->GetUnit((*i)->getUnitGuid()); - - if (pUnit && pUnit->isAlive()) - { - float threat = m_creature->getThreatManager().getThreat(pUnit); - pCreature->AddThreat(pUnit, threat); - } - } - } - - void MindControlGhost() + void JustSummoned(Creature* pSummoned) override { - /************************************************************************/ - /** NOTE FOR FUTURE DEVELOPER: PROPERLY IMPLEMENT THE GHOST PORTION *****/ - /** ONLY AFTER MaNGOS FULLY IMPLEMENTS MIND CONTROL ABILITIES *****/ - /** THE CURRENT CODE IN THIS FUNCTION IS ONLY THE BEGINNING OF *****/ - /** WHAT IS FULLY NECESSARY FOR GOREFIEND TO BE 100% COMPLETE *****/ - /************************************************************************/ - - Player* pGhost = NULL; - if (m_ghostGuid) - pGhost = m_creature->GetMap()->GetPlayer(m_ghostGuid); - - if (pGhost && pGhost->isAlive() && pGhost->HasAura(SPELL_SHADOW_OF_DEATH, EFFECT_INDEX_0)) - { - /*float x,y,z; - pGhost->GetPosition(x,y,z); - Creature* control = m_creature->SummonCreature(CREATURE_GHOST, x, y, z, 0, TEMPSUMMON_TIMED_DESAWN, 30000); - if (control) - { - ((Player*)pGhost)->Possess(control); - pGhost->DealDamage(pGhost, pGhost->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, - false); - }*/ - for(uint8 i = 0; i < 4; ++i) - { - float fX = CalculateRandomLocation(pGhost->GetPositionX(), 10); - float fY = CalculateRandomLocation(pGhost->GetPositionY(), 10); - - if (Creature* pConstruct = m_creature->SummonCreature(NPC_SHADOWY_CONSTRUCT, fX, fY, pGhost->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000)) - { - pConstruct->CastSpell(pConstruct, SPELL_PASSIVE_SHADOWFORM, true); + if (pSummoned->GetEntry() == NPC_SHADOWY_CONSTRUCT) + pSummoned->CastSpell(pSummoned, SPELL_SHADOWY_CONSTRUCT, true); - SetThreatList(pConstruct); // Use same function as Doom Blossom to set Threat List. - if (mob_shadowy_constructAI* pConstructAI = dynamic_cast(pConstruct->AI())) - pConstructAI->m_ghostGuid = m_ghostGuid; - - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - pConstruct->GetMotionMaster()->MoveChase(pTarget ? pTarget : m_creature->getVictim()); - } - } - } + pSummoned->SetInCombatWithZone(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (m_bIntro) - { - if (m_uiAggroTimer < uiDiff) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - DoScriptText(SAY_AGGRO, m_creature); - - m_creature->HandleEmote(EMOTE_STATE_NONE); - m_bIntro = false; - if (m_aggroTargetGuid) - { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_aggroTargetGuid)) - AttackStart(pPlayer); - - m_creature->SetInCombatWithZone(); - } - else - EnterEvadeMode(); - } - else - m_uiAggroTimer -= uiDiff; - } - - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim() || m_bIntro) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiSummonShadowsTimer < uiDiff) - { - //MindControlGhost(); - for(uint8 i = 0; i < 2; ++i) - { - float fX = CalculateRandomLocation(m_creature->GetPositionX(), 10); - - if (Creature* pShadow = m_creature->SummonCreature(NPC_SHADOWY_CONSTRUCT, fX, m_creature->GetPositionY(), m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 0)) - { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - pShadow->AI()->AttackStart(pTarget ? pTarget : m_creature->getVictim()); - } - } - m_uiSummonShadowsTimer = 60000; - } - else - m_uiSummonShadowsTimer -= uiDiff; - if (m_uiSummonDoomBlossomTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_DOOM_BLOSSOM) == CAST_OK) { - float fX = CalculateRandomLocation(pTarget->GetPositionX(), 20); - float fY = CalculateRandomLocation(pTarget->GetPositionY(), 20); - - if (Creature* pDoomBlossom = m_creature->SummonCreature(NPC_DOOM_BLOSSOM, fX, fY, pTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000)) - { - pDoomBlossom->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pDoomBlossom->setFaction(m_creature->getFaction()); - pDoomBlossom->AddThreat(pTarget); - - if (mob_doom_blossomAI* pDoomBlossomAI = dynamic_cast(pDoomBlossom->AI())) - pDoomBlossomAI->SetTeronGUID(m_creature->GetObjectGuid()); - - SetThreatList(pDoomBlossom); - } + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SPELL1 : SAY_SPELL2, m_creature); m_uiSummonDoomBlossomTimer = 35000; } @@ -420,76 +158,59 @@ struct MANGOS_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI if (m_uiIncinerateTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - DoCastSpellIfCan(pTarget ? pTarget : m_creature->getVictim(), SPELL_INCINERATE); - m_uiIncinerateTimer = urand(20000, 50000); + + if (DoCastSpellIfCan(pTarget ? pTarget : m_creature->getVictim(), SPELL_INCINERATE) == CAST_OK) + m_uiIncinerateTimer = urand(20000, 50000); } else m_uiIncinerateTimer -= uiDiff; if (m_uiCrushingShadowsTimer < uiDiff) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget && pTarget->isAlive()) - DoCastSpellIfCan(pTarget, SPELL_CRUSHING_SHADOWS); + if (DoCastSpellIfCan(m_creature, SPELL_CRUSHING_SHADOWS) == CAST_OK) + { + if (urand(0, 1)) + DoScriptText(urand(0, 1) ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); - m_uiCrushingShadowsTimer = urand(10000, 26000); + m_uiCrushingShadowsTimer = urand(10000, 26000); + } } else m_uiCrushingShadowsTimer -= uiDiff; - /*** NOTE FOR FUTURE DEV: UNCOMMENT BELOW ONLY IF MIND CONTROL IS FULLY IMPLEMENTED **/ - /*if (m_uiShadowOfDeathTimer < uiDiff) + if (m_uiShadowOfDeathTimer < uiDiff) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - - if (!pTarget) - pTarget = m_creature->getVictim(); - - if (pTarget && pTarget->isAlive() && pTarget->GetTypeId() == TYPEID_PLAYER) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_SHADOW_OF_DEATH, SELECT_FLAG_PLAYER)) { - DoCastSpellIfCan(pTarget, SPELL_SHADOW_OF_DEATH); - m_ghostGuid = pTarget->GetObjectGuid(); - m_uiShadowOfDeathTimer = 30000; - m_uiSummonShadowsTimer = 53000; // Make it VERY close but slightly less so that we can check if the aura is still on the pPlayer + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_OF_DEATH) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); + m_uiShadowOfDeathTimer = 30000; + } } - }else m_uiShadowOfDeathTimer -= uiDiff;*/ - - if (m_uiRandomYellTimer < uiDiff) - { - DoScriptText(urand(0, 1) ? SAY_SPELL1 : SAY_SPELL2, m_creature); - m_uiRandomYellTimer = urand(50000, 100000); } else - m_uiRandomYellTimer -= uiDiff; + m_uiShadowOfDeathTimer -= uiDiff; - if (!m_creature->HasAura(SPELL_BERSERK, EFFECT_INDEX_0)) + if (m_uiBerserkTimer) { - if (m_uiEnrageTimer < uiDiff) + if (m_uiBerserkTimer <= uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_BERSERK); - DoScriptText(SAY_ENRAGE, m_creature); + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_uiBerserkTimer = 0; + } } else - m_uiEnrageTimer -= uiDiff; + m_uiBerserkTimer -= uiDiff; } DoMeleeAttackIfReady(); } }; -CreatureAI* GetAI_mob_doom_blossom(Creature* pCreature) -{ - return new mob_doom_blossomAI(pCreature); -} - -CreatureAI* GetAI_mob_shadowy_construct(Creature* pCreature) -{ - return new mob_shadowy_constructAI(pCreature); -} - CreatureAI* GetAI_boss_teron_gorefiend(Creature* pCreature) { return new boss_teron_gorefiendAI(pCreature); @@ -499,16 +220,6 @@ void AddSC_boss_teron_gorefiend() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "mob_doom_blossom"; - pNewScript->GetAI = &GetAI_mob_doom_blossom; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_shadowy_construct"; - pNewScript->GetAI = &GetAI_mob_shadowy_construct; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "boss_teron_gorefiend"; pNewScript->GetAI = &GetAI_boss_teron_gorefiend; diff --git a/scripts/outland/black_temple/boss_warlord_najentus.cpp b/scripts/outland/black_temple/boss_warlord_najentus.cpp index 7095625bc..8beddbbed 100644 --- a/scripts/outland/black_temple/boss_warlord_najentus.cpp +++ b/scripts/outland/black_temple/boss_warlord_najentus.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -33,7 +33,7 @@ enum SAY_SLAY2 = -1564004, SAY_SPECIAL1 = -1564005, SAY_SPECIAL2 = -1564006, - SAY_ENRAGE1 = -1564007, //is this text actually in use? + SAY_ENRAGE1 = -1564007, // is this text actually in use? SAY_ENRAGE2 = -1564008, SAY_DEATH = -1564009, @@ -47,7 +47,7 @@ enum SPELL_BERSERK = 26662 }; -struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI +struct boss_najentusAI : public ScriptedAI { boss_najentusAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -65,12 +65,12 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI bool m_bIsShielded; - void Reset() + void Reset() override { m_bIsShielded = false; m_uiNeedleSpineTimer = 10000; - m_uiEnrageTimer = MINUTE*8*IN_MILLISECONDS; + m_uiEnrageTimer = MINUTE * 8 * IN_MILLISECONDS; m_uiSpecialYellTimer = urand(45000, 120000); m_uiTidalShieldTimer = 60000; m_uiImpalingSpineTimer = 20000; @@ -78,18 +78,18 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI SetCombatMovement(true); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NAJENTUS, NOT_STARTED); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NAJENTUS, DONE); @@ -97,7 +97,7 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI DoScriptText(SAY_DEATH, m_creature); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { if (m_bIsShielded && pSpell->Id == SPELL_HURL_SPINE) { @@ -113,7 +113,7 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NAJENTUS, IN_PROGRESS); @@ -121,7 +121,7 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI DoScriptText(SAY_AGGRO, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -129,17 +129,17 @@ struct MANGOS_DLL_DECL boss_najentusAI : public ScriptedAI // If shield expired after 45s, attack again if (m_bIsShielded && m_uiTidalShieldTimer < 16000 && !m_creature->HasAura(SPELL_TIDAL_SHIELD)) { - m_bIsShielded = false; + m_bIsShielded = false; - SetCombatMovement(true); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + SetCombatMovement(true); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } if (m_uiEnrageTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_BERSERK, CAST_INTERRUPT_PREVIOUS) == CAST_OK) { - m_uiEnrageTimer = MINUTE*8*IN_MILLISECONDS; + m_uiEnrageTimer = MINUTE * 8 * IN_MILLISECONDS; DoScriptText(SAY_ENRAGE2, m_creature); } } diff --git a/scripts/outland/black_temple/illidari_council.cpp b/scripts/outland/black_temple/illidari_council.cpp index 46fb541fb..275d2bb68 100644 --- a/scripts/outland/black_temple/illidari_council.cpp +++ b/scripts/outland/black_temple/illidari_council.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Illidari_Council -SD%Complete: 85 -SDComment: Circle of Healing not working properly. +SD%Complete: 90 +SDComment: The shared health is done by workaround - proper spells are NYI. SDCategory: Black Temple EndScriptData */ @@ -26,57 +26,39 @@ EndScriptData */ enum { - //Speech'n'Sounds + // Speech'n'Sounds + SAY_GATH_AGGRO = -1564069, SAY_GATH_SLAY = -1564085, SAY_GATH_SLAY_COMNT = -1564089, SAY_GATH_DEATH = -1564093, SAY_GATH_SPECIAL1 = -1564077, SAY_GATH_SPECIAL2 = -1564081, + SAY_GATH_BERSERK = -1564073, + SAY_VERA_AGGRO = -1564070, SAY_VERA_SLAY = -1564086, SAY_VERA_COMNT = -1564089, SAY_VERA_DEATH = -1564094, SAY_VERA_SPECIAL1 = -1564078, SAY_VERA_SPECIAL2 = -1564082, + SAY_VERA_BERSERK = -1564074, + SAY_MALA_AGGRO = -1564071, SAY_MALA_SLAY = -1564087, SAY_MALA_COMNT = -1564090, SAY_MALA_DEATH = -1564095, SAY_MALA_SPECIAL1 = -1564079, SAY_MALA_SPECIAL2 = -1564083, + SAY_MALA_BERSERK = -1564075, + SAY_ZERE_AGGRO = -1564072, SAY_ZERE_SLAY = -1564088, SAY_ZERE_COMNT = -1564091, SAY_ZERE_DEATH = -1564096, SAY_ZERE_SPECIAL1 = -1564080, SAY_ZERE_SPECIAL2 = -1564084, -}; - -struct CouncilYells -{ - int32 entry; - uint32 timer; -}; - -static const CouncilYells CouncilAggro[]= -{ - {-1564069, 5000}, // Gathios - {-1564070, 5500}, // Veras - {-1564071, 5000}, // Malande - {-1564072, 0}, // Zerevor -}; + SAY_ZERE_BERSERK = -1564076, -// Need to get proper timers for this later -static const CouncilYells CouncilEnrage[]= -{ - {-1564073, 2000}, // Gathios - {-1564074, 6000}, // Veras - {-1564075, 5000}, // Malande - {-1564076, 0}, // Zerevor -}; - -enum -{ // High Nethermancer Zerevor's spells SPELL_FLAMESTRIKE = 41481, SPELL_BLIZZARD = 41482, @@ -89,7 +71,6 @@ enum SPELL_CIRCLE_OF_HEALING = 41455, SPELL_REFLECTIVE_SHIELD = 41475, SPELL_DIVINE_WRATH = 41472, - SPELL_HEAL_VISUAL = 24171, // Gathios the Shatterer's spells SPELL_BLESS_PROTECTION = 41450, @@ -100,74 +81,80 @@ enum SPELL_SEAL_OF_BLOOD = 41459, SPELL_CHROMATIC_AURA = 41453, SPELL_DEVOTION_AURA = 41452, + SPELL_JUDGMENT = 41467, // triggers 41473 (41470 or 41461) // Veras Darkshadow's spells SPELL_DEADLY_POISON = 41485, SPELL_ENVENOM = 41487, - SPELL_VANISH = 41479, + SPELL_VANISH_TELEPORT = 41479, + SPELL_VANISH = 41476, SPELL_BERSERK = 45078, + // SPELL_BALANCE_OF_POWER = 41341, // somehow related to 41344 + SPELL_SHARED_RULE_DAM = 41342, + SPELL_SHARED_RULE_HEAL = 41343, + SPELL_EMPYREAL_EQUIVALENCY = 41333, + SPELL_EMPYREAL_BALANCE = 41499, +}; + +static const DialogueEntry aCouncilDialogue[] = +{ + {SAY_GATH_AGGRO, NPC_GATHIOS, 5000}, + {SAY_VERA_AGGRO, NPC_VERAS, 5500}, + {SAY_MALA_AGGRO, NPC_LADY_MALANDE, 5000}, + {SAY_ZERE_AGGRO, NPC_ZEREVOR, 0}, + {SAY_GATH_BERSERK, NPC_GATHIOS, 2000}, + {SAY_VERA_BERSERK, NPC_VERAS, 6000}, + {SAY_MALA_BERSERK, NPC_LADY_MALANDE, 5000}, + {SAY_ZERE_BERSERK, NPC_ZEREVOR, 0}, + {0, 0, 0}, }; static const uint32 aCouncilMember[] = {NPC_GATHIOS, NPC_VERAS, NPC_LADY_MALANDE, NPC_ZEREVOR}; -struct MANGOS_DLL_DECL mob_blood_elf_council_voice_triggerAI : public ScriptedAI +/*###### +## mob_blood_elf_council_voice_trigger +######*/ + +struct mob_blood_elf_council_voice_triggerAI : public ScriptedAI { - mob_blood_elf_council_voice_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_blood_elf_council_voice_triggerAI(Creature* pCreature) : ScriptedAI(pCreature), + m_councilDialogue(aCouncilDialogue) { m_pInstance = (ScriptedInstance*)(m_creature->GetInstanceData()); + m_councilDialogue.InitializeDialogueHelper(m_pInstance); Reset(); } + ScriptedInstance* m_pInstance; + DialogueHelper m_councilDialogue; uint32 m_uiEnrageTimer; uint32 m_uiAggroYellTimer; - uint8 m_uiYellCounter; // Serves as the counter for both the aggro and enrage yells - - bool m_bEventStarted; - - void StartVoiceEvent() + void Reset() override { - if (!m_pInstance) - return; - - m_bEventStarted = true; + m_uiEnrageTimer = 0; + m_uiAggroYellTimer = 0; } - void Reset() + void StartVoiceEvent() { - m_uiEnrageTimer = 15*MINUTE*IN_MILLISECONDS; // 15 minutes m_uiAggroYellTimer = 500; - m_uiYellCounter = 0; - - m_bEventStarted = false; + m_uiEnrageTimer = 15 * MINUTE * IN_MILLISECONDS; } - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_bEventStarted) - return; - - if (m_uiYellCounter > 3) - return; + m_councilDialogue.DialogueUpdate(uiDiff); if (m_uiAggroYellTimer) { if (m_uiAggroYellTimer <= uiDiff) { - if (Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[m_uiYellCounter])) - { - DoScriptText(CouncilAggro[m_uiYellCounter].entry, pMember); - m_uiAggroYellTimer = CouncilAggro[m_uiYellCounter].timer; - } - ++m_uiYellCounter; - - if (m_uiYellCounter > 3) - m_uiYellCounter = 0; // Reuse for Enrage Yells + // Start yells + m_councilDialogue.StartNextDialogueText(SAY_GATH_AGGRO); + m_uiAggroYellTimer = 0; } else m_uiAggroYellTimer -= uiDiff; @@ -177,13 +164,15 @@ struct MANGOS_DLL_DECL mob_blood_elf_council_voice_triggerAI : public ScriptedAI { if (m_uiEnrageTimer <= uiDiff) { - if (Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[m_uiYellCounter])) + // Cast berserk on all members + for (uint8 i = 0; i < 4; ++i) { - pMember->CastSpell(pMember, SPELL_BERSERK, true); - DoScriptText(CouncilEnrage[m_uiYellCounter].entry, pMember); - m_uiEnrageTimer = CouncilEnrage[m_uiYellCounter].timer; + if (Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) + pMember->CastSpell(pMember, SPELL_BERSERK, true); } - ++m_uiYellCounter; + // Start yells + m_councilDialogue.StartNextDialogueText(SAY_GATH_BERSERK); + m_uiEnrageTimer = 0; } else m_uiEnrageTimer -= uiDiff; @@ -191,7 +180,11 @@ struct MANGOS_DLL_DECL mob_blood_elf_council_voice_triggerAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_illidari_councilAI : public ScriptedAI +/*###### +## mob_illidari_council +######*/ + +struct mob_illidari_councilAI : public ScriptedAI { mob_illidari_councilAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -201,151 +194,92 @@ struct MANGOS_DLL_DECL mob_illidari_councilAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiCheckTimer; - uint32 m_uiEndEventTimer; - - uint8 m_uiDeathCount; + uint32 m_uiEquivalencyTimer; bool m_bEventBegun; + bool m_bEventEnd; - void Reset() + void Reset() override { - m_uiCheckTimer = 2000; - m_uiEndEventTimer = 0; - - m_uiDeathCount = 0; - m_bEventBegun = false; + m_bEventEnd = false; - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetDisplayId(11686); - - if (m_pInstance) - { - // If already done, not do anything - if (m_pInstance->GetData(TYPE_COUNCIL) == DONE) - return; + m_uiEquivalencyTimer = urand(2000, 3000); + } - if (Creature* VoiceTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_COUNCIL_VOICE)) - VoiceTrigger->AI()->EnterEvadeMode(); + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - m_pInstance->SetData(TYPE_COUNCIL, NOT_STARTED); + void JustDied(Unit* /*pKiller*/) override + { + DoEndEvent(); - for(uint8 i = 0; i < 4; ++i) - { - if (Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) - { - if (!pMember->isAlive()) - { - pMember->RemoveCorpse(); - pMember->Respawn(); - } - pMember->AI()->EnterEvadeMode(); - } - } - } + if (m_pInstance) + m_pInstance->SetData(TYPE_COUNCIL, DONE); } - void AttackStart(Unit* pWho) {} - void MoveInLineOfSight(Unit* pWho) {} - - void StartEvent(Unit* pTarget) + void DoStartEvent() { - if (!m_pInstance) + if (!m_pInstance || m_bEventBegun) return; - if (pTarget && pTarget->isAlive() && !m_bEventBegun) - { - // Prevent further handling for next council uiMember aggroing - m_bEventBegun = true; + // Prevent further handling for next council uiMember aggroing + m_bEventBegun = true; - // Start the event for the Voice Trigger - if (Creature* pVoiceTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_COUNCIL_VOICE)) - { - if (mob_blood_elf_council_voice_triggerAI* pVoiceAI = dynamic_cast(pVoiceTrigger->AI())) - pVoiceAI->StartVoiceEvent(); - } - - for(uint8 i = 0; i < 4; ++i) - { - Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i]); - if (pMember && pMember->isAlive() && !pMember->isInCombat()) - pMember->AI()->AttackStart(pTarget); - } - - // All are set into combat now, Set Instance Data - m_pInstance->SetData(TYPE_COUNCIL, IN_PROGRESS); + // Start the event for the Voice Trigger + if (Creature* pVoiceTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_COUNCIL_VOICE)) + { + if (mob_blood_elf_council_voice_triggerAI* pVoiceAI = dynamic_cast(pVoiceTrigger->AI())) + pVoiceAI->StartVoiceEvent(); } + + DoCastSpellIfCan(m_creature, SPELL_EMPYREAL_BALANCE); } - void UpdateAI(const uint32 diff) + void DoEndEvent() { - if (!m_bEventBegun) // Can only be true when m_pInstance is valid + if (!m_pInstance || m_bEventEnd) return; - if (m_uiEndEventTimer) - { - if (m_uiEndEventTimer <= diff) - { - if (m_uiDeathCount > 3) - { - if (Creature* VoiceTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_COUNCIL_VOICE)) - VoiceTrigger->DealDamage(VoiceTrigger, VoiceTrigger->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - - m_pInstance->SetData(TYPE_COUNCIL, DONE); + // Prevent further handling for next council uiMember death + m_bEventEnd = true; - m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - return; - } + // Kill all the other council members + for (uint8 i = 0; i < 4; ++i) + { + Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i]); + if (pMember && pMember->isAlive()) + pMember->DealDamage(pMember, pMember->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } - Creature* pMember = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[m_uiDeathCount]); - if (pMember && pMember->isAlive()) - pMember->DealDamage(pMember, pMember->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + // Self kill the voice trigger and the controller + if (Creature* pVoiceTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_COUNCIL_VOICE)) + pVoiceTrigger->DealDamage(pVoiceTrigger, pVoiceTrigger->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - ++m_uiDeathCount; - m_uiEndEventTimer = 1500; - } - else - m_uiEndEventTimer -= diff; - } + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } - if (m_uiCheckTimer) + void UpdateAI(const uint32 uiDiff) override + { + // Make the council members health equal every 2-3 secs + if (m_bEventBegun && !m_bEventEnd) { - if (m_uiCheckTimer <= diff) + if (m_uiEquivalencyTimer < uiDiff) { - uint8 EvadeCheck = 0; - for(uint8 i = 0; i < 4; ++i) - { - if (Creature* Member = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) - { - // This is the evade/death check. - if (Member->isAlive() && !Member->SelectHostileTarget()) - ++EvadeCheck; // If all members evade, we reset so that players can properly reset the event - else if (!Member->isAlive()) // If even one uiMember dies, kill the rest, set instance data, and kill self. - { - m_uiEndEventTimer = 1000; - m_uiCheckTimer = 0; - return; - } - } - } - - if (EvadeCheck > 3) - { - m_pInstance->SetData(TYPE_COUNCIL, FAIL); - Reset(); - } - - m_uiCheckTimer = 2000; + if (DoCastSpellIfCan(m_creature, SPELL_EMPYREAL_EQUIVALENCY) == CAST_OK) + m_uiEquivalencyTimer = urand(2000, 3000); } else - m_uiCheckTimer -= diff; + m_uiEquivalencyTimer -= uiDiff; } } }; -struct MANGOS_DLL_DECL boss_illidari_councilAI : public ScriptedAI +/*###### +## boss_illidari_council +######*/ + +struct boss_illidari_councilAI : public ScriptedAI { boss_illidari_councilAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -354,41 +288,70 @@ struct MANGOS_DLL_DECL boss_illidari_councilAI : public ScriptedAI ScriptedInstance* m_pInstance; - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { if (m_pInstance) { + // Note: council aggro handled by creature linking + if (Creature* pController = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDARI_COUNCIL)) { if (mob_illidari_councilAI* pControlAI = dynamic_cast(pController->AI())) - pControlAI->StartEvent(pWho); + pControlAI->DoStartEvent(); } + + m_pInstance->SetData(TYPE_COUNCIL, IN_PROGRESS); } - else - EnterEvadeMode(); } - void DamageTaken(Unit* done_by, uint32 &damage) + void JustDied(Unit* /*pKiller*/) override { - if (done_by == m_creature) - return; - - damage /= 4; - if (!m_pInstance) - return; - - for(uint8 i = 0; i < 4; ++i) + if (m_pInstance) { - if (Creature* pCouncil = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) + if (Creature* pController = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDARI_COUNCIL)) { - if (pCouncil != m_creature && damage < pCouncil->GetHealth()) - pCouncil->SetHealth(pCouncil->GetHealth() - damage); + if (mob_illidari_councilAI* pControlAI = dynamic_cast(pController->AI())) + pControlAI->DoEndEvent(); } + + m_pInstance->SetData(TYPE_COUNCIL, DONE); + } + } + + void JustReachedHome() override + { + if (m_pInstance) + { + // Note: council respawn handled by creature linking + + if (Creature* pVoiceTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_COUNCIL_VOICE)) + pVoiceTrigger->AI()->EnterEvadeMode(); + + if (Creature* pController = m_pInstance->GetSingleCreatureFromStorage(NPC_ILLIDARI_COUNCIL)) + pController->AI()->EnterEvadeMode(); + + m_pInstance->SetData(TYPE_COUNCIL, FAIL); } } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + int32 uiDamageTaken = (int32)uiDamage; + m_creature->CastCustomSpell(m_creature, SPELL_SHARED_RULE_DAM, &uiDamageTaken, NULL, NULL, true); + } + + void HealedBy(Unit* pHealer, uint32& uiHealedAmount) override + { + int32 uHealTaken = (int32)uiHealedAmount; + m_creature->CastCustomSpell(m_creature, SPELL_SHARED_RULE_HEAL, &uHealTaken, NULL, NULL, true); + } }; -struct MANGOS_DLL_DECL boss_gathios_the_shattererAI : public boss_illidari_councilAI +/*###### +## boss_gathios_the_shatterer +######*/ + +struct boss_gathios_the_shattererAI : public boss_illidari_councilAI { boss_gathios_the_shattererAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } @@ -397,98 +360,60 @@ struct MANGOS_DLL_DECL boss_gathios_the_shattererAI : public boss_illidari_counc uint32 m_uiSealTimer; uint32 m_uiAuraTimer; uint32 m_uiBlessingTimer; + uint32 m_uiJudgmentTimer; - void Reset() + void Reset() override { - m_uiConsecrationTimer = 40000; - m_uiHammerOfJusticeTimer = 10000; - m_uiSealTimer = 40000; - m_uiAuraTimer = 90000; - m_uiBlessingTimer = 60000; + m_uiConsecrationTimer = 40000; + m_uiHammerOfJusticeTimer = 10000; + m_uiSealTimer = 40000; + m_uiAuraTimer = 90000; + m_uiBlessingTimer = 60000; + m_uiJudgmentTimer = 0; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_GATH_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_GATH_DEATH, m_creature); - } - - Unit* SelectCouncilMember() - { - if (!m_pInstance) - return m_creature; - - Unit* pUnit = m_creature; - uint32 uiMember = 2; // He chooses Lady Malande most often - if (!urand(0, 9)) // But there is a chance he picks someone else. - { - uiMember += urand(1, 3); - uiMember %= 4; - } - - if (uiMember != 0) // No need to create another pointer - pUnit = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[uiMember]); - - return pUnit; - } - - void CastAuraOnCouncil() - { - uint32 uiSpellid = 0; - switch(urand(0, 1)) - { - case 0: uiSpellid = SPELL_DEVOTION_AURA; break; - case 1: uiSpellid = SPELL_CHROMATIC_AURA; break; - } - - if (!m_pInstance) - return; - - for(uint8 i = 0; i < 4; ++i) - { - if (Creature* pCouncil = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) - pCouncil->CastSpell(pCouncil, uiSpellid, true, NULL, NULL, m_creature->GetObjectGuid()); - } + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiBlessingTimer < uiDiff) { - if (Unit* pUnit = SelectCouncilMember()) - DoCastSpellIfCan(pUnit, urand(0, 1) ? SPELL_BLESS_SPELLWARD : SPELL_BLESS_PROTECTION); - - m_uiBlessingTimer = 60000; + if (Unit* pTarget = DoSelectLowestHpFriendly(80.0f)) + { + if (DoCastSpellIfCan(pTarget, urand(0, 1) ? SPELL_BLESS_SPELLWARD : SPELL_BLESS_PROTECTION) == CAST_OK) + m_uiBlessingTimer = 60000; + } } else m_uiBlessingTimer -= uiDiff; if (m_uiConsecrationTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_CONSECRATION); - m_uiConsecrationTimer = 40000; + if (DoCastSpellIfCan(m_creature, SPELL_CONSECRATION) == CAST_OK) + m_uiConsecrationTimer = urand(10000, 15000); } else m_uiConsecrationTimer -= uiDiff; if (m_uiHammerOfJusticeTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_HAMMER_OF_JUSTICE, SELECT_FLAG_PLAYER | SELECT_FLAG_NOT_IN_MELEE_RANGE)) { - // is in ~10-40 yd range - if (m_creature->IsInRange(target, 10.0f, 40.0f, false)) - { - DoCastSpellIfCan(target, SPELL_HAMMER_OF_JUSTICE); + if (DoCastSpellIfCan(pTarget, SPELL_HAMMER_OF_JUSTICE) == CAST_OK) m_uiHammerOfJusticeTimer = 20000; - } } } else @@ -496,25 +421,45 @@ struct MANGOS_DLL_DECL boss_gathios_the_shattererAI : public boss_illidari_counc if (m_uiSealTimer < uiDiff) { - DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SEAL_OF_COMMAND : SPELL_SEAL_OF_BLOOD); - m_uiSealTimer = 40000; + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SEAL_OF_COMMAND : SPELL_SEAL_OF_BLOOD) == CAST_OK) + { + m_uiSealTimer = 40000; + + if (urand(0, 1)) + m_uiJudgmentTimer = urand(4000, 7000); + } } else m_uiSealTimer -= uiDiff; if (m_uiAuraTimer < uiDiff) { - CastAuraOnCouncil(); - m_uiAuraTimer = 90000; + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_DEVOTION_AURA : SPELL_CHROMATIC_AURA) == CAST_OK) + m_uiAuraTimer = 90000; } else m_uiAuraTimer -= uiDiff; + if (m_uiJudgmentTimer) + { + if (m_uiJudgmentTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_JUDGMENT) == CAST_OK) + m_uiJudgmentTimer = 0; + } + else + m_uiJudgmentTimer -= uiDiff; + } + DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_councilAI +/*###### +## boss_high_nethermancer_zerevor +######*/ + +struct boss_high_nethermancer_zerevorAI : public boss_illidari_councilAI { boss_high_nethermancer_zerevorAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } @@ -522,81 +467,78 @@ struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_c uint32 m_uiFlamestrikeTimer; uint32 m_uiArcaneBoltTimer; uint32 m_uiDampenMagicTimer; - uint32 m_uiCooldown; uint32 m_uiArcaneExplosionTimer; - void Reset() + void Reset() override + { + m_uiBlizzardTimer = urand(10000, 20000); + m_uiFlamestrikeTimer = urand(10000, 20000); + m_uiArcaneBoltTimer = 3000; + m_uiDampenMagicTimer = 2000; + m_uiArcaneExplosionTimer = 13000; + } + + void AttackStart(Unit* pWho) override { - m_uiBlizzardTimer = urand(30000, 90000); - m_uiFlamestrikeTimer = urand(30000, 90000); - m_uiArcaneBoltTimer = 10000; - m_uiDampenMagicTimer = 2000; - m_uiArcaneExplosionTimer = 14000; - m_uiCooldown = 0; + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_ZERE_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_ZERE_DEATH, m_creature); + + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiCooldown) - { - if (m_uiCooldown < uiDiff) - m_uiCooldown = 0; - else - { - m_uiCooldown -= uiDiff; - return; // Don't cast any other spells if global cooldown is still ticking - } - } - if (m_uiDampenMagicTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_DAMPEN_MAGIC); - m_uiCooldown = 1000; - m_uiDampenMagicTimer = 110000; // Almost 2 minutes - m_uiArcaneBoltTimer += 1000; // Give the Mage some time to spellsteal Dampen. + if (DoCastSpellIfCan(m_creature, SPELL_DAMPEN_MAGIC) == CAST_OK) + m_uiDampenMagicTimer = 110000; // Almost 2 minutes } else m_uiDampenMagicTimer -= uiDiff; if (m_uiArcaneExplosionTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_EXPLOSION); - m_uiCooldown = 1000; - m_uiArcaneExplosionTimer = 14000; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = urand(5000, 15000); } else m_uiArcaneExplosionTimer -= uiDiff; if (m_uiArcaneBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BOLT); - m_uiArcaneBoltTimer = 3000; - m_uiCooldown = 2000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BOLT) == CAST_OK) + m_uiArcaneBoltTimer = 3000; } else m_uiArcaneBoltTimer -= uiDiff; if (m_uiBlizzardTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target, SPELL_BLIZZARD); - m_uiBlizzardTimer = urand(45000, 90000); - m_uiFlamestrikeTimer += 10000; - m_uiCooldown = 1000; + if (DoCastSpellIfCan(pTarget, SPELL_BLIZZARD) == CAST_OK) + { + m_uiBlizzardTimer = urand(5000, 15000); + m_uiFlamestrikeTimer += 5000; + } } } else @@ -604,12 +546,13 @@ struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_c if (m_uiFlamestrikeTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target, SPELL_FLAMESTRIKE); - m_uiFlamestrikeTimer = urand(55000, 100000); - m_uiBlizzardTimer += 10000; - m_uiCooldown = 2000; + if (DoCastSpellIfCan(pTarget, SPELL_FLAMESTRIKE) == CAST_OK) + { + m_uiFlamestrikeTimer = urand(5000, 15000); + m_uiBlizzardTimer += 5000; + } } } else @@ -617,7 +560,11 @@ struct MANGOS_DLL_DECL boss_high_nethermancer_zerevorAI : public boss_illidari_c } }; -struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI +/*###### +## boss_lady_malande +######*/ + +struct boss_lady_malandeAI : public boss_illidari_councilAI { boss_lady_malandeAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } @@ -626,25 +573,38 @@ struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI uint32 m_uiDivineWrathTimer; uint32 m_uiReflectiveShieldTimer; - void Reset() + void Reset() override { - m_uiEmpoweredSmiteTimer = 38000; - m_uiCircleOfHealingTimer = 20000; - m_uiDivineWrathTimer = 40000; - m_uiReflectiveShieldTimer = 0; + m_uiEmpoweredSmiteTimer = 10000; + m_uiCircleOfHealingTimer = 20000; + m_uiDivineWrathTimer = 5000; + m_uiReflectiveShieldTimer = 0; } - void KilledUnit(Unit* pVictim) + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 20.0f); + } + } + + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_MALA_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_MALA_DEATH, m_creature); + + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -653,8 +613,8 @@ struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(pTarget, SPELL_EMPOWERED_SMITE); - m_uiEmpoweredSmiteTimer = 38000; + if (DoCastSpellIfCan(pTarget, SPELL_EMPOWERED_SMITE) == CAST_OK) + m_uiEmpoweredSmiteTimer = urand(5000, 15000); } } else @@ -662,19 +622,18 @@ struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI if (m_uiCircleOfHealingTimer < uiDiff) { - //Currently bugged and puts Malande on the threatlist of the other council members. It also heals players. - //DoCastSpellIfCan(m_creature, SPELL_CIRCLE_OF_HEALING); - m_uiCircleOfHealingTimer = 60000; + if (DoCastSpellIfCan(m_creature, SPELL_CIRCLE_OF_HEALING) == CAST_OK) + m_uiCircleOfHealingTimer = 20000; } else m_uiCircleOfHealingTimer -= uiDiff; if (m_uiDivineWrathTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(target, SPELL_DIVINE_WRATH); - m_uiDivineWrathTimer = urand(40000, 80000); + if (DoCastSpellIfCan(pTarget, SPELL_DIVINE_WRATH) == CAST_OK) + m_uiDivineWrathTimer = urand(2000, 5000); } } else @@ -682,8 +641,8 @@ struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI if (m_uiReflectiveShieldTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_REFLECTIVE_SHIELD); - m_uiReflectiveShieldTimer = 65000; + if (DoCastSpellIfCan(m_creature, SPELL_REFLECTIVE_SHIELD) == CAST_OK) + m_uiReflectiveShieldTimer = urand(30000, 40000); } else m_uiReflectiveShieldTimer -= uiDiff; @@ -692,107 +651,97 @@ struct MANGOS_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI } }; -struct MANGOS_DLL_DECL boss_veras_darkshadowAI : public boss_illidari_councilAI +/*###### +## boss_veras_darkshadow +######*/ + +struct boss_veras_darkshadowAI : public boss_illidari_councilAI { boss_veras_darkshadowAI(Creature* pCreature) : boss_illidari_councilAI(pCreature) { Reset(); } uint32 m_uiDeadlyPoisonTimer; uint32 m_uiVanishTimer; - uint32 m_uiAppearEnvenomTimer; - - bool m_bHasVanished; + uint32 m_uiVanishEndtimer; + uint32 m_uiEnvenomTimer; - void Reset() + void Reset() override { - m_uiDeadlyPoisonTimer = 20000; - m_uiVanishTimer = urand(60000, 120000); - m_uiAppearEnvenomTimer = 150000; - - m_bHasVanished = false; - m_creature->SetVisibility(VISIBILITY_ON); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiDeadlyPoisonTimer = 1000; + m_uiVanishTimer = urand(30000, 40000); + m_uiEnvenomTimer = 5000; + m_uiVanishEndtimer = 0; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(SAY_VERA_SLAY, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { DoScriptText(SAY_VERA_DEATH, m_creature); + + boss_illidari_councilAI::JustDied(pKiller); } - void UpdateAI(const uint32 uiDiff) + void EnterEvadeMode() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_uiVanishEndtimer) return; - if (!m_bHasVanished) - { - if (m_uiDeadlyPoisonTimer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEADLY_POISON); - m_uiDeadlyPoisonTimer = urand(15000, 45000); - } - else - m_uiDeadlyPoisonTimer -= uiDiff; + ScriptedAI::EnterEvadeMode(); + } - if (m_uiAppearEnvenomTimer < uiDiff) // Cast Envenom. This is cast 4 seconds after Vanish is over - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENVENOM); - m_uiAppearEnvenomTimer = 90000; - } - else - m_uiAppearEnvenomTimer -= uiDiff; + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; - if (m_uiVanishTimer < uiDiff) // Disappear and stop attacking, but follow a random unit + if (m_uiVanishEndtimer) + { + if (m_uiVanishEndtimer <= uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + if (DoCastSpellIfCan(m_creature, SPELL_VANISH_TELEPORT) == CAST_OK) { - m_uiVanishTimer = 30000; - m_uiAppearEnvenomTimer= 28000; - m_bHasVanished = true; - m_creature->SetVisibility(VISIBILITY_OFF); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); DoResetThreat(); - // Chase a unit. Check before DoMeleeAttackIfReady prevents from attacking - m_creature->AddThreat(pTarget, 500000.0f); - m_creature->GetMotionMaster()->MoveChase(pTarget); + m_uiVanishEndtimer = 0; } } else - m_uiVanishTimer -= uiDiff; + m_uiVanishEndtimer -= uiDiff; + + // no more abilities during vanish + return; + } - DoMeleeAttackIfReady(); + if (m_uiDeadlyPoisonTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEADLY_POISON) == CAST_OK) + m_uiDeadlyPoisonTimer = urand(4000, 7000); } else + m_uiDeadlyPoisonTimer -= uiDiff; + + if (m_uiEnvenomTimer < uiDiff) { - if (m_uiVanishTimer < uiDiff) // Become attackable and poison current target - { - Unit* target = m_creature->getVictim(); - DoCastSpellIfCan(target, SPELL_DEADLY_POISON); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - DoResetThreat(); - m_creature->AddThreat(target, 3000.0f); // Make Veras attack his pTarget for a while, he will cast Envenom 4 seconds after. - m_uiDeadlyPoisonTimer += 6000; - m_uiVanishTimer = 90000; - m_uiAppearEnvenomTimer = 4000; - m_bHasVanished = false; - } - else - m_uiVanishTimer -= uiDiff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENVENOM) == CAST_OK) + m_uiEnvenomTimer = 5000; + } + else + m_uiEnvenomTimer -= uiDiff; - if (m_uiAppearEnvenomTimer < uiDiff) // Appear 2 seconds before becoming attackable (Shifting out of vanish) + if (m_uiVanishTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_VANISH) == CAST_OK) { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - m_creature->SetVisibility(VISIBILITY_ON); - m_uiAppearEnvenomTimer = 6000; + m_uiVanishTimer = urand(30000, 40000); + m_uiVanishEndtimer = 1000; } - else - m_uiAppearEnvenomTimer -= uiDiff; } + else + m_uiVanishTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; diff --git a/scripts/outland/black_temple/instance_black_temple.cpp b/scripts/outland/black_temple/instance_black_temple.cpp index 0dadef8ea..4003e79ed 100644 --- a/scripts/outland/black_temple/instance_black_temple.cpp +++ b/scripts/outland/black_temple/instance_black_temple.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -46,38 +46,61 @@ void instance_black_temple::Initialize() memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_black_temple::OnPlayerEnter(Player* /*pPlayer*/) +{ + DoSpawnAkamaIfCan(); +} + bool instance_black_temple::IsEncounterInProgress() const { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + return true; + } return false; } void instance_black_temple::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { - // SPECIAL - guid is directly used, keep open how to handle - case NPC_AKAMA: m_akamaGuid = pCreature->GetObjectGuid(); break; - case NPC_ILLIDAN_STORMRAGE: m_illidanStormrageGuid = pCreature->GetObjectGuid(); break; - + case NPC_SPIRIT_OF_OLUM: + case NPC_SPIRIT_OF_UDALO: + // Use only the summoned versions + if (!pCreature->IsTemporarySummon()) + break; + case NPC_AKAMA: + case NPC_ILLIDAN_STORMRAGE: + case NPC_MAIEV_SHADOWSONG: case NPC_AKAMA_SHADE: case NPC_SHADE_OF_AKAMA: + case NPC_RELIQUARY_OF_SOULS: case NPC_GATHIOS: case NPC_ZEREVOR: case NPC_LADY_MALANDE: case NPC_VERAS: case NPC_ILLIDARI_COUNCIL: case NPC_COUNCIL_VOICE: + case NPC_ILLIDAN_DOOR_TRIGGER: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_ASH_CHANNELER: + m_lChannelersGuidList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_CREATURE_GENERATOR: + m_vCreatureGeneratorGuidVector.push_back(pCreature->GetObjectGuid()); + break; + case NPC_GLAIVE_TARGET: + m_vGlaiveTargetGuidVector.push_back(pCreature->GetObjectGuid()); + break; } } void instance_black_temple::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_NAJENTUS_GATE: // Gate past Naj'entus (at the entrance to Supermoose's courtyards) if (m_auiEncounter[TYPE_NAJENTUS] == DONE) @@ -88,22 +111,23 @@ void instance_black_temple::OnObjectCreate(GameObject* pGo) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_SHADE_OF_AKAMA: // Door close during encounter + case GO_GOREFIEND_DOOR: // Door close during encounter + break; + case GO_GURTOGG_DOOR: // Door opens after encounter + if (m_auiEncounter[TYPE_BLOODBOIL] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PRE_SHAHRAZ_DOOR: // Door leading to Mother Shahraz - if (CanPreMotherDoorOpen()) + if (m_auiEncounter[TYPE_SHADE] == DONE && m_auiEncounter[TYPE_GOREFIEND] == DONE && m_auiEncounter[TYPE_BLOODBOIL] == DONE && m_auiEncounter[TYPE_RELIQUIARY] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; - case GO_POST_SHAHRAZ_DOOR: // Door after shahraz - if (m_auiEncounter[6] == DONE) + case GO_POST_SHAHRAZ_DOOR: // Door after shahraz + if (m_auiEncounter[TYPE_SHAHRAZ] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PRE_COUNCIL_DOOR: // Door leading to the Council (grand promenade) - break; case GO_COUNCIL_DOOR: // Door leading to the Council (inside) - break; case GO_ILLIDAN_GATE: // Gate leading to Temple Summit - // TODO - dependend on council state - break; case GO_ILLIDAN_DOOR_R: // Right door at Temple Summit case GO_ILLIDAN_DOOR_L: // Left door at Temple Summit break; @@ -114,23 +138,9 @@ void instance_black_temple::OnObjectCreate(GameObject* pGo) m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } -bool instance_black_temple::CanPreMotherDoorOpen() -{ - if (m_auiEncounter[TYPE_SHADE] == DONE && m_auiEncounter[TYPE_GOREFIEND] == DONE && m_auiEncounter[TYPE_BLOODBOIL] == DONE && m_auiEncounter[TYPE_RELIQUIARY] == DONE) - { - debug_log("SD2: Black Temple: door to Mother Shahraz can open"); - return true; - } - - debug_log("SD2: Black Temple: Door data to Mother Shahraz requested, cannot open yet (Encounter data: %u %u %u %u)",m_auiEncounter[2],m_auiEncounter[3],m_auiEncounter[4],m_auiEncounter[5]); - return false; -} - void instance_black_temple::SetData(uint32 uiType, uint32 uiData) { - debug_log("SD2: Instance Black Temple: SetData received for type %u with data %u",uiType,uiData); - - switch(uiType) + switch (uiType) { case TYPE_NAJENTUS: m_auiEncounter[uiType] = uiData; @@ -143,12 +153,44 @@ void instance_black_temple::SetData(uint32 uiType, uint32 uiData) DoUseDoorOrButton(GO_SUPREMUS_DOORS); break; case TYPE_SHADE: + m_auiEncounter[uiType] = uiData; + // combat door + DoUseDoorOrButton(GO_SHADE_OF_AKAMA); + if (uiData == FAIL) + { + // Reset channelers on fail + for (GuidList::const_iterator itr = m_lChannelersGuidList.begin(); itr != m_lChannelersGuidList.end(); ++itr) + { + if (Creature* pChanneler = instance->GetCreature(*itr)) + { + if (!pChanneler->isAlive()) + pChanneler->Respawn(); + else + pChanneler->AI()->EnterEvadeMode(); + } + } + } + if (uiData == DONE) + DoOpenPreMotherDoor(); + break; case TYPE_GOREFIEND: + m_auiEncounter[uiType] = uiData; + DoUseDoorOrButton(GO_GOREFIEND_DOOR); + if (uiData == DONE) + DoOpenPreMotherDoor(); + break; case TYPE_BLOODBOIL: + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + { + DoOpenPreMotherDoor(); + DoUseDoorOrButton(GO_GURTOGG_DOOR); + } + break; case TYPE_RELIQUIARY: m_auiEncounter[uiType] = uiData; - if (uiData == DONE && CanPreMotherDoorOpen()) - DoUseDoorOrButton(GO_PRE_SHAHRAZ_DOOR); + if (uiData == DONE) + DoOpenPreMotherDoor(); break; case TYPE_SHAHRAZ: if (uiData == DONE) @@ -156,12 +198,27 @@ void instance_black_temple::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; case TYPE_COUNCIL: + // Don't set the same data twice + if (m_auiEncounter[uiType] == uiData) + return; DoUseDoorOrButton(GO_COUNCIL_DOOR); m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + DoSpawnAkamaIfCan(); + break; + case TYPE_ILLIDAN: + DoUseDoorOrButton(GO_ILLIDAN_DOOR_R); + DoUseDoorOrButton(GO_ILLIDAN_DOOR_L); + if (uiData == FAIL) + { + // Cleanup encounter + DoSpawnAkamaIfCan(); + DoUseDoorOrButton(GO_ILLIDAN_GATE); + } + m_auiEncounter[uiType] = uiData; break; - case TYPE_ILLIDAN: m_auiEncounter[uiType] = uiData; break; default: - error_log("SD2: Instance Black Temple: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); + script_error_log("Instance Black Temple: ERROR SetData = %u for type %u does not exist/not implemented.", uiType, uiData); return; } @@ -171,8 +228,8 @@ void instance_black_temple::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " - << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8]; m_strInstData = saveStream.str(); @@ -181,7 +238,7 @@ void instance_black_temple::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_black_temple::GetData(uint32 uiType) +uint32 instance_black_temple::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -189,15 +246,24 @@ uint32 instance_black_temple::GetData(uint32 uiType) return 0; } -uint64 instance_black_temple::GetData64(uint32 uiData) +void instance_black_temple::DoOpenPreMotherDoor() { - switch(uiData) - { - case NPC_AKAMA: return m_akamaGuid.GetRawValue(); - case NPC_ILLIDAN_STORMRAGE: return m_illidanStormrageGuid.GetRawValue(); - default: - return 0; - } + if (GetData(TYPE_SHADE) == DONE && GetData(TYPE_GOREFIEND) == DONE && GetData(TYPE_BLOODBOIL) == DONE && GetData(TYPE_RELIQUIARY) == DONE) + DoUseDoorOrButton(GO_PRE_SHAHRAZ_DOOR); +} + +void instance_black_temple::DoSpawnAkamaIfCan() +{ + if (GetData(TYPE_ILLIDAN) == DONE || GetData(TYPE_COUNCIL) != DONE) + return; + + // If already spawned return + if (GetSingleCreatureFromStorage(NPC_AKAMA, true)) + return; + + // Summon Akama after the council has been defeated + if (Player* pPlayer = GetPlayerInMap()) + pPlayer->SummonCreature(NPC_AKAMA, 617.754f, 307.768f, 271.735f, 6.197f, TEMPSUMMON_DEAD_DESPAWN, 0); } void instance_black_temple::Load(const char* chrIn) @@ -212,11 +278,13 @@ void instance_black_temple::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8]; + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] >> m_auiEncounter[8]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. m_auiEncounter[i] = NOT_STARTED; + } OUT_LOAD_INST_DATA_COMPLETE; } diff --git a/scripts/outland/blades_edge_mountains.cpp b/scripts/outland/blades_edge_mountains.cpp index 12afa86e4..3df4c2c9a 100644 --- a/scripts/outland/blades_edge_mountains.cpp +++ b/scripts/outland/blades_edge_mountains.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,201 +17,191 @@ /* ScriptData SDName: Blades_Edge_Mountains SD%Complete: 90 -SDComment: Quest support: 10503, 10504, 10556, 10609. (npc_daranelle needs bit more work before consider complete) +SDComment: Quest support: 10503, 10504, 10512, 10545, 10556, 10609, 10674, 10859, 11058, 11080. (npc_daranelle needs bit more work before consider complete) SDCategory: Blade's Edge Mountains EndScriptData */ /* ContentData -mobs_bladespire_ogre mobs_nether_drake npc_daranelle +npc_bloodmaul_stout_trigger +npc_simon_game_bunny +npc_light_orb_collector EndContentData */ #include "precompiled.h" +#include "TemporarySummon.h" /*###### -## mobs_bladespire_ogre +## mobs_nether_drake ######*/ -//TODO: add support for quest 10512 + creature abilities -struct MANGOS_DLL_DECL mobs_bladespire_ogreAI : public ScriptedAI +enum { - mobs_bladespire_ogreAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() { } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - DoMeleeAttackIfReady(); - } -}; + SAY_NIHIL_1 = -1000169, + SAY_NIHIL_2 = -1000170, + SAY_NIHIL_3 = -1000171, + SAY_NIHIL_4 = -1000172, + SAY_NIHIL_INTERRUPT = -1000173, -CreatureAI* GetAI_mobs_bladespire_ogre(Creature* pCreature) -{ - return new mobs_bladespire_ogreAI(pCreature); -} + MAX_ENTRIES = 4, -/*###### -## mobs_nether_drake -######*/ + NPC_PROTO = 21821, + NPC_ADOLESCENT = 21817, + NPC_MATURE = 21820, + NPC_NIHIL = 21823, -#define SAY_NIHIL_1 -1000169 -#define SAY_NIHIL_2 -1000170 -#define SAY_NIHIL_3 -1000171 -#define SAY_NIHIL_4 -1000172 -#define SAY_NIHIL_INTERRUPT -1000173 + SPELL_T_PHASE_MODULATOR = 37573, -#define ENTRY_WHELP 20021 -#define ENTRY_PROTO 21821 -#define ENTRY_ADOLE 21817 -#define ENTRY_MATUR 21820 -#define ENTRY_NIHIL 21823 - -#define SPELL_T_PHASE_MODULATOR 37573 + SPELL_ARCANE_BLAST = 38881, + SPELL_MANA_BURN = 38884, + SPELL_INTANGIBLE_PRESENCE = 36513, +}; -#define SPELL_ARCANE_BLAST 38881 -#define SPELL_MANA_BURN 38884 -#define SPELL_INTANGIBLE_PRESENCE 36513 +static const uint32 aNetherDrakeEntries[MAX_ENTRIES] = {NPC_PROTO, NPC_ADOLESCENT, NPC_MATURE, NPC_NIHIL}; -struct MANGOS_DLL_DECL mobs_nether_drakeAI : public ScriptedAI +struct mobs_nether_drakeAI : public ScriptedAI { mobs_nether_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool IsNihil; - uint32 NihilSpeech_Timer; - uint32 NihilSpeech_Phase; + bool m_bIsNihil; + uint32 m_uiNihilSpeechTimer; + uint32 m_uiNihilSpeechPhase; - uint32 ArcaneBlast_Timer; - uint32 ManaBurn_Timer; - uint32 IntangiblePresence_Timer; + uint32 m_uiArcaneBlastTimer; + uint32 m_uiManaBurnTimer; + uint32 m_uiIntangiblePresenceTimer; - void Reset() + void Reset() override { - IsNihil = false; - NihilSpeech_Timer = 3000; - NihilSpeech_Phase = 0; + m_bIsNihil = false; + m_uiNihilSpeechTimer = 3000; + m_uiNihilSpeechPhase = 0; - ArcaneBlast_Timer = 7500; - ManaBurn_Timer = 10000; - IntangiblePresence_Timer = 15000; + m_uiArcaneBlastTimer = 7500; + m_uiManaBurnTimer = 10000; + m_uiIntangiblePresenceTimer = 15000; } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit* pWho) override { if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; - ScriptedAI::MoveInLineOfSight(who); + ScriptedAI::MoveInLineOfSight(pWho); } - //in case creature was not summoned (not expected) - void MovementInform(uint32 type, uint32 id) + // in case creature was not summoned (not expected) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - if (type != POINT_MOTION_TYPE) + if (uiMoveType != POINT_MOTION_TYPE) return; - if (id == 0) - { - m_creature->SetDeathState(JUST_DIED); - m_creature->RemoveCorpse(); - m_creature->SetHealth(0); - } + if (uiPointId) + m_creature->ForcedDespawn(); } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (spell->Id == SPELL_T_PHASE_MODULATOR && caster->GetTypeId() == TYPEID_PLAYER) + if (pSpell->Id == SPELL_T_PHASE_MODULATOR && pCaster->GetTypeId() == TYPEID_PLAYER) { - const uint32 entry_list[4] = {ENTRY_PROTO, ENTRY_ADOLE, ENTRY_MATUR, ENTRY_NIHIL}; - int cid = rand()%(4-1); - - if (entry_list[cid] == m_creature->GetEntry()) - ++cid; - - //we are nihil, so say before transform - if (m_creature->GetEntry() == ENTRY_NIHIL) + // we are nihil, so say before transform + if (m_creature->GetEntry() == NPC_NIHIL) { DoScriptText(SAY_NIHIL_INTERRUPT, m_creature); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - IsNihil = false; + m_bIsNihil = false; } - if (m_creature->UpdateEntry(entry_list[cid])) + // choose a new entry + uint8 uiIndex = urand(0, MAX_ENTRIES - 1); + + // If we choose the same entry, try again + while (aNetherDrakeEntries[uiIndex] == m_creature->GetEntry()) + uiIndex = urand(0, MAX_ENTRIES - 1); + + if (m_creature->UpdateEntry(aNetherDrakeEntries[uiIndex])) { - if (entry_list[cid] == ENTRY_NIHIL) + // Nihil does only dialogue + if (aNetherDrakeEntries[uiIndex] == NPC_NIHIL) { EnterEvadeMode(); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - IsNihil = true; - }else - AttackStart(caster); + m_bIsNihil = true; + } + else + AttackStart(pCaster); } } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (IsNihil) + if (m_bIsNihil) { - if (NihilSpeech_Timer <= diff) + if (m_uiNihilSpeechTimer < uiDiff) { - switch(NihilSpeech_Phase) + switch (m_uiNihilSpeechPhase) { case 0: DoScriptText(SAY_NIHIL_1, m_creature); - ++NihilSpeech_Phase; break; case 1: DoScriptText(SAY_NIHIL_2, m_creature); - ++NihilSpeech_Phase; break; case 2: DoScriptText(SAY_NIHIL_3, m_creature); - ++NihilSpeech_Phase; break; case 3: DoScriptText(SAY_NIHIL_4, m_creature); - ++NihilSpeech_Phase; break; case 4: m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //take off to location above - m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX()+50.0f, m_creature->GetPositionY(), m_creature->GetPositionZ()+50.0f); - ++NihilSpeech_Phase; + // take off to location above + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + m_creature->GetMotionMaster()->MovePoint(1, m_creature->GetPositionX() + 50.0f, m_creature->GetPositionY(), m_creature->GetPositionZ() + 50.0f); break; } - NihilSpeech_Timer = 5000; - }else NihilSpeech_Timer -=diff; + ++m_uiNihilSpeechPhase; + m_uiNihilSpeechTimer = 5000; + } + else + m_uiNihilSpeechTimer -= uiDiff; - //anything below here is not interesting for Nihil, so skip it + // anything below here is not interesting for Nihil, so skip it return; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (IntangiblePresence_Timer <= diff) + if (m_uiIntangiblePresenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_INTANGIBLE_PRESENCE); - IntangiblePresence_Timer = urand(15000, 30000); - }else IntangiblePresence_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_INTANGIBLE_PRESENCE) == CAST_OK) + m_uiIntangiblePresenceTimer = urand(15000, 30000); + } + else + m_uiIntangiblePresenceTimer -= uiDiff; - if (ManaBurn_Timer <= diff) + if (m_uiManaBurnTimer < uiDiff) { - Unit* target = m_creature->getVictim(); - if (target && target->getPowerType() == POWER_MANA) - DoCastSpellIfCan(target,SPELL_MANA_BURN); - ManaBurn_Timer = urand(8000, 16000); - }else ManaBurn_Timer -= diff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANA_BURN, SELECT_FLAG_POWER_MANA)) + { + if (DoCastSpellIfCan(pTarget, SPELL_MANA_BURN) == CAST_OK) + m_uiManaBurnTimer = urand(8000, 16000); + } + } + else + m_uiManaBurnTimer -= uiDiff; - if (ArcaneBlast_Timer <= diff) + if (m_uiArcaneBlastTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ARCANE_BLAST); - ArcaneBlast_Timer = urand(2500, 7500); - }else ArcaneBlast_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BLAST) == CAST_OK) + m_uiArcaneBlastTimer = urand(2500, 7500); + } + else + m_uiArcaneBlastTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -233,13 +223,13 @@ enum SPELL_LASHHAN_CHANNEL = 36904 }; -struct MANGOS_DLL_DECL npc_daranelleAI : public ScriptedAI +struct npc_daranelleAI : public ScriptedAI { npc_daranelleAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() { } + void Reset() override { } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (pWho->GetTypeId() == TYPEID_PLAYER) { @@ -247,7 +237,7 @@ struct MANGOS_DLL_DECL npc_daranelleAI : public ScriptedAI { DoScriptText(SAY_SPELL_INFLUENCE, m_creature, pWho); - //TODO: Move the below to updateAI and run if this statement == true + // TODO: Move the below to updateAI and run if this statement == true ((Player*)pWho)->KilledMonsterCredit(NPC_KALIRI_AURA_DISPEL, m_creature->GetObjectGuid()); pWho->RemoveAurasDueToSpell(SPELL_LASHHAN_CHANNEL); } @@ -263,18 +253,646 @@ CreatureAI* GetAI_npc_daranelle(Creature* pCreature) } /*###### -## AddSC +## npc_bloodmaul_stout_trigger ######*/ +enum +{ + SAY_BREW_1 = -1000156, + SAY_BREW_2 = -1000207, + SAY_BREW_3 = -1000208, + + SPELL_INTOXICATION = 35240, + SPELL_INTOXICATION_VISUAL = 35777, +}; + +static const uint32 aOgreEntries[] = {19995, 19998, 20334, 20723, 20726, 20730, 20731, 20732, 21296}; + +struct npc_bloodmaul_stout_triggerAI : public ScriptedAI +{ + npc_bloodmaul_stout_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiStartTimer; + bool m_bHasValidOgre; + + ObjectGuid m_selectedOgreGuid; + + void Reset() override + { + m_uiStartTimer = 1000; + m_bHasValidOgre = false; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (m_bHasValidOgre && pWho->GetObjectGuid() == m_selectedOgreGuid && m_creature->IsWithinDistInMap(pWho, 3.5f)) + { + // This part it's not 100% accurate - most of it is guesswork + // Some animations or spells may be missing + pWho->CastSpell(pWho, SPELL_INTOXICATION_VISUAL, true); + pWho->CastSpell(pWho, SPELL_INTOXICATION, true); + + // Handle evade after some time with EAI + m_creature->AI()->SendAIEvent(AI_EVENT_CUSTOM_EVENTAI_A, m_creature, (Creature*)pWho); + + // Give kill credit to the summoner player + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + pSummoner->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); + } + + m_bHasValidOgre = false; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiStartTimer) + { + if (m_uiStartTimer <= uiDiff) + { + // get all the ogres in range + std::list lOgreList; + for (uint8 i = 0; i < countof(aOgreEntries); ++i) + GetCreatureListWithEntryInGrid(lOgreList, m_creature, aOgreEntries[i], 30.0f); + + if (lOgreList.empty()) + { + m_uiStartTimer = 5000; + return; + } + + // sort by distance and get only the closest + lOgreList.sort(ObjectDistanceOrder(m_creature)); + + std::list::const_iterator ogreItr = lOgreList.begin(); + Creature* pOgre = NULL; + + do + { + if ((*ogreItr)->isAlive() && !(*ogreItr)->HasAura(SPELL_INTOXICATION)) + pOgre = *ogreItr; + + ++ogreItr; + } + while (!pOgre && ogreItr != lOgreList.end()); + + if (!pOgre) + { + m_uiStartTimer = 5000; + return; + } + + // Move ogre to the point + float fX, fY, fZ; + pOgre->GetMotionMaster()->MoveIdle(); + m_creature->GetContactPoint(pOgre, fX, fY, fZ); + pOgre->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_BREW_1, pOgre); break; + case 1: DoScriptText(SAY_BREW_2, pOgre); break; + case 2: DoScriptText(SAY_BREW_3, pOgre); break; + } + + m_selectedOgreGuid = pOgre->GetObjectGuid(); + m_uiStartTimer = 0; + m_bHasValidOgre = true; + } + else + m_uiStartTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_bloodmaul_stout_trigger(Creature* pCreature) +{ + return new npc_bloodmaul_stout_triggerAI(pCreature); +} + +/*###### +## npc_simon_game_bunny +######*/ + +enum +{ + // sounds + SOUND_ID_BLUE = 11588, + SOUND_ID_GREEN = 11589, + SOUND_ID_RED = 11590, + SOUND_ID_YELLOW = 11591, + SOUND_ID_DISABLE_NODE = 11758, + + // generic spells + SPELL_SIMON_GAME_START = 39993, // aura used to prepare the AI game + SPELL_PRE_EVENT_TIMER = 40041, // aura used to handle the color sequence + + // stage prepare spells (summons the colored auras) + SPELL_PRE_GAME_BLUE_AURA = 40176, + SPELL_PRE_GAME_GREEN_AURA = 40177, + SPELL_PRE_GAME_RED_AURA = 40178, + SPELL_PRE_GAME_YELLOW_AURA = 40179, + + // stage prepare spells large + SPELL_PRE_GAME_YELLOW_LARGE = 41110, + SPELL_PRE_GAME_RED_LARGE = 41111, + SPELL_PRE_GAME_GREEN_LARGE = 41112, + SPELL_PRE_GAME_BLUE_LARGE = 41113, + + // visual spells which define which buttons are pressed + SPELL_BUTTON_PUSH_BLUE = 40244, + SPELL_BUTTON_PUSH_GREEN = 40245, + SPELL_BUTTON_PUSH_RED = 40246, + SPELL_BUTTON_PUSH_YELLOW = 40247, + + // allow the clusters to be used and despawns the visual auras + SPELL_GAME_START_RED = 40169, + SPELL_GAME_START_BLUE = 40170, + SPELL_GAME_START_GREEN = 40171, + SPELL_GAME_START_YELLOW = 40172, + + // locks the clusters after a stage is completed + SPELL_GAME_END_BLUE = 40283, + SPELL_GAME_END_GREEN = 40284, + SPELL_GAME_END_RED = 40285, + SPELL_GAME_END_YELLOW = 40286, + + // other spells + // SPELL_SWITCHED_ON_OFF = 40512, // decharger lock (not used) + // SPELL_SWITCHED_ON_OFF_2 = 40499, // decharger unlock (not used) + SPELL_SWITCHED_ON = 40494, // apexis lock spell + SPELL_SWITCHED_OFF = 40495, // apexis unlock spell + + // misc visual spells + SPELL_VISUAL_LEVEL_START = 40436, // on Player game begin + SPELL_VISUAL_GAME_FAILED = 40437, // on Player game fail + SPELL_VISUAL_GAME_START = 40387, // on AI game begin + SPELL_VISUAL_GAME_TICK = 40391, // game tick (sound) + SPELL_VISUAL_GAME_TICK_LARGE = 42019, // game tick large (sound) + + // spells used by the player on GO press + SPELL_INTROSPECTION_GREEN = 40055, + SPELL_INTROSPECTION_BLUE = 40165, + SPELL_INTROSPECTION_RED = 40166, + SPELL_INTROSPECTION_YELLOW = 40167, + + // button press results + SPELL_SIMON_BUTTON_PRESSED = 39999, + SPELL_GOOD_PRESS = 40063, + SPELL_BAD_PRESS = 41241, // single player punishment + SPELL_SIMON_GROUP_REWARD = 41952, // group punishment + + // quest rewards + SPELL_APEXIS_VIBRATIONS = 40310, // quest complete spell + SPELL_APEXIS_EMANATIONS = 40311, // quest complete spell + SPELL_APEXIS_ENLIGHTENMENT = 40312, // quest complete spell + + // other + NPC_SIMON_GAME_BUNNY = 22923, + + GO_APEXIS_RELIC = 185890, + GO_APEXIS_MONUMENT = 185944, + + QUEST_AN_APEXIS_RELIC = 11058, + QUEST_RELICS_EMANATION = 11080, + + // colors + COLOR_IDX_BLUE = 0, + COLOR_IDX_GREEN = 1, + COLOR_IDX_RED = 2, + COLOR_IDX_YELLOW = 3, + + // phases + PHASE_LEVEL_PREPARE = 1, + PHASE_AI_GAME = 2, + PHASE_PLAYER_PREPARE = 3, + PHASE_PLAYER_GAME = 4, + PHASE_LEVEL_FINISHED = 5, + + MAX_SIMON_LEVELS = 8, // counts the max levels of the game + MAX_SIMON_FAIL_TIMER = 5, // counts the delay in which the player is allowed to click +}; + +struct SimonGame +{ + uint8 m_uiColor; + uint32 m_uiVisual, m_uiIntrospection, m_uiSoundId; +}; + +static const SimonGame aApexisGameData[4] = +{ + {COLOR_IDX_BLUE, SPELL_BUTTON_PUSH_BLUE, SPELL_INTROSPECTION_BLUE, SOUND_ID_BLUE}, + {COLOR_IDX_GREEN, SPELL_BUTTON_PUSH_GREEN, SPELL_INTROSPECTION_GREEN, SOUND_ID_GREEN}, + {COLOR_IDX_RED, SPELL_BUTTON_PUSH_RED, SPELL_INTROSPECTION_RED, SOUND_ID_RED}, + {COLOR_IDX_YELLOW, SPELL_BUTTON_PUSH_YELLOW, SPELL_INTROSPECTION_YELLOW, SOUND_ID_YELLOW} +}; + +struct npc_simon_game_bunnyAI : public ScriptedAI +{ + npc_simon_game_bunnyAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint8 m_uiGamePhase; + + uint32 m_uiLevelCount; + uint32 m_uiLevelStage; + uint32 m_uiPlayerStage; + + std::vector m_vColors; + bool m_bIsLargeEvent; + bool m_bIsEventStarted; + + ObjectGuid m_masterPlayerGuid; + + void Reset() override + { + m_uiGamePhase = PHASE_LEVEL_PREPARE; + m_bIsEventStarted = false; + + m_uiLevelCount = 0; + m_uiLevelStage = 0; + m_uiPlayerStage = 0; + } + + void GetAIInformation(ChatHandler& reader) override + { + reader.PSendSysMessage("Simon Game Bunny, current game phase = %u, current level = %u", m_uiGamePhase, m_uiLevelCount); + } + + // Prepare levels + void DoPrepareLevel() + { + // this visual is cast only after the first level + if (m_uiLevelCount) + DoCastSpellIfCan(m_creature, SPELL_VISUAL_GAME_START, CAST_TRIGGERED); + // this part is done only on the first tick + else + { + // lock apexis + DoCastSpellIfCan(m_creature, SPELL_SWITCHED_ON, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_PRE_EVENT_TIMER, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + + // Get original summoner + if (m_creature->IsTemporarySummon()) + m_masterPlayerGuid = ((TemporarySummon*)m_creature)->GetSummonerGuid(); + + // Get closest apexis + if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_APEXIS_RELIC, 5.0f)) + m_bIsLargeEvent = false; + else if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_APEXIS_MONUMENT, 17.0f)) + m_bIsLargeEvent = true; + } + + // prepare the buttons and summon the visual auras + DoCastSpellIfCan(m_creature, m_bIsLargeEvent ? SPELL_PRE_GAME_BLUE_LARGE : SPELL_PRE_GAME_BLUE_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, m_bIsLargeEvent ? SPELL_PRE_GAME_GREEN_LARGE : SPELL_PRE_GAME_GREEN_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, m_bIsLargeEvent ? SPELL_PRE_GAME_RED_LARGE : SPELL_PRE_GAME_RED_AURA, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, m_bIsLargeEvent ? SPELL_PRE_GAME_YELLOW_LARGE : SPELL_PRE_GAME_YELLOW_AURA, CAST_TRIGGERED); + + m_vColors.clear(); + ++m_uiLevelCount; + } + + // Setup the color sequence + void DoSetupLevel() + { + uint8 uiIndex = urand(COLOR_IDX_BLUE, COLOR_IDX_YELLOW); + m_vColors.push_back(uiIndex); + + DoCastSpellIfCan(m_creature, aApexisGameData[uiIndex].m_uiVisual, CAST_TRIGGERED); + DoPlaySoundToSet(m_creature, aApexisGameData[uiIndex].m_uiSoundId); + } + + // Setup the player level - called at the beginning at each player level + void DoSetupPlayerLevel() + { + // allow the buttons to be used and despawn the visual auras + DoCastSpellIfCan(m_creature, SPELL_GAME_START_RED, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_START_BLUE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_START_GREEN, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_START_YELLOW, CAST_TRIGGERED); + } + + // Complete level - called when one level is completed succesfully + void DoCompleteLevel() + { + // lock the buttons + DoCastSpellIfCan(m_creature, SPELL_GAME_END_RED, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_END_BLUE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_END_GREEN, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_END_YELLOW, CAST_TRIGGERED); + + // Complete game if all the levels + if (m_uiLevelCount == MAX_SIMON_LEVELS) + DoCompleteGame(); + } + + // Complete event - called when the game has been completed succesfully + void DoCompleteGame() + { + // ToDo: not sure if the quest reward spells are implemented right. They all give the same buff but with a different duration + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_masterPlayerGuid)) + { + if (Group* pGroup = pPlayer->GetGroup()) + { + for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + { + if (Player* pMember = pRef->getSource()) + { + // distance check - they need to be close to the Apexis + if (!pMember->IsWithinDistInMap(m_creature, 20.0f)) + continue; + + // on group event cast Enlightment on daily quest and Emanations on normal quest + if (pMember->GetQuestStatus(QUEST_AN_APEXIS_RELIC) == QUEST_STATUS_INCOMPLETE) + DoCastSpellIfCan(pMember, SPELL_APEXIS_EMANATIONS, CAST_TRIGGERED); + else if (pMember->GetQuestStatus(QUEST_RELICS_EMANATION) == QUEST_STATUS_INCOMPLETE) + DoCastSpellIfCan(pMember, SPELL_APEXIS_ENLIGHTENMENT, CAST_TRIGGERED); + } + } + } + else + { + // solo event - cast Emanations on daily quest and vibrations on normal quest + if (pPlayer->GetQuestStatus(QUEST_AN_APEXIS_RELIC) == QUEST_STATUS_INCOMPLETE) + DoCastSpellIfCan(pPlayer, SPELL_APEXIS_VIBRATIONS, CAST_TRIGGERED); + else if (pPlayer->GetQuestStatus(QUEST_RELICS_EMANATION) == QUEST_STATUS_INCOMPLETE) + DoCastSpellIfCan(pPlayer, SPELL_APEXIS_EMANATIONS, CAST_TRIGGERED); + } + } + + // cleanup event after quest is finished + DoCastSpellIfCan(m_creature, SPELL_SWITCHED_OFF, CAST_TRIGGERED); + DoPlaySoundToSet(m_creature, SOUND_ID_DISABLE_NODE); + m_creature->ForcedDespawn(); + } + + // Cleanup event - called when event fails + void DoCleanupGame() + { + // lock the buttons + DoCastSpellIfCan(m_creature, SPELL_GAME_END_RED, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_END_BLUE, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_END_GREEN, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_GAME_END_YELLOW, CAST_TRIGGERED); + + // unlock apexis and despawn + DoCastSpellIfCan(m_creature, SPELL_SWITCHED_OFF, CAST_TRIGGERED); + DoPlaySoundToSet(m_creature, SOUND_ID_DISABLE_NODE); + m_creature->ForcedDespawn(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + switch (m_uiGamePhase) + { + case PHASE_LEVEL_PREPARE: + // delay before each level - handled by big timer aura + if (eventType == AI_EVENT_CUSTOM_A) + m_uiGamePhase = PHASE_AI_GAME; + break; + case PHASE_AI_GAME: + // AI game - handled by small timer aura + if (eventType == AI_EVENT_CUSTOM_B) + { + // Move to next phase if the level is setup + if (m_uiLevelStage == m_uiLevelCount) + { + m_uiGamePhase = PHASE_PLAYER_PREPARE; + m_uiLevelStage = 0; + return; + } + + DoSetupLevel(); + ++m_uiLevelStage; + } + break; + case PHASE_PLAYER_PREPARE: + // Player prepare - handled by small timer aura + if (eventType == AI_EVENT_CUSTOM_B) + { + DoCastSpellIfCan(m_creature, SPELL_VISUAL_LEVEL_START, CAST_TRIGGERED); + DoSetupPlayerLevel(); + + m_uiGamePhase = PHASE_PLAYER_GAME; + m_uiPlayerStage = 0; + } + break; + case PHASE_PLAYER_GAME: + // Player game - listen to the player moves + if (eventType == AI_EVENT_CUSTOM_C) + { + // good button pressed + if (uiMiscValue == aApexisGameData[m_vColors[m_uiLevelStage]].m_uiIntrospection) + { + DoCastSpellIfCan(m_creature, SPELL_GOOD_PRESS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, aApexisGameData[m_vColors[m_uiLevelStage]].m_uiVisual, CAST_TRIGGERED); + + DoPlaySoundToSet(m_creature, aApexisGameData[m_vColors[m_uiLevelStage]].m_uiSoundId); + + // increase the level stage and reset the event counter + ++m_uiLevelStage; + m_uiPlayerStage = 0; + + // if all buttons were pressed succesfully, then move to next level + if (m_uiLevelStage == m_vColors.size()) + { + DoCompleteLevel(); + + m_uiLevelStage = 0; + m_uiGamePhase = PHASE_LEVEL_FINISHED; + } + // cast tick sound + else + DoCastSpellIfCan(pInvoker, m_bIsLargeEvent ? SPELL_VISUAL_GAME_TICK_LARGE : SPELL_VISUAL_GAME_TICK, CAST_TRIGGERED); + } + // bad button pressed + else + { + DoCastSpellIfCan(pInvoker, m_bIsLargeEvent ? SPELL_SIMON_GROUP_REWARD : SPELL_BAD_PRESS, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_VISUAL_GAME_FAILED, CAST_TRIGGERED); + DoCleanupGame(); + } + } + // AI ticks which handle the player timeout + else if (eventType == AI_EVENT_CUSTOM_B) + { + // if it takes too much time, the event will fail + if (m_uiPlayerStage == MAX_SIMON_FAIL_TIMER) + { + DoCastSpellIfCan(m_creature, SPELL_VISUAL_GAME_FAILED, CAST_TRIGGERED); + DoCleanupGame(); + } + + // Not sure if this is right, but we need to keep the buttons unlocked on every tick + DoSetupPlayerLevel(); + ++m_uiPlayerStage; + } + break; + case PHASE_LEVEL_FINISHED: + // small delay until the next level + if (eventType == AI_EVENT_CUSTOM_A) + { + DoPrepareLevel(); + m_uiGamePhase = PHASE_LEVEL_PREPARE; + } + break; + } + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + + void UpdateAI(const uint32 /*uiDiff*/) override + { + // Start game on first update tick - don't wait for dummy auras + if (!m_bIsEventStarted) + { + DoPrepareLevel(); + m_bIsEventStarted = true; + } + } +}; + +CreatureAI* GetAI_npc_simon_game_bunny(Creature* pCreature) +{ + return new npc_simon_game_bunnyAI(pCreature); +} + +bool EffectDummyCreature_npc_simon_game_bunny(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + if (pCreatureTarget->GetEntry() != NPC_SIMON_GAME_BUNNY) + return false; + + if (uiSpellId == SPELL_SIMON_GAME_START && uiEffIndex == EFFECT_INDEX_0) + { + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + return true; + } + else if (uiSpellId == SPELL_PRE_EVENT_TIMER && uiEffIndex == EFFECT_INDEX_0) + { + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_B, pCaster, pCreatureTarget); + return true; + } + + return false; +} + +bool EffectScriptEffectCreature_npc_simon_game_bunny(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid originalCasterGuid) +{ + if ((uiSpellId == SPELL_INTROSPECTION_BLUE || uiSpellId == SPELL_INTROSPECTION_GREEN || uiSpellId == SPELL_INTROSPECTION_RED || + uiSpellId == SPELL_INTROSPECTION_YELLOW) && uiEffIndex == EFFECT_INDEX_1) + { + if (pCreatureTarget->GetEntry() == NPC_SIMON_GAME_BUNNY && pCaster->GetTypeId() == TYPEID_PLAYER && originalCasterGuid.IsGameObject()) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_C, pCaster, pCreatureTarget, uiSpellId); + + return true; + } + + return false; +} + +/*###### +## npc_light_orb_collector +######*/ + +enum +{ + NPC_LIGHT_ORB_MINI = 20771, + NPC_KILL_CREDIT_TRIGGER = 21929, + + MAX_PULL_DISTANCE = 20, +}; + +struct npc_light_orb_collectorAI : public ScriptedAI +{ + npc_light_orb_collectorAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + ObjectGuid m_selectedOrbGuid; + bool m_bOrbPulled; + + uint32 m_uiStartTimer; + + void Reset() override + { + m_bOrbPulled = false; + m_uiStartTimer = 0; + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (pWho->GetTypeId() != TYPEID_UNIT || pWho->GetEntry() != NPC_LIGHT_ORB_MINI) + return; + + // Select an nearby orb to collect + if (!m_uiStartTimer && !m_bOrbPulled) + { + if (m_creature->GetDistance(pWho) <= MAX_PULL_DISTANCE) + { + m_selectedOrbGuid = pWho->GetObjectGuid(); + m_uiStartTimer = 2000; + } + } + else if (m_bOrbPulled && pWho->GetObjectGuid() == m_selectedOrbGuid && m_creature->IsWithinDistInMap(pWho, 3.5f)) + { + // Despawn the collected orb if close enough + ((Creature*)pWho)->ForcedDespawn(); + + // Give kill credit to the player + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + pSummoner->KilledMonsterCredit(NPC_KILL_CREDIT_TRIGGER, m_creature->GetObjectGuid()); + } + + // Despawn collector + m_creature->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiStartTimer) + { + // Start collecting after some delay + if (m_uiStartTimer <= uiDiff) + { + Creature* pSelectedOrb = m_creature->GetMap()->GetCreature(m_selectedOrbGuid); + if (!pSelectedOrb) + return; + + // Orb is pulled fast + pSelectedOrb->SetWalk(false); + + // Move orb to the collector + float fX, fY, fZ;; + pSelectedOrb->GetMotionMaster()->MoveIdle(); + m_creature->GetContactPoint(pSelectedOrb, fX, fY, fZ); + pSelectedOrb->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + + m_bOrbPulled = true; + m_uiStartTimer = 0; + } + else + m_uiStartTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_light_orb_collector(Creature* pCreature) +{ + return new npc_light_orb_collectorAI(pCreature); +} + void AddSC_blades_edge_mountains() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "mobs_bladespire_ogre"; - pNewScript->GetAI = &GetAI_mobs_bladespire_ogre; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "mobs_nether_drake"; pNewScript->GetAI = &GetAI_mobs_nether_drake; @@ -284,4 +902,21 @@ void AddSC_blades_edge_mountains() pNewScript->Name = "npc_daranelle"; pNewScript->GetAI = &GetAI_npc_daranelle; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_bloodmaul_stout_trigger"; + pNewScript->GetAI = &GetAI_npc_bloodmaul_stout_trigger; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_simon_game_bunny"; + pNewScript->GetAI = &GetAI_npc_simon_game_bunny; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_simon_game_bunny; + pNewScript->pEffectScriptEffectNPC = &EffectScriptEffectCreature_npc_simon_game_bunny; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_light_orb_collector"; + pNewScript->GetAI = &GetAI_npc_light_orb_collector; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/boss_doomlord_kazzak.cpp b/scripts/outland/boss_doomlord_kazzak.cpp index 4054ef2aa..cf2c13f10 100644 --- a/scripts/outland/boss_doomlord_kazzak.cpp +++ b/scripts/outland/boss_doomlord_kazzak.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -49,7 +49,7 @@ enum SPELL_BERSERK = 32965, // triggers 32963 }; -struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI +struct boss_doomlordkazzakAI : public ScriptedAI { boss_doomlordkazzakAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -62,7 +62,7 @@ struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI uint32 m_uiGreatEnrageTimer; uint32 m_uiTwistedReflectionTimer; - void Reset() + void Reset() override { m_uiShadowVolleyTimer = urand(6000, 10000); m_uiCleaveTimer = 7000; @@ -70,28 +70,28 @@ struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI m_uiVoidBoltTimer = 30000; m_uiMarkOfKazzakTimer = 25000; m_uiEnrageTimer = 60000; - m_uiGreatEnrageTimer = 3*MINUTE*IN_MILLISECONDS; - m_uiTwistedReflectionTimer = 33000; // Timer may be incorrect + m_uiGreatEnrageTimer = 3 * MINUTE * IN_MILLISECONDS; + m_uiTwistedReflectionTimer = 33000; // Timer may be incorrect } - void JustRespawned() + void JustRespawned() override { DoScriptText(SAY_INTRO, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(urand(0, 1) ? SAY_AGGRO1 : SAY_AGGRO2, m_creature); DoCastSpellIfCan(m_creature, SPELL_CAPTURE_SOUL, CAST_TRIGGERED); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { // When Kazzak kills a player (not pets/totems), he regens some health if (pVictim->GetTypeId() != TYPEID_PLAYER) return; - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL1, m_creature); break; case 1: DoScriptText(SAY_KILL2, m_creature); break; @@ -99,12 +99,12 @@ struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -199,7 +199,6 @@ struct MANGOS_DLL_DECL boss_doomlordkazzakAI : public ScriptedAI DoMeleeAttackIfReady(); } - }; CreatureAI* GetAI_boss_doomlordkazzak(Creature* pCreature) diff --git a/scripts/outland/boss_doomwalker.cpp b/scripts/outland/boss_doomwalker.cpp index 5b39a3daf..50b15c95b 100644 --- a/scripts/outland/boss_doomwalker.cpp +++ b/scripts/outland/boss_doomwalker.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,7 +44,7 @@ enum SPELL_MARK_OF_DEATH_AURA = 37125, // triggers 37131 on target if it has aura 37128 }; -struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI +struct boss_doomwalkerAI : public ScriptedAI { boss_doomwalkerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -55,7 +55,7 @@ struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI bool m_bHasEnrage; - void Reset() + void Reset() override { m_uiArmorTimer = urand(5000, 13000); m_uiChainTimer = urand(10000, 30000); @@ -65,7 +65,7 @@ struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI m_bHasEnrage = false; } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; @@ -81,21 +81,20 @@ struct MANGOS_DLL_DECL boss_doomwalkerAI : public ScriptedAI case 1: DoScriptText(SAY_SLAY_2, m_creature); break; case 2: DoScriptText(SAY_SLAY_3, m_creature); break; } - } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoCastSpellIfCan(m_creature, SPELL_MARK_OF_DEATH_AURA, CAST_TRIGGERED); DoScriptText(SAY_AGGRO, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_fathomlord_karathress.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_fathomlord_karathress.cpp index 254af1976..2ec63722e 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_fathomlord_karathress.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_fathomlord_karathress.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Fathomlord_Karathress -SD%Complete: 60 -SDComment: Missing Multishot, Totems, Windfury, Whirlwind +SD%Complete: 95 +SDComment: Timers may need adjustments. SDCategory: Coilfang Resevoir, Serpent Shrine Cavern EndScriptData */ @@ -36,48 +36,54 @@ enum SAY_SLAY3 = -1548028, SAY_DEATH = -1548029, - //Karathress spells + // Karathress spells SPELL_CATACLYSMIC_BOLT = 38441, - SPELL_POWER_OF_SHARKKIS = 38455, - SPELL_POWER_OF_TIDALVESS = 38452, - SPELL_POWER_OF_CARIBDIS = 38451, - SPELL_ENRAGE = 24318, + SPELL_ENRAGE = 24318, // ToDo: spell needs to be confirmed SPELL_SEAR_NOVA = 38445, - SPELL_BLESSING_OF_THE_TIDES = 38449, + SPELL_BLESSING_OF_THE_TIDES = 38449, // cast by each of the advisors when the boss reaches 75% hp - //Sharkkis spells + // Sharkkis spells SPELL_LEECHING_THROW = 29436, SPELL_THE_BEAST_WITHIN = 38373, SPELL_HURL_TRIDENT = 38374, SPELL_MULTI_TOSS = 38366, SPELL_SUMMON_FATHOM_LURKER = 38433, SPELL_SUMMON_FATHOM_SPOREBAT = 38431, + SPELL_POWER_OF_SHARKKIS = 38455, // cast on Karathress, on death - //Tidalvess spells + // Tidalvess spells SPELL_FROST_SHOCK = 38234, SPELL_SPITFIRE_TOTEM = 38236, SPELL_POISON_CLEANSING_TOTEM = 38306, SPELL_EARTHBIND_TOTEM = 38304, SPELL_WINDFURY_WEAPON = 32911, // triggers spell 32912 (Windfury) + SPELL_POWER_OF_TIDALVESS = 38452, // cast on Karathress, on death - //Caribdis Spells + // Caribdis Spells SPELL_WATER_BOLT_VOLLEY = 38335, SPELL_TIDAL_SURGE = 38358, // triggers 38353 which then triggers 38357 - SPELL_HEAL = 38330, + SPELL_HEALING_WAVE = 38330, SPELL_SUMMON_CYCLONE = 38337, // summons creature 22104 which uses spell 29538 + SPELL_POWER_OF_CARIBDIS = 38451, // cast on Karathress, on death + + SPELL_CYCLONE = 29538, MAX_ADVISORS = 3, + NPC_CYCLONE = 22104, NPC_SEER_OLUM = 22820 }; // position for Seer Olum -const float afCoords_Olum[] = {446.78f, -542.76f, -7.54773f, 0.401581f}; +static const float afCoordsOlum[4] = {446.78f, -542.76f, -7.547f, 0.401f}; + +static const uint32 aAdvisors[MAX_ADVISORS] = {NPC_SHARKKIS, NPC_TIDALVESS, NPC_CARIBDIS}; -static const uint32 aAdvisors[] = {NPC_SHARKKIS, NPC_TIDALVESS, NPC_CARIBDIS}; +/*###### +## boss_fathomlord_karathress +######*/ -//Fathom-Lord Karathress AI -struct MANGOS_DLL_DECL boss_fathomlord_karathressAI : public ScriptedAI +struct boss_fathomlord_karathressAI : public ScriptedAI { boss_fathomlord_karathressAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -87,69 +93,47 @@ struct MANGOS_DLL_DECL boss_fathomlord_karathressAI : public ScriptedAI ScriptedInstance* m_pInstance; - // timers uint32 m_uiCataclysmicBoltTimer; + uint32 m_uiSearingNovaTimer; uint32 m_uiEnrageTimer; - bool m_bBlessingOfTides_MobsChecked; + bool m_bBlessingOfTides; - void Reset() + void Reset() override { - m_uiCataclysmicBoltTimer = 10000; - m_uiEnrageTimer = 600000; - m_bBlessingOfTides_MobsChecked = false; + m_uiCataclysmicBoltTimer = 10000; + m_uiSearingNovaTimer = urand(20000, 30000); + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + m_bBlessingOfTides = false; } - // TODO - unneeded workaround - the spell should be cast by adviser onto karathress; text can also be handled in their AI - // select the spell and the text based on the advisor which died - void EventAdvisorDeath(uint32 uiAdvisor) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - if (!m_creature->isAlive()) - return; - - int32 iSayGainAbility = 0; - uint32 uiSpell = 0; - - switch(uiAdvisor) + switch (pSpell->Id) { - case NPC_SHARKKIS: - iSayGainAbility = SAY_GAIN_ABILITY1; - uiSpell = SPELL_POWER_OF_SHARKKIS; + case SPELL_POWER_OF_SHARKKIS: + DoScriptText(SAY_GAIN_ABILITY1, m_creature); break; - case NPC_TIDALVESS: - iSayGainAbility = SAY_GAIN_ABILITY2; - uiSpell = SPELL_POWER_OF_TIDALVESS; + case SPELL_POWER_OF_TIDALVESS: + DoScriptText(SAY_GAIN_ABILITY1, m_creature); break; - case NPC_CARIBDIS: - iSayGainAbility = SAY_GAIN_ABILITY3; - uiSpell = SPELL_POWER_OF_CARIBDIS; + case SPELL_POWER_OF_CARIBDIS: + DoScriptText(SAY_GAIN_ABILITY3, m_creature); break; - default: - error_log("SD2: invalid advisor (id %u) for karathress!", uiAdvisor); - return; } - - DoScriptText(iSayGainAbility, m_creature); - DoCastSpellIfCan(m_creature, uiSpell); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (!m_pInstance) - return; + if (m_pInstance) + m_pInstance->SetData(TYPE_KARATHRESS_EVENT, IN_PROGRESS); DoScriptText(SAY_AGGRO, m_creature); - - if (Player* pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself()) - { - m_pInstance->SetGuid(DATA_KARATHRESS_STARTER, pPlayer->GetObjectGuid()); - m_pInstance->SetData(TYPE_KARATHRESS_EVENT, IN_PROGRESS); - } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -157,256 +141,160 @@ struct MANGOS_DLL_DECL boss_fathomlord_karathressAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_KARATHRESS_EVENT, DONE); - //support for quest 10944 - m_creature->SummonCreature(NPC_SEER_OLUM, afCoords_Olum[0], afCoords_Olum[1], afCoords_Olum[2], afCoords_Olum[3], TEMPSUMMON_TIMED_DESPAWN, 3600000); + // support for quest 10944 + m_creature->SummonCreature(NPC_SEER_OLUM, afCoordsOlum[0], afCoordsOlum[1], afCoordsOlum[2], afCoordsOlum[3], TEMPSUMMON_TIMED_DESPAWN, 1 * HOUR * IN_MILLISECONDS); } - void JustReachedHome() + void JustReachedHome() override { - if (!m_pInstance) - return; - - for (uint8 i = 0; i < MAX_ADVISORS; ++i) - { - if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[i])) - { - if (pAdvisor->getVictim()) - pAdvisor->AI()->EnterEvadeMode(); - else if (!pAdvisor->isAlive()) - pAdvisor->Respawn(); - } - } - if (m_pInstance) m_pInstance->SetData(TYPE_KARATHRESS_EVENT, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_pInstance) - return; - - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetGuid(DATA_KARATHRESS_STARTER))) - AttackStart(pTarget); - } return; - } - //someone evaded! - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == FAIL) - { - EnterEvadeMode(); - return; - } - - //m_uiCataclysmicBoltTimer if (m_uiCataclysmicBoltTimer < uiDiff) { - //select a random unit other than the main tank + // select a random unit other than the main tank Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - //if there aren't other units, cast on the tank + // if there aren't other units, cast on the tank if (!pTarget) pTarget = m_creature->getVictim(); - if (DoCastSpellIfCan(pTarget, SPELL_CATACLYSMIC_BOLT) == CAST_OK) - m_uiCataclysmicBoltTimer = 10000; + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, SPELL_CATACLYSMIC_BOLT) == CAST_OK) + m_uiCataclysmicBoltTimer = 10000; + } } else m_uiCataclysmicBoltTimer -= uiDiff; - //hp under 75% - if (!m_bBlessingOfTides_MobsChecked && m_creature->GetHealthPercent() < 75.0f) + if (!m_bBlessingOfTides && m_creature->GetHealthPercent() < 75.0f) { - for(uint8 i = 0; i < MAX_ADVISORS; ++i) + for (uint8 i = 0; i < MAX_ADVISORS; ++i) { if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[i])) { - //stack max three times (one for each alive) + // stack max three times (one for each alive) if (pAdvisor->isAlive()) { pAdvisor->InterruptNonMeleeSpells(false); - pAdvisor->CastSpell(m_creature, SPELL_BLESSING_OF_THE_TIDES, false); + pAdvisor->CastSpell(m_creature, SPELL_BLESSING_OF_THE_TIDES, true); } } } - //yell if we now have the aura + // yell if we now have the aura if (m_creature->HasAura(SPELL_BLESSING_OF_THE_TIDES)) DoScriptText(SAY_GAIN_BLESSING, m_creature); - m_bBlessingOfTides_MobsChecked = true; + m_bBlessingOfTides = true; } - //m_uiEnrageTimer - if (m_uiEnrageTimer < uiDiff) + if (m_uiSearingNovaTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) - m_uiEnrageTimer = 90000; + if (DoCastSpellIfCan(m_creature, SPELL_SEAR_NOVA) == CAST_OK) + m_uiSearingNovaTimer = urand(20000, 30000); } else - m_uiEnrageTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -// Base AI for every advisor -struct MANGOS_DLL_DECL Advisor_Base_AI : public ScriptedAI -{ - Advisor_Base_AI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - } - - ScriptedInstance* m_pInstance; - - void JustReachedHome() - { - if (m_pInstance && m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - m_pInstance->SetData(TYPE_KARATHRESS_EVENT, FAIL); - } + m_uiSearingNovaTimer -= uiDiff; - void Aggro(Unit *pWho) - { - if (!m_pInstance) - return; - - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == NOT_STARTED || m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == FAIL) - m_pInstance->SetData(TYPE_KARATHRESS_EVENT, IN_PROGRESS); - - if (Player* pPlayer = pWho->GetCharmerOrOwnerPlayerOrPlayerItself()) - m_pInstance->SetGuid(DATA_KARATHRESS_STARTER, pPlayer->GetObjectGuid()); - } - - void JustDied(Unit* pVictim) - { - if (!m_pInstance) - return; - - if (Creature* pKarathress = m_pInstance->GetSingleCreatureFromStorage(NPC_KARATHRESS)) + if (m_uiEnrageTimer) { - if (boss_fathomlord_karathressAI* pKaraAI = dynamic_cast(pKarathress->AI())) - pKaraAI->EventAdvisorDeath(m_creature->GetEntry()); + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_uiEnrageTimer = 0; + } + else + m_uiEnrageTimer -= uiDiff; } + + DoMeleeAttackIfReady(); } }; -//Fathom-Guard Sharkkis AI -struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public Advisor_Base_AI +/*###### +## boss_fathomguard_sharkkis +######*/ + +struct boss_fathomguard_sharkkisAI : public ScriptedAI { - boss_fathomguard_sharkkisAI(Creature* pCreature) : Advisor_Base_AI(pCreature) { Reset(); } + boss_fathomguard_sharkkisAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - // timers uint32 m_uiHurlTridentTimer; uint32 m_uiLeechingThrowTimer; uint32 m_uiTheBeastWithinTimer; + uint32 m_uiMultiTossTimer; uint32 m_uiPetTimer; - bool m_bIsPetCheckNeeded; - - void Reset() + void Reset() override { m_uiHurlTridentTimer = 2500; m_uiLeechingThrowTimer = 20000; m_uiTheBeastWithinTimer = 30000; - m_uiPetTimer = 10000; - - m_bIsPetCheckNeeded = true; + m_uiMultiTossTimer = urand(7000, 11000); + if (!m_creature->GetPet()) + m_uiPetTimer = 10000; } - void AttackStart(Unit* pWho) + void JustDied(Unit* /*pKiller*/) override { - if (!pWho) - return; - - if (m_creature->Attack(pWho, false)) - { - m_creature->AddThreat(pWho); - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); - - //using larger distance, since hunter type - m_creature->GetMotionMaster()->MoveChase(pWho, 15.0f); - } + DoCastSpellIfCan(m_creature, SPELL_POWER_OF_SHARKKIS, CAST_TRIGGERED); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (pSummoned->IsPet()) - { - m_uiPetTimer = 10000; - m_bIsPetCheckNeeded = false; - } + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void SummonedCreatureDespawn(Creature* pDespawned) + void SummonedCreatureJustDied(Creature* pSummoned) override { - if (pDespawned->IsPet()) - m_bIsPetCheckNeeded = true; + // resummon the pet in 10 secs + if (pSummoned->IsPet()) + m_uiPetTimer = 10000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_pInstance) - return; - - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetGuid(DATA_KARATHRESS_STARTER))) - AttackStart(pTarget); - } return; - } - //someone evaded! - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == FAIL) + if (m_uiPetTimer) { - EnterEvadeMode(); - return; - } - - //after 10 seconds: spawn pet if not exist - if (m_bIsPetCheckNeeded) - { - if (m_uiPetTimer < uiDiff) + if (m_uiPetTimer <= uiDiff) { - if (!m_creature->GetPet()) - DoCastSpellIfCan(m_creature, urand(0,1) ? SPELL_SUMMON_FATHOM_LURKER : SPELL_SUMMON_FATHOM_SPOREBAT); + if (DoCastSpellIfCan(m_creature, urand(0, 1) ? SPELL_SUMMON_FATHOM_LURKER : SPELL_SUMMON_FATHOM_SPOREBAT) == CAST_OK) + m_uiPetTimer = 0; } else m_uiPetTimer -= uiDiff; } - //m_uiHurlTridentTimer if (m_uiHurlTridentTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_HURL_TRIDENT, 0)) - DoCastSpellIfCan(pTarget, SPELL_HURL_TRIDENT); - - m_uiHurlTridentTimer = 5000; + { + if (DoCastSpellIfCan(pTarget, SPELL_HURL_TRIDENT) == CAST_OK) + m_uiHurlTridentTimer = 5000; + } } else m_uiHurlTridentTimer -= uiDiff; - //m_uiLeechingThrowTimer if (m_uiLeechingThrowTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_LEECHING_THROW) == CAST_OK) @@ -415,7 +303,6 @@ struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public Advisor_Base_AI else m_uiLeechingThrowTimer -= uiDiff; - //m_uiTheBeastWithinTimer if (m_uiTheBeastWithinTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_THE_BEAST_WITHIN) == CAST_OK) @@ -424,102 +311,124 @@ struct MANGOS_DLL_DECL boss_fathomguard_sharkkisAI : public Advisor_Base_AI else m_uiTheBeastWithinTimer -= uiDiff; + if (m_uiMultiTossTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HURL_TRIDENT) == CAST_OK) + m_uiMultiTossTimer = urand(7000, 12000); + } + } + else + m_uiMultiTossTimer -= uiDiff; + DoMeleeAttackIfReady(); } }; -//Fathom-Guard Tidalvess AI -struct MANGOS_DLL_DECL boss_fathomguard_tidalvessAI : public Advisor_Base_AI +/*###### +## boss_fathomguard_tidalvess +######*/ + +struct boss_fathomguard_tidalvessAI : public ScriptedAI { - boss_fathomguard_tidalvessAI(Creature* pCreature) : Advisor_Base_AI(pCreature) { Reset(); } + boss_fathomguard_tidalvessAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - // timers uint32 m_uiFrostShockTimer; + uint32 m_uiWindfuryTimer; + uint32 m_uiTotemTimer; - void Reset() + void Reset() override { m_uiFrostShockTimer = 25000; + m_uiWindfuryTimer = 0; + m_uiTotemTimer = urand(2000, 5000); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override { - if (!m_pInstance) - return; + DoCastSpellIfCan(m_creature, SPELL_POWER_OF_TIDALVESS, CAST_TRIGGERED); + } - //Return since we have no target + void UpdateAI(const uint32 uiDiff) override + { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetGuid(DATA_KARATHRESS_STARTER))) - AttackStart(pTarget); - } return; + + if (m_uiFrostShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK) == CAST_OK) + m_uiFrostShockTimer = urand(25000, 30000); } + else + m_uiFrostShockTimer -= uiDiff; - //someone evaded! - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == FAIL) + if (m_uiWindfuryTimer < uiDiff) { - EnterEvadeMode(); - return; + if (DoCastSpellIfCan(m_creature, SPELL_WINDFURY_WEAPON) == CAST_OK) + m_uiWindfuryTimer = urand(90000, 100000); } + else + m_uiWindfuryTimer -= uiDiff; - //m_uiFrostShockTimer - if (m_uiFrostShockTimer < uiDiff) + if (m_uiTotemTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK); - m_uiFrostShockTimer = urand(25000, 30000); + if (m_creature->IsNonMeleeSpellCasted(false)) + { + switch (urand(0, 2)) + { + case 0: DoCastSpellIfCan(m_creature, SPELL_SPITFIRE_TOTEM); + case 1: DoCastSpellIfCan(m_creature, SPELL_POISON_CLEANSING_TOTEM); + case 2: DoCastSpellIfCan(m_creature, SPELL_EARTHBIND_TOTEM); + } + m_uiTotemTimer = urand(30000, 60000); + } } else - m_uiFrostShockTimer -= uiDiff; + m_uiTotemTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Fathom-Guard Caribdis AI -struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public Advisor_Base_AI +/*###### +## boss_fathomguard_caribdis +######*/ + +struct boss_fathomguard_caribdisAI : public ScriptedAI { - boss_fathomguard_caribdisAI(Creature* pCreature) : Advisor_Base_AI(pCreature) { Reset(); } + boss_fathomguard_caribdisAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - // timers uint32 m_uiWaterBoltVolleyTimer; uint32 m_uiTidalSurgeTimer; uint32 m_uiHealTimer; + uint32 m_uiCycloneTimer; - void Reset() + void Reset() override { m_uiWaterBoltVolleyTimer = 35000; m_uiTidalSurgeTimer = urand(15000, 20000); m_uiHealTimer = 55000; + m_uiCycloneTimer = urand(10000, 15000); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override { - if (!m_pInstance) - return; + DoCastSpellIfCan(m_creature, SPELL_POWER_OF_CARIBDIS, CAST_TRIGGERED); + } - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { - //check if the event is started - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == IN_PROGRESS) - { - if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_pInstance->GetGuid(DATA_KARATHRESS_STARTER))) - AttackStart(pTarget); - } - return; - } + void JustSummoned(Creature* pSummoned) override + { + // ToDo: research if this creature should follow the summoner or a random target + if (pSummoned->GetEntry() == NPC_CYCLONE) + pSummoned->CastSpell(pSummoned, SPELL_CYCLONE, true); + } - //someone evaded! - if (m_pInstance->GetData(TYPE_KARATHRESS_EVENT) == FAIL) - { - EnterEvadeMode(); + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - } - //m_uiWaterBoltVolleyTimer if (m_uiWaterBoltVolleyTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WATER_BOLT_VOLLEY) == CAST_OK) @@ -528,7 +437,6 @@ struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public Advisor_Base_AI else m_uiWaterBoltVolleyTimer -= uiDiff; - //m_uiTidalSurgeTimer if (m_uiTidalSurgeTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_TIDAL_SURGE) == CAST_OK) @@ -537,26 +445,19 @@ struct MANGOS_DLL_DECL boss_fathomguard_caribdisAI : public Advisor_Base_AI else m_uiTidalSurgeTimer -= uiDiff; - //m_uiHealTimer - if (m_uiHealTimer < uiDiff) + if (m_uiCycloneTimer < uiDiff) { - // It can be cast on any of the mobs - Unit* pUnit = NULL; - - switch (urand(0, 3)) - { - case 0: pUnit = m_pInstance->GetSingleCreatureFromStorage(NPC_KARATHRESS); break; - case 1: pUnit = m_pInstance->GetSingleCreatureFromStorage(NPC_SHARKKIS); break; - case 2: pUnit = m_pInstance->GetSingleCreatureFromStorage(NPC_TIDALVESS); break; - case 3: pUnit = m_creature; break; - } - - if (!pUnit) - pUnit = m_creature; + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_CYCLONE) == CAST_OK) + m_uiCycloneTimer = urand(45000, 60000); + } + else + m_uiCycloneTimer -= uiDiff; - if (pUnit->isAlive()) + if (m_uiHealTimer < uiDiff) + { + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - if (DoCastSpellIfCan(pUnit, SPELL_HEAL) == CAST_OK) + if (DoCastSpellIfCan(pTarget, SPELL_HEALING_WAVE) == CAST_OK) m_uiHealTimer = 60000; } } diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_hydross_the_unstable.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_hydross_the_unstable.cpp index c02fb5ad3..a23f3ea56 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_hydross_the_unstable.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_hydross_the_unstable.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Hydross_The_Unstable -SD%Complete: 90 -SDComment: Some details and adjustments left to do, probably nothing major. Spawns may be spawned in different way/location. code cleanup needed +SD%Complete: 95 +SDComment: Timers may need improvemets. SDCategory: Coilfang Resevoir, Serpent Shrine Cavern EndScriptData */ @@ -36,87 +36,73 @@ enum SAY_CORRUPT_SLAY2 = -1548007, SAY_CORRUPT_DEATH = -1548008, - SWITCH_RADIUS = 18, - - MODEL_CORRUPT = 20609, - MODEL_CLEAN = 20162, - SPELL_WATER_TOMB = 38235, - SPELL_MARK_OF_HYDROSS1 = 38215, - SPELL_MARK_OF_HYDROSS2 = 38216, - SPELL_MARK_OF_HYDROSS3 = 38217, - SPELL_MARK_OF_HYDROSS4 = 38218, - SPELL_MARK_OF_HYDROSS5 = 38231, - SPELL_MARK_OF_HYDROSS6 = 40584, - SPELL_MARK_OF_CORRUPTION1 = 38219, - SPELL_MARK_OF_CORRUPTION2 = 38220, - SPELL_MARK_OF_CORRUPTION3 = 38221, - SPELL_MARK_OF_CORRUPTION4 = 38222, - SPELL_MARK_OF_CORRUPTION5 = 38230, - SPELL_MARK_OF_CORRUPTION6 = 40583, SPELL_VILE_SLUDGE = 38246, - SPELL_ENRAGE = 27680, //this spell need verification - SPELL_SUMMON_WATER_ELEMENT = 36459, //not in use yet(in use ever?) - SPELL_ELEMENTAL_SPAWNIN = 25035, - SPELL_BLUE_BEAM = 38015, //channeled Hydross Beam Helper (not in use yet) - SPELL_PURIFY_ELEMENTAL = 36461, //(not in use) visualize the line by tainting/purifying mobs + SPELL_CORRUPTION = 37961, // transform spell + SPELL_ENRAGE = 27680, // ToDo: this spell need verification + SPELL_BLUE_BEAM = 38015, + SPELL_SUMMON_WATER_ELEMENT = 36459, // spawn elemental on OOC timer + // SPELL_ELEMENTAL_SPAWNIN = 25035, // already handled in eventAI + SPELL_PURIFY_ELEMENTAL = 36461, // purify elemental on OOC timer NPC_PURE_SPAWN = 22035, - NPC_TAINTED_SPAWN = 22036 -}; + NPC_TAINTED_SPAWN = 22036, + NPC_PURIFIED_ELEMENTAL = 21260, + NPC_TAINTED_ELEMENTAL = 21253, -const float afSpawnDiffs[4][2] = -{ - {6.934003f , -11.255012f}, // diff 1 - {-6.934003f , 11.255012f }, // diff 2 - {-12.577011f, -4.72702f }, // diff 3 - {12.577011f , 4.72702f } // diff 4 + POINT_ID_ELEMENTAL_CLEAN = 1, + POINT_ID_ELEMENTAL_EXIT = 2, + + SWITCH_RADIUS = 18, + MAX_HYDROSS_ADDS = 4, + MAX_HYDROSS_MARKS = 6, }; -struct MANGOS_DLL_DECL boss_hydross_the_unstableAI : public ScriptedAI +static const uint32 aMarkHydross[MAX_HYDROSS_MARKS] = {38215, 38216, 38217, 38218, 38231, 40584}; +static const uint32 aMarkCorruption[MAX_HYDROSS_MARKS] = {38219, 38220, 38221, 38222, 38230, 40583}; + +static const float aElementalCleanPoint[3] = { -231.48f, -343.05f, -1.58f}; +static const float aElementalExitPoint[3] = { -177.41f, -395.72f, -1.60f}; + +struct boss_hydross_the_unstableAI : public ScriptedAI { boss_hydross_the_unstableAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_serpentshrine_cavern*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance* m_pInstance; // the instance + instance_serpentshrine_cavern* m_pInstance; - uint32 m_uiPosCheck_Timer; - uint32 m_uiMarkOfHydross_Timer; - uint32 m_uiMarkOfCorruption_Timer; - uint32 m_uiWaterTomb_Timer; - uint32 m_uiVileSludge_Timer; - uint32 m_uiMarkOfHydross_Count; - uint32 m_uiMarkOfCorruption_Count; + uint32 m_uiBeamInitTimer; + uint32 m_uiElementalTimer; + uint32 m_uiPosCheckTimer; + uint32 m_uiMarkTimer; + uint32 m_uiWaterTombTimer; + uint32 m_uiVileSludgeTimer; uint32 m_uiEnrageTimer; - bool m_bCorruptedForm; + uint8 m_uiMarkCount; + bool m_bCorruptedForm; - void Reset() + void Reset() override { - m_uiPosCheck_Timer = 2500; - m_uiMarkOfHydross_Timer = 15000; - m_uiMarkOfCorruption_Timer = 15000; - m_uiWaterTomb_Timer = 7000; - m_uiVileSludge_Timer = 7000; - m_uiMarkOfHydross_Count = 0; - m_uiMarkOfCorruption_Count = 0; - m_uiEnrageTimer = 600000; + m_uiBeamInitTimer = 5000; + m_uiElementalTimer = 20000; + m_uiPosCheckTimer = 2000; + m_uiMarkTimer = 15000; + m_uiWaterTombTimer = 7000; + m_uiVileSludgeTimer = 7000; + m_uiMarkCount = 0; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; - m_bCorruptedForm = false; + m_bCorruptedForm = false; m_creature->SetMeleeDamageSchool(SPELL_SCHOOL_FROST); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); - - m_creature->SetDisplayId(MODEL_CLEAN); - - if (m_pInstance) - m_pInstance->SetData(TYPE_HYDROSS_EVENT, NOT_STARTED); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -124,85 +110,147 @@ struct MANGOS_DLL_DECL boss_hydross_the_unstableAI : public ScriptedAI m_pInstance->SetData(TYPE_HYDROSS_EVENT, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (m_bCorruptedForm) - DoScriptText(urand(0,1) ? SAY_CORRUPT_SLAY1 : SAY_CORRUPT_SLAY2, m_creature); + DoScriptText(urand(0, 1) ? SAY_CORRUPT_SLAY1 : SAY_CORRUPT_SLAY2, m_creature); else - DoScriptText(urand(0,1) ? SAY_CLEAN_SLAY1 : SAY_CLEAN_SLAY2, m_creature); + DoScriptText(urand(0, 1) ? SAY_CLEAN_SLAY1 : SAY_CLEAN_SLAY2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustDied(Unit* /*pKiller*/) override { - if (pSummoned->GetEntry() == NPC_PURE_SPAWN) - pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); - else if (pSummoned->GetEntry() == NPC_TAINTED_SPAWN) - pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + DoScriptText(m_bCorruptedForm ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH, m_creature); - pSummoned->CastSpell(pSummoned, SPELL_ELEMENTAL_SPAWNIN, true); + if (m_pInstance) + m_pInstance->SetData(TYPE_HYDROSS_EVENT, DONE); } - void JustDied(Unit* pVictim) + void JustReachedHome() override { - DoScriptText(m_bCorruptedForm ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH, m_creature); - if (m_pInstance) - m_pInstance->SetData(TYPE_HYDROSS_EVENT, DONE); + m_pInstance->SetData(TYPE_HYDROSS_EVENT, FAIL); } - void SpawnAdds() + void JustSummoned(Creature* pSummoned) override { - for(uint8 i = 0; i < 4; ++i) - DoSpawnCreature(m_bCorruptedForm ? NPC_TAINTED_SPAWN : NPC_PURE_SPAWN, - afSpawnDiffs[i][0], afSpawnDiffs[i][1], 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); + switch (pSummoned->GetEntry()) + { + case NPC_PURE_SPAWN: + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); + break; + case NPC_TAINTED_SPAWN: + pSummoned->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + break; + case NPC_TAINTED_ELEMENTAL: + pSummoned->GetMotionMaster()->MovePoint(POINT_ID_ELEMENTAL_CLEAN, aElementalCleanPoint[0], aElementalCleanPoint[1], aElementalCleanPoint[2]); + break; + } + + // Attack only in combat + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void SummonedMovementInform(Creature* pSummoned, uint32 uiMotionType, uint32 uiPointId) override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (uiMotionType != POINT_MOTION_TYPE) return; - // corrupted form - if (m_bCorruptedForm) + if (uiPointId == POINT_ID_ELEMENTAL_CLEAN) { - //MarkOfCorruption_Timer - if (m_uiMarkOfCorruption_Timer < uiDiff) - { - if (m_uiMarkOfCorruption_Count <= 5) - { - uint32 uiMarkSpell = 0; + pSummoned->SetFacingToObject(m_creature); + DoCastSpellIfCan(pSummoned, SPELL_PURIFY_ELEMENTAL); + } + else if (uiPointId == POINT_ID_ELEMENTAL_EXIT) + pSummoned->ForcedDespawn(); + } - switch(m_uiMarkOfCorruption_Count) - { - case 0: uiMarkSpell = SPELL_MARK_OF_CORRUPTION1; break; - case 1: uiMarkSpell = SPELL_MARK_OF_CORRUPTION2; break; - case 2: uiMarkSpell = SPELL_MARK_OF_CORRUPTION3; break; - case 3: uiMarkSpell = SPELL_MARK_OF_CORRUPTION4; break; - case 4: uiMarkSpell = SPELL_MARK_OF_CORRUPTION5; break; - case 5: uiMarkSpell = SPELL_MARK_OF_CORRUPTION6; break; - } + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + // Purify elementals and make them go to exit + if (pSpell->Id == SPELL_PURIFY_ELEMENTAL) + { + ((Creature*)pTarget)->UpdateEntry(NPC_PURIFIED_ELEMENTAL); + pTarget->GetMotionMaster()->MovePoint(POINT_ID_ELEMENTAL_EXIT, aElementalExitPoint[0], aElementalExitPoint[1], aElementalExitPoint[2]); + } + } - DoCastSpellIfCan(m_creature->getVictim(), uiMarkSpell); + // Adds summon during phase switch + void DoSpawnAdds() + { + float fX, fY, fZ; + for (uint8 i = 0; i < MAX_HYDROSS_ADDS; ++i) + { + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 10, M_PI_F / 2 * i); + m_creature->SummonCreature(m_bCorruptedForm ? NPC_PURE_SPAWN : NPC_TAINTED_SPAWN, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } - if (m_uiMarkOfCorruption_Count < 5) - ++m_uiMarkOfCorruption_Count; - } + // Wrapper to handle the blue beams animation + void DoHandleBeamHelpers(bool bReset) + { + if (!m_pInstance) + return; - m_uiMarkOfCorruption_Timer = 15000; - }else m_uiMarkOfCorruption_Timer -= uiDiff; + GuidList lBeamHelpersGuid; + m_pInstance->GetBeamHelpersGUIDList(lBeamHelpersGuid); - //VileSludge_Timer - if (m_uiVileSludge_Timer < uiDiff) + for (GuidList::const_iterator itr = lBeamHelpersGuid.begin(); itr != lBeamHelpersGuid.end(); ++itr) + { + if (Creature* pBeam = m_creature->GetMap()->GetCreature(*itr)) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_VILE_SLUDGE); + if (bReset) + pBeam->InterruptNonMeleeSpells(false); + else + pBeam->CastSpell(m_creature, SPELL_BLUE_BEAM, false); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + { + // handle elementals on OOC timer + if (m_uiElementalTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_WATER_ELEMENT) == CAST_OK) + m_uiElementalTimer = 20000; + } + else + m_uiElementalTimer -= uiDiff; + + return; + } + + if (m_uiBeamInitTimer) + { + if (m_uiBeamInitTimer <= uiDiff) + { + DoHandleBeamHelpers(false); + m_uiBeamInitTimer = 0; + } + else + m_uiBeamInitTimer -= uiDiff; + } - m_uiVileSludge_Timer = 15000; - }else m_uiVileSludge_Timer -= uiDiff; + // corrupted form + if (m_bCorruptedForm) + { + if (m_uiVileSludgeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_VILE_SLUDGE) == CAST_OK) + m_uiVileSludgeTimer = 15000; + } + } + else + m_uiVileSludgeTimer -= uiDiff; - //PosCheck_Timer - if (m_uiPosCheck_Timer < uiDiff) + // Change to clean + if (m_uiPosCheckTimer < uiDiff) { float fPosX, fPosY, fPosZ; m_creature->GetCombatStartPosition(fPosX, fPosY, fPosZ); @@ -210,98 +258,98 @@ struct MANGOS_DLL_DECL boss_hydross_the_unstableAI : public ScriptedAI if (m_creature->IsWithinDist2d(fPosX, fPosY, SWITCH_RADIUS)) { DoScriptText(SAY_SWITCH_TO_CLEAN, m_creature); + m_creature->RemoveAurasDueToSpell(SPELL_CORRUPTION); + m_uiMarkCount = 0; - // switch to clean form - m_creature->SetDisplayId(MODEL_CLEAN); - m_uiMarkOfHydross_Count = 0; + DoHandleBeamHelpers(false); DoResetThreat(); - - // spawn 4 adds - SpawnAdds(); + DoSpawnAdds(); m_creature->SetMeleeDamageSchool(SPELL_SCHOOL_FROST); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); m_bCorruptedForm = false; + m_uiMarkTimer = 15000; } - m_uiPosCheck_Timer = 2500; - }else m_uiPosCheck_Timer -=uiDiff; + m_uiPosCheckTimer = 2000; + } + else + m_uiPosCheckTimer -= uiDiff; } // clean form else { - //MarkOfHydross_Timer - if (m_uiMarkOfHydross_Timer < uiDiff) + if (m_uiWaterTombTimer < uiDiff) { - if (m_uiMarkOfHydross_Count <= 5) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - uint32 uiMarkSpell = 0; - - switch(m_uiMarkOfHydross_Count) - { - case 0: uiMarkSpell = SPELL_MARK_OF_HYDROSS1; break; - case 1: uiMarkSpell = SPELL_MARK_OF_HYDROSS2; break; - case 2: uiMarkSpell = SPELL_MARK_OF_HYDROSS3; break; - case 3: uiMarkSpell = SPELL_MARK_OF_HYDROSS4; break; - case 4: uiMarkSpell = SPELL_MARK_OF_HYDROSS5; break; - case 5: uiMarkSpell = SPELL_MARK_OF_HYDROSS6; break; - } - - DoCastSpellIfCan(m_creature->getVictim(), uiMarkSpell); - - if (m_uiMarkOfHydross_Count < 5) - ++m_uiMarkOfHydross_Count; + if (DoCastSpellIfCan(pTarget, SPELL_WATER_TOMB) == CAST_OK) + m_uiWaterTombTimer = 7000; } + } + else + m_uiWaterTombTimer -= uiDiff; - m_uiMarkOfHydross_Timer = 15000; - }else m_uiMarkOfHydross_Timer -= uiDiff; - - //WaterTomb_Timer - if (m_uiWaterTomb_Timer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_WATER_TOMB); - - m_uiWaterTomb_Timer = 7000; - }else m_uiWaterTomb_Timer -= uiDiff; - - //PosCheck_Timer - if (m_uiPosCheck_Timer < uiDiff) + // Change to corrupt + if (m_uiPosCheckTimer < uiDiff) { float fPosX, fPosY, fPosZ; m_creature->GetCombatStartPosition(fPosX, fPosY, fPosZ); if (!m_creature->IsWithinDist2d(fPosX, fPosY, SWITCH_RADIUS)) { - DoScriptText(SAY_SWITCH_TO_CORRUPT, m_creature); - - // switch to corrupted form - m_creature->SetDisplayId(MODEL_CORRUPT); - m_uiMarkOfCorruption_Count = 0; - DoResetThreat(); + if (DoCastSpellIfCan(m_creature, SPELL_CORRUPTION) == CAST_OK) + { + DoScriptText(SAY_SWITCH_TO_CORRUPT, m_creature); + m_uiMarkCount = 0; - // spawn 4 adds - SpawnAdds(); + DoHandleBeamHelpers(true); + DoResetThreat(); + DoSpawnAdds(); - m_creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); - m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); + m_creature->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); - m_bCorruptedForm = true; + m_bCorruptedForm = true; + m_uiMarkTimer = 15000; + } } - m_uiPosCheck_Timer = 2500; - }else m_uiPosCheck_Timer -=uiDiff; + m_uiPosCheckTimer = 2000; + } + else + m_uiPosCheckTimer -= uiDiff; } - //EnrageTimer - if (m_uiEnrageTimer < uiDiff) + // Apply mark debuff + if (m_uiMarkTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - m_uiEnrageTimer = 60000; - }else m_uiEnrageTimer -= uiDiff; + if (DoCastSpellIfCan(m_creature, m_bCorruptedForm ? aMarkCorruption[m_uiMarkCount] : aMarkHydross[m_uiMarkCount]) == CAST_OK) + { + ++m_uiMarkCount; + m_uiMarkTimer = 15000; + + // limit the mark counter to 6 + if (m_uiMarkCount == MAX_HYDROSS_MARKS) + m_uiMarkCount = MAX_HYDROSS_MARKS - 1; + } + } + else + m_uiMarkTimer -= uiDiff; + + if (m_uiEnrageTimer) + { + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_ENRAGE) == CAST_OK) + m_uiEnrageTimer = 0; + } + else + m_uiEnrageTimer -= uiDiff; + } DoMeleeAttackIfReady(); } diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_lady_vashj.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_lady_vashj.cpp index 4e74b5e8a..703f066eb 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_lady_vashj.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_lady_vashj.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,18 +16,17 @@ /* ScriptData SDName: Boss_Lady_Vashj -SD%Complete: 60 -SDComment: Code cleanup needed. This script needs further adjustments. +SD%Complete: 80 +SDComment: Some details are not very clear: the usage of Shoot and Multishot spells; the summons positions. Tainted Core paralize NYI. Timers need improvements. SDCategory: Coilfang Resevoir, Serpent Shrine Cavern EndScriptData */ #include "precompiled.h" #include "serpent_shrine.h" -#include "Item.h" -#include "Spell.h" enum { + // yells SAY_INTRO = -1548042, SAY_AGGRO1 = -1548043, SAY_AGGRO2 = -1548044, @@ -43,43 +42,44 @@ enum SAY_SLAY3 = -1548054, SAY_DEATH = -1548055, - POINT_MOVE_CENTER = 0, - - PHASE_1 = 1, - PHASE_2 = 2, - PHASE_3 = 3, - - MAX_SHIELD_GEN = 4, - + // spells SPELL_MULTI_SHOT = 38310, SPELL_SHOCK_BLAST = 38509, SPELL_ENTANGLE = 38316, - SPELL_STATIC_CHARGE_TRIGGER = 38280, + SPELL_STATIC_CHARGE = 38280, SPELL_FORKED_LIGHTNING = 38145, SPELL_SHOOT = 38295, - SPELL_TOXIC_SPORES = 38575, SPELL_MAGIC_BARRIER = 38112, SPELL_SURGE = 38044, + SPELL_SUMMON_TAINTED_ELEM = 38139, // maybe also related to spell 38494 + SPELL_PARALIZE = 38132, // aura which should apply to the player which picked the tainted core - //tainted elemental - SPELL_POISON_BOLT = 38253, - SPELL_SUMMON_TAINTED = 38139, - + // summons NPC_ENCHANTED_ELEMENTAL = 21958, NPC_TAINTED_ELEMENTAL = 22009, NPC_COILFANG_STRIDER = 22056, NPC_COILFANG_ELITE = 22055, NPC_TOXIC_SPOREBAT = 22140, - NPC_SHIELD_GENERATOR = 19870 + // other + POINT_MOVE_CENTER = 1, + + PHASE_1 = 1, + PHASE_2 = 2, + PHASE_3 = 3, + + MAX_SHIELD_GEN = 4, }; -const float afMiddlePos[3] = {30.134f, -923.65f, 42.9f}; +static const float afMiddlePos[3] = {30.134f, -923.65f, 42.9f}; -const float afSporebatPos[4] = {30.977156f, -925.297761f, 77.176567f, 5.223932f}; +// ToDo: all the following mobs are probably summoned by trigger npcs. +// Remove the hardcoded coords and set the right summoning when then DB will suppot this! -const float afElementPos[8][4] = +static const float afSporebatPos[4] = {30.977156f, -925.297761f, 77.176567f, 5.223932f}; + +static const float afElementPos[8][4] = { {8.3f , -835.3f , 21.9f, 5.0f}, {53.4f , -835.3f , 21.9f, 4.5f}, @@ -87,8 +87,8 @@ const float afElementPos[8][4] = {96.0f , -986.4f , 21.4f, 2.5f}, {54.4f , -1010.6f, 22.0f, 1.8f}, {9.8f , -1012.0f, 21.7f, 1.4f}, - {-35.0f, -987.6f , 21.5f, 0.8f}, - {-58.9f, -901.6f , 21.5f, 6.0f} + { -35.0f, -987.6f , 21.5f, 0.8f}, + { -58.9f, -901.6f , 21.5f, 6.0f} }; const float afCoilfangElitePos[3][4] = @@ -102,92 +102,62 @@ const float afCoilfangStriderPos[3][4] = { {66.427f, -948.778f, 41.262245f, 2.584f}, {7.513f , -959.538f, 41.300422f, 1.0346f}, - {-12.843f, -907.798f, 41.239620f, 6.087f} -}; - -const float afShieldGeneratorChannelPos[4][4] = -{ - {49.626f, -902.181f, 41.54f, 3.956f}, - {10.988f, -901.616f, 41.54f, 5.437f}, - {10.385f, -944.036f, 41.54f, 0.779f}, - {49.312f, -943.398f, 41.54f, 2.401f} + { -12.843f, -907.798f, 41.239620f, 6.087f} }; -//Lady Vashj AI -struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI +struct boss_lady_vashjAI : public ScriptedAI { boss_lady_vashjAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_serpentshrine_cavern*)pCreature->GetInstanceData(); Reset(); } - ScriptedInstance *m_pInstance; // the instance - - ObjectGuid m_auiShieldGeneratorChannel[MAX_SHIELD_GEN]; - - // timers - uint32 m_uiShockBlast_Timer; - uint32 m_uiEntangle_Timer; - uint32 m_uiStaticCharge_Timer; - uint32 m_uiForkedLightning_Timer; - uint32 m_uiCheck_Timer; - uint32 m_uiEnchantedElemental_Timer; - uint32 m_uiTaintedElemental_Timer; - uint32 m_uiCoilfangElite_Timer; - uint32 m_uiCoilfangStrider_Timer; - uint32 m_uiSummonSporebat_Timer; - uint32 m_uiSummonSporebat_StaticTimer; - uint8 m_uiEnchantedElemental_Pos; - uint8 m_uiPhase; + instance_serpentshrine_cavern* m_pInstance; + + uint32 m_uiShockBlastTimer; + uint32 m_uiEntangleTimer; + uint32 m_uiStaticChargeTimer; + uint32 m_uiRangedCheckTimer; + uint32 m_uiForkedLightningTimer; + uint32 m_uiEnchantedElementalTimer; + uint32 m_uiTaintedElementalTimer; + uint32 m_uiCoilfangEliteTimer; + uint32 m_uiCoilfangStriderTimer; + uint32 m_uiSummonSporebatTimer; + uint32 m_uiSummonSporebatStaticTimer; + + uint8 m_uiPhase; + uint8 m_uiGeneratorsUsed; bool m_bEntangle; - void Reset() + void Reset() override { SetCombatMovement(true); - m_uiShockBlast_Timer = urand(1000, 60000); - m_uiEntangle_Timer = 30000; - m_uiStaticCharge_Timer = urand(10000, 25000); - m_uiCheck_Timer = 1000; - - m_uiForkedLightning_Timer = urand(43000, 49000); - m_uiEnchantedElemental_Timer = 10000; - m_uiTaintedElemental_Timer = 50000; - m_uiCoilfangElite_Timer = 45000; - m_uiCoilfangStrider_Timer = 60000; + m_uiPhase = PHASE_1; + m_uiGeneratorsUsed = 0; - m_uiSummonSporebat_Timer = 10000; - m_uiSummonSporebat_StaticTimer = 30000; - m_uiEnchantedElemental_Pos = 0; - m_uiPhase = PHASE_1; + m_uiShockBlastTimer = urand(1000, 60000); + m_uiEntangleTimer = 30000; + m_uiStaticChargeTimer = urand(10000, 25000); + m_uiRangedCheckTimer = 2000; + m_bEntangle = false; - m_bEntangle = false; + m_uiForkedLightningTimer = urand(3000, 5000); + m_uiEnchantedElementalTimer = 10000; + m_uiTaintedElementalTimer = 53000; + m_uiCoilfangEliteTimer = 47000; + m_uiCoilfangStriderTimer = 60000; - RemoveAllShieldGenerators(); - - if (m_pInstance) - m_pInstance->SetData(TYPE_LADYVASHJ_EVENT, NOT_STARTED); + m_uiSummonSporebatTimer = 10000; + m_uiSummonSporebatStaticTimer = 30000; } - void RemoveAllShieldGenerators() + void Aggro(Unit* /*pWho*/) override { - for(uint8 i = 0; i < MAX_SHIELD_GEN; ++i) - { - if (Creature* pTemp = m_creature->GetMap()->GetCreature(m_auiShieldGeneratorChannel[i])) - { - if (pTemp->isAlive()) - pTemp->SetDeathState(JUST_DIED); - - m_auiShieldGeneratorChannel[i].Clear(); - } - } - } - - void Aggro(Unit* pWho) - { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -199,59 +169,66 @@ struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI m_pInstance->SetData(TYPE_LADYVASHJ_EVENT, IN_PROGRESS); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; if (uiPointId == POINT_MOVE_CENTER) { - m_creature->RemoveAllAuras(); - - for(uint8 i = 0; i < MAX_SHIELD_GEN; ++i) + // Initialize all the shield generators + if (m_pInstance) { - if (Creature* pCreature = m_creature->SummonCreature(NPC_SHIELD_GENERATOR, afShieldGeneratorChannelPos[i][0], afShieldGeneratorChannelPos[i][1], afShieldGeneratorChannelPos[i][2], afShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN, 0)) - m_auiShieldGeneratorChannel[i] = pCreature->GetObjectGuid(); + GuidList lShieldGeneratorsGuid; + m_pInstance->GetShieldGeneratorsGUIDList(lShieldGeneratorsGuid); + + for (GuidList::const_iterator itr = lShieldGeneratorsGuid.begin(); itr != lShieldGeneratorsGuid.end(); ++itr) + { + if (Creature* pGenerator = m_creature->GetMap()->GetCreature(*itr)) + pGenerator->CastSpell(m_creature, SPELL_MAGIC_BARRIER, false); + } } + + m_uiPhase = PHASE_2; } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - uint32 uiEntry = pSummoned->GetEntry(); - - if (uiEntry == NPC_COILFANG_STRIDER || uiEntry == NPC_COILFANG_ELITE || uiEntry == NPC_TOXIC_SPOREBAT) + switch (pSummoned->GetEntry()) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); + case NPC_COILFANG_STRIDER: + case NPC_COILFANG_ELITE: + case NPC_TOXIC_SPOREBAT: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + break; + case NPC_ENCHANTED_ELEMENTAL: + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + break; } + } - if (uiEntry == NPC_SHIELD_GENERATOR) - { - //we should really expect database to have this set already - if (!pSummoned->HasFlag(UNIT_FIELD_FLAGS, (UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))) - { - pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - - pSummoned->CastSpell(m_creature,SPELL_MAGIC_BARRIER,true); - } + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // Set the timer when summoned killed + if (pSummoned->GetEntry() == NPC_TAINTED_ELEMENTAL) + m_uiTaintedElementalTimer = 50000; } - //called when any summoned (by m_creature) despawns - void SummonedCreatureDespawn(Creature* pDespawned) + void SummonedCreatureDespawn(Creature* pSummoned) override { - if (pDespawned->GetEntry() == NPC_TAINTED_ELEMENTAL) + // Set the timer when summoned despawned, if not already killed + if (pSummoned->GetEntry() == NPC_TAINTED_ELEMENTAL) { - if (m_uiTaintedElemental_Timer > 50000) - m_uiTaintedElemental_Timer = 50000; + if (!m_uiTaintedElementalTimer) + m_uiTaintedElementalTimer = 50000; } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -259,7 +236,7 @@ struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI } } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -267,431 +244,247 @@ struct MANGOS_DLL_DECL boss_lady_vashjAI : public ScriptedAI m_pInstance->SetData(TYPE_LADYVASHJ_EVENT, DONE); } - void CastShootOrMultishot() + void JustReachedHome() override { - //Shoot: Used in m_uiPhases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits her target for 4097-5543 Physical damage. - //Multishot: Used in m_uiPhases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits 1 person and 4 people around him for 6475-7525 physical damage. - DoCastSpellIfCan(m_creature->getVictim(), urand(0,1) ? SPELL_SHOOT : SPELL_MULTI_SHOT); + if (m_pInstance) + m_pInstance->SetData(TYPE_LADYVASHJ_EVENT, FAIL); + } - if (urand(0, 2)) - DoScriptText(urand(0,1) ? SAY_BOWSHOT1 : SAY_BOWSHOT2, m_creature); + bool CanCastShootOrMultishot() + { + // It's not very clear how this should work - requires additional research! + if (DoCastSpellIfCan(m_creature->getVictim(), urand(0, 1) ? SPELL_SHOOT : SPELL_MULTI_SHOT) == CAST_OK) + { + if (urand(0, 2)) + DoScriptText(urand(0, 1) ? SAY_BOWSHOT1 : SAY_BOWSHOT2, m_creature); + + return true; + } + + return false; } - void UpdateAI(const uint32 uiDiff) + // Wrapper to inform the boss that a generator has been deactivated + void DoInformGeneratorStopped() + { + ++m_uiGeneratorsUsed; + + // Remove 5% of health on each generator used + // ToDo: research if this should be done by spell + m_creature->SetHealth(m_creature->GetHealth() - m_creature->GetMaxHealth()*.05f); + + // Check if all generators have been deactivated, or the creature doesn't have the spell barrier aura (in order to avoid eventual aura stacking bugs) + if (m_uiGeneratorsUsed == MAX_SHIELD_GEN || !m_creature->HasAura(SPELL_MAGIC_BARRIER)) + { + DoScriptText(SAY_PHASE3, m_creature); + SetCombatMovement(true); + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + m_uiPhase = PHASE_3; + m_uiRangedCheckTimer = 3000; + } + } + + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiPhase == PHASE_1 || m_uiPhase == PHASE_3) { - //m_uiShockBlast_Timer - if (m_uiShockBlast_Timer < uiDiff) + if (m_uiShockBlastTimer < uiDiff) { - //Randomly used in m_uiPhases 1 and 3 on Vashj's target, it's a Shock spell doing 8325-9675 nature damage and stunning the target for 5 seconds, during which she will not attack her target but switch to the next person on the aggro list. - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCK_BLAST); - - m_uiShockBlast_Timer = urand(1000, 15000); //random cooldown - }else m_uiShockBlast_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCK_BLAST) == CAST_OK) + m_uiShockBlastTimer = urand(1000, 15000); + } + else + m_uiShockBlastTimer -= uiDiff; - //m_uiStaticCharge_Timer - if (m_uiStaticCharge_Timer < uiDiff) + if (m_uiStaticChargeTimer < uiDiff) { - //Used on random people (only 1 person at any given time) in m_uiPhases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of Shadows, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. - Unit *pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - //cast Static Charge every 2 seconds for 20 seconds - if (pTarget && !pTarget->HasAura(SPELL_STATIC_CHARGE_TRIGGER)) - DoCastSpellIfCan(pTarget, SPELL_STATIC_CHARGE_TRIGGER); - - m_uiStaticCharge_Timer = urand(10000, 30000); - }else m_uiStaticCharge_Timer -= uiDiff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_STATIC_CHARGE, SELECT_FLAG_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(pTarget, SPELL_STATIC_CHARGE) == CAST_OK) + m_uiStaticChargeTimer = urand(10000, 30000); + } + } + else + m_uiStaticChargeTimer -= uiDiff; - //m_uiEntangle_Timer - if (m_uiEntangle_Timer < uiDiff) + if (m_uiEntangleTimer < uiDiff) { if (!m_bEntangle) { - //Used in m_uiPhases 1 and 3, it casts Entangling Roots on everybody in a 15 yard radius of Vashj, immobilzing them for 10 seconds and dealing 500 damage every 2 seconds. It's not a magic effect so it cannot be dispelled, but is removed by various buffs such as Cloak of Shadows or Blessing of Freedom. - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENTANGLE); - m_bEntangle = true; - m_uiEntangle_Timer = 10000; + if (DoCastSpellIfCan(m_creature, SPELL_ENTANGLE) == CAST_OK) + { + m_bEntangle = true; + m_uiEntangleTimer = 5000; + } } else { - CastShootOrMultishot(); - m_bEntangle = false; - m_uiEntangle_Timer = urand(20000, 25000); + // Cast Shoot or Multishot after Entangle + if (CanCastShootOrMultishot()) + { + m_bEntangle = false; + m_uiEntangleTimer = urand(20000, 25000); + } } - }else m_uiEntangle_Timer -= uiDiff; + } + else + m_uiEntangleTimer -= uiDiff; - //m_uiPhase 1 + // Phase 1 abilities if (m_uiPhase == PHASE_1) { - //m_uiPhase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. + // m_uiPhase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. if (m_creature->GetHealthPercent() <= 70.0f) { DoScriptText(SAY_PHASE2, m_creature); - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) - { - //set false, so MoveChase is not triggered in AttackStart - SetCombatMovement(false); + SetCombatMovement(false); - m_creature->GetMotionMaster()->MovementExpired(); - m_creature->GetMotionMaster()->MovePoint(POINT_MOVE_CENTER, afMiddlePos[0], afMiddlePos[1], afMiddlePos[2]); - } + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_MOVE_CENTER, afMiddlePos[0], afMiddlePos[1], afMiddlePos[2]); m_uiPhase = PHASE_2; - return; + m_uiRangedCheckTimer = 10000; } } - //m_uiPhase PHASE_3 + // Phase 3 abilities else { - //m_uiSummonSporebat_Timer - if (m_uiSummonSporebat_Timer < uiDiff) + // ToDo: this is not very clear how it should work - requires additional research! + if (m_uiSummonSporebatTimer < uiDiff) { - m_creature->SummonCreature(NPC_TOXIC_SPOREBAT, - afSporebatPos[0], afSporebatPos[1], afSporebatPos[2], afSporebatPos[3], - TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + m_creature->SummonCreature(NPC_TOXIC_SPOREBAT, afSporebatPos[0], afSporebatPos[1], afSporebatPos[2], afSporebatPos[3], TEMPSUMMON_DEAD_DESPAWN, 0); - //summon sporebats faster and faster - if (m_uiSummonSporebat_StaticTimer > 1000) - m_uiSummonSporebat_StaticTimer -= 1000; + // summon sporebats faster and faster + if (m_uiSummonSporebatStaticTimer > 1000) + m_uiSummonSporebatStaticTimer -= 1000; - m_uiSummonSporebat_Timer = m_uiSummonSporebat_StaticTimer; - }else m_uiSummonSporebat_Timer -= uiDiff; + m_uiSummonSporebatTimer = m_uiSummonSporebatStaticTimer; + } + else + m_uiSummonSporebatTimer -= uiDiff; } - //Melee attack - DoMeleeAttackIfReady(); - - //m_uiCheck_Timer - used to check if somebody is in melee range - if (m_uiCheck_Timer < uiDiff) + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + else { - //if nobody is in melee range - if (!m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) - CastShootOrMultishot(); - - m_uiCheck_Timer = 1500; - }else m_uiCheck_Timer -= uiDiff; + // Cast Shoot or Multishot when nobody in melee range + if (m_uiRangedCheckTimer < uiDiff) + { + if (CanCastShootOrMultishot()) + m_uiRangedCheckTimer = urand(1000, 2000); + } + else + m_uiRangedCheckTimer -= uiDiff; + } } - //m_uiPhase PHASE_2 + // Phase 2 only else { - //m_uiForkedLightning_Timer - if (m_uiForkedLightning_Timer < uiDiff) - { - //Used constantly in m_uiPhase 2, it shoots out completely randomly targeted bolts of lightning which hit everybody in a roughtly 60 degree cone in front of Vashj for 2313-2687 nature damage. - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (!pTarget) - pTarget = m_creature->getVictim(); - - DoCastSpellIfCan(pTarget, SPELL_FORKED_LIGHTNING); - - m_uiForkedLightning_Timer = urand(3000, 9000); - }else m_uiForkedLightning_Timer -= uiDiff; - - //NPC_ENCHANTED_ELEMENTAL - if (m_uiEnchantedElemental_Timer < uiDiff) + if (m_uiForkedLightningTimer < uiDiff) { - if (Creature* pElemental = m_creature->SummonCreature(NPC_ENCHANTED_ELEMENTAL, afElementPos[m_uiEnchantedElemental_Pos][0], afElementPos[m_uiEnchantedElemental_Pos][1], afElementPos[m_uiEnchantedElemental_Pos][2], afElementPos[m_uiEnchantedElemental_Pos][3], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000)) - pElemental->GetMotionMaster()->MoveFollow(m_creature, 0.0f, 0.0f); - - if (m_uiEnchantedElemental_Pos == 7) - m_uiEnchantedElemental_Pos = 0; - else - ++m_uiEnchantedElemental_Pos; - - m_uiEnchantedElemental_Timer = urand(10000, 15000); - }else m_uiEnchantedElemental_Timer -= uiDiff; - - //NPC_TAINTED_ELEMENTAL - if (m_uiTaintedElemental_Timer < uiDiff) - { - uint32 uiPos = urand(0,7); - - m_creature->SummonCreature(NPC_TAINTED_ELEMENTAL, - afElementPos[uiPos][0], afElementPos[uiPos][1], afElementPos[uiPos][2], afElementPos[uiPos][3], - TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 15000); - - m_uiTaintedElemental_Timer = 120000; - }else m_uiTaintedElemental_Timer -= uiDiff; - - //NPC_COILFANG_ELITE - if (m_uiCoilfangElite_Timer < uiDiff) - { - uint32 uiPos = urand(0,2); - - m_creature->SummonCreature(NPC_COILFANG_ELITE, - afCoilfangElitePos[uiPos][0], afCoilfangElitePos[uiPos][1], afCoilfangElitePos[uiPos][2], afCoilfangElitePos[uiPos][3], - TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 45000); - - //wowwiki says 50 seconds, bosskillers says 45 - m_uiCoilfangElite_Timer = urand(45000, 50000); - }else m_uiCoilfangElite_Timer -= uiDiff; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FORKED_LIGHTNING) == CAST_OK) + m_uiForkedLightningTimer = urand(3000, 6000); + } + } + else + m_uiForkedLightningTimer -= uiDiff; - //NPC_COILFANG_STRIDER - if (m_uiCoilfangStrider_Timer < uiDiff) + if (m_uiEnchantedElementalTimer < uiDiff) { - uint32 uiPos = urand(0,2); - - m_creature->SummonCreature(NPC_COILFANG_STRIDER, - afCoilfangStriderPos[uiPos][0], afCoilfangStriderPos[uiPos][1], afCoilfangStriderPos[uiPos][2], afCoilfangStriderPos[uiPos][3], - TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + uint8 uiPos = urand(0, 7); + m_creature->SummonCreature(NPC_ENCHANTED_ELEMENTAL, afElementPos[uiPos][0], afElementPos[uiPos][1], afElementPos[uiPos][2], afElementPos[uiPos][3], TEMPSUMMON_DEAD_DESPAWN, 0); - //wowwiki says 60 seconds, bosskillers says 60-70 - m_uiCoilfangStrider_Timer = urand(60000, 70000); - }else m_uiCoilfangStrider_Timer -= uiDiff; + m_uiEnchantedElementalTimer = urand(5000, 10000); + } + else + m_uiEnchantedElementalTimer -= uiDiff; - //m_uiCheck_Timer - if (m_uiCheck_Timer < uiDiff) + if (m_uiTaintedElementalTimer) { - //Start m_uiPhase 3 - if (m_pInstance && m_pInstance->GetData(TYPE_VASHJ_PHASE3_CHECK) == DONE) + if (m_uiTaintedElementalTimer <= uiDiff) { - DoScriptText(SAY_PHASE3, m_creature); - - //set life 50%, not correct. Must remove 5% for each generator switched off - m_creature->SetHealth(m_creature->GetMaxHealth()/2); - - //m_creature->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); - - SetCombatMovement(true); + uint8 uiPos = urand(0, 7); - //return to chase top aggro - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - - m_uiPhase = PHASE_3; + m_creature->SummonCreature(NPC_TAINTED_ELEMENTAL, afElementPos[uiPos][0], afElementPos[uiPos][1], afElementPos[uiPos][2], afElementPos[uiPos][3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiTaintedElementalTimer = 0; } - m_uiCheck_Timer = 1000; - }else m_uiCheck_Timer -= uiDiff; - } - } -}; - -//Enchanted Elemental -//If one of them reaches Vashj he will increase her damage done by 5%. -struct MANGOS_DLL_DECL mob_enchanted_elementalAI : public ScriptedAI -{ - mob_enchanted_elementalAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - SetCombatMovement(false); - Reset(); - } + else + m_uiTaintedElementalTimer -= uiDiff; + } - ScriptedInstance *m_pInstance; // the instance + if (m_uiCoilfangEliteTimer < uiDiff) + { + uint8 uiPos = urand(0, 2); - void Reset() { } + m_creature->SummonCreature(NPC_COILFANG_ELITE, afCoilfangElitePos[uiPos][0], afCoilfangElitePos[uiPos][1], afCoilfangElitePos[uiPos][2], afCoilfangElitePos[uiPos][3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiCoilfangEliteTimer = urand(45000, 50000); + } + else + m_uiCoilfangEliteTimer -= uiDiff; - void MoveInLineOfSight(Unit* pWho) - { - if (m_pInstance) - { - if (Creature* pVashj = m_pInstance->GetSingleCreatureFromStorage(NPC_LADYVASHJ)) + if (m_uiCoilfangStriderTimer < uiDiff) { - if (pVashj->IsWithinDistInMap(m_creature, INTERACTION_DISTANCE)) - { - //increase lady vashj damage - if (pVashj->isAlive() && pVashj->isInCombat()) - m_creature->CastSpell(pVashj, SPELL_SURGE, false, NULL, NULL, pVashj->GetObjectGuid()); - else - m_creature->SetDeathState(JUST_DIED); - } + uint8 uiPos = urand(0, 2); + + m_creature->SummonCreature(NPC_COILFANG_STRIDER, afCoilfangStriderPos[uiPos][0], afCoilfangStriderPos[uiPos][1], afCoilfangStriderPos[uiPos][2], afCoilfangStriderPos[uiPos][3], TEMPSUMMON_DEAD_DESPAWN, 0); + m_uiCoilfangStriderTimer = urand(60000, 70000); } + else + m_uiCoilfangStriderTimer -= uiDiff; } } - - void UpdateAI(const uint32 uiDiff) { } }; -//Tainted Elemental -//This mob has 7,900 life, doesn't move, and shoots Poison Bolts at one person anywhere in the area, doing 3,000 nature damage and placing a posion doing 2,000 damage every 2 seconds. He will switch targets often, or sometimes just hang on a single player, but there is nothing you can do about it except heal the damage and kill the Tainted Elemental -struct MANGOS_DLL_DECL mob_tainted_elementalAI : public ScriptedAI +struct mob_enchanted_elementalAI : public ScriptedAI { - mob_tainted_elementalAI(Creature* pCreature) : ScriptedAI(pCreature) + mob_enchanted_elementalAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); SetCombatMovement(false); Reset(); } - ScriptedInstance* m_pInstance; // the instance - - // timers - uint32 m_uiPoisonBolt_Timer; + void Reset() override { } - void Reset() + void MoveInLineOfSight(Unit* pWho) override { - m_uiPoisonBolt_Timer = urand(5000, 10000); + // Buff Lady Vashj on range check - spell has script target + if (pWho->GetEntry() == NPC_LADYVASHJ && pWho->IsWithinDistInMap(m_creature, INTERACTION_DISTANCE) && pWho->IsWithinLOSInMap(m_creature)) + DoCastSpellIfCan(m_creature, SPELL_SURGE, CAST_TRIGGERED); } - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //m_uiPoisonBolt_Timer - if (m_uiPoisonBolt_Timer < uiDiff) - { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - if (pTarget && pTarget->IsWithinDistInMap(m_creature, 30.0f)) - DoCastSpellIfCan(pTarget, SPELL_POISON_BOLT); - - m_uiPoisonBolt_Timer = urand(5000, 10000); - }else m_uiPoisonBolt_Timer -= uiDiff; - } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } }; -//Toxic Sporebat -//Toxic Spores: Used in m_uiPhase 3 by the Spore Bats, it creates a contaminated green patch of ground, dealing about 2775-3225 nature damage every second to anyone who stands in it. -struct MANGOS_DLL_DECL mob_toxic_sporebatAI : public ScriptedAI +bool GOUse_go_shield_generator(Player* /*pPlayer*/, GameObject* pGo) { - mob_toxic_sporebatAI(Creature* pCreature) : ScriptedAI(pCreature) + // Interrupt Magic barrier spell casting, inform the boss and make the GO unusable + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; - - uint32 m_uiToxicSpore_Timer; - uint32 m_uiCheck_Timer; + if (Creature* pGenerator = GetClosestCreatureWithEntry(pGo, NPC_SHIELD_GENERATOR, 5.0f)) + pGenerator->InterruptNonMeleeSpells(false); - void Reset() - { - m_creature->setFaction(14); - m_uiToxicSpore_Timer = 5000; - m_uiCheck_Timer = 1000; - } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //m_uiToxicSpore_Timer - if (m_uiToxicSpore_Timer < uiDiff) + if (Creature* pVashj = pInstance->GetSingleCreatureFromStorage(NPC_LADYVASHJ)) { - //The Spores will hit you anywhere in the instance: underwater, at the elevator, at the entrance, wherever. - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_TOXIC_SPORES); - - m_uiToxicSpore_Timer = urand(20000, 25000); - }else m_uiToxicSpore_Timer -= uiDiff; - - //m_uiCheck_Timer - if (m_uiCheck_Timer < uiDiff) - { - if (m_pInstance) - { - //check if vashj is death - Creature* pVashj = m_pInstance->GetSingleCreatureFromStorage(NPC_LADYVASHJ); - if (!pVashj || !pVashj->isAlive()) - { - //remove - m_creature->SetDeathState(DEAD); - m_creature->RemoveCorpse(); - m_creature->setFaction(35); - } - } - - m_uiCheck_Timer = 1000; - }else m_uiCheck_Timer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -enum -{ - SPELL_CLEAVE = 31345, - SPELL_MIND_BLAST = 41374 -}; - -//can probably be removed -struct MANGOS_DLL_DECL mob_shield_generator_channelAI : public ScriptedAI -{ - mob_shield_generator_channelAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; // the instance - - void Reset() { } - - void MoveInLineOfSight(Unit* pWho) { } -}; - -//this is wrong, alternative script needed -bool ItemUse_item_tainted_core(Player* pPlayer, Item* pItem, SpellCastTargets const& sctTargets) -{ - ScriptedInstance* pInstance = (ScriptedInstance*)pPlayer->GetInstanceData(); + if (boss_lady_vashjAI* pLadyAI = dynamic_cast(pVashj->AI())) + pLadyAI->DoInformGeneratorStopped(); + } - if (!pInstance) - { - error_log("SD2: Lady Vashj Tainted Core: Instance Script Not Initialized"); - return true; + pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); } - Creature* pVashj = pInstance->GetSingleCreatureFromStorage(NPC_LADYVASHJ); - - if (!pVashj) - return true; - - boss_lady_vashjAI* pVashjAI = dynamic_cast(pVashj->AI()); - - if (pVashjAI && pVashjAI->m_uiPhase == 2) - { - if (sctTargets.getGOTarget() && sctTargets.getGOTarget()->GetTypeId()==TYPEID_GAMEOBJECT) - { - uint32 uiIdentifier; - uint8 uiChannelIdentifier; - switch(sctTargets.getGOTarget()->GetEntry()) - { - case 185052: - uiIdentifier = TYPE_SHIELDGENERATOR1; - uiChannelIdentifier = 0; - break; - case 185053: - uiIdentifier = TYPE_SHIELDGENERATOR2; - uiChannelIdentifier = 1; - break; - case 185051: - uiIdentifier = TYPE_SHIELDGENERATOR3; - uiChannelIdentifier = 2; - break; - case 185054: - uiIdentifier = TYPE_SHIELDGENERATOR4; - uiChannelIdentifier = 3; - break; - default: - return true; - break; - } - - if (pInstance->GetData(uiIdentifier) == DONE) - return true; - - //get and remove channel - if (Creature* pChannel = pVashj->GetMap()->GetCreature(pVashjAI->m_auiShieldGeneratorChannel[uiChannelIdentifier])) - pChannel->SetDeathState(JUST_DIED); //calls Unsummon() - - pInstance->SetData(uiIdentifier, DONE); - - //remove this item - pPlayer->DestroyItemCount(31088, 1, true); - } - } - return true; + return false; } CreatureAI* GetAI_boss_lady_vashj(Creature* pCreature) @@ -704,21 +497,6 @@ CreatureAI* GetAI_mob_enchanted_elemental(Creature* pCreature) return new mob_enchanted_elementalAI(pCreature); } -CreatureAI* GetAI_mob_tainted_elemental(Creature* pCreature) -{ - return new mob_tainted_elementalAI(pCreature); -} - -CreatureAI* GetAI_mob_toxic_sporebat(Creature* pCreature) -{ - return new mob_toxic_sporebatAI(pCreature); -} - -CreatureAI* GetAI_mob_shield_generator_channel(Creature* pCreature) -{ - return new mob_shield_generator_channelAI(pCreature); -} - void AddSC_boss_lady_vashj() { Script* pNewScript; @@ -734,22 +512,7 @@ void AddSC_boss_lady_vashj() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "mob_tainted_elemental"; - pNewScript->GetAI = &GetAI_mob_tainted_elemental; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_toxic_sporebat"; - pNewScript->GetAI = &GetAI_mob_toxic_sporebat; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_shield_generator_channel"; - pNewScript->GetAI = &GetAI_mob_shield_generator_channel; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "item_tainted_core"; - pNewScript->pItemUse = &ItemUse_item_tainted_core; + pNewScript->Name = "go_shield_generator"; + pNewScript->pGOUse = &GOUse_go_shield_generator; pNewScript->RegisterSelf(); } diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_leotheras_the_blind.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_leotheras_the_blind.cpp index e386b67f2..62ca4603c 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_leotheras_the_blind.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_leotheras_the_blind.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Leotheras_The_Blind -SD%Complete: 50 -SDComment: Missing Inner Demons +SD%Complete: 70 +SDComment: Inner Demons NYI; Transition to final phase needs more work. SDCategory: Coilfang Resevoir, Serpent Shrine Cavern EndScriptData */ @@ -39,31 +39,30 @@ enum SAY_FREE = -1548019, SAY_DEATH = -1548020, - SPELL_ENRAGE = 26662, - + SPELL_BERSERK = 27680, SPELL_WHIRLWIND = 37640, - SPELL_CHAOS_BLAST = 37674, - SPELL_INSIDIOUS_WHISPER = 37676, //not implemented yet. After cast (spellHit), do the inner demon - SPELL_CONS_MADNESS = 37749, - - SPELL_DEMON_ALIGNMENT = 37713, //inner demon have this aura - SPELL_SHADOW_BOLT = 39309, //inner demon spell spam - - FACTION_DEMON_1 = 1829, - FACTION_DEMON_2 = 1830, - FACTION_DEMON_3 = 1831, - FACTION_DEMON_4 = 1832, - FACTION_DEMON_5 = 1833, - - MODEL_NIGHTELF = 20514, - MODEL_DEMON = 20125, + SPELL_CHAOS_BLAST = 37674, // triggers 37675 + SPELL_INSIDIOUS_WHISPER = 37676, + SPELL_WHISPER_CLEAR = 37922, // purpose unk - probably clear the demons on evade + SPELL_CONS_MADNESS = 37749, // charm spell for the players which didn't kill the inner demons during the demon phase + SPELL_METAMORPHOSIS = 37673, // demon transform spell + + // Inner demons already scripted in eventAI + // SPELL_DEMON_ALIGNMENT = 37713, + // SPELL_SHADOW_BOLT = 39309, + // SPELL_DEMON_LINK = 37716, + + // FACTION_DEMON_1 = 1829, + // FACTION_DEMON_2 = 1830, + // FACTION_DEMON_3 = 1831, + // FACTION_DEMON_4 = 1832, + // FACTION_DEMON_5 = 1833, NPC_INNER_DEMON = 21857, NPC_SHADOW_LEO = 21875 }; -//Original Leotheras the Blind AI -struct MANGOS_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI +struct boss_leotheras_the_blindAI : public ScriptedAI { boss_leotheras_the_blindAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -71,50 +70,68 @@ struct MANGOS_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI Reset(); } - ScriptedInstance* m_pInstance; // the instance + ScriptedInstance* m_pInstance; - // timers - uint32 m_uiWhirlwind_Timer; - uint32 m_uiInnerDemon_Timer; - uint32 m_uiSwitch_Timer; - uint32 m_uiEnrage_Timer; + uint32 m_uiBanishTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiInnerDemonTimer; + uint32 m_uiSwitchTimer; + uint32 m_uiChaosBlastTimer; + uint32 m_uiFinalFormTimer; + uint32 m_uiEnrageTimer; bool m_bDemonForm; bool m_bIsFinalForm; - ObjectGuid m_shadowLeoGuid; + void Reset() override + { + m_uiBanishTimer = 10000; + m_uiWhirlwindTimer = 18500; + m_uiInnerDemonTimer = 27500; + m_uiSwitchTimer = 60000; + m_uiChaosBlastTimer = 0; + m_uiFinalFormTimer = 0; + m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + + m_bDemonForm = false; + m_bIsFinalForm = false; + + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetCombatMovement(true); + } - void Reset() + void Aggro(Unit* /*pWho*/) override { - m_uiWhirlwind_Timer = 18500; - m_uiInnerDemon_Timer = 15000; - m_uiSwitch_Timer = 45000; - m_uiEnrage_Timer = MINUTE*10*IN_MILLISECONDS; + DoScriptText(SAY_AGGRO, m_creature); - m_bDemonForm = false; - m_bIsFinalForm = false; + if (m_pInstance) + m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, IN_PROGRESS); + } - if (m_creature->GetDisplayId() != MODEL_NIGHTELF) - m_creature->SetDisplayId(MODEL_NIGHTELF); + void AttackStart(Unit* pWho) override + { + // Don't attack while banished + if (m_creature->HasAura(SPELL_LEOTHERAS_BANISH)) + return; - if (m_pInstance) - m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, NOT_STARTED); + ScriptedAI::AttackStart(pWho); } - void Aggro(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { - DoScriptText(SAY_AGGRO, m_creature); + // Don't attack while banished + if (m_creature->HasAura(SPELL_LEOTHERAS_BANISH)) + return; - if (m_pInstance) - m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, IN_PROGRESS); + ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_PLAYER) return; - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(m_bDemonForm ? SAY_DEMON_SLAY1 : SAY_NIGHTELF_SLAY1, m_creature); break; case 1: DoScriptText(m_bDemonForm ? SAY_DEMON_SLAY2 : SAY_NIGHTELF_SLAY2, m_creature); break; @@ -122,197 +139,188 @@ struct MANGOS_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - if (m_creature->getVictim() && pSummoned->GetEntry() == NPC_SHADOW_LEO) + if (pSummoned->GetEntry() == NPC_SHADOW_LEO) { - m_shadowLeoGuid = pSummoned->GetObjectGuid(); pSummoned->AI()->AttackStart(m_creature->getVictim()); + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); } } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - //despawn copy - if (m_shadowLeoGuid) - { - if (Creature* pShadowLeo = m_creature->GetMap()->GetCreature(m_shadowLeoGuid)) - pShadowLeo->ForcedDespawn(); - } - if (m_pInstance) m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override { - //Return since we have no target + if (m_pInstance) + m_pInstance->SetData(TYPE_LEOTHERAS_EVENT, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Banish the boss before combat + if (m_uiBanishTimer) + { + if (m_uiBanishTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_LEOTHERAS_BANISH) == CAST_OK) + m_uiBanishTimer = 0; + } + else + m_uiBanishTimer -= uiDiff; + } + + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; + if (m_uiFinalFormTimer) + { + if (m_uiFinalFormTimer <= uiDiff) + { + DoSpawnCreature(NPC_SHADOW_LEO, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); + m_uiFinalFormTimer = 0; + } + else + m_uiFinalFormTimer -= uiDiff; + + // Wait until we finish the transition + return; + } + + // Human form spells if (!m_bDemonForm) { - //Whirlwind_Timer - if (m_uiWhirlwind_Timer < uiDiff) + if (m_uiWhirlwindTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlwind_Timer = 30000; - }else m_uiWhirlwind_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = 32000; + } + else + m_uiWhirlwindTimer -= uiDiff; - //Switch_Timer if (!m_bIsFinalForm) { - if (m_uiSwitch_Timer < uiDiff) + if (m_uiSwitchTimer < uiDiff) { - DoScriptText(SAY_SWITCH_TO_DEMON, m_creature); - - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) + if (DoCastSpellIfCan(m_creature, SPELL_METAMORPHOSIS) == CAST_OK) { - //set false, so MoveChase is not triggered in AttackStart - SetCombatMovement(false); + DoScriptText(SAY_SWITCH_TO_DEMON, m_creature); - m_creature->GetMotionMaster()->Clear(false); + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); - m_creature->StopMoving(); - } - //switch to demon form - m_creature->SetDisplayId(MODEL_DEMON); - DoResetThreat(); - m_bDemonForm = true; + DoResetThreat(); + m_bDemonForm = true; - m_uiInnerDemon_Timer = 15000; - m_uiSwitch_Timer = 60000; - }else m_uiSwitch_Timer -= uiDiff; + m_uiInnerDemonTimer = 27500; + m_uiSwitchTimer = 60000; + } + } + else + m_uiSwitchTimer -= uiDiff; } + + DoMeleeAttackIfReady(); } + // Demon form spells else { - //inner demon - if (m_uiInnerDemon_Timer < uiDiff) + if (m_uiInnerDemonTimer) { - DoScriptText(SAY_INNER_DEMONS, m_creature); - - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(m_creature, SPELL_INSIDIOUS_WHISPER); - - m_uiInnerDemon_Timer = 60000; - }else m_uiInnerDemon_Timer -= uiDiff; + if (m_uiInnerDemonTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_INSIDIOUS_WHISPER, CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + DoScriptText(SAY_INNER_DEMONS, m_creature); + m_uiInnerDemonTimer = 0; + } + } + else + m_uiInnerDemonTimer -= uiDiff; + } - //chaos blast spam - if (!m_creature->IsNonMeleeSpellCasted(false)) - m_creature->CastSpell(m_creature->getVictim(), SPELL_CHAOS_BLAST, false); + if (m_uiChaosBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAOS_BLAST) == CAST_OK) + m_uiChaosBlastTimer = urand(2000, 3000); + } + else + m_uiChaosBlastTimer -= uiDiff; - //Switch_Timer - if (m_uiSwitch_Timer < uiDiff) + if (m_uiSwitchTimer < uiDiff) { if (m_creature->IsNonMeleeSpellCasted(false)) m_creature->InterruptNonMeleeSpells(false); - //switch to nightelf form - m_creature->SetDisplayId(MODEL_NIGHTELF); - - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + // switch to nightelf form + m_creature->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS); - //set true SetCombatMovement(true); + DoStartMovement(m_creature->getVictim()); DoResetThreat(); m_bDemonForm = false; - m_uiWhirlwind_Timer = 18500; - m_uiSwitch_Timer = 45000; - }else m_uiSwitch_Timer -= uiDiff; + m_uiWhirlwindTimer = 18500; + m_uiSwitchTimer = 45000; + } + else + m_uiSwitchTimer -= uiDiff; } + // Prepare to summon the Shadow of Leotheras if (!m_bIsFinalForm && m_creature->GetHealthPercent() < 15.0f) { DoScriptText(SAY_FINAL_FORM, m_creature); + m_uiFinalFormTimer = 10000; - //at this point he divides himself in two parts - m_creature->SummonCreature(NPC_SHADOW_LEO, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0); - + // reset him to human form if necessary if (m_bDemonForm) { if (m_creature->IsNonMeleeSpellCasted(false)) m_creature->InterruptNonMeleeSpells(false); - //switch to nightelf form - m_creature->SetDisplayId(MODEL_NIGHTELF); - - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - - //set true - SetCombatMovement(true); + // switch to nightelf form + m_creature->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS); DoResetThreat(); m_bDemonForm = false; } - m_bIsFinalForm = true; - } - - //m_uiEnrage_Timer - if (m_uiEnrage_Timer < uiDiff) - { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(m_creature, SPELL_ENRAGE); - m_uiEnrage_Timer = MINUTE*5*IN_MILLISECONDS; - }else m_uiEnrage_Timer -= uiDiff; - - if (!m_bDemonForm) - DoMeleeAttackIfReady(); - } -}; - -//Leotheras the Blind Demon Form AI -struct MANGOS_DLL_DECL boss_leotheras_the_blind_demonformAI : public ScriptedAI -{ - boss_leotheras_the_blind_demonformAI(Creature* pCreature) : ScriptedAI(pCreature) - { - SetCombatMovement(false); - Reset(); - } - - void Reset() { } + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->HandleEmote(EMOTE_ONESHOT_KNEEL); - void Aggro(Unit* pWho) - { - DoScriptText(SAY_FREE, m_creature); - } + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); - void KilledUnit(Unit* pVictim) - { - if (pVictim->GetTypeId() != TYPEID_PLAYER) - return; + m_bIsFinalForm = true; + } - switch(urand(0, 2)) + // Hard enrage timer + if (m_uiEnrageTimer) { - case 0: DoScriptText(SAY_DEMON_SLAY1, m_creature); break; - case 1: DoScriptText(SAY_DEMON_SLAY2, m_creature); break; - case 2: DoScriptText(SAY_DEMON_SLAY3, m_creature); break; + if (m_uiEnrageTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiEnrageTimer = 0; + } + else + m_uiEnrageTimer -= uiDiff; } } - - void UpdateAI(const uint32 uiDiff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (!m_creature->IsNonMeleeSpellCasted(false)) - m_creature->CastSpell(m_creature->getVictim(), SPELL_CHAOS_BLAST, false); - - //Do NOT deal any melee damage to the target. - } }; CreatureAI* GetAI_boss_leotheras_the_blind(Creature* pCreature) @@ -320,11 +328,6 @@ CreatureAI* GetAI_boss_leotheras_the_blind(Creature* pCreature) return new boss_leotheras_the_blindAI(pCreature); } -CreatureAI* GetAI_boss_leotheras_the_blind_demonform(Creature* pCreature) -{ - return new boss_leotheras_the_blind_demonformAI(pCreature); -} - void AddSC_boss_leotheras_the_blind() { Script* pNewScript; @@ -333,9 +336,4 @@ void AddSC_boss_leotheras_the_blind() pNewScript->Name = "boss_leotheras_the_blind"; pNewScript->GetAI = &GetAI_boss_leotheras_the_blind; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_leotheras_the_blind_demonform"; - pNewScript->GetAI = &GetAI_boss_leotheras_the_blind_demonform; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_morogrim_tidewalker.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_morogrim_tidewalker.cpp index 582dea808..2990e972e 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_morogrim_tidewalker.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_morogrim_tidewalker.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Boss_Morogrim_Tidewalker SD%Complete: 90 -SDComment: +SDComment: Water Globule script is not complete - requires additional research. SDCategory: Coilfang Resevoir, Serpent Shrine Cavern EndScriptData */ @@ -39,13 +39,11 @@ enum EMOTE_EARTHQUAKE = -1548040, EMOTE_WATERY_GLOBULES = -1548041, + SPELL_DOUBLE_ATTACK = 18943, SPELL_TIDAL_WAVE = 37730, SPELL_EARTHQUAKE = 37764, - - SPELL_WATERY_GRAVE_1 = 37850, - SPELL_WATERY_GRAVE_2 = 38023, - SPELL_WATERY_GRAVE_3 = 38024, - SPELL_WATERY_GRAVE_4 = 38025, + SPELL_WATERY_GRAVE = 38028, + // SPELL_WATERY_GRAVE_EXPLOSION = 38049, // spell purpose unk SPELL_SUMMON_MURLOC_A6 = 39813, SPELL_SUMMON_MURLOC_A7 = 39814, @@ -64,12 +62,15 @@ enum SPELL_SUMMON_GLOBULE_3 = 37860, SPELL_SUMMON_GLOBULE_4 = 37861, + SPELL_WATER_GLOBULE_NEW_TARGET = 39848, // spell requires additional research and probably core or script support + NPC_WATER_GLOBULE = 21913, NPC_TIDEWALKER_LURKER = 21920 }; -//Morogrim Tidewalker AI -struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI +static const uint32 m_auiSpellWateryGraveTeleport[] = { 37850, 38023, 38024, 38025 }; + +struct boss_morogrim_tidewalkerAI : public ScriptedAI { boss_morogrim_tidewalkerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -77,32 +78,30 @@ struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI Reset(); } - ScriptedInstance* m_pInstance; // the instance + ScriptedInstance* m_pInstance; - // timers - uint32 m_uiTidalWave_Timer; - uint32 m_uiWateryGrave_Timer; - uint32 m_uiEarthquake_Timer; - uint32 m_uiWateryGlobules_Timer; + uint32 m_uiTidalWaveTimer; + uint32 m_uiWateryGraveTimer; + uint32 m_uiEarthquakeTimer; + uint32 m_uiWateryGlobulesTimer; + uint8 m_uiGraveIndex; - bool m_bEarthquake; - bool m_bPhase2; + bool m_bIsPhase2; - void Reset() + void Reset() override { - m_uiTidalWave_Timer = 10000; - m_uiWateryGrave_Timer = 30000; - m_uiEarthquake_Timer = 40000; - m_uiWateryGlobules_Timer = 0; + m_uiTidalWaveTimer = 10000; + m_uiWateryGraveTimer = 30000; + m_uiEarthquakeTimer = 40000; + m_uiWateryGlobulesTimer = 0; + m_uiGraveIndex = 0; - m_bEarthquake = false; - m_bPhase2 = false; + m_bIsPhase2 = false; - if (m_pInstance) - m_pInstance->SetData(TYPE_MOROGRIM_EVENT, NOT_STARTED); + DoCastSpellIfCan(m_creature, SPELL_DOUBLE_ATTACK); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -110,9 +109,9 @@ struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI m_pInstance->SetData(TYPE_MOROGRIM_EVENT, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -120,7 +119,7 @@ struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI } } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -128,177 +127,155 @@ struct MANGOS_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI m_pInstance->SetData(TYPE_MOROGRIM_EVENT, DONE); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MOROGRIM_EVENT, FAIL); + } + + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_TIDEWALKER_LURKER) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); } - - if (pSummoned->GetEntry() == NPC_WATER_GLOBULE) + else if (pSummoned->GetEntry() == NPC_WATER_GLOBULE) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->GetMotionMaster()->MoveFollow(pTarget, 0.0f, 0.0f); } } - void UpdateAI(const uint32 uiDiff) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override + { + // Handle watery grave teleport - each player hit has his own teleport spell + if (pSpell->Id == SPELL_WATERY_GRAVE && pTarget->GetTypeId() == TYPEID_PLAYER) + { + DoCastSpellIfCan(pTarget, m_auiSpellWateryGraveTeleport[m_uiGraveIndex], CAST_TRIGGERED); + ++m_uiGraveIndex; + } + } + + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiEarthquake_Timer - if (m_uiEarthquake_Timer < uiDiff) + if (m_uiEarthquakeTimer < uiDiff) { - if (!m_bEarthquake) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_EARTHQUAKE); - m_bEarthquake = true; - m_uiEarthquake_Timer = 5000; - } - else + if (DoCastSpellIfCan(m_creature, SPELL_EARTHQUAKE) == CAST_OK) { - DoScriptText(urand(0,1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); - - //north - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A6,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A7,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A8,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A9,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_A10,true); - - //south - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B6,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B7,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B8,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B9,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_MURLOC_B10,true); - DoScriptText(EMOTE_EARTHQUAKE, m_creature); - - m_bEarthquake = false; - m_uiEarthquake_Timer = urand(40000, 45000); + DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + + // summon murlocs - north + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_A6, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_A7, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_A8, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_A9, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_A10, CAST_TRIGGERED); + + // summon murlocs - south + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_B6, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_B7, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_B8, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_B9, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_MURLOC_B10, CAST_TRIGGERED); + + m_uiEarthquakeTimer = 50000; } - }else m_uiEarthquake_Timer -= uiDiff; + } + else + m_uiEarthquakeTimer -= uiDiff; - //m_uiTidalWave_Timer - if (m_uiTidalWave_Timer < uiDiff) + if (m_uiTidalWaveTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_TIDAL_WAVE); - m_uiTidalWave_Timer = 20000; - }else m_uiTidalWave_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_TIDAL_WAVE) == CAST_OK) + m_uiTidalWaveTimer = urand(20000, 25000); + } + else + m_uiTidalWaveTimer -= uiDiff; - if (!m_bPhase2) + // Phase one specific spells + if (!m_bIsPhase2) { - //m_uiWateryGrave_Timer - if (m_uiWateryGrave_Timer < uiDiff) + if (m_uiWateryGraveTimer < uiDiff) { - //Teleport 4 players under the waterfalls - for (uint8 i = 0; i < 4; ++i) + if (DoCastSpellIfCan(m_creature, SPELL_WATERY_GRAVE) == CAST_OK) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_WATERY_GRAVE_1, SELECT_FLAG_PLAYER); - - if (pTarget && !pTarget->HasAuraType(SPELL_AURA_MOD_STUN)) - { - switch(i) - { - case 0: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_1,false); break; - case 1: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_2,false); break; - case 2: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_3,false); break; - case 3: pTarget->CastSpell(pTarget,SPELL_WATERY_GRAVE_4,false); break; - } - } + DoScriptText(EMOTE_WATERY_GRAVE, m_creature); + m_uiWateryGraveTimer = 30000; + m_uiGraveIndex = 0; } + } + else + m_uiWateryGraveTimer -= uiDiff; - DoScriptText(urand(0,1) ? SAY_SUMMON_BUBL1 : SAY_SUMMON_BUBL2, m_creature); - DoScriptText(EMOTE_WATERY_GRAVE, m_creature); - - m_uiWateryGrave_Timer = 30000; - }else m_uiWateryGrave_Timer -= uiDiff; - - //Start Phase2 + // Start Phase2 below 25% hp if (m_creature->GetHealthPercent() < 25.0f) - m_bPhase2 = true; + m_bIsPhase2 = true; } else { - //m_uiWateryGlobules_Timer - if (m_uiWateryGlobules_Timer < uiDiff) + if (m_uiWateryGlobulesTimer < uiDiff) { - DoScriptText(EMOTE_WATERY_GLOBULES, m_creature); + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_GLOBULE_1) == CAST_OK) + { + DoScriptText(EMOTE_WATERY_GLOBULES, m_creature); + DoScriptText(urand(0, 1) ? SAY_SUMMON_BUBL1 : SAY_SUMMON_BUBL2, m_creature); - m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_1,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_2,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_3,true); - m_creature->CastSpell(m_creature,SPELL_SUMMON_GLOBULE_4,false); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_GLOBULE_2, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_GLOBULE_3, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SUMMON_GLOBULE_4, CAST_TRIGGERED); - m_uiWateryGlobules_Timer = 25000; - }else m_uiWateryGlobules_Timer -= uiDiff; + m_uiWateryGlobulesTimer = 25000; + } + } + else + m_uiWateryGlobulesTimer -= uiDiff; } DoMeleeAttackIfReady(); } }; -//Water Globule AI -struct MANGOS_DLL_DECL mob_water_globuleAI : public ScriptedAI +struct mob_water_globuleAI : public ScriptedAI { mob_water_globuleAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - // timers - uint32 m_uiCheck_Timer; + uint32 m_uiTargetTimer; - void Reset() + void Reset() override { - m_uiCheck_Timer = 1000; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiTargetTimer = 10000; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* /*pWho*/) override { - if (!pWho || m_creature->getVictim()) - return; - - if (pWho->isTargetableForAttack() && pWho->isInAccessablePlaceFor(m_creature) && m_creature->IsHostileTo(pWho)) - { - //no attack radius check - it attacks the first target that moves in his los - pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(pWho); - } + // ToDo: cast damage spell here, after proper checks are done } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiCheck_Timer < uiDiff) + if (m_uiTargetTimer < uiDiff) { - if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) - { - m_creature->DealDamage(m_creature->getVictim(), 4000+rand()%2000, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_FROST, NULL, false); - - //despawn - m_creature->ForcedDespawn(); - return; - } - m_uiCheck_Timer = 500; - }else m_uiCheck_Timer -= uiDiff; - - //do NOT deal any melee damage to the target. + if (DoCastSpellIfCan(m_creature, SPELL_WATER_GLOBULE_NEW_TARGET) == CAST_OK) + m_uiTargetTimer = 10000; + } + else + m_uiTargetTimer -= uiDiff; } }; CreatureAI* GetAI_boss_morogrim_tidewalker(Creature* pCreature) { - return new boss_morogrim_tidewalkerAI (pCreature); + return new boss_morogrim_tidewalkerAI(pCreature); } + CreatureAI* GetAI_mob_water_globule(Creature* pCreature) { - return new mob_water_globuleAI (pCreature); + return new mob_water_globuleAI(pCreature); } void AddSC_boss_morogrim_tidewalker() diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_the_lurker_below.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_the_lurker_below.cpp index ef8fc4afd..fcf25cbff 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/boss_the_lurker_below.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/boss_the_lurker_below.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_the_lurker_below -SD%Complete: 5 -SDComment: Timers from ACID, only placeholder quality, Spout unused, submerge phase missing +SD%Complete: 90 +SDComment: Spawn animation NYI; Timers may need adjustments. SDCategory: Coilfang Resevoir, Serpent Shrine Cavern EndScriptData */ @@ -26,11 +26,21 @@ EndScriptData */ enum { + EMOTE_DEEP_BREATH = -1548056, + SPELL_LURKER_SPAWN_TRIGGER = 54587, - SPELL_WHIRL = 37363, + SPELL_WHIRL = 37660, SPELL_GEYSER = 37478, - SPELL_SPOUT = 37433, // TODO should sweep the room 360degrees, related spells 37429 37430 37431 - SPELL_WATERBOLT = 37138, // TODO is used when no enemy in melee range (unknown if on random or top-most aggro holder in this case + SPELL_SPOUT = 37431, // trigger spells 37429, 37430 + SPELL_SPOUT_LEFT = 37429, + SPELL_SPOUT_RIGHT = 37430, + SPELL_WATERBOLT = 37138, + SPELL_SUBMERGE = 37550, + + NPC_COILFANG_AMBUSHER = 21865, + NPC_COILFANG_GUARDIAN = 21873, + + MAX_SUBMERGE_ADDS = 9, }; enum Phases @@ -41,72 +51,221 @@ enum Phases PHASE_SUBMERGED = 3, }; -// TODO This boss should infact be a Scripted_NoMovementAI, but selecting only melee targets is not supported yet, change when implemented -struct MANGOS_DLL_DECL boss_the_lurker_belowAI : public ScriptedAI +struct AddsLocations +{ + uint32 uiEntry; + float fX, fY, fZ; +}; + +// Coords are guesswork +static const AddsLocations aLurkerLoc[MAX_SUBMERGE_ADDS] = { - boss_the_lurker_belowAI(Creature* pCreature) : ScriptedAI(pCreature) + {NPC_COILFANG_AMBUSHER, 2.855f, -459.823f, -19.18f}, + {NPC_COILFANG_AMBUSHER, 12.458f, -466.042f, -19.18f}, + {NPC_COILFANG_AMBUSHER, 51.366f, -460.836f, -19.18f}, + {NPC_COILFANG_AMBUSHER, 62.597f, -457.433f, -19.18f}, + {NPC_COILFANG_AMBUSHER, 77.607f, -384.302f, -19.18f}, + {NPC_COILFANG_AMBUSHER, 63.897f, -378.984f, -19.18f}, + {NPC_COILFANG_GUARDIAN, 34.447f, -387.333f, -19.18f}, + {NPC_COILFANG_GUARDIAN, 14.388f, -423.468f, -19.62f}, + {NPC_COILFANG_GUARDIAN, 42.471f, -445.115f, -19.76f}, +}; + +struct boss_the_lurker_belowAI : public Scripted_NoMovementAI +{ + boss_the_lurker_belowAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_creature->SetSwim(true); Reset(); } ScriptedInstance* m_pInstance; Phases m_uiPhase; + uint32 m_uiPhaseChangeTimer; uint32 m_uiWhirlTimer; uint32 m_uiGeyserTimer; + uint32 m_uiSpoutTimer; + uint32 m_uiSpoutEndTimer; - void Reset() + void Reset() override { - m_uiPhase = PHASE_NORMAL; + m_uiPhase = PHASE_NORMAL; + m_uiPhaseChangeTimer = 90000; - m_uiWhirlTimer = 19500; - m_uiGeyserTimer = 49700; + DoResetCombatTimers(); + } + + void DoResetCombatTimers() + { + m_uiWhirlTimer = 18000; + m_uiGeyserTimer = 50000; + m_uiSpoutTimer = 42000; + m_uiSpoutEndTimer = 23000; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_THELURKER_EVENT, NOT_STARTED); + m_pInstance->SetData(TYPE_THELURKER_EVENT, FAIL); m_creature->ForcedDespawn(); } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_THELURKER_EVENT, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustSummoned(Creature* pSummoned) override { - // Return since we have no target - // Unclear if we will use this selecting for spout-alike situations - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Allow the adds to attack + pSummoned->SetInCombatWithZone(); + } + + // Wrapper to summon adds in phase 2 + void DoSummonCoilfangNaga() + { + for (uint8 i = 0; i < MAX_SUBMERGE_ADDS; ++i) + m_creature->SummonCreature(aLurkerLoc[i].uiEntry, aLurkerLoc[i].fX, aLurkerLoc[i].fY, aLurkerLoc[i].fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + // Custom threat management + bool SelectHostileTarget() + { + Unit* pTarget = NULL; + Unit* pOldTarget = m_creature->getVictim(); + + if (!m_creature->getThreatManager().isThreatListEmpty()) + pTarget = m_creature->getThreatManager().getHostileTarget(); + + if (pTarget) + { + if (pOldTarget != pTarget && m_uiPhase != PHASE_SPOUT) + AttackStart(pTarget); + + // Set victim to old target (if not while Spout) + if (pOldTarget && pOldTarget->isAlive() && m_uiPhase != PHASE_SPOUT) + { + m_creature->SetTargetGuid(pOldTarget->GetObjectGuid()); + m_creature->SetInFront(pOldTarget); + } + + return true; + } + + // Will call EnterEvadeMode if fit + return m_creature->SelectHostileTarget(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!SelectHostileTarget()) return; switch (m_uiPhase) { + case PHASE_SPOUT: + + if (m_uiSpoutEndTimer < uiDiff) + { + // Remove rotation auras + m_creature->RemoveAurasDueToSpell(SPELL_SPOUT_LEFT); + m_creature->RemoveAurasDueToSpell(SPELL_SPOUT_RIGHT); + + m_uiPhase = PHASE_NORMAL; + m_uiSpoutEndTimer = 23000; + } + else + m_uiSpoutEndTimer -= uiDiff; + + // no break; case PHASE_NORMAL: - if (m_uiWhirlTimer < uiDiff) + + // Count the first phase during Spout too + if (m_uiPhaseChangeTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_WHIRL) == CAST_OK) - m_uiWhirlTimer = urand(15000, 30000); + if (DoCastSpellIfCan(m_creature, SPELL_SUBMERGE) == CAST_OK) + { + DoSummonCoilfangNaga(); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_uiPhase = PHASE_SUBMERGED; + m_uiPhaseChangeTimer = MINUTE * IN_MILLISECONDS; + } } else - m_uiWhirlTimer -= uiDiff; + m_uiPhaseChangeTimer -= uiDiff; + + // Combat spells are only in normal phase + if (m_uiPhase == PHASE_NORMAL) + { + if (m_uiSpoutTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SPOUT) == CAST_OK) + { + DoScriptText(EMOTE_DEEP_BREATH, m_creature); + + // Remove the target focus but allow the boss to face the current victim + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->SetFacingToObject(m_creature->getVictim()); + + m_uiPhase = PHASE_SPOUT; + m_uiSpoutTimer = 30000; + } + } + else + m_uiSpoutTimer -= uiDiff; + + if (m_uiWhirlTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WHIRL) == CAST_OK) + m_uiWhirlTimer = 18000; + } + else + m_uiWhirlTimer -= uiDiff; + + if (m_uiGeyserTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_GEYSER) == CAST_OK) + m_uiGeyserTimer = urand(50000, 60000); + } + } + else + m_uiGeyserTimer -= uiDiff; + + // If we are within range melee the target + if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) + DoMeleeAttackIfReady(); + // Spam Waterbolt spell when not tanked + else + { + if (!m_creature->IsNonMeleeSpellCasted(false)) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + DoCastSpellIfCan(pTarget, SPELL_WATERBOLT); + } + } + } + + break; + case PHASE_SUBMERGED: - if (m_uiGeyserTimer < uiDiff) + if (m_uiPhaseChangeTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - if (DoCastSpellIfCan(pTarget, SPELL_GEYSER) == CAST_OK) - m_uiGeyserTimer = urand(49700, 60000); + DoResetCombatTimers(); + m_uiPhase = PHASE_NORMAL; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); + m_uiPhaseChangeTimer = 2 * MINUTE * IN_MILLISECONDS; } else - m_uiGeyserTimer -= uiDiff; + m_uiPhaseChangeTimer -= uiDiff; - DoMeleeAttackIfReady(); break; } } @@ -121,11 +280,11 @@ CreatureAI* GetAI_boss_the_lurker_below(Creature* pCreature) bool GOUse_go_strange_pool(Player* pPlayer, GameObject* pGo) { // There is some chance to fish The Lurker Below, sources are from 20s to 10minutes, average 5min => 20 tries, hence 5% - if (urand(0,99) < 5) + if (urand(0, 99) < 5) { if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) { - if (pInstance->GetData(TYPE_THELURKER_EVENT) == NOT_STARTED) + if (pInstance->GetData(TYPE_THELURKER_EVENT) == NOT_STARTED || pInstance->GetData(TYPE_THELURKER_EVENT) == FAIL) { pPlayer->CastSpell(pPlayer, SPELL_LURKER_SPAWN_TRIGGER, true); pInstance->SetData(TYPE_THELURKER_EVENT, IN_PROGRESS); diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/instance_serpent_shrine.cpp b/scripts/outland/coilfang_reservoir/serpent_shrine/instance_serpent_shrine.cpp index ec8623157..17a859291 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/instance_serpent_shrine.cpp +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/instance_serpent_shrine.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -33,7 +33,8 @@ EndScriptData */ 5 - Lady Vashj Event */ -instance_serpentshrine_cavern::instance_serpentshrine_cavern(Map* pMap) : ScriptedInstance(pMap) +instance_serpentshrine_cavern::instance_serpentshrine_cavern(Map* pMap) : ScriptedInstance(pMap), + m_uiSpellBinderCount(0) { Initialize(); } @@ -41,7 +42,6 @@ instance_serpentshrine_cavern::instance_serpentshrine_cavern(Map* pMap) : Script void instance_serpentshrine_cavern::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - memset(&m_auiShieldGenerator, 0, sizeof(m_auiShieldGenerator)); } bool instance_serpentshrine_cavern::IsEncounterInProgress() const @@ -60,27 +60,43 @@ void instance_serpentshrine_cavern::OnCreatureCreate(Creature* pCreature) switch (pCreature->GetEntry()) { case NPC_LADYVASHJ: - case NPC_KARATHRESS: case NPC_SHARKKIS: case NPC_TIDALVESS: case NPC_CARIBDIS: + case NPC_LEOTHERAS: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_GREYHEART_SPELLBINDER: + m_lSpellBindersGUIDList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_HYDROSS_BEAM_HELPER: + m_lBeamHelpersGUIDList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_SHIELD_GENERATOR: + m_lShieldGeneratorGUIDList.push_back(pCreature->GetObjectGuid()); + break; + case NPC_COILFANG_PRIESTESS: + case NPC_COILFANG_SHATTERER: + case NPC_VASHJIR_HONOR_GUARD: + case NPC_GREYHEART_TECHNICIAN: + // Filter only the mobs spawned on the platforms + if (pCreature->GetPositionZ() > 0) + m_sPlatformMobsGUIDSet.insert(pCreature->GetObjectGuid()); + break; } } -void instance_serpentshrine_cavern::SetData64(uint32 uiType, uint64 uiData) -{ - if (uiType == DATA_KARATHRESS_STARTER) - m_karathressEventStarterGuid = ObjectGuid(uiData); -} - -uint64 instance_serpentshrine_cavern::GetData64(uint32 uiData) +void instance_serpentshrine_cavern::OnObjectCreate(GameObject* pGo) { - if (uiData == DATA_KARATHRESS_STARTER) - return m_karathressEventStarterGuid.GetRawValue(); - - return 0; + switch (pGo->GetEntry()) + { + case GO_SHIELD_GENERATOR_1: + case GO_SHIELD_GENERATOR_2: + case GO_SHIELD_GENERATOR_3: + case GO_SHIELD_GENERATOR_4: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + } } void instance_serpentshrine_cavern::SetData(uint32 uiType, uint32 uiData) @@ -88,31 +104,44 @@ void instance_serpentshrine_cavern::SetData(uint32 uiType, uint32 uiData) switch (uiType) { case TYPE_HYDROSS_EVENT: - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_LEOTHERAS_EVENT: - m_auiEncounter[1] = uiData; + m_auiEncounter[uiType] = uiData; + if (uiData == FAIL) + { + for (GuidList::const_iterator itr = m_lSpellBindersGUIDList.begin(); itr != m_lSpellBindersGUIDList.end(); ++itr) + { + if (Creature* pSpellBinder = instance->GetCreature(*itr)) + pSpellBinder->Respawn(); + } + + m_uiSpellBinderCount = 0; + } break; case TYPE_THELURKER_EVENT: - m_auiEncounter[2] = uiData; - break; case TYPE_KARATHRESS_EVENT: - m_auiEncounter[3] = uiData; - break; case TYPE_MOROGRIM_EVENT: - m_auiEncounter[4] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_LADYVASHJ_EVENT: - if (uiData == NOT_STARTED) - memset(&m_auiShieldGenerator, 0, sizeof(m_auiShieldGenerator)); - m_auiEncounter[5] = uiData; + m_auiEncounter[uiType] = uiData; + if (uiData == FAIL) + { + // interrupt the shield + for (GuidList::const_iterator itr = m_lShieldGeneratorGUIDList.begin(); itr != m_lShieldGeneratorGUIDList.end(); ++itr) + { + if (Creature* pGenerator = instance->GetCreature(*itr)) + pGenerator->InterruptNonMeleeSpells(false); + } + + // reset generators + DoToggleGameObjectFlags(GO_SHIELD_GENERATOR_1, GO_FLAG_NO_INTERACT, false); + DoToggleGameObjectFlags(GO_SHIELD_GENERATOR_2, GO_FLAG_NO_INTERACT, false); + DoToggleGameObjectFlags(GO_SHIELD_GENERATOR_3, GO_FLAG_NO_INTERACT, false); + DoToggleGameObjectFlags(GO_SHIELD_GENERATOR_4, GO_FLAG_NO_INTERACT, false); + } break; - case TYPE_SHIELDGENERATOR1: - case TYPE_SHIELDGENERATOR2: - case TYPE_SHIELDGENERATOR3: - case TYPE_SHIELDGENERATOR4: - m_auiShieldGenerator[uiType - TYPE_SHIELDGENERATOR1] = uiData; - return; } if (uiData == DONE) @@ -121,7 +150,7 @@ void instance_serpentshrine_cavern::SetData(uint32 uiType, uint32 uiData) std::ostringstream saveStream; saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5]; m_strInstData = saveStream.str(); @@ -142,7 +171,7 @@ void instance_serpentshrine_cavern::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5]; + >> m_auiEncounter[4] >> m_auiEncounter[5]; for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { @@ -153,32 +182,70 @@ void instance_serpentshrine_cavern::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_serpentshrine_cavern::GetData(uint32 uiType) +uint32 instance_serpentshrine_cavern::GetData(uint32 uiType) const { - switch (uiType) + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_serpentshrine_cavern::SetData64(uint32 uiData, uint64 uiGuid) +{ + // Note: this is handled in Acid. The purpose is check which npc from the platform set is alive + // The function is triggered by eventAI on generic timer + if (uiData == DATA_WATERSTATE_EVENT) + { + if (m_sPlatformMobsGUIDSet.find(ObjectGuid(uiGuid)) != m_sPlatformMobsGUIDSet.end()) + m_sPlatformMobsAliveGUIDSet.insert(ObjectGuid(uiGuid)); + } +} + +bool instance_serpentshrine_cavern::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const +{ + switch (uiInstanceConditionId) { - case TYPE_HYDROSS_EVENT: return m_auiEncounter[0]; - case TYPE_LEOTHERAS_EVENT: return m_auiEncounter[1]; - case TYPE_THELURKER_EVENT: return m_auiEncounter[2]; - case TYPE_KARATHRESS_EVENT: return m_auiEncounter[3]; - case TYPE_MOROGRIM_EVENT: return m_auiEncounter[4]; - case TYPE_LADYVASHJ_EVENT: return m_auiEncounter[5]; - - case TYPE_SHIELDGENERATOR1: return m_auiShieldGenerator[0]; - case TYPE_SHIELDGENERATOR2: return m_auiShieldGenerator[1]; - case TYPE_SHIELDGENERATOR3: return m_auiShieldGenerator[2]; - case TYPE_SHIELDGENERATOR4: return m_auiShieldGenerator[3]; - - case TYPE_VASHJ_PHASE3_CHECK: - for(uint8 i = 0; i < MAX_GENERATOR; ++i) + case INSTANCE_CONDITION_ID_LURKER: + return GetData(TYPE_THELURKER_EVENT) != DONE; + case INSTANCE_CONDITION_ID_SCALDING_WATER: + return m_sPlatformMobsAliveGUIDSet.empty(); + } + + script_error_log("instance_serpentshrine_cavern::CheckConditionCriteriaMeet called with unsupported Id %u. Called with param plr %s, src %s, condition source type %u", + uiInstanceConditionId, pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", pConditionSource ? pConditionSource->GetGuidStr().c_str() : "NULL", conditionSourceType); + return false; +} + +void instance_serpentshrine_cavern::OnCreatureEnterCombat(Creature* pCreature) +{ + // Interrupt spell casting on aggro + if (pCreature->GetEntry() == NPC_GREYHEART_SPELLBINDER) + pCreature->InterruptNonMeleeSpells(false); +} + +void instance_serpentshrine_cavern::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_GREYHEART_SPELLBINDER: + ++m_uiSpellBinderCount; + + if (m_uiSpellBinderCount == MAX_SPELLBINDERS) { - if (m_auiShieldGenerator[i] != DONE) - return NOT_STARTED; + if (Creature* pLeotheras = GetSingleCreatureFromStorage(NPC_LEOTHERAS)) + { + pLeotheras->RemoveAurasDueToSpell(SPELL_LEOTHERAS_BANISH); + pLeotheras->SetInCombatWithZone(); + } } - return DONE; - - default: - return 0; + break; + case NPC_COILFANG_PRIESTESS: + case NPC_COILFANG_SHATTERER: + case NPC_VASHJIR_HONOR_GUARD: + case NPC_GREYHEART_TECHNICIAN: + if (m_sPlatformMobsGUIDSet.find(pCreature->GetObjectGuid()) != m_sPlatformMobsGUIDSet.end()) + m_sPlatformMobsAliveGUIDSet.erase(pCreature->GetObjectGuid()); + break; } } diff --git a/scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h b/scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h index cce375d52..52b4ca42a 100644 --- a/scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h +++ b/scripts/outland/coilfang_reservoir/serpent_shrine/serpent_shrine.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,54 +8,89 @@ enum { MAX_ENCOUNTER = 6, - MAX_GENERATOR = 4, + MAX_SPELLBINDERS = 3, - TYPE_HYDROSS_EVENT = 1, - TYPE_KARATHRESS_EVENT = 2, - TYPE_LADYVASHJ_EVENT = 3, - TYPE_LEOTHERAS_EVENT = 4, - TYPE_MOROGRIM_EVENT = 5, - TYPE_THELURKER_EVENT = 6, - TYPE_VASHJ_PHASE3_CHECK = 7, + TYPE_HYDROSS_EVENT = 0, + TYPE_KARATHRESS_EVENT = 1, + TYPE_LADYVASHJ_EVENT = 2, + TYPE_LEOTHERAS_EVENT = 3, + TYPE_MOROGRIM_EVENT = 4, + TYPE_THELURKER_EVENT = 5, - TYPE_SHIELDGENERATOR1 = 8, - TYPE_SHIELDGENERATOR2 = TYPE_SHIELDGENERATOR1 + 1, - TYPE_SHIELDGENERATOR3 = TYPE_SHIELDGENERATOR1 + 2, - TYPE_SHIELDGENERATOR4 = TYPE_SHIELDGENERATOR1 + 3, + DATA_WATERSTATE_EVENT = 1, // DO NOT CHANGE! Used by Acid. - used to check the mobs for the water event. - DATA_KARATHRESS_STARTER = 12, // Player who started the Karathress encounter - - NPC_KARATHRESS = 21214, + // NPC_KARATHRESS = 21214, NPC_CARIBDIS = 21964, NPC_SHARKKIS = 21966, NPC_TIDALVESS = 21965, + NPC_LEOTHERAS = 21215, NPC_LADYVASHJ = 21212, + NPC_GREYHEART_SPELLBINDER = 21806, + NPC_HYDROSS_BEAM_HELPER = 21933, + NPC_SHIELD_GENERATOR = 19870, + + // waterstate event related + NPC_COILFANG_PRIESTESS = 21220, + NPC_COILFANG_SHATTERER = 21301, + NPC_VASHJIR_HONOR_GUARD = 21218, + NPC_GREYHEART_TECHNICIAN = 21263, + + GO_SHIELD_GENERATOR_1 = 185051, + GO_SHIELD_GENERATOR_2 = 185052, + GO_SHIELD_GENERATOR_3 = 185053, + GO_SHIELD_GENERATOR_4 = 185054, + + // Objects and doors no longer used since 2.4.0 + // GO_CONSOLE_HYDROSS = 185117, + // GO_CONSOLE_LURKER = 185118, + // GO_CONSOLE_LEOTHERAS = 185115, + // GO_CONSOLE_KARATHRESS = 185114, + // GO_CONSOLE_MOROGRIM = 185116, + // GO_CONSOLE_VASHJ = 184568, + // GO_BRIDGE_PART_1 = 184203, + // GO_BRIDGE_PART_2 = 184204, + // GO_BRIDGE_PART_3 = 184205, + + SPELL_LEOTHERAS_BANISH = 37546, }; -class MANGOS_DLL_DECL instance_serpentshrine_cavern : public ScriptedInstance +class instance_serpentshrine_cavern : public ScriptedInstance { public: instance_serpentshrine_cavern(Map* pMap); - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); - void SetData64(uint32 uiType, uint64 uiData); - uint64 GetData64(uint32 uiData); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + void SetData64(uint32 uiType, uint64 uiGuid) override; + + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const override; + + void GetBeamHelpersGUIDList(GuidList& lList) { lList = m_lBeamHelpersGUIDList; } + void GetShieldGeneratorsGUIDList(GuidList& lList) { lList = m_lShieldGeneratorGUIDList; } + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; - uint32 m_auiShieldGenerator[MAX_GENERATOR]; std::string m_strInstData; - ObjectGuid m_karathressEventStarterGuid; + uint32 m_uiSpellBinderCount; + + GuidList m_lSpellBindersGUIDList; + GuidList m_lBeamHelpersGUIDList; + GuidList m_lShieldGeneratorGUIDList; + GuidSet m_sPlatformMobsGUIDSet; + GuidSet m_sPlatformMobsAliveGUIDSet; }; #endif diff --git a/scripts/outland/coilfang_reservoir/slave_pens/boss_ahune.cpp b/scripts/outland/coilfang_reservoir/slave_pens/boss_ahune.cpp index 708debcdd..8a0eee304 100644 --- a/scripts/outland/coilfang_reservoir/slave_pens/boss_ahune.cpp +++ b/scripts/outland/coilfang_reservoir/slave_pens/boss_ahune.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,13 +16,397 @@ /* ScriptData SDName: boss_ahune -SD%Complete: 0 -SDComment: Placeholder +SD%Complete: 75 +SDComment: Submerged phase visual spells NYI; they require additional research. SDCategory: Slave Pens EndScriptData */ #include "precompiled.h" +#include "TemporarySummon.h" + +enum +{ + // general spells + SPELL_AHUNES_SHIELD = 45954, + SPELL_SPANKY_HANDS = 46146, // procs on melee hit; should proc 46430 but currently is not used because of the invalid proc flag + SPELL_SYNCH_HEALTH = 46430, + SPELL_SUICIDE = 45254, + SPELL_AHUNE_LOOT = 45941, + SPELL_AHUNE_LOOT_H = 46623, + SPELL_ISDEAD_CHECK = 61976, // purpose unk + SPELL_AHUNE_DIES_ACHIEV = 62043, + + // ground phase spells + SPELL_SUMMON_HAILSTONE = 45951, + SPELL_SUMMON_COLDWAVE = 45952, + SPELL_SUMMON_FROSTWIND = 45953, + + // submerged phase spells + SPELL_BIRTH = 37745, // spawn animation - not confirmed + SPELL_SUBMERGE = 37550, // submerge animation - not confirmed + SPELL_STAY_SUBMERGED = 46981, // triggers 37751; this should keep the boss submerged + SPELL_AHUNE_SELF_STUN = 46416, + SPELL_ICE_BOMBARD = 46397, // cast on phase 2 end; related to the fire opening visuals + SPELL_CLOSE_OPENING_VISUAL = 46236, // same as above + SPELL_STAND = 37752, // purpose unk + + // frozen core spells + SPELL_ICE_SPEAR_AURA = 46371, + SPELL_FROZEN_CORE_HIT = 46810, // procs on melee hit; should summon npc 26239 for a 2 seconds + SPELL_GHOST_DISGUISE = 46786, // triggered by spell 46809 + + // ice spear spells + SPELL_SUMMON_ICE_SPEAR_GO = 46369, + SPELL_ICE_SPEAR_DELAY = 46878, + SPELL_ICE_SPEAR_KNOCKBACK = 46360, + SPELL_ICE_SPEAR_VISUAL = 75498, + + // npcs and GOs + NPC_FROZEN_CORE = 25865, + NPC_GHOST_OF_AHUNE = 26239, + NPC_AHUNITE_HAILSTONE = 25755, + NPC_AHUNITE_COLDWAVE = 25756, + NPC_AHUNITE_FROSTWIND = 25757, + NPC_ICE_SPEAR_BUNNY = 25985, + GO_ICE_SPEAR = 188077, + + PHASE_GROUND = 1, + PHASE_SUBMERGED = 2, +}; + +/*###### +## boss_ahune +######*/ + +struct boss_ahuneAI : public Scripted_NoMovementAI +{ + boss_ahuneAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) + { + m_bHasCombatStarted = false; + Reset(); + } + + bool m_bHasCombatStarted; + + uint8 m_uiPhase; + uint8 m_uiPhaseChangeCount; + uint32 m_uiPhaseChangeTimer; + + uint32 m_uiHailstoneTimer; + uint32 m_uiColdwaveTimer; + uint32 m_uiFrostwindTimer; + + ObjectGuid m_frozenCoreGuid; + + void Reset() override + { + m_uiPhase = PHASE_GROUND; + m_uiPhaseChangeTimer = 90000; + m_uiPhaseChangeCount = 0; + + m_uiHailstoneTimer = 1000; + m_uiColdwaveTimer = urand(5000, 10000); + m_uiFrostwindTimer = urand(20000, 25000); + } + + void Aggro(Unit* /*pWho*/) override + { + DoCastSpellIfCan(m_creature, SPELL_BIRTH); + DoCastSpellIfCan(m_creature, SPELL_AHUNES_SHIELD, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_SPANKY_HANDS, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + + void JustDied(Unit* /*pKiller*/) override + { + DoCastSpellIfCan(m_creature, SPELL_AHUNE_DIES_ACHIEV, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, m_creature->GetMap()->IsRegularDifficulty() ? SPELL_AHUNE_LOOT : SPELL_AHUNE_LOOT_H, CAST_TRIGGERED); + } + + void JustReachedHome() override + { + // Cleanup on evade is done by creature_linking + m_creature->ForcedDespawn(); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + // it's not clear whether this should work like this or should be handled by the proc aura + if (Creature* pCore = m_creature->GetMap()->GetCreature(m_frozenCoreGuid)) + DoCastSpellIfCan(pCore, SPELL_SYNCH_HEALTH, CAST_TRIGGERED); + } + + void SpellHit(Unit* /*pSource*/, const SpellEntry* pSpell) override + { + if (pSpell->Id == SPELL_SUBMERGE) + { + // Note: the following spell breaks the visual. Needs to be fixed! + // DoCastSpellIfCan(m_creature, SPELL_AHUNE_SELF_STUN, CAST_TRIGGERED); + + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (Creature* pCore = m_creature->GetMap()->GetCreature(m_frozenCoreGuid)) + pCore->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_AHUNITE_HAILSTONE: + case NPC_AHUNITE_COLDWAVE: + case NPC_AHUNITE_FROSTWIND: + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + break; + case NPC_FROZEN_CORE: + m_frozenCoreGuid = pSummoned->GetObjectGuid(); + break; + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // When the core dies, commit suicide + if (pSummoned->GetEntry() == NPC_FROZEN_CORE) + DoCastSpellIfCan(m_creature, SPELL_SUICIDE, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override + { + // Attack on first update tick, in order to properly handle the spawn animation + if (!m_bHasCombatStarted) + { + if (m_creature->IsTemporarySummon()) + { + TemporarySummon* pTemporary = (TemporarySummon*)m_creature; + + if (Player* pSummoner = m_creature->GetMap()->GetPlayer(pTemporary->GetSummonerGuid())) + AttackStart(pSummoner); + } + + m_bHasCombatStarted = true; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiPhase == PHASE_GROUND) + { + // only once at the beginning of the phase + if (m_uiHailstoneTimer) + { + if (m_uiHailstoneTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_HAILSTONE) == CAST_OK) + m_uiHailstoneTimer = 0; + } + else + m_uiHailstoneTimer -= uiDiff; + } + + if (m_uiColdwaveTimer < uiDiff) + { + for (uint8 i = 0; i < 2; ++i) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_COLDWAVE); + + m_uiColdwaveTimer = urand(5000, 10000); + } + else + m_uiColdwaveTimer -= uiDiff; + + // starts only after the first phase change + if (m_uiPhaseChangeCount) + { + if (m_uiFrostwindTimer < uiDiff) + { + for (uint8 i = 0; i < m_uiPhaseChangeCount; ++i) + DoCastSpellIfCan(m_creature, SPELL_SUMMON_FROSTWIND); + + m_uiFrostwindTimer = urand(5000, 10000); + } + else + m_uiFrostwindTimer -= uiDiff; + } + + if (m_uiPhaseChangeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SUBMERGE) == CAST_OK) + { + m_uiPhaseChangeTimer = 40000; + m_uiPhase = PHASE_SUBMERGED; + ++m_uiPhaseChangeCount; + } + } + else + m_uiPhaseChangeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + else if (m_uiPhase == PHASE_SUBMERGED) + { + if (m_uiPhaseChangeTimer < uiDiff) + { + m_creature->RemoveAurasDueToSpell(SPELL_SUBMERGE); + m_creature->RemoveAurasDueToSpell(SPELL_AHUNE_SELF_STUN); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + DoCastSpellIfCan(m_creature, SPELL_BIRTH); + + if (Creature* pCore = m_creature->GetMap()->GetCreature(m_frozenCoreGuid)) + pCore->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_OOC_NOT_ATTACKABLE); + + m_uiPhase = PHASE_GROUND; + m_uiHailstoneTimer = 1000; + m_uiPhaseChangeTimer = 90000; + } + else + m_uiPhaseChangeTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_boss_ahune(Creature* pCreature) +{ + return new boss_ahuneAI(pCreature); +} + +/*###### +## npc_frozen_core +######*/ + +struct npc_frozen_coreAI : public Scripted_NoMovementAI +{ + npc_frozen_coreAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + ObjectGuid m_ahuheGuid; + + void Reset() override + { + if (m_creature->IsTemporarySummon()) + m_ahuheGuid = ((TemporarySummon*)m_creature)->GetSummonerGuid(); + + DoCastSpellIfCan(m_creature, SPELL_FROZEN_CORE_HIT, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + DoCastSpellIfCan(m_creature, SPELL_ICE_SPEAR_AURA, CAST_TRIGGERED | CAST_AURA_NOT_PRESENT); + } + + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override + { + // it's not clear whether this should work like this or should be handled by the proc aura + if (Creature* pAhune = m_creature->GetMap()->GetCreature(m_ahuheGuid)) + DoCastSpellIfCan(pAhune, SPELL_SYNCH_HEALTH, CAST_TRIGGERED); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_ICE_SPEAR_BUNNY) + { + pSummoned->CastSpell(pSummoned, SPELL_ICE_SPEAR_VISUAL, true); + pSummoned->CastSpell(pSummoned, SPELL_SUMMON_ICE_SPEAR_GO, true); + pSummoned->CastSpell(pSummoned, SPELL_ICE_SPEAR_DELAY, true); + } + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_frozen_core(Creature* pCreature) +{ + return new npc_frozen_coreAI(pCreature); +} + +/*###### +## npc_ice_spear_bunny +######*/ + +struct npc_ice_spear_bunnyAI : public Scripted_NoMovementAI +{ + npc_ice_spear_bunnyAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + ObjectGuid m_iceSpearGuid; + + uint8 m_uiEventCount; + + void Reset() override + { + m_uiEventCount = 0; + } + + void JustSummoned(GameObject* pGo) override + { + if (pGo->GetEntry() == GO_ICE_SPEAR) + m_iceSpearGuid = pGo->GetObjectGuid(); + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_CUSTOM_A) + { + ++m_uiEventCount; + + // Knockback at 4 aura stacks (2 seconds) + if (m_uiEventCount == 4) + { + DoCastSpellIfCan(m_creature, SPELL_ICE_SPEAR_KNOCKBACK); + + if (GameObject* pSpear = m_creature->GetMap()->GetGameObject(m_iceSpearGuid)) + pSpear->Use(m_creature); + } + // Cleanup at 10 aura stacks (5 seconds) + else if (m_uiEventCount == 10) + { + if (GameObject* pSpear = m_creature->GetMap()->GetGameObject(m_iceSpearGuid)) + pSpear->SetLootState(GO_JUST_DEACTIVATED); + + m_creature->ForcedDespawn(); + } + } + } + + void AttackStart(Unit* /*pWho*/) override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + +CreatureAI* GetAI_npc_ice_spear_bunny(Creature* pCreature) +{ + return new npc_ice_spear_bunnyAI(pCreature); +} + +bool EffectDummyCreature_npc_ice_spear_bunny(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_ICE_SPEAR_DELAY && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_ICE_SPEAR_BUNNY) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_CUSTOM_A, pCaster, pCreatureTarget); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} void AddSC_boss_ahune() { + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_ahune"; + pNewScript->GetAI = &GetAI_boss_ahune; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_frozen_core"; + pNewScript->GetAI = &GetAI_npc_frozen_core; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_ice_spear_bunny"; + pNewScript->GetAI = &GetAI_npc_ice_spear_bunny; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_ice_spear_bunny; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/coilfang_reservoir/steam_vault/boss_hydromancer_thespia.cpp b/scripts/outland/coilfang_reservoir/steam_vault/boss_hydromancer_thespia.cpp index 77a246397..109a6c06c 100644 --- a/scripts/outland/coilfang_reservoir/steam_vault/boss_hydromancer_thespia.cpp +++ b/scripts/outland/coilfang_reservoir/steam_vault/boss_hydromancer_thespia.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,13 +44,9 @@ enum SPELL_LUNG_BURST = 31481, SPELL_ENVELOPING_WINDS = 31718, SPELL_SUMMON_ELEMENTALS = 31476, // not sure where to use this - - // Water elemental spells - SPELL_WATER_BOLT_VOLLEY = 34449, - SPELL_WATER_BOLT_VOLLEY_H = 37924, }; -struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI +struct boss_thespiaAI : public ScriptedAI { boss_thespiaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -66,20 +62,20 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI uint32 m_uiLungBurstTimer; uint32 m_uiEnvelopingWindsTimer; - void Reset() + void Reset() override { m_uiLightningCloudTimer = 15000; m_uiLungBurstTimer = urand(15000, 18000); m_uiEnvelopingWindsTimer = urand(20000, 25000); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEAD, m_creature); @@ -87,14 +83,14 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA, DONE); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -105,7 +101,7 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI m_pInstance->SetData(TYPE_HYDROMANCER_THESPIA, IN_PROGRESS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -154,47 +150,11 @@ struct MANGOS_DLL_DECL boss_thespiaAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_coilfang_waterelementalAI : public ScriptedAI -{ - mob_coilfang_waterelementalAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - bool m_bIsRegularMode; - uint32 WaterBoltVolley_Timer; - - void Reset() - { - WaterBoltVolley_Timer = urand(3000, 6000); - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (WaterBoltVolley_Timer < diff) - { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_WATER_BOLT_VOLLEY : SPELL_WATER_BOLT_VOLLEY_H); - WaterBoltVolley_Timer = urand(7000, 12000); - }else WaterBoltVolley_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - CreatureAI* GetAI_boss_thespiaAI(Creature* pCreature) { return new boss_thespiaAI(pCreature); } -CreatureAI* GetAI_mob_coilfang_waterelementalAI(Creature* pCreature) -{ - return new mob_coilfang_waterelementalAI(pCreature); -} - void AddSC_boss_hydromancer_thespia() { Script* pNewScript; @@ -203,9 +163,4 @@ void AddSC_boss_hydromancer_thespia() pNewScript->Name = "boss_hydromancer_thespia"; pNewScript->GetAI = &GetAI_boss_thespiaAI; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_coilfang_waterelemental"; - pNewScript->GetAI = &GetAI_mob_coilfang_waterelementalAI; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/coilfang_reservoir/steam_vault/boss_mekgineer_steamrigger.cpp b/scripts/outland/coilfang_reservoir/steam_vault/boss_mekgineer_steamrigger.cpp index c1fd82616..38a97d5c4 100644 --- a/scripts/outland/coilfang_reservoir/steam_vault/boss_mekgineer_steamrigger.cpp +++ b/scripts/outland/coilfang_reservoir/steam_vault/boss_mekgineer_steamrigger.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Mekgineer_Steamrigger -SD%Complete: 60 -SDComment: Mechanics' interrrupt heal doesn't work very well, also a proper movement needs to be implemented -> summon further away and move towards target to repair. +SD%Complete: 80 +SDComment: Enrage on heroic NYI SDCategory: Coilfang Resevoir, The Steamvault EndScriptData */ @@ -29,24 +29,45 @@ EndContentData */ #include "precompiled.h" #include "steam_vault.h" -#define SAY_MECHANICS -1545007 -#define SAY_AGGRO_1 -1545008 -#define SAY_AGGRO_2 -1545009 -#define SAY_AGGRO_3 -1545010 -#define SAY_AGGRO_4 -1545011 -#define SAY_SLAY_1 -1545012 -#define SAY_SLAY_2 -1545013 -#define SAY_SLAY_3 -1545014 -#define SAY_DEATH -1545015 +enum +{ + SAY_MECHANICS = -1545007, + SAY_AGGRO_1 = -1545008, + SAY_AGGRO_2 = -1545009, + SAY_AGGRO_3 = -1545010, + SAY_AGGRO_4 = -1545011, + SAY_SLAY_1 = -1545012, + SAY_SLAY_2 = -1545013, + SAY_SLAY_3 = -1545014, + SAY_DEATH = -1545015, + + SPELL_SUPER_SHRINK_RAY = 31485, + SPELL_SAW_BLADE = 31486, + SPELL_ELECTRIFIED_NET = 35107, + // SPELL_ENRAGE_H = 1, // current enrage spell not known + + NPC_STEAMRIGGER_MECHANIC = 17951, + + // Mechanic spells + SPELL_DISPEL_MAGIC = 17201, + SPELL_REPAIR = 31532, + SPELL_REPAIR_H = 37936, +}; -#define SPELL_SUPER_SHRINK_RAY 31485 -#define SPELL_SAW_BLADE 31486 -#define SPELL_ELECTRIFIED_NET 35107 -#define SPELL_ENRAGE_H 1 //corrent enrage spell not known +struct SummonLocation +{ + float m_fX, m_fY, m_fZ; +}; -#define ENTRY_STREAMRIGGER_MECHANIC 17951 +// Spawn locations +static const SummonLocation aSteamriggerSpawnLocs[] = +{ + { -316.101f, -166.444f, -7.66f}, + { -348.497f, -161.718f, -7.66f}, + { -331.161f, -112.212f, -7.66f}, +}; -struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI +struct boss_mekgineer_steamriggerAI : public ScriptedAI { boss_mekgineer_steamriggerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -58,28 +79,28 @@ struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 Shrink_Timer; - uint32 Saw_Blade_Timer; - uint32 Electrified_Net_Timer; - bool Summon75; - bool Summon50; - bool Summon25; + uint32 m_uiShrinkTimer; + uint32 m_uiSawBladeTimer; + uint32 m_uiElectrifiedNetTimer; + uint32 m_uiMechanicTimer; + uint8 m_uiMechanicPhaseCount; - void Reset() + void Reset() override { - Shrink_Timer = 20000; - Saw_Blade_Timer = 15000; - Electrified_Net_Timer = 10000; - - Summon75 = false; - Summon50 = false; - Summon25 = false; + m_uiShrinkTimer = 20000; + m_uiSawBladeTimer = 15000; + m_uiElectrifiedNetTimer = 10000; + m_uiMechanicTimer = 20000; + m_uiMechanicPhaseCount = 1; + } - if (m_pInstance && m_creature->isAlive()) - m_pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER,NOT_STARTED); + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, FAIL); } - void JustDied(Unit* Killer) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -87,9 +108,9 @@ struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI m_pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, DONE); } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY_1, m_creature); break; case 1: DoScriptText(SAY_SLAY_2, m_creature); break; @@ -97,9 +118,9 @@ struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI } } - void Aggro(Unit *who) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -110,75 +131,76 @@ struct MANGOS_DLL_DECL boss_mekgineer_steamriggerAI : public ScriptedAI m_pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, IN_PROGRESS); } - //no known summon spells exist + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_STEAMRIGGER_MECHANIC) + pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); + } + + // Wrapper to summon three Mechanics void SummonMechanichs() { DoScriptText(SAY_MECHANICS, m_creature); - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,5,5,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,-5,5,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,-5,-5,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); - - if (urand(0, 1)) - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,5,-7,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); - - if (urand(0, 1)) - DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC,7,-5,0,0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); + for (uint8 i = 0; i < 3; ++i) + m_creature->SummonCreature(NPC_STEAMRIGGER_MECHANIC, aSteamriggerSpawnLocs[i].m_fX, aSteamriggerSpawnLocs[i].m_fY, aSteamriggerSpawnLocs[i].m_fZ, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 240000); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Shrink_Timer < diff) + if (m_uiShrinkTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SUPER_SHRINK_RAY); - Shrink_Timer = 20000; - }else Shrink_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_SUPER_SHRINK_RAY) == CAST_OK) + m_uiShrinkTimer = 20000; + } + else + m_uiShrinkTimer -= uiDiff; - if (Saw_Blade_Timer < diff) + if (m_uiSawBladeTimer < uiDiff) { - if (Unit* target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,1)) - DoCastSpellIfCan(target,SPELL_SAW_BLADE); - else - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SAW_BLADE); + Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); + if (!pTarget) + pTarget = m_creature->getVictim(); - Saw_Blade_Timer = 15000; - } else Saw_Blade_Timer -= diff; - - if (Electrified_Net_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ELECTRIFIED_NET); - Electrified_Net_Timer = 10000; + if (pTarget) + { + if (DoCastSpellIfCan(pTarget, SPELL_SAW_BLADE) == CAST_OK) + m_uiSawBladeTimer = 15000; + } } - else Electrified_Net_Timer -= diff; + else + m_uiSawBladeTimer -= uiDiff; - if (!Summon75) + if (m_uiElectrifiedNetTimer < uiDiff) { - if (m_creature->GetHealthPercent() < 75.0f) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - SummonMechanichs(); - Summon75 = true; + if (DoCastSpellIfCan(pTarget, SPELL_ELECTRIFIED_NET) == CAST_OK) + m_uiElectrifiedNetTimer = 10000; } } + else + m_uiElectrifiedNetTimer -= uiDiff; - if (!Summon50) + // On Heroic mode summon a mechanic at each 20 secs + if (!m_bIsRegularMode) { - if (m_creature->GetHealthPercent() < 50.0f) + if (m_uiMechanicTimer < uiDiff) { - SummonMechanichs(); - Summon50 = true; + m_creature->SummonCreature(NPC_STEAMRIGGER_MECHANIC, aSteamriggerSpawnLocs[2].m_fX, aSteamriggerSpawnLocs[2].m_fY, aSteamriggerSpawnLocs[2].m_fZ, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 240000); + m_uiMechanicTimer = 20000; } + else + m_uiMechanicTimer -= uiDiff; } - if (!Summon25) + if (m_creature->GetHealthPercent() < (100 - 25 * m_uiMechanicPhaseCount)) { - if (m_creature->GetHealthPercent() < 25.0f) - { - SummonMechanichs(); - Summon25 = true; - } + SummonMechanichs(); + ++m_uiMechanicPhaseCount; } DoMeleeAttackIfReady(); @@ -190,14 +212,7 @@ CreatureAI* GetAI_boss_mekgineer_steamrigger(Creature* pCreature) return new boss_mekgineer_steamriggerAI(pCreature); } -#define SPELL_DISPEL_MAGIC 17201 -#define SPELL_REPAIR 31532 -#define SPELL_REPAIR_H 37936 - -#define MAX_REPAIR_RANGE (13.0f) //we should be at least at this range for repair -#define MIN_REPAIR_RANGE (7.0f) //we can stop movement at this range to repair but not required - -struct MANGOS_DLL_DECL mob_steamrigger_mechanicAI : public ScriptedAI +struct mob_steamrigger_mechanicAI : public ScriptedAI { mob_steamrigger_mechanicAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -209,48 +224,45 @@ struct MANGOS_DLL_DECL mob_steamrigger_mechanicAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - uint32 Repair_Timer; + bool m_bCanStartAttack; - void Reset() + void Reset() override { - Repair_Timer = 2000; + m_bCanStartAttack = false; } - void MoveInLineOfSight(Unit* who) + void AttackStart(Unit* pWho) override { - //react only if attacked - return; + // Trigger attack only for players + if (pWho->GetTypeId() != TYPEID_PLAYER) + return; + + m_creature->InterruptNonMeleeSpells(false); + ScriptedAI::AttackStart(pWho); + m_bCanStartAttack = true; } - void UpdateAI(const uint32 diff) + void MoveInLineOfSight(Unit* pWho) override { - if (Repair_Timer < diff) + // Return if already in combat + if (m_bCanStartAttack) + return; + + // Don't attack players unless attacked + if (pWho->GetEntry() == NPC_STEAMRIGGER) { - if (m_pInstance && m_pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == IN_PROGRESS) + if (m_pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == IN_PROGRESS) { - if (Creature* pMekgineer = m_pInstance->GetSingleCreatureFromStorage(NPC_STEAMRIGGER)) - { - if (m_creature->IsWithinDistInMap(pMekgineer, MAX_REPAIR_RANGE)) - { - //are we already channeling? Doesn't work very well, find better check? - if (!m_creature->GetUInt32Value(UNIT_CHANNEL_SPELL)) - { - //m_creature->GetMotionMaster()->MovementExpired(); - //m_creature->GetMotionMaster()->MoveIdle(); - - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_REPAIR : SPELL_REPAIR_H, CAST_TRIGGERED); - } - Repair_Timer = 5000; - } - else - { - //m_creature->GetMotionMaster()->MovementExpired(); - //m_creature->GetMotionMaster()->MoveFollow(pMekgineer,0,0); - } - } - }else Repair_Timer = 5000; - }else Repair_Timer -= diff; + // Channel the repair spell on Steamrigger + // This will also stop creature movement and will allow them to continue to follow the boss after channeling is finished or the boss is out of range + if (m_creature->IsWithinDistInMap(pWho, 2 * INTERACTION_DISTANCE)) + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_REPAIR : SPELL_REPAIR_H); + } + } + } + void UpdateAI(const uint32 /*uiDiff*/) override + { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/outland/coilfang_reservoir/steam_vault/boss_warlord_kalithresh.cpp b/scripts/outland/coilfang_reservoir/steam_vault/boss_warlord_kalithresh.cpp index d18d66fd8..3b60d5d9e 100644 --- a/scripts/outland/coilfang_reservoir/steam_vault/boss_warlord_kalithresh.cpp +++ b/scripts/outland/coilfang_reservoir/steam_vault/boss_warlord_kalithresh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,10 +39,9 @@ enum SPELL_IMPALE = 39061, SPELL_WARLORDS_RAGE = 37081, // triggers 36453 SPELL_WARLORDS_RAGE_NAGA = 31543, // triggers 37076 - SPELL_WARLORDS_RAGE_AURA = 36453, }; -struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI +struct boss_warlord_kalithreshAI : public ScriptedAI { boss_warlord_kalithreshAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -62,7 +61,7 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI bool m_bHasTaunted; - void Reset() + void Reset() override { m_uiReflectionTimer = 15000; m_uiImpaleTimer = urand(7000, 14000); @@ -70,15 +69,15 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI m_uiRageCastTimer = 0; } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, FAIL); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -89,12 +88,12 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -102,7 +101,7 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI m_pInstance->SetData(TYPE_WARLORD_KALITHRESH, DONE); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 40.0f)) { @@ -113,7 +112,7 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void MovementInform(uint32 uiMoveType, uint32 uiPointId) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) return; @@ -122,7 +121,7 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI m_uiRageCastTimer = 1000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -141,9 +140,7 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI if (Creature* pDistiller = m_creature->GetMap()->GetCreature(m_distillerGuid)) { pDistiller->CastSpell(pDistiller, SPELL_WARLORDS_RAGE_NAGA, true); - // ToDo: check with DB if this is really needed pDistiller->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pDistiller->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } } } @@ -152,31 +149,21 @@ struct MANGOS_DLL_DECL boss_warlord_kalithreshAI : public ScriptedAI } // Move to closest distiller - if (m_uiRageTimer) + if (m_uiRageTimer < uiDiff) { - if (m_uiRageTimer <= uiDiff) + if (Creature* pDistiller = GetClosestCreatureWithEntry(m_creature, NPC_NAGA_DISTILLER, 100.0f)) { - // If the boss already has the rage aura we don't have to do this again - if (m_creature->HasAura(SPELL_WARLORDS_RAGE_AURA)) - { - m_uiRageTimer = 0; - return; - } - - if (Creature* pDistiller = GetClosestCreatureWithEntry(m_creature, NPC_NAGA_DISTILLER, 100.0f)) - { - float fX, fY, fZ; - pDistiller->GetContactPoint(m_creature, fX, fY, fZ, INTERACTION_DISTANCE); - m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); - SetCombatMovement(false); - m_distillerGuid = pDistiller->GetObjectGuid(); - } - - m_uiRageTimer = urand(35000, 45000); + float fX, fY, fZ; + pDistiller->GetContactPoint(m_creature, fX, fY, fZ, INTERACTION_DISTANCE); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + SetCombatMovement(false); + m_distillerGuid = pDistiller->GetObjectGuid(); } - else - m_uiRageTimer -= uiDiff; + + m_uiRageTimer = urand(35000, 45000); } + else + m_uiRageTimer -= uiDiff; // Reflection_Timer if (m_uiReflectionTimer < uiDiff) @@ -224,20 +211,18 @@ bool EffectAuraDummy_spell_aura_dummy_warlord_rage(const Aura* pAura, bool bAppl return true; } -struct MANGOS_DLL_DECL mob_naga_distillerAI : public Scripted_NoMovementAI +struct mob_naga_distillerAI : public Scripted_NoMovementAI { mob_naga_distillerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - void Reset() + void Reset() override { - // ToDo - move to DB m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void MoveInLineOfSight(Unit* pWho) { } - void AttackStart(Unit* pWho) { } - void UpdateAI(const uint32 uiDiff) { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } }; CreatureAI* GetAI_boss_warlord_kalithresh(Creature* pCreature) diff --git a/scripts/outland/coilfang_reservoir/steam_vault/instance_steam_vault.cpp b/scripts/outland/coilfang_reservoir/steam_vault/instance_steam_vault.cpp index d0394f8c9..ca3a978a8 100644 --- a/scripts/outland/coilfang_reservoir/steam_vault/instance_steam_vault.cpp +++ b/scripts/outland/coilfang_reservoir/steam_vault/instance_steam_vault.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,20 +30,19 @@ EndScriptData */ 3 - Warlord Kalithresh Event */ -bool GOUse_go_main_chambers_access_panel(Player* pPlayer, GameObject* pGo) +bool GOUse_go_main_chambers_access_panel(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); if (!pInstance) - return false; + return true; - if (pGo->GetEntry() == GO_ACCESS_PANEL_HYDRO && pInstance->GetData(TYPE_HYDROMANCER_THESPIA) == DONE) + if (pGo->GetEntry() == GO_ACCESS_PANEL_HYDRO) pInstance->SetData(TYPE_HYDROMANCER_THESPIA, SPECIAL); - - if (pGo->GetEntry() == GO_ACCESS_PANEL_MEK && pInstance->GetData(TYPE_MEKGINEER_STEAMRIGGER) == DONE) + else if (pGo->GetEntry() == GO_ACCESS_PANEL_MEK) pInstance->SetData(TYPE_MEKGINEER_STEAMRIGGER, SPECIAL); - return true; + return false; } instance_steam_vault::instance_steam_vault(Map* pMap) : ScriptedInstance(pMap) @@ -58,25 +57,38 @@ void instance_steam_vault::Initialize() void instance_steam_vault::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_STEAMRIGGER: case NPC_KALITHRESH: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; + case NPC_NAGA_DISTILLER: + m_lNagaDistillerGuidList.push_back(pCreature->GetObjectGuid()); + break; } } void instance_steam_vault::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_MAIN_CHAMBERS_DOOR: + if (m_auiEncounter[TYPE_HYDROMANCER_THESPIA] == SPECIAL && m_auiEncounter[TYPE_MEKGINEER_STEAMRIGGER] == SPECIAL) + pGo->SetGoState(GO_STATE_ACTIVE); + break; case GO_ACCESS_PANEL_HYDRO: + if (m_auiEncounter[TYPE_HYDROMANCER_THESPIA] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + break; case GO_ACCESS_PANEL_MEK: - m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + if (m_auiEncounter[TYPE_MEKGINEER_STEAMRIGGER] == DONE) + pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); break; + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } void instance_steam_vault::OnCreatureDeath(Creature* pCreature) @@ -94,46 +106,85 @@ void instance_steam_vault::SetData(uint32 uiType, uint32 uiData) switch (uiType) { case TYPE_HYDROMANCER_THESPIA: + if (uiData == DONE) + DoToggleGameObjectFlags(GO_ACCESS_PANEL_HYDRO, GO_FLAG_NO_INTERACT, false); if (uiData == SPECIAL) { - DoUseDoorOrButton(GO_ACCESS_PANEL_HYDRO); - if (GetData(TYPE_MEKGINEER_STEAMRIGGER) == SPECIAL) DoUseDoorOrButton(GO_MAIN_CHAMBERS_DOOR); - - debug_log("SD2: Instance Steamvault: Access panel used."); } - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_MEKGINEER_STEAMRIGGER: + if (uiData == DONE) + DoToggleGameObjectFlags(GO_ACCESS_PANEL_MEK, GO_FLAG_NO_INTERACT, false); if (uiData == SPECIAL) { - DoUseDoorOrButton(GO_ACCESS_PANEL_MEK); - if (GetData(TYPE_HYDROMANCER_THESPIA) == SPECIAL) DoUseDoorOrButton(GO_MAIN_CHAMBERS_DOOR); - - debug_log("SD2: Instance Steamvault: Access panel used."); } - m_auiEncounter[1] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_WARLORD_KALITHRESH: - m_auiEncounter[2] = uiData; + DoUseDoorOrButton(GO_MAIN_CHAMBERS_DOOR); + if (uiData == FAIL) + { + // Reset Distiller flags - respawn is handled by DB + for (GuidList::const_iterator itr = m_lNagaDistillerGuidList.begin(); itr != m_lNagaDistillerGuidList.end(); ++itr) + { + if (Creature* pDistiller = instance->GetCreature(*itr)) + { + if (!pDistiller->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + pDistiller->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + } + } + m_auiEncounter[uiType] = uiData; break; } + + if (uiData == DONE || uiData == SPECIAL) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_steam_vault::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; } -uint32 instance_steam_vault::GetData(uint32 uiType) +void instance_steam_vault::Load(const char* chrIn) { - switch(uiType) + if (!chrIn) { - case TYPE_HYDROMANCER_THESPIA: return m_auiEncounter[0]; - case TYPE_MEKGINEER_STEAMRIGGER: return m_auiEncounter[1]; - case TYPE_WARLORD_KALITHRESH: return m_auiEncounter[2]; + OUT_LOAD_INST_DATA_FAIL; + return; + } - default: - return 0; + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; } + + OUT_LOAD_INST_DATA_COMPLETE; } InstanceData* GetInstanceData_instance_steam_vault(Map* pMap) diff --git a/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h b/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h index d228c401c..a8db93d76 100644 --- a/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h +++ b/scripts/outland/coilfang_reservoir/steam_vault/steam_vault.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -9,37 +9,43 @@ enum { MAX_ENCOUNTER = 3, - TYPE_HYDROMANCER_THESPIA = 1, - TYPE_MEKGINEER_STEAMRIGGER = 2, - TYPE_WARLORD_KALITHRESH = 3, + TYPE_HYDROMANCER_THESPIA = 0, + TYPE_MEKGINEER_STEAMRIGGER = 1, + TYPE_WARLORD_KALITHRESH = 2, NPC_NAGA_DISTILLER = 17954, NPC_STEAMRIGGER = 17796, NPC_KALITHRESH = 17798, - //NPC_THESPIA = 17797, + // NPC_THESPIA = 17797, GO_MAIN_CHAMBERS_DOOR = 183049, GO_ACCESS_PANEL_HYDRO = 184125, GO_ACCESS_PANEL_MEK = 184126, }; -class MANGOS_DLL_DECL instance_steam_vault : public ScriptedInstance +class instance_steam_vault : public ScriptedInstance { public: instance_steam_vault(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + GuidList m_lNagaDistillerGuidList; }; #endif diff --git a/scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp b/scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp index 1a3db2d02..65b6bd443 100644 --- a/scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp +++ b/scripts/outland/coilfang_reservoir/underbog/boss_hungarfen.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,7 +37,7 @@ enum NPC_UNDERBOG_MUSHROOM = 17990, }; -struct MANGOS_DLL_DECL boss_hungarfenAI : public ScriptedAI +struct boss_hungarfenAI : public ScriptedAI { boss_hungarfenAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -50,24 +50,24 @@ struct MANGOS_DLL_DECL boss_hungarfenAI : public ScriptedAI uint32 m_uiMushroomTimer; uint32 m_uiAcidGeyserTimer; - void Reset() + void Reset() override { m_bHasSpores = false; - m_uiMushroomTimer = 5000; // 1 mushroom after 5s, then one per 10s. This should be different in heroic mode + m_uiMushroomTimer = 5000; // 1 mushroom after 5s, then one per 10s. This should be different in heroic mode m_uiAcidGeyserTimer = 10000; } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoCastSpellIfCan(m_creature, SPELL_DESPAWN_MUSHROOMS, CAST_TRIGGERED); } - void JustReachedHome() + void JustReachedHome() override { DoCastSpellIfCan(m_creature, SPELL_DESPAWN_MUSHROOMS, CAST_TRIGGERED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -109,7 +109,7 @@ CreatureAI* GetAI_boss_hungarfen(Creature* pCreature) return new boss_hungarfenAI(pCreature); } -struct MANGOS_DLL_DECL mob_underbog_mushroomAI : public ScriptedAI +struct mob_underbog_mushroomAI : public ScriptedAI { mob_underbog_mushroomAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -117,7 +117,7 @@ struct MANGOS_DLL_DECL mob_underbog_mushroomAI : public ScriptedAI uint32 m_uiShrinkTimer; uint32 m_uiSporeTimer; - void Reset() + void Reset() override { m_uiGrowTimer = 1000; m_uiSporeTimer = 15000; @@ -126,10 +126,10 @@ struct MANGOS_DLL_DECL mob_underbog_mushroomAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_PUTRID_MUSHROOM); } - void MoveInLineOfSight(Unit* pWho) { return; } - void AttackStart(Unit* pWho) { return; } + void MoveInLineOfSight(Unit* /*pWho*/) override { return; } + void AttackStart(Unit* /*pWho*/) override { return; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiSporeTimer) { diff --git a/scripts/outland/gruuls_lair/boss_gruul.cpp b/scripts/outland/gruuls_lair/boss_gruul.cpp index 63e00f4c3..aabf3ac66 100644 --- a/scripts/outland/gruuls_lair/boss_gruul.cpp +++ b/scripts/outland/gruuls_lair/boss_gruul.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -40,19 +40,19 @@ enum SPELL_GROWTH = 36300, SPELL_CAVE_IN = 36240, - SPELL_GROUND_SLAM = 33525, //AoE Ground Slam applying Ground Slam to everyone with a script effect (most likely the knock back, we can code it to a set knockback) + SPELL_GROUND_SLAM = 33525, // AoE Ground Slam applying Ground Slam to everyone with a script effect (most likely the knock back, we can code it to a set knockback) SPELL_REVERBERATION = 36297, SPELL_SHATTER = 33654, SPELL_SHATTER_EFFECT = 33671, SPELL_HURTFUL_STRIKE = 33813, - SPELL_STONED = 33652, //Spell is self cast by target + SPELL_STONED = 33652, // Spell is self cast by target SPELL_MAGNETIC_PULL = 28337, - SPELL_KNOCK_BACK = 24199 //Knockback spell until correct implementation is made + SPELL_KNOCK_BACK = 24199 // Knockback spell until correct implementation is made }; -struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI +struct boss_gruulAI : public ScriptedAI { boss_gruulAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -62,45 +62,43 @@ struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiGrowth_Timer; - uint32 m_uiCaveIn_Timer; - uint32 m_uiCaveIn_StaticTimer; + uint32 m_uiGrowthTimer; + uint32 m_uiCaveInTimer; + uint32 m_uiCaveInStaticTimer; uint32 m_uiGroundSlamTimer; - uint32 m_uiHurtfulStrike_Timer; - uint32 m_uiReverberation_Timer; + uint32 m_uiHurtfulStrikeTimer; + uint32 m_uiReverberationTimer; bool m_bPerformingGroundSlam; - void Reset() + void Reset() override { - m_uiGrowth_Timer = 30000; - m_uiCaveIn_Timer = 27000; - m_uiCaveIn_StaticTimer = 30000; + m_uiGrowthTimer = 30000; + m_uiCaveInTimer = 27000; + m_uiCaveInStaticTimer = 30000; m_uiGroundSlamTimer = 35000; - m_uiHurtfulStrike_Timer = 8000; - m_uiReverberation_Timer = 60000+45000; + m_uiHurtfulStrikeTimer = 8000; + m_uiReverberationTimer = 60000 + 45000; m_bPerformingGroundSlam = false; } - void Aggro(Unit *pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - if (!m_pInstance) - return; - - m_pInstance->SetData(TYPE_GRUUL_EVENT, IN_PROGRESS); + if (m_pInstance) + m_pInstance->SetData(TYPE_GRUUL_EVENT, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_GRUUL_EVENT, NOT_STARTED); + m_pInstance->SetData(TYPE_GRUUL_EVENT, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -108,25 +106,23 @@ struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - if (!m_pInstance) - return; - - m_pInstance->SetData(TYPE_GRUUL_EVENT, DONE); + if (m_pInstance) + m_pInstance->SetData(TYPE_GRUUL_EVENT, DONE); } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - //This to emulate effect1 (77) of SPELL_GROUND_SLAM, knock back to any direction - //It's initially wrong, since this will cause fall damage, which is by comments, not intended. + // This to emulate effect1 (77) of SPELL_GROUND_SLAM, knock back to any direction + // It's initially wrong, since this will cause fall damage, which is by comments, not intended. if (pSpell->Id == SPELL_GROUND_SLAM) { if (pTarget->GetTypeId() == TYPEID_PLAYER) { - switch(urand(0, 1)) + switch (urand(0, 1)) { case 0: pTarget->CastSpell(pTarget, SPELL_MAGNETIC_PULL, true, NULL, NULL, m_creature->GetObjectGuid()); break; case 1: pTarget->CastSpell(pTarget, SPELL_KNOCK_BACK, true, NULL, NULL, m_creature->GetObjectGuid()); break; @@ -134,21 +130,21 @@ struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI } } - //this part should be in mangos + // this part should be in mangos if (pSpell->Id == SPELL_SHATTER) { - //this spell must have custom handling in mangos, dealing damage based on distance + // this spell must have custom handling in mangos, dealing damage based on distance pTarget->CastSpell(pTarget, SPELL_SHATTER_EFFECT, true); if (pTarget->HasAura(SPELL_STONED)) pTarget->RemoveAurasDueToSpell(SPELL_STONED); - //clear this, if we are still performing + // clear this, if we are still performing if (m_bPerformingGroundSlam) { m_bPerformingGroundSlam = false; - //and correct movement, if not already + // and correct movement, if not already if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) { if (m_creature->getVictim()) @@ -158,35 +154,37 @@ struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - // Growth // Gruul can cast this spell up to 30 times - if (m_uiGrowth_Timer < uiDiff) + if (m_uiGrowthTimer < uiDiff) { - DoScriptText(EMOTE_GROW, m_creature); - DoCastSpellIfCan(m_creature,SPELL_GROWTH); - m_uiGrowth_Timer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_GROWTH) == CAST_OK) + { + DoScriptText(EMOTE_GROW, m_creature); + m_uiGrowthTimer = 30000; + } } else - m_uiGrowth_Timer -= uiDiff; + m_uiGrowthTimer -= uiDiff; if (m_bPerformingGroundSlam) { if (m_uiGroundSlamTimer < uiDiff) { - m_uiGroundSlamTimer = 120000; - m_uiHurtfulStrike_Timer = 8000; - - //Give a little time to the players to undo the damage from shatter - if (m_uiReverberation_Timer < 10000) - m_uiReverberation_Timer += 10000; + if (DoCastSpellIfCan(m_creature, SPELL_SHATTER) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SHATTER1 : SAY_SHATTER2, m_creature); + m_uiGroundSlamTimer = 120000; + m_uiHurtfulStrikeTimer = 8000; - DoCastSpellIfCan(m_creature, SPELL_SHATTER); + // Give a little time to the players to undo the damage from shatter + if (m_uiReverberationTimer < 10000) + m_uiReverberationTimer += 10000; + } } else m_uiGroundSlamTimer -= uiDiff; @@ -194,52 +192,56 @@ struct MANGOS_DLL_DECL boss_gruulAI : public ScriptedAI else { // Hurtful Strike - if (m_uiHurtfulStrike_Timer < uiDiff) + if (m_uiHurtfulStrikeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1, SPELL_HURTFUL_STRIKE, SELECT_FLAG_PLAYER)) DoCastSpellIfCan(pTarget, SPELL_HURTFUL_STRIKE); else DoCastSpellIfCan(m_creature->getVictim(), SPELL_HURTFUL_STRIKE); - m_uiHurtfulStrike_Timer = 8000; + m_uiHurtfulStrikeTimer = 8000; } else - m_uiHurtfulStrike_Timer -= uiDiff; + m_uiHurtfulStrikeTimer -= uiDiff; // Reverberation - if (m_uiReverberation_Timer < uiDiff) + if (m_uiReverberationTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_REVERBERATION, CAST_TRIGGERED); - m_uiReverberation_Timer = urand(15000, 25000); + if (DoCastSpellIfCan(m_creature, SPELL_REVERBERATION) == CAST_OK) + m_uiReverberationTimer = urand(15000, 25000); } else - m_uiReverberation_Timer -= uiDiff; + m_uiReverberationTimer -= uiDiff; // Cave In - if (m_uiCaveIn_Timer < uiDiff) + if (m_uiCaveInTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) - DoCastSpellIfCan(pTarget,SPELL_CAVE_IN); - - if (m_uiCaveIn_StaticTimer >= 4000) - m_uiCaveIn_StaticTimer -= 2000; - - m_uiCaveIn_Timer = m_uiCaveIn_StaticTimer; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CAVE_IN) == CAST_OK) + { + if (m_uiCaveInStaticTimer >= 4000) + m_uiCaveInStaticTimer -= 2000; + m_uiCaveInTimer = m_uiCaveInStaticTimer; + } + } } else - m_uiCaveIn_Timer -= uiDiff; + m_uiCaveInTimer -= uiDiff; // Ground Slam, Gronn Lord's Grasp, Stoned, Shatter if (m_uiGroundSlamTimer < uiDiff) { - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - - m_bPerformingGroundSlam = true; - m_uiGroundSlamTimer = 10000; + if (DoCastSpellIfCan(m_creature, SPELL_GROUND_SLAM) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SLAM1 : SAY_SLAM2, m_creature); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); - DoCastSpellIfCan(m_creature, SPELL_GROUND_SLAM); + m_bPerformingGroundSlam = true; + m_uiGroundSlamTimer = 10000; + } } else m_uiGroundSlamTimer -= uiDiff; diff --git a/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp b/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp index 31495586b..84533e02e 100644 --- a/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp +++ b/scripts/outland/gruuls_lair/boss_high_king_maulgar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -50,32 +50,25 @@ enum SPELL_DEATH_COIL = 33130, SPELL_SUMMON_WILD_FELHUNTER = 33131, - //Kiggler the Crazed Spells + // Kiggler the Crazed Spells SPELL_GREATER_POLYMORPH = 33173, SPELL_LIGHTNING_BOLT = 36152, SPELL_ARCANE_SHOCK = 33175, SPELL_ARCANE_EXPLOSION = 33237, - //Blindeye the Seer Spells + // Blindeye the Seer Spells SPELL_GREATER_PW_SHIELD = 33147, SPELL_HEAL = 33144, SPELL_PRAYEROFHEALING = 33152, - //Krosh Firehand Spells + // Krosh Firehand Spells SPELL_GREATER_FIREBALL = 33051, SPELL_SPELLSHIELD = 33054, SPELL_BLAST_WAVE = 33061, - - MAX_COUNCIL = 4 }; -const float DISTANCE_KIGGLER = 20.0f; -const float DISTANCE_KROSH = 30.0f; - -static const uint32 aCouncilMember[] = {NPC_BLINDEYE, NPC_KIGGLER, NPC_KROSH, NPC_OLM}; - -//High King Maulgar AI -struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI +// High King Maulgar AI +struct boss_high_king_maulgarAI : public ScriptedAI { boss_high_king_maulgarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -85,48 +78,35 @@ struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiArcingSmash_Timer; - uint32 m_uiMightyBlow_Timer; - uint32 m_uiWhirlwind_Timer; - uint32 m_uiCharge_Timer; - uint32 m_uiFear_Timer; + uint32 m_uiArcingSmashTimer; + uint32 m_uiMightyBlowTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiChargeTimer; + uint32 m_uiFearTimer; uint32 m_uiCouncilDeathCount; bool m_bPhase2; - void Reset() + void Reset() override { - m_uiArcingSmash_Timer = urand(8000, 14000); - m_uiMightyBlow_Timer = urand(15000, 25000); - m_uiWhirlwind_Timer = 30000; - m_uiCharge_Timer = 2000; - m_uiFear_Timer = urand(10000, 25000); + m_uiArcingSmashTimer = urand(8000, 14000); + m_uiMightyBlowTimer = urand(15000, 25000); + m_uiWhirlwindTimer = 30000; + m_uiChargeTimer = 2000; + m_uiFearTimer = urand(10000, 25000); m_uiCouncilDeathCount = 0; m_bPhase2 = false; } - void JustReachedHome() + void JustReachedHome() override { - if (!m_pInstance) - return; - - for (uint8 i = 0; i < MAX_COUNCIL; ++i) - { - if (Creature* pCreature = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) - { - if (!pCreature->isAlive()) - pCreature->Respawn(); - else if (pCreature->getVictim()) - pCreature->AI()->EnterEvadeMode(); - } - } - - m_pInstance->SetData(TYPE_MAULGAR_EVENT, FAIL); + if (m_pInstance) + m_pInstance->SetData(TYPE_MAULGAR_EVENT, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -134,41 +114,26 @@ struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); - if (!m_pInstance) - return; - - //we risk being DONE before adds are in fact dead - m_pInstance->SetData(TYPE_MAULGAR_EVENT, DONE); + // Set data to Special on Death + if (m_pInstance) + m_pInstance->SetData(TYPE_MAULGAR_EVENT, SPECIAL); } - void Aggro(Unit *pWho) + void Aggro(Unit* /*pWho*/) override { - if (!m_pInstance) - return; - DoScriptText(SAY_AGGRO, m_creature); - m_pInstance->SetData(TYPE_MAULGAR_EVENT, IN_PROGRESS); - - for (uint8 i = 0; i < MAX_COUNCIL; ++i) - { - if (Creature* pCreature = m_pInstance->GetSingleCreatureFromStorage(aCouncilMember[i])) - { - if (!pCreature->isAlive()) - pCreature->Respawn(); - if (!pCreature->getVictim()) - pCreature->AI()->AttackStart(pWho); - } - } + if (m_pInstance) + m_pInstance->SetData(TYPE_MAULGAR_EVENT, IN_PROGRESS); } void EventCouncilDeath() { - switch(++m_uiCouncilDeathCount) + switch (++m_uiCouncilDeathCount) { case 1: DoScriptText(SAY_OGRE_DEATH1, m_creature); break; case 2: DoScriptText(SAY_OGRE_DEATH2, m_creature); break; @@ -177,68 +142,64 @@ struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiArcingSmash_Timer - if (m_uiArcingSmash_Timer < uiDiff) + if (m_uiArcingSmashTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_ARCING_SMASH); - m_uiArcingSmash_Timer = urand(8000, 12000); + if (DoCastSpellIfCan(m_creature, SPELL_ARCING_SMASH) == CAST_OK) + m_uiArcingSmashTimer = urand(8000, 12000); } else - m_uiArcingSmash_Timer -= uiDiff; + m_uiArcingSmashTimer -= uiDiff; - //m_uiWhirlwind_Timer - if (m_uiWhirlwind_Timer < uiDiff) + if (m_uiWhirlwindTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND); - m_uiWhirlwind_Timer = urand(30000, 40000); + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + m_uiWhirlwindTimer = urand(30000, 40000); } else - m_uiWhirlwind_Timer -= uiDiff; + m_uiWhirlwindTimer -= uiDiff; - //m_uiMightyBlow_Timer - if (m_uiMightyBlow_Timer < uiDiff) + if (m_uiMightyBlowTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTY_BLOW); - m_uiMightyBlow_Timer = urand(20000, 35000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTY_BLOW) == CAST_OK) + m_uiMightyBlowTimer = urand(20000, 35000); } else - m_uiMightyBlow_Timer -= uiDiff; + m_uiMightyBlowTimer -= uiDiff; - //Entering Phase 2 if (!m_bPhase2 && m_creature->GetHealthPercent() < 50.0f) { - m_bPhase2 = true; - DoScriptText(SAY_ENRAGE, m_creature); - DoCastSpellIfCan(m_creature, SPELL_FLURRY); + if (DoCastSpellIfCan(m_creature, SPELL_FLURRY) == CAST_OK) + { + DoScriptText(SAY_ENRAGE, m_creature); + m_bPhase2 = true; + } } if (m_bPhase2) { - //m_uiCharge_Timer - if (m_uiCharge_Timer < uiDiff) + if (m_uiChargeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - DoCastSpellIfCan(pTarget, SPELL_CHARGE); - - m_uiCharge_Timer = urand(14000, 20000); + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) + m_uiChargeTimer = urand(14000, 20000); + } } else - m_uiCharge_Timer -= uiDiff; + m_uiChargeTimer -= uiDiff; - //m_uiFear_Timer - if (m_uiFear_Timer < uiDiff) + if (m_uiFearTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FEAR); - m_uiFear_Timer = urand(20000, 35000); + if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = urand(20000, 35000); } else - m_uiFear_Timer -= uiDiff; + m_uiFearTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -246,7 +207,7 @@ struct MANGOS_DLL_DECL boss_high_king_maulgarAI : public ScriptedAI }; // Base AI for every council member -struct MANGOS_DLL_DECL Council_Base_AI : public ScriptedAI +struct Council_Base_AI : public ScriptedAI { Council_Base_AI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -255,27 +216,7 @@ struct MANGOS_DLL_DECL Council_Base_AI : public ScriptedAI ScriptedInstance* m_pInstance; - void JustReachedHome() - { - if (!m_pInstance) - return; - - Creature* pMaulgar = m_pInstance->GetSingleCreatureFromStorage(NPC_MAULGAR); - if (pMaulgar && pMaulgar->isAlive() && pMaulgar->getVictim()) - pMaulgar->AI()->EnterEvadeMode(); - } - - void Aggro(Unit *pWho) - { - if (!m_pInstance) - return; - - Creature* pMaulgar = m_pInstance->GetSingleCreatureFromStorage(NPC_MAULGAR); - if (pMaulgar && pMaulgar->isAlive() && !pMaulgar->getVictim()) - pMaulgar->AI()->AttackStart((pWho)); - } - - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { if (!m_pInstance) return; @@ -286,81 +227,80 @@ struct MANGOS_DLL_DECL Council_Base_AI : public ScriptedAI if (boss_high_king_maulgarAI* pMaulgarAI = dynamic_cast(pMaulgar->AI())) pMaulgarAI->EventCouncilDeath(); } + + // Set data to Special on Death + m_pInstance->SetData(TYPE_MAULGAR_EVENT, SPECIAL); } }; -//Olm The Summoner AI -struct MANGOS_DLL_DECL boss_olm_the_summonerAI : public Council_Base_AI +// Olm The Summoner AI +struct boss_olm_the_summonerAI : public Council_Base_AI { boss_olm_the_summonerAI(Creature* pCreature) : Council_Base_AI(pCreature) {Reset();} - uint32 m_uiDarkDecay_Timer; - uint32 m_uiDeathCoil_Timer; - uint32 m_uiSummon_Timer; + uint32 m_uiDarkDecayTimer; + uint32 m_uiDeathCoilTimer; + uint32 m_uiSummonTimer; - void Reset() + void Reset() override { - m_uiDarkDecay_Timer = 18000; - m_uiDeathCoil_Timer = 14000; - m_uiSummon_Timer = 10000; + m_uiDarkDecayTimer = 18000; + m_uiDeathCoilTimer = 14000; + m_uiSummonTimer = 10000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiDarkDecay_Timer - if (m_uiDarkDecay_Timer < uiDiff) + if (m_uiDarkDecayTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_DECAY); - m_uiDarkDecay_Timer = 20000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DARK_DECAY) == CAST_OK) + m_uiDarkDecayTimer = 20000; } else - m_uiDarkDecay_Timer -= uiDiff; + m_uiDarkDecayTimer -= uiDiff; - //m_uiDeathCoil_Timer - if (m_uiDeathCoil_Timer < uiDiff) + if (m_uiDeathCoilTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_COIL); - m_uiDeathCoil_Timer = urand(8000, 13000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DEATH_COIL) == CAST_OK) + m_uiDeathCoilTimer = urand(8000, 13000); } else - m_uiDeathCoil_Timer -= uiDiff; + m_uiDeathCoilTimer -= uiDiff; - //m_uiSummon_Timer - if (m_uiSummon_Timer < uiDiff) + if (m_uiSummonTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SUMMON_WILD_FELHUNTER); - m_uiSummon_Timer = urand(25000, 35000); + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_WILD_FELHUNTER) == CAST_OK) + m_uiSummonTimer = urand(25000, 35000); } else - m_uiSummon_Timer -= uiDiff; + m_uiSummonTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Kiggler The Crazed AI -struct MANGOS_DLL_DECL boss_kiggler_the_crazedAI : public Council_Base_AI +// Kiggler The Crazed AI +struct boss_kiggler_the_crazedAI : public Council_Base_AI { boss_kiggler_the_crazedAI(Creature* pCreature) : Council_Base_AI(pCreature) {Reset();} - uint32 m_uiGreatherPolymorph_Timer; - uint32 m_uiLightningBolt_Timer; - uint32 m_uiArcaneShock_Timer; - uint32 m_uiArcaneExplosion_Timer; + uint32 m_uiGreatherPolymorphTimer; + uint32 m_uiLightningBoltTimer; + uint32 m_uiArcaneShockTimer; + uint32 m_uiArcaneExplosionTimer; - void Reset() + void Reset() override { - m_uiGreatherPolymorph_Timer = 15000; - m_uiLightningBolt_Timer = 10000; - m_uiArcaneShock_Timer = 20000; - m_uiArcaneExplosion_Timer = 30000; + m_uiGreatherPolymorphTimer = 15000; + m_uiLightningBoltTimer = 10000; + m_uiArcaneShockTimer = 20000; + m_uiArcaneExplosionTimer = 30000; } - void SpellHitTarget(Unit* pVictim, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pVictim, const SpellEntry* pSpell) override { // Spell currently not supported by core. Knock back effect should lower threat // Workaround in script: @@ -369,11 +309,11 @@ struct MANGOS_DLL_DECL boss_kiggler_the_crazedAI : public Council_Base_AI if (pVictim->GetTypeId() != TYPEID_PLAYER) return; - m_creature->getThreatManager().modifyThreatPercent(pVictim,-75); + m_creature->getThreatManager().modifyThreatPercent(pVictim, -75); } } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!pWho) return; @@ -384,126 +324,123 @@ struct MANGOS_DLL_DECL boss_kiggler_the_crazedAI : public Council_Base_AI m_creature->SetInCombatWith(pWho); pWho->SetInCombatWith(m_creature); - m_creature->GetMotionMaster()->MoveChase(pWho, DISTANCE_KIGGLER); + m_creature->GetMotionMaster()->MoveChase(pWho, 20.0f); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiGreatherPolymorph_Timer < uiDiff) + if (m_uiGreatherPolymorphTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_GREATER_POLYMORPH); - m_uiGreatherPolymorph_Timer = urand(15000, 20000); + { + if (DoCastSpellIfCan(pTarget, SPELL_GREATER_POLYMORPH) == CAST_OK) + m_uiGreatherPolymorphTimer = urand(15000, 20000); + } } else - m_uiGreatherPolymorph_Timer -= uiDiff; + m_uiGreatherPolymorphTimer -= uiDiff; - //LightningBolt_Timer - if (m_uiLightningBolt_Timer < uiDiff) + if (m_uiLightningBoltTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); - m_uiLightningBolt_Timer = urand(2500, 4000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_LIGHTNING_BOLT) == CAST_OK) + m_uiLightningBoltTimer = urand(2500, 4000); } else - m_uiLightningBolt_Timer -= uiDiff; + m_uiLightningBoltTimer -= uiDiff; - //ArcaneShock_Timer - if (m_uiArcaneShock_Timer < uiDiff) + if (m_uiArcaneShockTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_SHOCK); - m_uiArcaneShock_Timer = urand(15000, 20000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_SHOCK) == CAST_OK) + m_uiArcaneShockTimer = urand(15000, 20000); } else - m_uiArcaneShock_Timer -= uiDiff; + m_uiArcaneShockTimer -= uiDiff; - //ArcaneExplosion_Timer - if (m_uiArcaneExplosion_Timer < uiDiff) + if (m_uiArcaneExplosionTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION); - m_uiArcaneExplosion_Timer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION) == CAST_OK) + m_uiArcaneExplosionTimer = 30000; } else - m_uiArcaneExplosion_Timer -= uiDiff; + m_uiArcaneExplosionTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Blindeye The Seer AI -struct MANGOS_DLL_DECL boss_blindeye_the_seerAI : public Council_Base_AI +// Blindeye The Seer AI +struct boss_blindeye_the_seerAI : public Council_Base_AI { boss_blindeye_the_seerAI(Creature* pCreature) : Council_Base_AI(pCreature) {Reset();} - uint32 m_uiGreaterPowerWordShield_Timer; - uint32 m_uiHeal_Timer; - uint32 m_uiPrayerofHealing_Timer; + uint32 m_uiGreaterPowerWordShieldTimer; + uint32 m_uiHealTimer; + uint32 m_uiPrayerofHealingTimer; - void Reset() + void Reset() override { - m_uiGreaterPowerWordShield_Timer = 5000; - m_uiHeal_Timer = urand(25000, 40000); - m_uiPrayerofHealing_Timer = urand(45000, 55000); + m_uiGreaterPowerWordShieldTimer = 5000; + m_uiHealTimer = urand(25000, 40000); + m_uiPrayerofHealingTimer = urand(45000, 55000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiGreaterPowerWordShield_Timer - if (m_uiGreaterPowerWordShield_Timer < uiDiff) + if (m_uiGreaterPowerWordShieldTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_GREATER_PW_SHIELD); - m_uiGreaterPowerWordShield_Timer = urand(30000, 40000); + if (DoCastSpellIfCan(m_creature, SPELL_GREATER_PW_SHIELD) == CAST_OK) + m_uiGreaterPowerWordShieldTimer = urand(30000, 40000); } else - m_uiGreaterPowerWordShield_Timer -= uiDiff; + m_uiGreaterPowerWordShieldTimer -= uiDiff; - //m_uiHeal_Timer - if (m_uiHeal_Timer < uiDiff) + if (m_uiHealTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_HEAL); - m_uiHeal_Timer = urand(15000, 40000); + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) + { + if (DoCastSpellIfCan(pTarget, SPELL_HEAL) == CAST_OK) + m_uiHealTimer = urand(15000, 40000); + } } else - m_uiHeal_Timer -= uiDiff; + m_uiHealTimer -= uiDiff; - //PrayerofHealing_Timer - if (m_uiPrayerofHealing_Timer < uiDiff) + if (m_uiPrayerofHealingTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_PRAYEROFHEALING); - m_uiPrayerofHealing_Timer = urand(35000, 50000); + if (DoCastSpellIfCan(m_creature, SPELL_PRAYEROFHEALING) == CAST_OK) + m_uiPrayerofHealingTimer = urand(35000, 50000); } else - m_uiPrayerofHealing_Timer -= uiDiff; + m_uiPrayerofHealingTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Krosh Firehand AI -struct MANGOS_DLL_DECL boss_krosh_firehandAI : public Council_Base_AI +// Krosh Firehand AI +struct boss_krosh_firehandAI : public Council_Base_AI { boss_krosh_firehandAI(Creature* pCreature) : Council_Base_AI(pCreature) {Reset();} - uint32 m_uiGreaterFireball_Timer; - uint32 m_uiSpellShield_Timer; - uint32 m_uiBlastWave_Timer; + uint32 m_uiGreaterFireballTimer; + uint32 m_uiSpellShieldTimer; + uint32 m_uiBlastWaveTimer; - void Reset() + void Reset() override { - m_uiGreaterFireball_Timer = 4000; - m_uiSpellShield_Timer = 1000; - m_uiBlastWave_Timer = 12000; + m_uiGreaterFireballTimer = 4000; + m_uiSpellShieldTimer = 1000; + m_uiBlastWaveTimer = 12000; } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (!pWho) return; @@ -514,40 +451,36 @@ struct MANGOS_DLL_DECL boss_krosh_firehandAI : public Council_Base_AI m_creature->SetInCombatWith(pWho); pWho->SetInCombatWith(m_creature); - m_creature->GetMotionMaster()->MoveChase(pWho, DISTANCE_KROSH); + m_creature->GetMotionMaster()->MoveChase(pWho, 30.0f); } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiGreaterFireball_Timer - if (m_uiGreaterFireball_Timer < uiDiff) + if (m_uiGreaterFireballTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_GREATER_FIREBALL); - m_uiGreaterFireball_Timer = 3200; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GREATER_FIREBALL) == CAST_OK) + m_uiGreaterFireballTimer = 3200; } else - m_uiGreaterFireball_Timer -= uiDiff; + m_uiGreaterFireballTimer -= uiDiff; - //SpellShield_Timer - if (m_uiSpellShield_Timer < uiDiff) + if (m_uiSpellShieldTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SPELLSHIELD, CAST_INTERRUPT_PREVIOUS); - m_uiSpellShield_Timer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_SPELLSHIELD) == CAST_OK) + m_uiSpellShieldTimer = 30000; } else - m_uiSpellShield_Timer -= uiDiff; + m_uiSpellShieldTimer -= uiDiff; - //BlastWave_Timer - if (m_uiBlastWave_Timer < uiDiff) + if (m_uiBlastWaveTimer < uiDiff) { - std::vector vGuids; + GuidVector vGuids; m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin(); i != vGuids.end(); ++i) + for (GuidVector::const_iterator i = vGuids.begin(); i != vGuids.end(); ++i) { Unit* pUnit = m_creature->GetMap()->GetUnit(*i); @@ -558,10 +491,10 @@ struct MANGOS_DLL_DECL boss_krosh_firehandAI : public Council_Base_AI } } - m_uiBlastWave_Timer = 6000; + m_uiBlastWaveTimer = 6000; } else - m_uiBlastWave_Timer -= uiDiff; + m_uiBlastWaveTimer -= uiDiff; } }; @@ -575,17 +508,17 @@ CreatureAI* GetAI_boss_olm_the_summoner(Creature* pCreature) return new boss_olm_the_summonerAI(pCreature); } -CreatureAI *GetAI_boss_kiggler_the_crazed(Creature* pCreature) +CreatureAI* GetAI_boss_kiggler_the_crazed(Creature* pCreature) { return new boss_kiggler_the_crazedAI(pCreature); } -CreatureAI *GetAI_boss_blindeye_the_seer(Creature* pCreature) +CreatureAI* GetAI_boss_blindeye_the_seer(Creature* pCreature) { return new boss_blindeye_the_seerAI(pCreature); } -CreatureAI *GetAI_boss_krosh_firehand(Creature* pCreature) +CreatureAI* GetAI_boss_krosh_firehand(Creature* pCreature) { return new boss_krosh_firehandAI(pCreature); } diff --git a/scripts/outland/gruuls_lair/gruuls_lair.h b/scripts/outland/gruuls_lair/gruuls_lair.h index 53b7fb90c..d62ae5f7f 100644 --- a/scripts/outland/gruuls_lair/gruuls_lair.h +++ b/scripts/outland/gruuls_lair/gruuls_lair.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -8,42 +8,45 @@ enum { MAX_ENCOUNTER = 2, + MAX_COUNCIL = 5, // Encounter Status - TYPE_MAULGAR_EVENT = 1, - TYPE_GRUUL_EVENT = 2, + TYPE_MAULGAR_EVENT = 0, + TYPE_GRUUL_EVENT = 1, GO_PORT_GRONN_1 = 183817, // 184468 not in use GO_PORT_GRONN_2 = 184662, // NPC GUIDs - NPC_MAULGAR = 18831, - NPC_BLINDEYE = 18836, - NPC_KIGGLER = 18835, - NPC_KROSH = 18832, - NPC_OLM = 18834, + NPC_MAULGAR = 18831, + // NPC_BLINDEYE = 18836, + // NPC_KIGGLER = 18835, + // NPC_KROSH = 18832, + // NPC_OLM = 18834, }; -class MANGOS_DLL_DECL instance_gruuls_lair : public ScriptedInstance +class instance_gruuls_lair : public ScriptedInstance { public: - instance_gruuls_lair(Map *pMap); + instance_gruuls_lair(Map* pMap); - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strSaveData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strSaveData.c_str(); } + void Load(const char* chrIn) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strSaveData; + + uint8 m_uiCouncilMembersDied; }; #endif diff --git a/scripts/outland/gruuls_lair/instance_gruuls_lair.cpp b/scripts/outland/gruuls_lair/instance_gruuls_lair.cpp index cf0c2731f..d96c8a2b2 100644 --- a/scripts/outland/gruuls_lair/instance_gruuls_lair.cpp +++ b/scripts/outland/gruuls_lair/instance_gruuls_lair.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,7 +29,8 @@ EndScriptData */ 2 - Gruul event */ -instance_gruuls_lair::instance_gruuls_lair(Map *pMap) : ScriptedInstance(pMap) +instance_gruuls_lair::instance_gruuls_lair(Map* pMap) : ScriptedInstance(pMap), + m_uiCouncilMembersDied(0) { Initialize(); } @@ -50,16 +51,8 @@ bool instance_gruuls_lair::IsEncounterInProgress() const void instance_gruuls_lair::OnCreatureCreate(Creature* pCreature) { - switch (pCreature->GetEntry()) - { - case NPC_MAULGAR: - case NPC_KROSH: - case NPC_OLM: - case NPC_KIGGLER: - case NPC_BLINDEYE: - m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); - break; - } + if (pCreature->GetEntry() == NPC_MAULGAR) + m_mNpcEntryGuidStore[NPC_MAULGAR] = pCreature->GetObjectGuid(); } void instance_gruuls_lair::OnObjectCreate(GameObject* pGo) @@ -67,7 +60,7 @@ void instance_gruuls_lair::OnObjectCreate(GameObject* pGo) switch (pGo->GetEntry()) { case GO_PORT_GRONN_1: - if (m_auiEncounter[0] == DONE) + if (m_auiEncounter[TYPE_MAULGAR_EVENT] == DONE) pGo->SetGoState(GO_STATE_ACTIVE); break; case GO_PORT_GRONN_2: @@ -84,13 +77,24 @@ void instance_gruuls_lair::SetData(uint32 uiType, uint32 uiData) switch (uiType) { case TYPE_MAULGAR_EVENT: + if (uiData == SPECIAL) + { + ++m_uiCouncilMembersDied; + + if (m_uiCouncilMembersDied == MAX_COUNCIL) + SetData(TYPE_MAULGAR_EVENT, DONE); + // Don't store special data + break; + } + if (uiData == FAIL) + m_uiCouncilMembersDied = 0; if (uiData == DONE) DoUseDoorOrButton(GO_PORT_GRONN_1); - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_GRUUL_EVENT: DoUseDoorOrButton(GO_PORT_GRONN_2); - m_auiEncounter[1] = uiData; + m_auiEncounter[uiType] = uiData; break; } @@ -108,16 +112,12 @@ void instance_gruuls_lair::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_gruuls_lair::GetData(uint32 uiType) +uint32 instance_gruuls_lair::GetData(uint32 uiType) const { - switch (uiType) - { - case TYPE_MAULGAR_EVENT: return m_auiEncounter[0]; - case TYPE_GRUUL_EVENT: return m_auiEncounter[1]; + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - default: - return 0; - } + return 0; } void instance_gruuls_lair::Load(const char* chrIn) @@ -134,7 +134,7 @@ void instance_gruuls_lair::Load(const char* chrIn) loadStream >> m_auiEncounter[0] >> m_auiEncounter[1]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; diff --git a/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h b/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h index effed3407..2186059f5 100644 --- a/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h +++ b/scripts/outland/hellfire_citadel/blood_furnace/blood_furnace.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -41,6 +41,9 @@ enum SAY_BROGGOK_INTRO = -1542015, }; +// Random Magtheridon taunt +static const int32 aRandomTaunt[] = { -1544000, -1544001, -1544002, -1544003, -1544004, -1544005}; + struct BroggokEventInfo { BroggokEventInfo() : m_bIsCellOpened(false), m_uiKilledOrcCount(0) {} @@ -48,33 +51,33 @@ struct BroggokEventInfo ObjectGuid m_cellGuid; bool m_bIsCellOpened; uint8 m_uiKilledOrcCount; - GUIDSet m_sSortedOrcGuids; + GuidSet m_sSortedOrcGuids; }; -class MANGOS_DLL_DECL instance_blood_furnace : public ScriptedInstance +class instance_blood_furnace : public ScriptedInstance { public: instance_blood_furnace(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; - void Load(const char* chrIn); - const char* Save() { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + const char* Save() const override { return m_strInstData.c_str(); } void GetMovementDistanceForIndex(uint32 uiIndex, float& dx, float& dy); - void GetKelidanAddList(GUIDList& lList) { lList = m_lChannelersGuids; m_lChannelersGuids.clear(); } + void GetKelidanAddList(GuidList& lList) { lList = m_lChannelersGuids; m_lChannelersGuids.clear(); } private: void DoSortBroggokOrcs(); @@ -87,9 +90,10 @@ class MANGOS_DLL_DECL instance_blood_furnace : public ScriptedInstance uint32 m_uiBroggokEventTimer; // Timer for opening the event cages; only on heroic mode = 30 secs uint32 m_uiBroggokEventPhase; + uint32 m_uiRandYellTimer; // Random yell for Magtheridon - GUIDList m_luiNascentOrcGuids; - GUIDList m_lChannelersGuids; + GuidList m_luiNascentOrcGuids; + GuidList m_lChannelersGuids; }; #endif diff --git a/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp b/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp index 888bf39a0..43e4bca05 100644 --- a/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp +++ b/scripts/outland/hellfire_citadel/blood_furnace/boss_broggok.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,7 +39,7 @@ enum POINT_EVENT_COMBAT = 1, }; -struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI +struct boss_broggokAI : public ScriptedAI { boss_broggokAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -55,14 +55,14 @@ struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI uint32 m_uiPoisonSpawnTimer; uint32 m_uiPoisonBoltTimer; - void Reset() + void Reset() override { m_uiAcidSprayTimer = 10000; m_uiPoisonSpawnTimer = 5000; m_uiPoisonBoltTimer = 7000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -70,7 +70,7 @@ struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI m_pInstance->SetData(TYPE_BROGGOK_EVENT, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // ToDo: set correct flags and data in DB!!! pSummoned->setFaction(16); @@ -79,15 +79,15 @@ struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI pSummoned->CastSpell(pSummoned, SPELL_POISON, false, NULL, NULL, m_creature->GetObjectGuid()); } - void JustDied(Unit* pWho) + void JustDied(Unit* /*pWho*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_BROGGOK_EVENT, DONE); } - void EnterEvadeMode() + void EnterEvadeMode() override { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->LoadCreatureAddon(true); @@ -112,7 +112,7 @@ struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI } // Reset Orientation - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE || uiPointId != POINT_EVENT_COMBAT) return; @@ -121,7 +121,7 @@ struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI m_creature->SetFacingToObject(pFrontDoor); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -154,13 +154,13 @@ struct MANGOS_DLL_DECL boss_broggokAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_broggok_poisoncloudAI : public ScriptedAI +struct mob_broggok_poisoncloudAI : public ScriptedAI { mob_broggok_poisoncloudAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() { } - void MoveInLineOfSight(Unit *who) { } - void AttackStart(Unit *who) { } + void Reset() override { } + void MoveInLineOfSight(Unit* /*who*/) override { } + void AttackStart(Unit* /*who*/) override { } }; CreatureAI* GetAI_boss_broggok(Creature* pCreature) diff --git a/scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp b/scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp index aafd65140..63308892d 100644 --- a/scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp +++ b/scripts/outland/hellfire_citadel/blood_furnace/boss_kelidan_the_breaker.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -68,7 +68,7 @@ struct SortByAngle WorldObject const* m_pRef; }; -struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI +struct boss_kelidan_the_breakerAI : public ScriptedAI { boss_kelidan_the_breakerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -92,9 +92,9 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI uint8 m_uiKilledAdds; bool m_bDidMagtheridonYell; - GUIDVector m_vAddGuids; + GuidVector m_vAddGuids; - void Reset() + void Reset() override { m_uiShadowVolleyTimer = 1000; m_uiBurningNovaTimer = 15000; @@ -103,7 +103,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI m_uiKilledAdds = 0; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bDidMagtheridonYell && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->_IsWithinDist(pWho, 73.0f, false)) { @@ -116,12 +116,12 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_WAKE, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -129,7 +129,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); @@ -137,7 +137,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI m_pInstance->SetData(TYPE_KELIDAN_EVENT, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_KELIDAN_EVENT, FAIL); @@ -153,7 +153,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI if (!m_pInstance) return; - GUIDList lAddGuids; + GuidList lAddGuids; m_pInstance->GetKelidanAddList(lAddGuids); // Sort Adds to vector if not already done @@ -161,7 +161,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI { m_vAddGuids.reserve(lAddGuids.size()); std::list lAdds; - for (GUIDList::const_iterator itr = lAddGuids.begin(); itr != lAddGuids.end(); ++itr) + for (GuidList::const_iterator itr = lAddGuids.begin(); itr != lAddGuids.end(); ++itr) { if (Creature* pAdd = m_pInstance->instance->GetCreature(*itr)) lAdds.push_back(pAdd); @@ -174,7 +174,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI // Respawn killed adds and reset counter m_uiKilledAdds = 0; - for (GUIDVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) + for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) { Creature* pAdd = m_pInstance->instance->GetCreature(*itr); if (pAdd && !pAdd->isAlive()) @@ -195,7 +195,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI void AddJustAggroed(Unit* pWho) { // Let all adds attack - for (GUIDVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) + for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) { Creature* pAdd = m_creature->GetMap()->GetCreature(*itr); if (pAdd && !pAdd->getVictim()) @@ -218,7 +218,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiSetupAddsTimer) { @@ -242,7 +242,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI } } else - m_uiFirenovaTimer -=uiDiff; + m_uiFirenovaTimer -= uiDiff; } if (m_uiShadowVolleyTimer < uiDiff) @@ -251,7 +251,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI m_uiShadowVolleyTimer = urand(5000, 13000); } else - m_uiShadowVolleyTimer -=uiDiff; + m_uiShadowVolleyTimer -= uiDiff; if (m_uiCorruptionTimer < uiDiff) { @@ -259,7 +259,7 @@ struct MANGOS_DLL_DECL boss_kelidan_the_breakerAI : public ScriptedAI m_uiCorruptionTimer = urand(30000, 50000); } else - m_uiCorruptionTimer -=uiDiff; + m_uiCorruptionTimer -= uiDiff; if (m_uiBurningNovaTimer < uiDiff) { @@ -298,7 +298,7 @@ enum SPELL_MARK_OF_SHADOW = 30937, }; -struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI +struct mob_shadowmoon_channelerAI : public ScriptedAI { mob_shadowmoon_channelerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -313,17 +313,17 @@ struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI uint32 m_uiShadowBoltTimer; uint32 m_uiMarkOfShadowTimer; - void Reset() + void Reset() override { m_uiShadowBoltTimer = urand(1000, 2000); m_uiMarkOfShadowTimer = urand(5000, 7000); } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { m_creature->InterruptNonMeleeSpells(false); - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_ADD_AGGRO_1, m_creature); @@ -340,31 +340,31 @@ struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI return; if (Creature* pKelidan = m_pInstance->GetSingleCreatureFromStorage(NPC_KELIDAN_THE_BREAKER)) - if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast (pKelidan->AI())) + if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast(pKelidan->AI())) pKelidanAI->AddJustAggroed(pWho); } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (!m_pInstance) return; if (Creature* pKelidan = m_pInstance->GetSingleCreatureFromStorage(NPC_KELIDAN_THE_BREAKER)) - if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast (pKelidan->AI())) + if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast(pKelidan->AI())) pKelidanAI->AddJustDied(pKiller); } - void JustReachedHome() + void JustReachedHome() override { if (!m_pInstance) return; if (Creature* pKelidan = m_pInstance->GetSingleCreatureFromStorage(NPC_KELIDAN_THE_BREAKER)) - if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast (pKelidan->AI())) + if (boss_kelidan_the_breakerAI* pKelidanAI = dynamic_cast(pKelidan->AI())) pKelidanAI->AddJustReachedHome(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -378,7 +378,7 @@ struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI } } else - m_uiMarkOfShadowTimer -=uiDiff; + m_uiMarkOfShadowTimer -= uiDiff; if (m_uiShadowBoltTimer < uiDiff) { @@ -389,7 +389,7 @@ struct MANGOS_DLL_DECL mob_shadowmoon_channelerAI : public ScriptedAI } } else - m_uiShadowBoltTimer -=uiDiff; + m_uiShadowBoltTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp b/scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp index f4c599af4..a912985a6 100644 --- a/scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp +++ b/scripts/outland/hellfire_citadel/blood_furnace/boss_the_maker.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,10 +37,10 @@ enum SPELL_EXPLODING_BREAKER = 30925, SPELL_EXPLODING_BREAKER_H = 40059, SPELL_KNOCKDOWN = 20276, - SPELL_DOMINATION = 25772 // ??? + SPELL_DOMINATION = 30923 }; -struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI +struct boss_the_makerAI : public ScriptedAI { boss_the_makerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -57,7 +57,7 @@ struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI uint32 m_uiDominationTimer; uint32 m_uiKnockdownTimer; - void Reset() + void Reset() override { m_uiAcidSprayTimer = 15000; m_uiExplodingBreakerTimer = 6000; @@ -65,7 +65,7 @@ struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI m_uiKnockdownTimer = 10000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { switch (urand(0, 2)) { @@ -78,18 +78,18 @@ struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI m_pInstance->SetData(TYPE_THE_MAKER_EVENT, IN_PROGRESS); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_THE_MAKER_EVENT, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); @@ -97,7 +97,7 @@ struct MANGOS_DLL_DECL boss_the_makerAI : public ScriptedAI m_pInstance->SetData(TYPE_THE_MAKER_EVENT, DONE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp b/scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp index 900762c9f..754b93025 100644 --- a/scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp +++ b/scripts/outland/hellfire_citadel/blood_furnace/instance_blood_furnace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -26,7 +26,8 @@ EndScriptData */ instance_blood_furnace::instance_blood_furnace(Map* pMap) : ScriptedInstance(pMap), m_uiBroggokEventTimer(30000), - m_uiBroggokEventPhase(0) + m_uiBroggokEventPhase(0), + m_uiRandYellTimer(90000) { Initialize(); } @@ -42,6 +43,7 @@ void instance_blood_furnace::OnCreatureCreate(Creature* pCreature) { case NPC_BROGGOK: case NPC_KELIDAN_THE_BREAKER: + case NPC_MAGTHERIDON: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; @@ -92,7 +94,7 @@ void instance_blood_furnace::OnObjectCreate(GameObject* pGo) void instance_blood_furnace::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_THE_MAKER_EVENT: if (uiData == IN_PROGRESS) @@ -134,7 +136,7 @@ void instance_blood_furnace::SetData(uint32 uiType, uint32 uiData) continue; m_aBroggokEvent[i].m_uiKilledOrcCount = 0; - for (GUIDSet::const_iterator itr = m_aBroggokEvent[i].m_sSortedOrcGuids.begin(); itr != m_aBroggokEvent[i].m_sSortedOrcGuids.end(); ++itr) + for (GuidSet::const_iterator itr = m_aBroggokEvent[i].m_sSortedOrcGuids.begin(); itr != m_aBroggokEvent[i].m_sSortedOrcGuids.end(); ++itr) { if (Creature* pOrc = instance->GetCreature(*itr)) { @@ -160,7 +162,7 @@ void instance_blood_furnace::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[uiType] = uiData; break; default: - error_log("SD2: Instance Blood Furnace SetData with Type %u Data %u, but this is not implemented.", uiType, uiData); + script_error_log("Instance Blood Furnace SetData with Type %u Data %u, but this is not implemented.", uiType, uiData); return; } @@ -203,7 +205,7 @@ void instance_blood_furnace::DoNextBroggokEventPhase() m_aBroggokEvent[m_uiBroggokEventPhase].m_bIsCellOpened = true; - for(GUIDSet::const_iterator itr = m_aBroggokEvent[m_uiBroggokEventPhase].m_sSortedOrcGuids.begin(); itr != m_aBroggokEvent[m_uiBroggokEventPhase].m_sSortedOrcGuids.end(); ++itr) + for (GuidSet::const_iterator itr = m_aBroggokEvent[m_uiBroggokEventPhase].m_sSortedOrcGuids.begin(); itr != m_aBroggokEvent[m_uiBroggokEventPhase].m_sSortedOrcGuids.end(); ++itr) { if (Creature* pOrc = instance->GetCreature(*itr)) { @@ -281,9 +283,20 @@ void instance_blood_furnace::Update(uint32 uiDiff) else m_uiBroggokEventTimer -= uiDiff; } + + if (m_uiRandYellTimer < uiDiff) + { + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) + { + DoScriptText(aRandomTaunt[urand(0, 5)], pMagtheridon); + m_uiRandYellTimer = 90000; + } + } + else + m_uiRandYellTimer -= uiDiff; } -uint32 instance_blood_furnace::GetData(uint32 uiType) +uint32 instance_blood_furnace::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -304,7 +317,7 @@ void instance_blood_furnace::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS || m_auiEncounter[i] == FAIL) m_auiEncounter[i] = NOT_STARTED; @@ -314,7 +327,7 @@ void instance_blood_furnace::Load(const char* chrIn) // Sort all nascent orcs in the instance in order to get only those near broggok doors void instance_blood_furnace::DoSortBroggokOrcs() { - for (GUIDList::const_iterator itr = m_luiNascentOrcGuids.begin(); itr != m_luiNascentOrcGuids.end(); ++itr) + for (GuidList::const_iterator itr = m_luiNascentOrcGuids.begin(); itr != m_luiNascentOrcGuids.end(); ++itr) { if (Creature* pOrc = instance->GetCreature(*itr)) { @@ -374,7 +387,7 @@ InstanceData* GetInstanceData_instance_blood_furnace(Map* pMap) return new instance_blood_furnace(pMap); } -bool GOUse_go_prison_cell_lever(Player* pPlayer, GameObject* pGo) +bool GOUse_go_prison_cell_lever(Player* /*pPlayer*/, GameObject* pGo) { ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData(); diff --git a/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_nazan_and_vazruden.cpp b/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_nazan_and_vazruden.cpp index d3301bdfe..dbb56148d 100644 --- a/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_nazan_and_vazruden.cpp +++ b/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_nazan_and_vazruden.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -38,24 +38,23 @@ enum SPELL_SUMMON_VAZRUDEN = 30717, - //vazruden + // vazruden SPELL_REVENGE = 19130, SPELL_REVENGE_H = 40392, - //nazan - SPELL_FIREBALL = 30691, // This and the next while flying (dmg values will change in cata) - SPELL_FIREBALL_B = 33793, - SPELL_FIREBALL_H = 32491, - SPELL_FIREBALL_B_H = 33794, - SPELL_FIREBALL_LAND = 34653, // While landed - SPELL_FIREBALL_LAND_H = 36920, - + // nazan + //SPELL_FIREBALL_H = 32491, // purpose unk; not sure if they are related to this encounter + //SPELL_FIREBALL_B_H = 33794, + SPELL_FIREBALL = 34653, + SPELL_FIREBALL_H = 36920, + //SPELL_FIREBALL_LAND = 30691, // cast while on land? + //SPELL_FIREBALL_LAND_H = 33793, SPELL_CONE_OF_FIRE = 30926, SPELL_CONE_OF_FIRE_H = 36921, SPELL_BELLOW_ROAR_H = 39427, - //misc + // misc POINT_ID_CENTER = 100, POINT_ID_FLYING = 101, POINT_ID_COMBAT = 102, @@ -63,103 +62,13 @@ enum NPC_NAZAN = 17536, }; -const float afCenterPos[3] = {-1399.401f, 1736.365f, 87.008f}; //moves here to drop off nazan -const float afCombatPos[3] = {-1413.848f, 1754.019f, 83.146f}; //moves here when decending - -struct MANGOS_DLL_DECL boss_vazrudenAI : public ScriptedAI -{ - boss_vazrudenAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; - - uint32 m_uiRevengeTimer; - bool m_bHealthBelow; - - void Reset() - { - m_bHealthBelow = false; - m_uiRevengeTimer = urand(5500, 8400); - } - - void Aggro(Unit* pWho) - { - switch(urand(0, 2)) - { - case 0: DoScriptText(SAY_AGGRO1, m_creature); break; - case 1: DoScriptText(SAY_AGGRO2, m_creature); break; - case 2: DoScriptText(SAY_AGGRO3, m_creature); break; - } - } - - void JustDied(Unit* pKiller) - { - DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_VAZRUDEN, DONE); - } - - void JustReachedHome() - { - if (m_pInstance) - m_pInstance->SetData(TYPE_VAZRUDEN, FAIL); - } - - void KilledUnit(Unit* pVictim) - { - DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); - } - - void PrepareAndDescendMount() - { - if (Creature* pHerald = m_pInstance->GetSingleCreatureFromStorage(NPC_VAZRUDEN_HERALD)) - { - pHerald->SetWalk(false); - pHerald->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, afCombatPos[0], afCombatPos[1], afCombatPos[2]); - DoScriptText(EMOTE_DESCEND, pHerald); - } - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (!m_bHealthBelow && m_creature->GetHealthPercent() <= 30.0f) - { - if (m_pInstance) - PrepareAndDescendMount(); - - m_bHealthBelow = true; - } - - if (m_uiRevengeTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_REVENGE : SPELL_REVENGE_H) == CAST_OK) - m_uiRevengeTimer = urand(11400, 14300); - } - else - m_uiRevengeTimer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_boss_vazruden(Creature* pCreature) -{ - return new boss_vazrudenAI(pCreature); -} +const float afCenterPos[3] = { -1399.401f, 1736.365f, 87.008f}; // moves here to drop off nazan +const float afCombatPos[3] = { -1413.848f, 1754.019f, 83.146f}; // moves here when decending -// Creature fly around platform by default. -// After "dropping off" Vazruden, transforms to mount (Nazan) and are then ready to fight when -// Vazruden reach 30% HP -struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI +// This is the flying mob ("mounted" on dragon) spawned initially +// This npc will morph into the "unmounted" dragon (nazan) after vazruden is summoned and continue flying +// Descent after Vazruden reach 30% HP +struct boss_vazruden_heraldAI : public ScriptedAI { boss_vazruden_heraldAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -173,16 +82,16 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI bool m_bIsRegularMode; bool m_bIsEventInProgress; + bool m_bIsDescending; uint32 m_uiMovementTimer; uint32 m_uiFireballTimer; - uint32 m_uiFireballBTimer; uint32 m_uiConeOfFireTimer; uint32 m_uiBellowingRoarTimer; ObjectGuid m_lastSeenPlayerGuid; ObjectGuid m_vazrudenGuid; - void Reset() + void Reset() override { if (m_creature->GetEntry() != NPC_VAZRUDEN_HERALD) m_creature->UpdateEntry(NPC_VAZRUDEN_HERALD); @@ -191,20 +100,20 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI m_uiMovementTimer = 0; m_bIsEventInProgress = false; + m_bIsDescending = false; m_lastSeenPlayerGuid.Clear(); m_vazrudenGuid.Clear(); m_uiFireballTimer = 0; - m_uiFireballBTimer = 2100; m_uiConeOfFireTimer = urand(8100, 19700); m_uiBellowingRoarTimer = 100; // TODO Guesswork, though such an AoE fear soon after landing seems fitting // see boss_onyxia // sort of a hack, it is unclear how this really work but the values appear to be valid - m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_UNK_2); + m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); m_creature->SetLevitate(true); } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (m_bIsEventInProgress && !m_lastSeenPlayerGuid && pWho->GetTypeId() == TYPEID_PLAYER && pWho->isAlive() && !((Player*)pWho)->isGameMaster()) { @@ -218,7 +127,15 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void AttackStart(Unit* pWho) override + { + if (m_pInstance && m_pInstance->GetData(TYPE_NAZAN) != IN_PROGRESS) + return; + + ScriptedAI::AttackStart(pWho); + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (!m_pInstance) return; @@ -273,7 +190,19 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI void DoMoveToCenter() { DoScriptText(SAY_INTRO, m_creature); - m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, afCenterPos[0], afCenterPos[1], afCenterPos[2]); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, afCenterPos[0], afCenterPos[1], afCenterPos[2], false); + } + + void DoSplit() + { + m_creature->UpdateEntry(NPC_NAZAN); + + DoCastSpellIfCan(m_creature, SPELL_SUMMON_VAZRUDEN); + + m_uiMovementTimer = 3000; + + // Let him idle for now + m_creature->GetMotionMaster()->MoveIdle(); } void DoMoveToAir() @@ -285,22 +214,22 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE) m_creature->GetMotionMaster()->MovementExpired(false); - m_creature->GetMotionMaster()->MovePoint(POINT_ID_FLYING, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_FLYING, fX, fY, fZ, false); } - void DoSplit() + void DoMoveToCombat() { - m_creature->UpdateEntry(NPC_NAZAN); - - DoCastSpellIfCan(m_creature, SPELL_SUMMON_VAZRUDEN); + if (m_bIsDescending || !m_pInstance || m_pInstance->GetData(TYPE_NAZAN) == IN_PROGRESS) + return; - m_uiMovementTimer = 3000; + m_bIsDescending = true; - // Let him idle for now - m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_COMBAT, afCombatPos[0], afCombatPos[1], afCombatPos[2], false); + DoScriptText(EMOTE_DESCEND, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() != NPC_VAZRUDEN) return; @@ -314,19 +243,19 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI m_pInstance->SetData(TYPE_VAZRUDEN, IN_PROGRESS); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) m_pInstance->SetData(TYPE_NAZAN, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NAZAN, FAIL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -362,22 +291,11 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI } else m_uiFireballTimer -= uiDiff; - - if (m_uiFireballBTimer < uiDiff) - { - if (Creature* pVazruden = m_creature->GetMap()->GetCreature(m_vazrudenGuid)) - { - if (Unit* pEnemy = pVazruden->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(pEnemy, m_bIsRegularMode ? SPELL_FIREBALL_B : SPELL_FIREBALL_B_H, 0, pVazruden->GetObjectGuid()) == CAST_OK) - m_uiFireballBTimer = 15700; - } - } - } - else - m_uiFireballBTimer -= uiDiff; } + if (m_creature->GetHealthPercent() < 20.0f) + DoMoveToCombat(); + return; } @@ -386,7 +304,7 @@ struct MANGOS_DLL_DECL boss_vazruden_heraldAI : public ScriptedAI { if (Unit* pEnemy = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - if (DoCastSpellIfCan(pEnemy, m_bIsRegularMode ? SPELL_FIREBALL_LAND : SPELL_FIREBALL_LAND_H) == CAST_OK) + if (DoCastSpellIfCan(pEnemy, m_bIsRegularMode ? SPELL_FIREBALL : SPELL_FIREBALL_H) == CAST_OK) m_uiFireballTimer = urand(7300, 13200); } } @@ -421,6 +339,91 @@ CreatureAI* GetAI_boss_vazruden_herald(Creature* pCreature) return new boss_vazruden_heraldAI(pCreature); } +// This is the summoned boss ("dismounted") that starts attacking the players +struct boss_vazrudenAI : public ScriptedAI +{ + boss_vazrudenAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiRevengeTimer; + bool m_bHealthBelow; + + void Reset() override + { + m_bHealthBelow = false; + m_uiRevengeTimer = urand(5500, 8400); + } + + void Aggro(Unit* /*pWho*/) override + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_AGGRO1, m_creature); break; + case 1: DoScriptText(SAY_AGGRO2, m_creature); break; + case 2: DoScriptText(SAY_AGGRO3, m_creature); break; + } + } + + void JustDied(Unit* /*pKiller*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_VAZRUDEN, DONE); + } + + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VAZRUDEN, FAIL); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_KILL1 : SAY_KILL2, m_creature); + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + if (!m_bHealthBelow && m_pInstance && (float(m_creature->GetHealth() - uiDamage) / m_creature->GetMaxHealth()) < 0.30f) + { + if (Creature* pNazan = m_pInstance->GetSingleCreatureFromStorage(NPC_VAZRUDEN_HERALD)) + if (boss_vazruden_heraldAI* pNazanAI = dynamic_cast(pNazan->AI())) + pNazanAI->DoMoveToCombat(); + + m_bHealthBelow = true; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiRevengeTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_REVENGE : SPELL_REVENGE_H) == CAST_OK) + m_uiRevengeTimer = urand(11400, 14300); + } + else + m_uiRevengeTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_vazruden(Creature* pCreature) +{ + return new boss_vazrudenAI(pCreature); +} + void AddSC_boss_nazan_and_vazruden() { Script* pNewScript; diff --git a/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp b/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp index 28598a245..fad8b788b 100644 --- a/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp +++ b/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_omor_the_unscarred.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,7 +44,7 @@ enum SPELL_SUMMON_FIENDISH_HOUND = 30707, }; -struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI +struct boss_omor_the_unscarredAI : public ScriptedAI { boss_omor_the_unscarredAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -64,7 +64,7 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI ObjectGuid m_playerGuid; bool m_bCanPullBack; - void Reset() + void Reset() override { DoScriptText(SAY_WIPE, m_creature); @@ -78,9 +78,9 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI m_bCanPullBack = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -88,7 +88,7 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { if (urand(0, 1)) return; @@ -96,7 +96,7 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI DoScriptText(SAY_KILL_1, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { DoScriptText(SAY_SUMMON, m_creature); @@ -104,12 +104,12 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI pSummoned->AI()->AttackStart(pTarget); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -128,7 +128,7 @@ struct MANGOS_DLL_DECL boss_omor_the_unscarredAI : public ScriptedAI { if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { - //if unit dosen't have this flag, then no pulling back (script will attempt cast, even if orbital strike was resisted) + // if unit dosen't have this flag, then no pulling back (script will attempt cast, even if orbital strike was resisted) if (pPlayer->HasMovementFlag(MOVEFLAG_FALLING)) DoCastSpellIfCan(pPlayer, SPELL_SHADOW_WHIP, CAST_INTERRUPT_PREVIOUS); } diff --git a/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp b/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp index 07851384d..41533c454 100644 --- a/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp +++ b/scripts/outland/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -42,7 +42,7 @@ enum SPELL_OVERPOWER = 32154, }; -struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI +struct boss_watchkeeper_gargolmarAI : public ScriptedAI { boss_watchkeeper_gargolmarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -60,7 +60,7 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI bool m_bHasTaunted; bool m_bYelledForHeal; - void Reset() + void Reset() override { m_uiSurgeTimer = urand(2400, 6100); m_uiMortalWoundTimer = urand(3500, 14400); @@ -71,9 +71,9 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI m_bYelledForHeal = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -81,7 +81,7 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bHasTaunted && m_creature->IsWithinDistInMap(pWho, 60.0f)) { @@ -92,17 +92,17 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -133,7 +133,7 @@ struct MANGOS_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI { if (m_uiRetaliationTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature,SPELL_RETALIATION) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_RETALIATION) == CAST_OK) m_uiRetaliationTimer = 30000; } else diff --git a/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h b/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h index 07dc17521..6a254a431 100644 --- a/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h +++ b/scripts/outland/hellfire_citadel/hellfire_ramparts/hellfire_ramparts.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -20,18 +20,18 @@ enum GO_FEL_IRON_CHEST_H = 185169, }; -class MANGOS_DLL_DECL instance_ramparts : public ScriptedInstance +class instance_ramparts : public ScriptedInstance { public: instance_ramparts(Map* pMap); - void Initialize(); + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; // No need to save and load this instance (only one encounter needs special handling, no doors used) @@ -41,7 +41,7 @@ class MANGOS_DLL_DECL instance_ramparts : public ScriptedInstance uint32 m_auiEncounter[MAX_ENCOUNTER]; uint32 m_uiSentryCounter; - GUIDList m_lSentryGUIDs; + GuidList m_lSentryGUIDs; }; #endif diff --git a/scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp b/scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp index 01ef20c25..535ff8d4f 100644 --- a/scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp +++ b/scripts/outland/hellfire_citadel/hellfire_ramparts/instance_hellfire_ramparts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -62,11 +62,13 @@ void instance_ramparts::OnObjectCreate(GameObject* pGo) void instance_ramparts::SetData(uint32 uiType, uint32 uiData) { - debug_log("SD2: Instance Ramparts: SetData received for type %u with data %u",uiType,uiData); + debug_log("SD2: Instance Ramparts: SetData received for type %u with data %u", uiType, uiData); switch (uiType) { case TYPE_VAZRUDEN: + if (m_auiEncounter[0] == uiData) + return; if (uiData == DONE && m_auiEncounter[1] == DONE) DoRespawnGameObject(instance->IsRegularDifficulty() ? GO_FEL_IRON_CHEST : GO_FEL_IRON_CHEST_H, HOUR); if (uiData == FAIL && m_auiEncounter[0] != FAIL) @@ -74,7 +76,9 @@ void instance_ramparts::SetData(uint32 uiType, uint32 uiData) m_auiEncounter[0] = uiData; break; case TYPE_NAZAN: - if (uiData == SPECIAL) + if (m_auiEncounter[1] == uiData) + return; + if (uiData == SPECIAL) // SPECIAL set via ACID { ++m_uiSentryCounter; @@ -96,7 +100,7 @@ void instance_ramparts::SetData(uint32 uiType, uint32 uiData) } } -uint32 instance_ramparts::GetData(uint32 uiType) +uint32 instance_ramparts::GetData(uint32 uiType) const { if (uiType == TYPE_VAZRUDEN) return m_auiEncounter[0]; @@ -115,7 +119,7 @@ void instance_ramparts::DoFailVazruden() // Restore Sentries (counter and respawn them) m_uiSentryCounter = 0; - for (GUIDList::const_iterator itr = m_lSentryGUIDs.begin(); itr != m_lSentryGUIDs.end(); ++itr) + for (GuidList::const_iterator itr = m_lSentryGUIDs.begin(); itr != m_lSentryGUIDs.end(); ++itr) { if (Creature* pSentry = instance->GetCreature(*itr)) pSentry->Respawn(); @@ -128,8 +132,8 @@ void instance_ramparts::DoFailVazruden() pVazruden->Respawn(); else { - if (ScriptedAI* pVazrudenAI = dynamic_cast (pVazruden->AI())) - pVazrudenAI->Reset(); + if (ScriptedAI* pVazrudenAI = dynamic_cast(pVazruden->AI())) + pVazrudenAI->EnterEvadeMode(); } } diff --git a/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp b/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp index ce8f99442..e42cd691c 100644 --- a/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp +++ b/scripts/outland/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,32 +17,18 @@ /* ScriptData SDName: Boss_Magtheridon SD%Complete: 80 -SDComment: Some spell issues with target selection. +SDComment: Phase 3 transition requires additional research. The Manticron cubes require additional core support. Timers need to be revised. SDCategory: Hellfire Citadel, Magtheridon's lair EndScriptData */ #include "precompiled.h" #include "magtheridons_lair.h" -struct Yell -{ - int32 id; -}; - -static Yell RandomTaunt[]= -{ - {-1544000}, - {-1544001}, - {-1544002}, - {-1544003}, - {-1544004}, - {-1544005}, -}; - enum { - SAY_FREED = -1544006, - SAY_AGGRO = -1544007, + // yells + SAY_AGGRO_1 = -1544006, + SAY_AGGRO_2 = -1544007, SAY_BANISH = -1544008, SAY_CHAMBER_DESTROY = -1544009, SAY_PLAYER_KILLED = -1544010, @@ -50,460 +36,273 @@ enum EMOTE_GENERIC_ENRAGED = -1000003, EMOTE_BLASTNOVA = -1544013, - EMOTE_BEGIN = -1544014, EMOTE_FREED = -1544015, + // Maghteridon spells + SPELL_SHADOW_CAGE_DUMMY = 30205, // dummy aura - in creature_template_addon SPELL_BLASTNOVA = 30616, SPELL_CLEAVE = 30619, - SPELL_QUAKE_TRIGGER = 30576, // must be cast with 30561 as the proc spell + // SPELL_QUAKE = 30657, // spell may be related but probably used in the recent versions of the script + // SPELL_QUAKE_TRIGGER = 30576, // spell removed from DBC - triggers 30571 SPELL_QUAKE_KNOCKBACK = 30571, + SPELL_BLAZE = 30541, // triggers 30542 + SPELL_BERSERK = 27680, - SPELL_BLAZE_TRAP = 30542, - SPELL_DEBRIS_VISUAL = 30632, + // phase 3 spells SPELL_CAMERA_SHAKE = 36455, - SPELL_BERSERK = 27680, + SPELL_DEBRIS_KNOCKDOWN = 36449, + SPELL_QUAKE_EFFECT = 30572, // sets the debris during phase 3 - triggers 30632 + SPELL_DEBRIS_DAMAGE = 30631, + SPELL_DEBRIS_VISUAL = 30632, - SPELL_SHADOW_CAGE_DUMMY = 30205, + // Cube spells SPELL_SHADOW_CAGE = 30168, - - SPELL_SHADOW_GRASP_DUMMY = 30207, - SPELL_SHADOW_GRASP = 30410, SPELL_SHADOW_GRASP_VISUAL = 30166, - SPELL_MIND_EXHAUSTION = 44032, // Casted by the cubes when channeling ends - - SPELL_FIRE_BLAST = 37110, + SPELL_SHADOW_GRASP = 30410, + SPELL_MIND_EXHAUSTION = 44032, + // Hellfire channeler spells + SPELL_SHADOW_GRASP_DUMMY = 30207, // dummy spell - cast on OOC timer SPELL_SHADOW_BOLT_VOLLEY = 30510, SPELL_DARK_MENDING = 30528, SPELL_FEAR = 30530, // 39176 SPELL_BURNING_ABYSSAL = 30511, + SPELL_SOUL_TRANSFER = 30531, + + // Abyss spells + SPELL_FIRE_BLAST = 37110, - NPC_MAGS_ROOM = 17516, + // summons + // NPC_MAGS_ROOM = 17516, NPC_BURNING_ABYSS = 17454, + NPC_RAID_TRIGGER = 17376, - // count of clickers needed to interrupt blast nova - MAX_CLICK = 5 + MAX_QUAKE_COUNT = 7, }; -typedef std::map CubeMap; +/*###### +## boss_magtheridon +######*/ -struct MANGOS_DLL_DECL mob_abyssalAI : public ScriptedAI +struct boss_magtheridonAI : public ScriptedAI { - mob_abyssalAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_magtheridonAI(Creature* pCreature) : ScriptedAI(pCreature) { - m_uiTriggerId = 0; - m_uiDespawn_Timer = 60000; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); Reset(); } - uint32 m_uiFireBlast_Timer; - uint32 m_uiDespawn_Timer; - uint32 m_uiTriggerId; + ScriptedInstance* m_pInstance; - void Reset() - { - m_uiFireBlast_Timer = 6000; - } + uint32 m_uiBerserkTimer; + uint32 m_uiQuakeTimer; + uint32 m_uiCleaveTimer; + uint32 m_uiBlastNovaTimer; + uint32 m_uiBlazeTimer; + uint32 m_uiDebrisTimer; + uint32 m_uiTransitionTimer; + uint8 m_uiTransitionCount; + uint8 m_uiQuakeCount; - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) - { - if (m_uiTriggerId == 2 && pSpell->Id == SPELL_BLAZE_TARGET) - { - m_creature->CastSpell(m_creature, SPELL_BLAZE_TRAP, true); - m_creature->SetVisibility(VISIBILITY_OFF); - m_uiDespawn_Timer = 130000; - } - } + bool m_bIsPhase3; - void SetTrigger(uint32 uiTrigger) + void Reset() override { - m_uiTriggerId = uiTrigger; - m_creature->SetDisplayId(11686); + m_uiBerserkTimer = 20 * MINUTE * IN_MILLISECONDS; + m_uiQuakeTimer = 30000; + m_uiBlazeTimer = urand(10000, 15000); + m_uiBlastNovaTimer = 60000; + m_uiCleaveTimer = 15000; + m_uiTransitionTimer = 0; + m_uiTransitionCount = 0; + m_uiDebrisTimer = urand(20000, 30000); - if (m_uiTriggerId == 1) //debris - { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->CastSpell(m_creature, SPELL_DEBRIS_VISUAL, true); - m_uiFireBlast_Timer = 5000; - m_uiDespawn_Timer = 10000; - } - } - - void Aggro(Unit* pWho) - { - m_creature->SetInCombatWithZone(); - } + m_bIsPhase3 = false; - void AttackStart(Unit* pWho) - { - if (m_uiTriggerId) - return; + SetCombatMovement(true); - ScriptedAI::AttackStart(pWho); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void MoveInLineOfSight(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (m_uiTriggerId) - return; + DoScriptText(EMOTE_FREED, m_creature); + DoScriptText(urand(0, 1) ? SAY_AGGRO_1 : SAY_AGGRO_2, m_creature); - ScriptedAI::MoveInLineOfSight(pWho); + m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE_DUMMY); } - void UpdateAI(const uint32 uiDiff) + void KilledUnit(Unit* /*pVictim*/) override { - if (m_uiTriggerId) - { - if (m_uiTriggerId == 1) - { - if (m_uiFireBlast_Timer < uiDiff) - { - m_creature->CastSpell(m_creature, SPELL_DEBRIS_DAMAGE, true); - m_uiTriggerId = 3; - } - else - m_uiFireBlast_Timer -= uiDiff; - } - } - - if (m_uiDespawn_Timer < uiDiff) - { - m_creature->ForcedDespawn(); - return; - } - else - m_uiDespawn_Timer -= uiDiff; - - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiFireBlast_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIRE_BLAST); - m_uiFireBlast_Timer = urand(5000, 15000); - } - else - m_uiFireBlast_Timer -= uiDiff; - - DoMeleeAttackIfReady(); + DoScriptText(SAY_PLAYER_KILLED, m_creature); } -}; -struct MANGOS_DLL_DECL boss_magtheridonAI : public ScriptedAI -{ - boss_magtheridonAI(Creature* pCreature) : ScriptedAI(pCreature) + void JustDied(Unit* /*pKiller*/) override { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - CubeMap m_mCube; - - ScriptedInstance* m_pInstance; - - uint32 m_uiRandChat_Timer; - - uint32 m_uiBerserk_Timer; - uint32 m_uiQuake_Timer; - uint32 m_uiCleave_Timer; - uint32 m_uiBlastNova_Timer; - uint32 m_uiBlaze_Timer; - uint32 m_uiPhase3_Timer; - uint32 m_uiPhase3_Count; - - bool m_bIsIntroDone; - bool m_bIsPhase3; - bool m_bNeedCheckCube; + if (m_pInstance) + m_pInstance->SetData(TYPE_MAGTHERIDON_EVENT, DONE); - void Reset() - { - m_uiRandChat_Timer = 90000; - - m_uiBerserk_Timer = 1320000; - m_uiQuake_Timer = 40000; - m_uiPhase3_Timer = 5000; - m_uiPhase3_Count = 0; - m_uiBlaze_Timer = urand(10000, 30000); - m_uiBlastNova_Timer = 60000; - m_uiCleave_Timer = 15000; - - m_bIsIntroDone = false; - m_bIsPhase3 = false; - m_bNeedCheckCube = false; - - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoScriptText(SAY_DEATH, m_creature); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) - { - m_pInstance->SetData(TYPE_MAGTHERIDON_EVENT, NOT_STARTED); - m_pInstance->SetData(TYPE_HALL_COLLAPSE, NOT_STARTED); - } - } - - void SetClicker(GameObject* pGo, Player* pPlayer) - { - // to avoid multiclicks from 1 cube - if (ObjectGuid guid = m_mCube[pGo->GetObjectGuid()]) - DebuffClicker(m_creature->GetMap()->GetPlayer(guid)); - - m_mCube[pGo->GetObjectGuid()] = pPlayer->GetObjectGuid(); - m_bNeedCheckCube = true; + m_pInstance->SetData(TYPE_MAGTHERIDON_EVENT, FAIL); } - //function to interrupt channeling and debuff clicker with mind exhaused if second person clicks with same cube or after dispeling/ending shadow grasp DoT) - void DebuffClicker(Player* pClicker) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - if (!pClicker || !pClicker->isAlive()) - return; - - pClicker->RemoveAurasDueToSpell(SPELL_SHADOW_GRASP);// cannot interrupt triggered spells - pClicker->InterruptNonMeleeSpells(false); - pClicker->CastSpell(pClicker, SPELL_MIND_EXHAUSTION, true); + // When banished by the cubes + if (pSpell->Id == SPELL_SHADOW_CAGE) + DoScriptText(SAY_BANISH, m_creature); } - void MoveInLineOfSight(Unit* pWho) + void UpdateAI(const uint32 uiDiff) override { - if (!m_bIsIntroDone) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - ScriptedAI::MoveInLineOfSight(pWho); - } - - void NeedCheckCubeStatus() - { - uint32 ClickerNum = 0; - - // now checking if every clicker has debuff from manticron - // if not - apply mind exhaustion and delete from clicker's list - for(CubeMap::iterator i = m_mCube.begin(); i != m_mCube.end(); ++i) + if (m_uiBerserkTimer) { - Player* pClicker = m_creature->GetMap()->GetPlayer(i->second); - - if (!pClicker || !pClicker->HasAura(SPELL_SHADOW_GRASP, EFFECT_INDEX_1)) + if (m_uiBerserkTimer <= uiDiff) { - DebuffClicker(pClicker); - i->second.Clear(); + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + { + DoScriptText(EMOTE_GENERIC_ENRAGED, m_creature); + m_uiBerserkTimer = 0; + } } else - ++ClickerNum; + m_uiBerserkTimer -= uiDiff; } - // if 5 clickers from other cubes apply shadow cage - if (ClickerNum >= MAX_CLICK && !m_creature->HasAura(SPELL_SHADOW_CAGE, EFFECT_INDEX_0) && m_creature->HasAura(SPELL_BLASTNOVA, EFFECT_INDEX_0)) + // Transition to phase 3 + if (m_uiTransitionTimer) { - DoScriptText(SAY_BANISH, m_creature); - m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE, true); - } - else - { - if (ClickerNum < MAX_CLICK && m_creature->HasAura(SPELL_SHADOW_CAGE, EFFECT_INDEX_0)) - m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE); - } - - if (!ClickerNum) - m_bNeedCheckCube = false; - } - - void IntroDone() - { - if (!m_pInstance) - return; - - if (m_pInstance->GetData(TYPE_MAGTHERIDON_EVENT) == NOT_STARTED) - return; - - if (m_pInstance->GetData(TYPE_MAGTHERIDON_EVENT) == DONE) - return; - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE_DUMMY); - m_creature->clearUnitState(UNIT_STAT_STUNNED); - - DoScriptText(EMOTE_FREED, m_creature); - DoScriptText(SAY_FREED, m_creature); + if (m_uiTransitionTimer <= uiDiff) + { + switch (m_uiTransitionCount) + { + case 0: + // Shake the room + if (DoCastSpellIfCan(m_creature, SPELL_CAMERA_SHAKE) == CAST_OK) + { + if (m_pInstance) + m_pInstance->SetData(TYPE_MAGTHERIDON_EVENT, SPECIAL); - m_bIsIntroDone = true; - } + m_uiTransitionTimer = 8000; + } + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_DEBRIS_KNOCKDOWN) == CAST_OK) + m_uiTransitionTimer = 0; + break; + } - void Aggro(Unit* pWho) - { - DoScriptText(SAY_AGGRO, m_creature); - } + ++m_uiTransitionCount; + } + else + m_uiTransitionTimer -= uiDiff; - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) - { - if (pSpell->Id == SPELL_SHADOW_GRASP_DUMMY) - { - m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE_DUMMY, false); - m_creature->addUnitState(UNIT_STAT_STUNNED); + // Workaround for missing spell: no other spells during transition + if (!m_uiTransitionCount) + return; } - } - - void KilledUnit(Unit* pVictim) - { - DoScriptText(SAY_PLAYER_KILLED, m_creature); - } - void JustDied(Unit* pKiller) - { - if (m_pInstance) - m_pInstance->SetData(TYPE_MAGTHERIDON_EVENT, DONE); - - DoScriptText(SAY_DEATH, m_creature); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (m_uiQuakeTimer < uiDiff) { - if (!m_bIsIntroDone) + // Workaround for missing spell + // Note: this won't really stun the boss, but it won't allow him to use other spells + if (!m_uiQuakeCount) { - IntroDone(); - return; + SetCombatMovement(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); } - if (m_uiRandChat_Timer < uiDiff) + if (m_uiQuakeCount < MAX_QUAKE_COUNT) { - DoScriptText(RandomTaunt[rand()%6].id, m_creature); - m_uiRandChat_Timer = 90000; + if (DoCastSpellIfCan(m_creature, SPELL_QUAKE_KNOCKBACK) == CAST_OK) + { + m_uiQuakeTimer = 1000; + ++m_uiQuakeCount; + } } else - m_uiRandChat_Timer -= uiDiff; - - return; - } - - if (m_bNeedCheckCube) - NeedCheckCubeStatus(); - - if (m_uiBerserk_Timer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) { - DoScriptText(EMOTE_GENERIC_ENRAGED, m_creature); - m_uiBerserk_Timer = 60000; + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + m_uiQuakeTimer = 43000; + m_uiQuakeCount = 0; } } else - m_uiBerserk_Timer -= uiDiff; + m_uiQuakeTimer -= uiDiff; - //Cleave_Timer - if (m_uiCleave_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); - m_uiCleave_Timer = 10000; - } - else - m_uiCleave_Timer -= uiDiff; + // don't use other spells during quake + if (m_uiQuakeCount) + return; - if (m_uiQuake_Timer < uiDiff) + if (m_uiCleaveTimer < uiDiff) { - // to avoid blastnova interruption - if (!m_creature->IsNonMeleeSpellCasted(false)) - { - int32 i = SPELL_QUAKE_KNOCKBACK; - m_creature->CastCustomSpell(m_creature, SPELL_QUAKE_TRIGGER, &i, 0, 0, false); - m_uiQuake_Timer = 50000; - } + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) + m_uiCleaveTimer = 10000; } else - m_uiQuake_Timer -= uiDiff; + m_uiCleaveTimer -= uiDiff; - if (m_uiBlastNova_Timer < uiDiff) + if (m_uiBlastNovaTimer < uiDiff) { - // to avoid earthquake interruption - if (!m_creature->hasUnitState(UNIT_STAT_STUNNED)) + if (DoCastSpellIfCan(m_creature, SPELL_BLASTNOVA) == CAST_OK) { DoScriptText(EMOTE_BLASTNOVA, m_creature); - DoCastSpellIfCan(m_creature, SPELL_BLASTNOVA); - m_uiBlastNova_Timer = 60000; + m_uiBlastNovaTimer = 60000; } } else - m_uiBlastNova_Timer -= uiDiff; + m_uiBlastNovaTimer -= uiDiff; - if (m_uiBlaze_Timer < uiDiff) + if (m_uiBlazeTimer < uiDiff) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - float x, y, z; - pTarget->GetPosition(x, y, z); - - if (Creature* pSummon = m_creature->SummonCreature(NPC_BURNING_ABYSS, x, y, z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - { - if (mob_abyssalAI* pAbyssAI = dynamic_cast(pSummon->AI())) - pAbyssAI->SetTrigger(2); - - m_creature->CastSpell(pSummon, SPELL_BLAZE_TARGET, true); - pSummon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - } - } - - m_uiBlaze_Timer = urand(20000, 40000); + if (DoCastSpellIfCan(m_creature, SPELL_BLAZE) == CAST_OK) + m_uiBlazeTimer = urand(10000, 15000); } else - m_uiBlaze_Timer -= uiDiff; + m_uiBlazeTimer -= uiDiff; - if (!m_bIsPhase3 && m_creature->GetHealthPercent() < 30.0f - && !m_creature->IsNonMeleeSpellCasted(false) // blast nova - && !m_creature->hasUnitState(UNIT_STAT_STUNNED))// shadow cage and earthquake + // Transition to phase 3 + if (!m_bIsPhase3 && m_creature->GetHealthPercent() < 30.0f) { - m_bIsPhase3 = true; + // ToDo: maybe there is a spell here - requires additional research DoScriptText(SAY_CHAMBER_DESTROY, m_creature); + m_uiTransitionTimer = 5000; + m_bIsPhase3 = true; } + // Debris fall in phase 3 if (m_bIsPhase3) { - if (m_uiPhase3_Timer < uiDiff) + if (m_uiDebrisTimer < uiDiff) { - switch(m_uiPhase3_Count) - { - case 0: - m_creature->CastSpell(m_creature, SPELL_CAMERA_SHAKE, true); - ++m_uiPhase3_Count; - m_uiPhase3_Timer = 2000; - break; - case 1: - if (m_pInstance) - m_pInstance->SetData(TYPE_HALL_COLLAPSE, IN_PROGRESS); - ++m_uiPhase3_Count; - m_uiPhase3_Timer = 8000; - break; - case 2: - m_creature->CastSpell(m_creature, SPELL_DEBRIS_KNOCKDOWN, true); - ++m_uiPhase3_Count; - m_uiPhase3_Timer = 15000; - break; - case 3: - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - float x, y, z; - pTarget->GetPosition(x, y, z); - - if (Creature* pSummon = m_creature->SummonCreature(NPC_BURNING_ABYSS, x, y, z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 0)) - { - if (mob_abyssalAI* pAbyssAI = dynamic_cast(pSummon->AI())) - pAbyssAI->SetTrigger(1); - } - - m_uiPhase3_Timer = 15000; - } - break; - } + if (DoCastSpellIfCan(m_creature, SPELL_QUAKE_EFFECT) == CAST_OK) + m_uiDebrisTimer = urand(20000, 30000); } else - m_uiPhase3_Timer -= uiDiff; + m_uiDebrisTimer -= uiDiff; } DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI +/*###### +## mob_hellfire_channeler +######*/ + +struct mob_hellfire_channelerAI : public ScriptedAI { mob_hellfire_channelerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -513,131 +312,130 @@ struct MANGOS_DLL_DECL mob_hellfire_channelerAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 m_uiShadowBoltVolley_Timer; - uint32 m_uiDarkMending_Timer; - uint32 m_uiFear_Timer; - uint32 m_uiInfernal_Timer; - - bool m_bIsInfernalSpawned; + uint32 m_uiShadowGraspTimer; + uint32 m_uiShadowBoltVolleyTimer; + uint32 m_uiDarkMendingTimer; + uint32 m_uiFearTimer; + uint32 m_uiInfernalTimer; - void Reset() + void Reset() override { - m_uiShadowBoltVolley_Timer = urand(8000, 10000); - m_uiDarkMending_Timer = 10000; - m_uiFear_Timer = urand(15000, 20000); - m_uiInfernal_Timer = urand(10000, 50000); - - m_bIsInfernalSpawned = false; + m_uiShadowGraspTimer = 10000; + m_uiShadowBoltVolleyTimer = urand(8000, 10000); + m_uiDarkMendingTimer = 10000; + m_uiFearTimer = urand(15000, 20000); + m_uiInfernalTimer = urand(10000, 50000); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (!m_pInstance) - return; - m_creature->InterruptNonMeleeSpells(false); - if (Creature* pMagtheridon = m_pInstance->GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) - { - if (!pMagtheridon->isAlive()) - return; - - if (m_pInstance->GetData(TYPE_CHANNELER_EVENT) == NOT_STARTED) - DoScriptText(EMOTE_BEGIN, pMagtheridon); - } - - m_pInstance->SetData(TYPE_CHANNELER_EVENT, IN_PROGRESS); + if (m_pInstance) + m_pInstance->SetData(TYPE_CHANNELER_EVENT, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) - { - if (m_creature->getVictim()) - pSummoned->AI()->AttackStart(m_creature->getVictim()); - } + // Don't attack on LoS check + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void MoveInLineOfSight(Unit* pWho) + void JustDied(Unit* /*pKiller*/) override { + DoCastSpellIfCan(m_creature, SPELL_SOUL_TRANSFER, CAST_TRIGGERED); } - void JustDied(Unit* pKiller) + void JustReachedHome() override { if (m_pInstance) - m_pInstance->SetData(TYPE_CHANNELER_EVENT, DONE); + m_pInstance->SetData(TYPE_CHANNELER_EVENT, FAIL); + } - pKiller->CastSpell(pKiller, SPELL_SOUL_TRANSFER, false); + void JustSummoned(Creature* pSummoned) override + { + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void JustReachedHome() + void SummonedCreatureDespawn(Creature* pSummoned) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_CHANNELER_EVENT, NOT_STARTED); + if (pSummoned->GetEntry() == NPC_BURNING_ABYSS) + m_uiInfernalTimer = urand(10000, 15000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Channel spell on Magtheridon, on OOC timer + if (m_uiShadowGraspTimer) { - if (!m_creature->IsNonMeleeSpellCasted(false) && !m_creature->IsInEvadeMode()) - DoCastSpellIfCan(m_creature, SPELL_SHADOW_GRASP_DUMMY); + if (m_uiShadowGraspTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_GRASP_DUMMY) == CAST_OK) + m_uiShadowGraspTimer = 0; + } + else + m_uiShadowGraspTimer -= uiDiff; + } + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - } - //Shadow bolt volley - if (m_uiShadowBoltVolley_Timer < uiDiff) + if (m_uiShadowBoltVolleyTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SHADOW_BOLT_VOLLEY); - m_uiShadowBoltVolley_Timer = urand(10000, 20000); + if (DoCastSpellIfCan(m_creature, SPELL_SHADOW_BOLT_VOLLEY) == CAST_OK) + m_uiShadowBoltVolleyTimer = urand(10000, 20000); } else - m_uiShadowBoltVolley_Timer -= uiDiff; + m_uiShadowBoltVolleyTimer -= uiDiff; - //Dark Mending - if (m_uiDarkMending_Timer < uiDiff) + if (m_uiDarkMendingTimer < uiDiff) { - if (m_creature->GetHealthPercent() < 50.0f) + if (Unit* pTarget = DoSelectLowestHpFriendly(30.0f)) { - //Cast on ourselves if we are lower then lowest hp friendly unit - /*if (pLowestHPTarget && LowestHP < m_creature->GetHealth()) - DoCastSpellIfCan(pLowestHPTarget, SPELL_DARK_MENDING); - else*/ - DoCastSpellIfCan(m_creature, SPELL_DARK_MENDING); + if (DoCastSpellIfCan(pTarget, SPELL_DARK_MENDING) == CAST_OK) + m_uiDarkMendingTimer = urand(10000, 20000); } - - m_uiDarkMending_Timer = urand(10000, 20000); } else - m_uiDarkMending_Timer -= uiDiff; + m_uiDarkMendingTimer -= uiDiff; - //Fear - if (m_uiFear_Timer < uiDiff) + if (m_uiFearTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - DoCastSpellIfCan(pTarget, SPELL_FEAR); - - m_uiFear_Timer = urand(25000, 40000); + { + if (DoCastSpellIfCan(pTarget, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = urand(25000, 40000); + } } else - m_uiFear_Timer -= uiDiff; + m_uiFearTimer -= uiDiff; - //Infernal spawning - if (!m_bIsInfernalSpawned && m_uiInfernal_Timer < uiDiff) + if (m_uiInfernalTimer) { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - m_creature->CastSpell(pTarget, SPELL_BURNING_ABYSSAL, true); - - m_bIsInfernalSpawned = true; + if (m_uiInfernalTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BURNING_ABYSSAL) == CAST_OK) + m_uiInfernalTimer = 0; + } + } + else + m_uiInfernalTimer -= uiDiff; } - else - m_uiInfernal_Timer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Manticron Cube +/*###### +## go_manticron_cube +######*/ + bool GOUse_go_manticron_cube(Player* pPlayer, GameObject* pGo) { + // if exhausted or already channeling return + if (pPlayer->HasAura(SPELL_MIND_EXHAUSTION) || pPlayer->HasAura(SPELL_SHADOW_GRASP)) + return true; + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) { if (pInstance->GetData(TYPE_MAGTHERIDON_EVENT) != IN_PROGRESS) @@ -648,22 +446,98 @@ bool GOUse_go_manticron_cube(Player* pPlayer, GameObject* pGo) if (!pMagtheridon->isAlive()) return true; - // if exhausted or already channeling return - if (pPlayer->HasAura(SPELL_MIND_EXHAUSTION, EFFECT_INDEX_0) || pPlayer->HasAura(SPELL_SHADOW_GRASP, EFFECT_INDEX_1)) - return true; - - pPlayer->InterruptNonMeleeSpells(false); - pPlayer->CastSpell(pPlayer, SPELL_SHADOW_GRASP, true); - pPlayer->CastSpell(pPlayer, SPELL_SHADOW_GRASP_VISUAL, false); + // visual is cast by cube + if (Creature* pTrigger = GetClosestCreatureWithEntry(pGo, NPC_RAID_TRIGGER, 5.0f)) + pTrigger->CastSpell(pTrigger, SPELL_SHADOW_GRASP_VISUAL, false); - if (boss_magtheridonAI* pMagAI = dynamic_cast(pMagtheridon->AI())) - pMagAI->SetClicker(pGo, pPlayer); + // the real spell is cast by player + pPlayer->CastSpell(pPlayer, SPELL_SHADOW_GRASP, false, NULL, NULL, pGo->GetObjectGuid()); } } - return false; + return true; } +// TODO Remove this 'script' when combat and persistent area auras can be proper prevented from core-side +struct npc_target_triggerAI : public Scripted_NoMovementAI +{ + npc_target_triggerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} + + uint32 m_uiDebrisTimer; + + void Reset() override + { + m_uiDebrisTimer = 0; + } + + void AttackStart(Unit* /*pWho*/) override {} + void MoveInLineOfSight(Unit* /*pWho*/) override {} + + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override + { + // Workaround for missing core support for this type of dummy aura + if (pSpell->Id == SPELL_QUAKE_EFFECT) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEBRIS_VISUAL) == CAST_OK) + m_uiDebrisTimer = 5000; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Cast debris damage after 5 seconds (on visual removal) + if (m_uiDebrisTimer) + { + if (m_uiDebrisTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEBRIS_DAMAGE) == CAST_OK) + m_uiDebrisTimer = 0; + } + else + m_uiDebrisTimer -= uiDiff; + } + } +}; + +// ToDo: move this script to eventAI +struct mob_abyssalAI : public ScriptedAI +{ + mob_abyssalAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiFireBlastTimer; + uint32 m_uiDespawnTimer; + + void Reset() override + { + m_uiDespawnTimer = 60000; + m_uiFireBlastTimer = 6000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiDespawnTimer < uiDiff) + { + m_creature->ForcedDespawn(); + m_uiDespawnTimer = 10000; + } + else + m_uiDespawnTimer -= uiDiff; + + if (m_uiFireBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIRE_BLAST) == CAST_OK) + m_uiFireBlastTimer = urand(5000, 15000); + } + else + m_uiFireBlastTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + CreatureAI* GetAI_boss_magtheridon(Creature* pCreature) { return new boss_magtheridonAI(pCreature); @@ -674,6 +548,11 @@ CreatureAI* GetAI_mob_hellfire_channeler(Creature* pCreature) return new mob_hellfire_channelerAI(pCreature); } +CreatureAI* GetAI_npc_target_triggerAI(Creature* pCreature) +{ + return new npc_target_triggerAI(pCreature); +} + CreatureAI* GetAI_mob_abyssalAI(Creature* pCreature) { return new mob_abyssalAI(pCreature); @@ -698,6 +577,11 @@ void AddSC_boss_magtheridon() pNewScript->pGOUse = &GOUse_go_manticron_cube; pNewScript->RegisterSelf(); + pNewScript = new Script; + pNewScript->Name = "npc_target_trigger"; + pNewScript->GetAI = &GetAI_npc_target_triggerAI; + pNewScript->RegisterSelf(); + pNewScript = new Script; pNewScript->Name = "mob_abyssal"; pNewScript->GetAI = &GetAI_mob_abyssalAI; diff --git a/scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp b/scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp index bb5a35056..d7b12481b 100644 --- a/scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp +++ b/scripts/outland/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,45 +24,47 @@ EndScriptData */ #include "precompiled.h" #include "magtheridons_lair.h" -instance_magtheridons_lair::instance_magtheridons_lair(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } +instance_magtheridons_lair::instance_magtheridons_lair(Map* pMap) : ScriptedInstance(pMap), + m_uiRandYellTimer(90000), + m_uiCageBreakTimer(0), + m_uiCageBreakStage(0) +{ + Initialize(); +} void instance_magtheridons_lair::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiCageTimer = 0; - m_uiRespawnTimer = 0; } bool instance_magtheridons_lair::IsEncounterInProgress() const { - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { if (m_auiEncounter[i] == IN_PROGRESS) return true; + } return false; } void instance_magtheridons_lair::OnCreatureCreate(Creature* pCreature) { - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_MAGTHERIDON: m_mNpcEntryGuidStore[NPC_MAGTHERIDON] = pCreature->GetObjectGuid(); break; case NPC_CHANNELER: - m_sChannelerGuid.insert(pCreature->GetObjectGuid()); + m_lChannelerGuidList.push_back(pCreature->GetObjectGuid()); break; } } void instance_magtheridons_lair::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { - case GO_MANTICRON_CUBE: - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); - break; case GO_DOODAD_HF_MAG_DOOR01: // event door m_mGoEntryGuidStore[GO_DOODAD_HF_MAG_DOOR01] = pGo->GetObjectGuid(); break; @@ -73,179 +75,170 @@ void instance_magtheridons_lair::OnObjectCreate(GameObject* pGo) case GO_MAGTHERIDON_COLUMN_005: case GO_MAGTHERIDON_COLUMN_000: case GO_MAGTHERIDON_COLUMN_001: - m_sColumnGuid.insert(pGo->GetObjectGuid()); + m_lColumnGuidList.push_back(pGo->GetObjectGuid()); + break; + case GO_MANTICRON_CUBE: + m_lCubeGuidList.push_back(pGo->GetObjectGuid()); break; } } void instance_magtheridons_lair::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_MAGTHERIDON_EVENT: - m_auiEncounter[0] = uiData; - if (uiData == NOT_STARTED) - m_uiRespawnTimer = 10000; - if (uiData != IN_PROGRESS) + switch (uiData) { - if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_DOODAD_HF_MAG_DOOR01)) - pDoor->SetGoState(GO_STATE_ACTIVE); - } - break; - case TYPE_CHANNELER_EVENT: - switch(uiData) - { - case NOT_STARTED: // Reset all channelers once one is reset. - if (m_auiEncounter[1] != NOT_STARTED) + case FAIL: + // Reset channelers + for (GuidList::const_iterator itr = m_lChannelerGuidList.begin(); itr != m_lChannelerGuidList.end(); ++itr) { - m_auiEncounter[1] = NOT_STARTED; - - if (m_sChannelerGuid.empty()) + if (Creature* pChanneler = instance->GetCreature(*itr)) { - debug_log("SD2: Instance Magtheridon: Channeler GUID list are empty."); - break; + if (!pChanneler->isAlive()) + pChanneler->Respawn(); } - - for(GUIDSet::const_iterator itr = m_sChannelerGuid.begin(); itr != m_sChannelerGuid.end(); ++itr) - { - if (Creature* pChanneler = instance->GetCreature(*itr)) - { - if (pChanneler->isAlive()) - pChanneler->AI()->EnterEvadeMode(); - else - pChanneler->Respawn(); - } - } - - m_uiCageTimer = 0; - - if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_DOODAD_HF_MAG_DOOR01)) - pDoor->SetGoState(GO_STATE_ACTIVE); } - break; - case IN_PROGRESS: // Event start. - if (m_auiEncounter[1] != IN_PROGRESS) - { - m_auiEncounter[1] = IN_PROGRESS; - - // Let all five channelers aggro. - for(GUIDSet::const_iterator itr = m_sChannelerGuid.begin(); itr != m_sChannelerGuid.end(); ++itr) - { - Creature* pChanneler = instance->GetCreature(*itr); - if (pChanneler && pChanneler->isAlive()) - AttackNearestTarget(pChanneler); - } + // Reset columns + for (GuidList::const_iterator itr = m_lColumnGuidList.begin(); itr != m_lColumnGuidList.end(); ++itr) + { + if (GameObject* pColumn = instance->GetGameObject(*itr)) + pColumn->ResetDoorOrButton(); + } - // Magtheridon breaks free after two minutes. - Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON); + // Reset cubes + for (GuidList::const_iterator itr = m_lCubeGuidList.begin(); itr != m_lCubeGuidList.end(); ++itr) + DoToggleGameObjectFlags(*itr, GO_FLAG_NO_INTERACT, true); - if (pMagtheridon && pMagtheridon->isAlive()) - m_uiCageTimer = 120000; + // Reset timers and doors + SetData(TYPE_CHANNELER_EVENT, NOT_STARTED); + m_uiCageBreakTimer = 0; + m_uiCageBreakStage = 0; - if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_DOODAD_HF_MAG_DOOR01)) - pDoor->SetGoState(GO_STATE_READY); - } + // no break; + case DONE: + // Reset door on Fail or Done + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_DOODAD_HF_MAG_DOOR01)) + pDoor->ResetDoorOrButton(); break; - case DONE: // Add buff and check if all channelers are dead. - for(GUIDSet::iterator itr = m_sChannelerGuid.begin(); itr != m_sChannelerGuid.end(); ++itr) + case IN_PROGRESS: + // Set boss in combat + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) { - Creature* pChanneler = instance->GetCreature(*itr); - - if (pChanneler && pChanneler->isAlive()) + if (pMagtheridon->isAlive()) { - //Channeler->InterruptNonMeleeSpells(false); - //Channeler->CastSpell(Channeler, SPELL_SOUL_TRANSFER, false); - uiData = IN_PROGRESS; - break; + pMagtheridon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pMagtheridon->SetInCombatWithZone(); } } + // Enable cubes + for (GuidList::const_iterator itr = m_lCubeGuidList.begin(); itr != m_lCubeGuidList.end(); ++itr) + DoToggleGameObjectFlags(*itr, GO_FLAG_NO_INTERACT, false); break; + case SPECIAL: + // Collapse the hall - don't store this value + for (GuidList::const_iterator itr = m_lColumnGuidList.begin(); itr != m_lColumnGuidList.end(); ++itr) + DoUseDoorOrButton(*itr); + // return, don't set encounter as special + return; } - m_auiEncounter[1] = uiData; + m_auiEncounter[uiType] = uiData; break; - case TYPE_HALL_COLLAPSE: - // IN_PROGRESS - collapse / NOT_STARTED - reset - for(GUIDSet::const_iterator itr = m_sColumnGuid.begin(); itr != m_sColumnGuid.end(); ++itr) - DoUseDoorOrButton(*itr); + case TYPE_CHANNELER_EVENT: + // don't set the same data twice + if (m_auiEncounter[1] == uiData) + break; + // stop the event timer on fail + if (uiData == FAIL) + { + m_uiCageBreakTimer = 0; + m_uiCageBreakStage = 0; + + // Reset door on Fail + if (GameObject* pDoor = GetSingleGameObjectFromStorage(GO_DOODAD_HF_MAG_DOOR01)) + pDoor->ResetDoorOrButton(); + + // Reset Magtheridon + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) + { + if (pMagtheridon->isAlive()) + pMagtheridon->AI()->EnterEvadeMode(); + } + } + // prepare Magtheridon for release + if (uiData == IN_PROGRESS) + { + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) + { + if (pMagtheridon->isAlive()) + { + DoScriptText(EMOTE_EVENT_BEGIN, pMagtheridon); + m_uiCageBreakTimer = MINUTE * IN_MILLISECONDS; + } + } + + // combat door + DoUseDoorOrButton(GO_DOODAD_HF_MAG_DOOR01); + } + m_auiEncounter[uiType] = uiData; break; } + + // Instance save isn't needed for this one } -uint32 instance_magtheridons_lair::GetData(uint32 uiType) +uint32 instance_magtheridons_lair::GetData(uint32 uiType) const { - if (uiType == TYPE_MAGTHERIDON_EVENT) - return m_auiEncounter[0]; - if (uiType == TYPE_CHANNELER_EVENT) - return m_auiEncounter[1]; + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; return 0; } -void instance_magtheridons_lair::AttackNearestTarget(Creature* pCreature) +void instance_magtheridons_lair::Update(uint32 uiDiff) { - float minRange = VISIBLE_RANGE; - float range; - Player* target = NULL; - - Map::PlayerList const& players = instance->GetPlayers(); - for(Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + // Prepare to release Magtheridon + if (m_uiCageBreakTimer) { - if (Player* i_pl = itr->getSource()) + if (m_uiCageBreakTimer <= uiDiff) { - if (i_pl->isTargetableForAttack()) + switch (m_uiCageBreakStage) { - range = i_pl->GetDistance(pCreature); - if (range < minRange) - { - minRange = range; - target = i_pl; - } + case 0: + if (Creature* pMagtheridon = GetSingleCreatureFromStorage(NPC_MAGTHERIDON)) + { + if (pMagtheridon->isAlive()) + { + DoScriptText(EMOTE_NEARLY_FREE, pMagtheridon); + m_uiCageBreakTimer = MINUTE * IN_MILLISECONDS; + } + } + break; + case 1: + SetData(TYPE_MAGTHERIDON_EVENT, IN_PROGRESS); + m_uiCageBreakTimer = 0; + break; } - } - } - if (!target) - { - debug_log("SD2: Instance Magtheridon: AttackNearestTarget failed. No player."); - return; - } - pCreature->AI()->AttackStart(target); -} - -void instance_magtheridons_lair::Update(uint32 uiDiff) -{ - if (m_uiCageTimer) - { - if (m_uiCageTimer <= uiDiff) - { - SetData(TYPE_MAGTHERIDON_EVENT, IN_PROGRESS); - m_uiCageTimer = 0; + ++m_uiCageBreakStage; } else - m_uiCageTimer -= uiDiff; + m_uiCageBreakTimer -= uiDiff; } - if (m_uiRespawnTimer) - { - if (m_uiRespawnTimer <= uiDiff) - { - for(GUIDSet::const_iterator itr = m_sChannelerGuid.begin(); itr != m_sChannelerGuid.end(); ++itr) - { - if (Creature* pChanneler = instance->GetCreature(*itr)) - { - if (pChanneler->isAlive()) - pChanneler->AI()->EnterEvadeMode(); - else - pChanneler->Respawn(); - } - } + // no yell if event is in progress or finished + if (m_auiEncounter[TYPE_CHANNELER_EVENT] == IN_PROGRESS || m_auiEncounter[TYPE_MAGTHERIDON_EVENT] == DONE) + return; - m_uiRespawnTimer = 0; - } - else - m_uiRespawnTimer -= uiDiff; + if (m_uiRandYellTimer < uiDiff) + { + DoOrSimulateScriptTextForThisInstance(aRandomTaunt[urand(0, 5)], NPC_MAGTHERIDON); + m_uiRandYellTimer = 90000; } + else + m_uiRandYellTimer -= uiDiff; } InstanceData* GetInstanceData_instance_magtheridons_lair(Map* pMap) diff --git a/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h b/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h index 2a7c8fe7f..be77b8ab4 100644 --- a/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h +++ b/scripts/outland/hellfire_citadel/magtheridons_lair/magtheridons_lair.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -9,20 +9,12 @@ enum { MAX_ENCOUNTER = 2, - TYPE_MAGTHERIDON_EVENT = 1, - TYPE_CHANNELER_EVENT = 2, - TYPE_HALL_COLLAPSE = 4, - - DATA_CHANNELER = 5, + TYPE_MAGTHERIDON_EVENT = 0, + TYPE_CHANNELER_EVENT = 1, NPC_MAGTHERIDON = 17257, NPC_CHANNELER = 17256, - SPELL_SOUL_TRANSFER = 30531, - SPELL_BLAZE_TARGET = 30541, - SPELL_DEBRIS_DAMAGE = 30631, - SPELL_DEBRIS_KNOCKDOWN = 36449, - GO_MANTICRON_CUBE = 181713, GO_DOODAD_HF_MAG_DOOR01 = 183847, GO_DOODAD_HF_RAID_FX01 = 184653, @@ -32,35 +24,40 @@ enum GO_MAGTHERIDON_COLUMN_005 = 184637, GO_MAGTHERIDON_COLUMN_000 = 184638, GO_MAGTHERIDON_COLUMN_001 = 184639, + + EMOTE_EVENT_BEGIN = -1544014, + EMOTE_NEARLY_FREE = -1544016, }; -class MANGOS_DLL_DECL instance_magtheridons_lair : public ScriptedInstance +static const int32 aRandomTaunt[] = { -1544000, -1544001, -1544002, -1544003, -1544004, -1544005}; + +class instance_magtheridons_lair : public ScriptedInstance { public: instance_magtheridons_lair(Map* pMap); - void Initialize(); - - bool IsEncounterInProgress() const; + void Initialize() override; - void OnCreatureCreate(Creature* pCreature); - void OnObjectCreate(GameObject* pGo); + bool IsEncounterInProgress() const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void AttackNearestTarget(Creature* pCreature); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void Update(uint32 uiDiff); + void Update(uint32 uiDiff) override; private: uint32 m_auiEncounter[MAX_ENCOUNTER]; - GUIDSet m_sChannelerGuid; - GUIDSet m_sColumnGuid; + GuidList m_lChannelerGuidList; + GuidList m_lColumnGuidList; + GuidList m_lCubeGuidList; - uint32 m_uiCageTimer; - uint32 m_uiRespawnTimer; + uint32 m_uiRandYellTimer; + uint32 m_uiCageBreakTimer; + uint8 m_uiCageBreakStage; }; #endif diff --git a/scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp b/scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp index 9762fa8ce..e84619b0f 100644 --- a/scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp +++ b/scripts/outland/hellfire_citadel/shattered_halls/boss_nethekurse.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,20 +35,20 @@ struct Say int32 id; }; -static Say PeonAttacked[]= +static Say PeonAttacked[] = { - {-1540001}, - {-1540002}, - {-1540003}, - {-1540004}, + { -1540001}, + { -1540002}, + { -1540003}, + { -1540004}, }; -static Say PeonDies[]= +static Say PeonDies[] = { - {-1540005}, - {-1540006}, - {-1540007}, - {-1540008}, + { -1540005}, + { -1540006}, + { -1540007}, + { -1540008}, }; enum @@ -79,7 +79,7 @@ enum NPC_FEL_ORC_CONVERT = 17083, }; -struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI +struct boss_grand_warlock_nethekurseAI : public ScriptedAI { boss_grand_warlock_nethekurseAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -96,7 +96,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI bool m_bIsIntroEvent; bool m_bIsMainEvent; bool m_bSpinOnce; - //bool m_bHasTaunted; + // bool m_bHasTaunted; bool m_bPhase; uint32 m_uiPeonEngagedCount; @@ -109,13 +109,13 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI ObjectGuid m_lastEventInvokerGuid; - void Reset() + void Reset() override { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_bIsIntroEvent = false; m_bIsMainEvent = false; - //m_bHasTaunted = false; + // m_bHasTaunted = false; m_bSpinOnce = false; m_bPhase = false; @@ -158,13 +158,12 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI if (pKiller) AttackStart(pKiller); - } } void DoTauntPeons() { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_TAUNT_1, m_creature); break; case 1: DoScriptText(SAY_TAUNT_2, m_creature); break; @@ -186,7 +185,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI AttackStart(pEnemy); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_bIsIntroEvent || !m_bIsMainEvent) return; @@ -204,7 +203,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI } } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bIntroOnce && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && m_creature->IsWithinDistInMap(pWho, 50.0f) && m_creature->IsWithinLOSInMap(pWho)) { @@ -224,9 +223,9 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI ScriptedAI::MoveInLineOfSight(pWho); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO_1, m_creature); break; case 1: DoScriptText(SAY_AGGRO_2, m_creature); break; @@ -234,7 +233,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // ToDo: this should be done in DB pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -243,12 +242,12 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI pSummoned->CastSpell(pSummoned, SPELL_CONSUMPTION, false, NULL, NULL, m_creature->GetObjectGuid()); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DIE, m_creature); @@ -258,7 +257,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI m_pInstance->SetData(TYPE_NETHEKURSE, DONE); } - void JustReachedHome() + void JustReachedHome() override { if (m_pInstance) m_pInstance->SetData(TYPE_NETHEKURSE, FAIL); @@ -272,7 +271,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bIsIntroEvent) { @@ -338,7 +337,7 @@ struct MANGOS_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI +struct mob_fel_orc_convertAI : public ScriptedAI { mob_fel_orc_convertAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -349,18 +348,18 @@ struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI ScriptedInstance* m_pInstance; uint32 m_uiHemorrhageTimer; - void Reset() + void Reset() override { m_creature->SetNoCallAssistance(true); // we don't want any assistance (WE R HEROZ!) m_uiHemorrhageTimer = 3000; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* /*pWho*/) override { return; } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (m_pInstance) { @@ -378,7 +377,7 @@ struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (m_pInstance) { @@ -393,7 +392,7 @@ struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -411,13 +410,13 @@ struct MANGOS_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI }; // NOTE: this creature are also summoned by other spells, for different creatures -struct MANGOS_DLL_DECL mob_lesser_shadow_fissureAI : public Scripted_NoMovementAI +struct mob_lesser_shadow_fissureAI : public Scripted_NoMovementAI { mob_lesser_shadow_fissureAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } - void Reset() { } - void MoveInLineOfSight(Unit* pWho) { } - void AttackStart(Unit* pWho) { } + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } }; CreatureAI* GetAI_boss_grand_warlock_nethekurse(Creature* pCreature) diff --git a/scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp b/scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp index bbee1ec9c..dd86c3e26 100644 --- a/scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp +++ b/scripts/outland/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -52,62 +52,62 @@ struct Yell uint32 creature; }; -static Yell GoCombat[]= +static Yell GoCombat[] = { - {-1540018, NPC_LEFT_HEAD}, - {-1540019, NPC_LEFT_HEAD}, - {-1540020, NPC_LEFT_HEAD}, + { -1540018, NPC_LEFT_HEAD}, + { -1540019, NPC_LEFT_HEAD}, + { -1540020, NPC_LEFT_HEAD}, }; -static Yell GoCombatDelay[]= +static Yell GoCombatDelay[] = { - {-1540021, NPC_RIGHT_HEAD}, - {-1540022, NPC_RIGHT_HEAD}, - {-1540023, NPC_RIGHT_HEAD}, + { -1540021, NPC_RIGHT_HEAD}, + { -1540022, NPC_RIGHT_HEAD}, + { -1540023, NPC_RIGHT_HEAD}, }; -static Yell Threat[]= +static Yell Threat[] = { - {-1540024, NPC_LEFT_HEAD}, - {-1540025, NPC_RIGHT_HEAD}, - {-1540026, NPC_LEFT_HEAD}, - {-1540027, NPC_LEFT_HEAD}, + { -1540024, NPC_LEFT_HEAD}, + { -1540025, NPC_RIGHT_HEAD}, + { -1540026, NPC_LEFT_HEAD}, + { -1540027, NPC_LEFT_HEAD}, }; -static Yell ThreatDelay1[]= +static Yell ThreatDelay1[] = { - {-1540028, NPC_RIGHT_HEAD}, - {-1540029, NPC_LEFT_HEAD}, - {-1540030, NPC_RIGHT_HEAD}, - {-1540031, NPC_RIGHT_HEAD}, + { -1540028, NPC_RIGHT_HEAD}, + { -1540029, NPC_LEFT_HEAD}, + { -1540030, NPC_RIGHT_HEAD}, + { -1540031, NPC_RIGHT_HEAD}, }; -static Yell ThreatDelay2[]= +static Yell ThreatDelay2[] = { - {-1540032, NPC_LEFT_HEAD}, - {-1540033, NPC_RIGHT_HEAD}, - {-1540034, NPC_LEFT_HEAD}, - {-1540035, NPC_LEFT_HEAD}, + { -1540032, NPC_LEFT_HEAD}, + { -1540033, NPC_RIGHT_HEAD}, + { -1540034, NPC_LEFT_HEAD}, + { -1540035, NPC_LEFT_HEAD}, }; -static Yell Killing[]= +static Yell Killing[] = { - {-1540036, NPC_LEFT_HEAD}, - {-1540037, NPC_RIGHT_HEAD}, + { -1540036, NPC_LEFT_HEAD}, + { -1540037, NPC_RIGHT_HEAD}, }; -static Yell KillingDelay[]= +static Yell KillingDelay[] = { - {-1540038, NPC_RIGHT_HEAD}, - {-1000000, NPC_LEFT_HEAD}, + { -1540038, NPC_RIGHT_HEAD}, + { -1000000, NPC_LEFT_HEAD}, }; -struct MANGOS_DLL_DECL mob_omrogg_headsAI : public ScriptedAI +struct mob_omrogg_headsAI : public ScriptedAI { mob_omrogg_headsAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 m_uiDeath_Timer; + uint32 m_uiDeathTimer; bool m_bDeathYell; - void Reset() + void Reset() override { - m_uiDeath_Timer = 4000; + m_uiDeathTimer = 2000; m_bDeathYell = false; } @@ -116,21 +116,23 @@ struct MANGOS_DLL_DECL mob_omrogg_headsAI : public ScriptedAI m_bDeathYell = true; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_bDeathYell) return; - if (m_uiDeath_Timer < uiDiff) + if (m_uiDeathTimer < uiDiff) { DoScriptText(YELL_DIE_R, m_creature); - m_uiDeath_Timer = false; - m_creature->SetDeathState(JUST_DIED); - }else m_uiDeath_Timer -= uiDiff; + m_uiDeathTimer = 10000; + m_creature->ForcedDespawn(1000); + } + else + m_uiDeathTimer -= uiDiff; } }; -struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI +struct boss_warbringer_omroggAI : public ScriptedAI { boss_warbringer_omroggAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -154,43 +156,28 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI bool m_bThreatYell2; bool m_bKillingYell; - uint32 m_uiDelay_Timer; - uint32 m_uiBlastWave_Timer; + uint32 m_uiDelayTimer; + uint32 m_uiBlastWaveTimer; uint32 m_uiBlastCount; - uint32 m_uiFear_Timer; - uint32 m_uiBurningMaul_Timer; - uint32 m_uiThunderClap_Timer; - uint32 m_uiResetThreat_Timer; + uint32 m_uiFearTimer; + uint32 m_uiBurningMaulTimer; + uint32 m_uiThunderClapTimer; + uint32 m_uiResetThreatTimer; - void Reset() + void Reset() override { - if (Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid)) - { - pLeftHead->SetDeathState(JUST_DIED); - m_leftHeadGuid.Clear(); - } - - if (Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid)) - { - pRightHead->SetDeathState(JUST_DIED); - m_rightHeadGuid.Clear(); - } - - m_bAggroYell = false; - m_bThreatYell = false; - m_bThreatYell2 = false; - m_bKillingYell = false; - - m_uiDelay_Timer = 4000; - m_uiBlastWave_Timer = 0; - m_uiBlastCount = 0; - m_uiFear_Timer = 8000; - m_uiBurningMaul_Timer = 25000; - m_uiThunderClap_Timer = 15000; - m_uiResetThreat_Timer = 30000; - - if (m_pInstance) - m_pInstance->SetData(TYPE_OMROGG, NOT_STARTED); //End boss can use this later. O'mrogg must be defeated(DONE) or he will come to aid. + m_bAggroYell = false; + m_bThreatYell = false; + m_bThreatYell2 = false; + m_bKillingYell = false; + + m_uiDelayTimer = 4000; + m_uiBlastWaveTimer = 0; + m_uiBlastCount = 0; + m_uiFearTimer = 8000; + m_uiBurningMaulTimer = 25000; + m_uiThunderClapTimer = 15000; + m_uiResetThreatTimer = 30000; } void DoYellForThreat() @@ -207,11 +194,11 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI DoScriptText(Threat[m_iThreat].id, pSource); - m_uiDelay_Timer = 3500; + m_uiDelayTimer = 3500; m_bThreatYell = true; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { m_creature->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); m_creature->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); @@ -222,7 +209,7 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI DoScriptText(GoCombat[m_iAggro].id, pLeftHead); - m_uiDelay_Timer = 3500; + m_uiDelayTimer = 3500; m_bAggroYell = true; } @@ -230,20 +217,15 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI m_pInstance->SetData(TYPE_OMROGG, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_LEFT_HEAD) m_leftHeadGuid = pSummoned->GetObjectGuid(); - - if (pSummoned->GetEntry() == NPC_RIGHT_HEAD) + else if (pSummoned->GetEntry() == NPC_RIGHT_HEAD) m_rightHeadGuid = pSummoned->GetObjectGuid(); - - //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - //summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pSummoned->SetVisibility(VISIBILITY_OFF); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); @@ -255,11 +237,11 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI Creature* pSource = (pLeftHead->GetEntry() == Killing[m_iKilling].creature ? pLeftHead : pRightHead); - switch(m_iKilling) + switch (m_iKilling) { case 0: DoScriptText(Killing[m_iKilling].id, pSource); - m_uiDelay_Timer = 3500; + m_uiDelayTimer = 3500; m_bKillingYell = true; break; case 1: @@ -269,7 +251,7 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); @@ -278,7 +260,7 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI return; DoScriptText(YELL_DIE_L, pLeftHead); - pLeftHead->SetDeathState(JUST_DIED); + pLeftHead->ForcedDespawn(1000); if (mob_omrogg_headsAI* pHeadAI = dynamic_cast(pRightHead->AI())) pHeadAI->DoDeathYell(); @@ -287,11 +269,29 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI m_pInstance->SetData(TYPE_OMROGG, DONE); } - void UpdateAI(const uint32 uiDiff) + void JustReachedHome() override + { + if (Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid)) + { + pLeftHead->ForcedDespawn(); + m_leftHeadGuid.Clear(); + } + + if (Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid)) + { + pRightHead->ForcedDespawn(); + m_rightHeadGuid.Clear(); + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_OMROGG, FAIL); + } + + void UpdateAI(const uint32 uiDiff) override { - if (m_uiDelay_Timer < uiDiff) + if (m_uiDelayTimer < uiDiff) { - m_uiDelay_Timer = 3500; + m_uiDelayTimer = 3500; Creature* pLeftHead = m_creature->GetMap()->GetCreature(m_leftHeadGuid); Creature* pRightHead = m_creature->GetMap()->GetCreature(m_rightHeadGuid); @@ -329,52 +329,71 @@ struct MANGOS_DLL_DECL boss_warbringer_omroggAI : public ScriptedAI DoScriptText(KillingDelay[m_iKilling].id, pSource); m_bKillingYell = false; } - }else m_uiDelay_Timer -= uiDiff; + } + else + m_uiDelayTimer -= uiDiff; if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiBlastCount && m_uiBlastWave_Timer <= uiDiff) + if (m_uiBlastCount && m_uiBlastWaveTimer) { - DoCastSpellIfCan(m_creature,SPELL_BLAST_WAVE); - m_uiBlastWave_Timer = 5000; - ++m_uiBlastCount; - - if (m_uiBlastCount == 3) - m_uiBlastCount = 0; - }else m_uiBlastWave_Timer -= uiDiff; + if (m_uiBlastWaveTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BLAST_WAVE) == CAST_OK) + { + m_uiBlastWaveTimer = 5000; + ++m_uiBlastCount; + + if (m_uiBlastCount == 3) + m_uiBlastCount = 0; + } + } + else + m_uiBlastWaveTimer -= uiDiff; + } - if (m_uiBurningMaul_Timer < uiDiff) + if (m_uiBurningMaulTimer < uiDiff) { - DoScriptText(EMOTE_ENRAGE, m_creature); - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_BURNING_MAUL : SPELL_BURNING_MAUL_H); - m_uiBurningMaul_Timer = 40000; - m_uiBlastWave_Timer = 16000; - m_uiBlastCount = 1; - }else m_uiBurningMaul_Timer -= uiDiff; - - if (m_uiResetThreat_Timer < uiDiff) + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_BURNING_MAUL : SPELL_BURNING_MAUL_H) == CAST_OK) + { + DoScriptText(EMOTE_ENRAGE, m_creature); + m_uiBurningMaulTimer = 40000; + m_uiBlastWaveTimer = 16000; + m_uiBlastCount = 1; + } + } + else + m_uiBurningMaulTimer -= uiDiff; + + if (m_uiResetThreatTimer < uiDiff) { - if (Unit *target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0)) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { DoYellForThreat(); DoResetThreat(); - m_creature->AddThreat(target); + AttackStart(pTarget); } - m_uiResetThreat_Timer = urand(25000, 40000); - }else m_uiResetThreat_Timer -= uiDiff; + m_uiResetThreatTimer = urand(25000, 40000); + } + else + m_uiResetThreatTimer -= uiDiff; - if (m_uiFear_Timer < uiDiff) + if (m_uiFearTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_FEAR); - m_uiFear_Timer = urand(15000, 35000); - }else m_uiFear_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) + m_uiFearTimer = urand(15000, 35000); + } + else + m_uiFearTimer -= uiDiff; - if (m_uiThunderClap_Timer < uiDiff) + if (m_uiThunderClapTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_THUNDERCLAP); - m_uiThunderClap_Timer = urand(15000, 30000); - }else m_uiThunderClap_Timer -= uiDiff; + if (DoCastSpellIfCan(m_creature, SPELL_THUNDERCLAP) == CAST_OK) + m_uiThunderClapTimer = urand(15000, 30000); + } + else + m_uiThunderClapTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp b/scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp index 62acb0394..432cb74c1 100644 --- a/scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp +++ b/scripts/outland/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -53,7 +53,7 @@ float AssassEntrance[3] = {275.136f, -84.29f, 2.3f}; // y -8 float AssassExit[3] = {184.233f, -84.29f, 2.3f}; // y -8 float AddsEntrance[3] = {306.036f, -84.29f, 1.93f}; -struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI +struct boss_warchief_kargath_bladefistAI : public ScriptedAI { boss_warchief_kargath_bladefistAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -65,8 +65,8 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - GUIDVector m_vAddGuids; - GUIDVector m_vAssassinGuids; + GuidVector m_vAddGuids; + GuidVector m_vAssassinGuids; uint32 m_uiChargeTimer; uint32 m_uiBladeDanceTimer; @@ -80,7 +80,7 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI uint32 m_uiTargetNum; - void Reset() + void Reset() override { m_creature->SetSpeedRate(MOVE_RUN, 2.0f); @@ -94,9 +94,9 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI m_uiAssassinsTimer = 5000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_AGGRO1, m_creature); break; case 1: DoScriptText(SAY_AGGRO2, m_creature); break; @@ -107,9 +107,9 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI m_pInstance->SetData(TYPE_BLADEFIST, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - switch(pSummoned->GetEntry()) + switch (pSummoned->GetEntry()) { case NPC_HEARTHEN_GUARD: case NPC_SHARPSHOOTER_GUARD: @@ -125,13 +125,13 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_PLAYER) DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); DoDespawnAdds(); @@ -140,7 +140,7 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI m_pInstance->SetData(TYPE_BLADEFIST, DONE); } - void JustReachedHome() + void JustReachedHome() override { DoDespawnAdds(); @@ -148,7 +148,7 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI m_pInstance->SetData(TYPE_BLADEFIST, FAIL); } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (m_bInBlade) { @@ -170,7 +170,7 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI // Note: this should be done by creature linkin in core void DoDespawnAdds() { - for (GUIDVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) + for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) pTemp->ForcedDespawn(); @@ -178,7 +178,7 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI m_vAddGuids.clear(); - for (GUIDVector::const_iterator itr = m_vAssassinGuids.begin(); itr != m_vAssassinGuids.end(); ++itr) + for (GuidVector::const_iterator itr = m_vAssassinGuids.begin(); itr != m_vAssassinGuids.end(); ++itr) { if (Creature* pTemp = m_creature->GetMap()->GetCreature(*itr)) pTemp->ForcedDespawn(); @@ -189,13 +189,13 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI void SpawnAssassin() { - m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1]+8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 24000); - m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1]-8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 24000); - m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1]+8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 24000); - m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1]-8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 24000); + m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] + 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 24000); + m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] - 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 24000); + m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] + 8, AssassExit[2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 24000); + m_creature->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] - 8, AssassExit[2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 24000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -238,10 +238,10 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI { // move in bladedance float x, y, randx, randy; - randx = (rand()%40); - randy = (rand()%40); - x = 210+ randx ; - y = -60- randy ; + randx = (rand() % 40); + randy = (rand() % 40); + x = 210 + randx ; + y = -60 - randy ; m_creature->GetMotionMaster()->MovePoint(1, x, y, m_creature->GetPositionZ()); m_uiWaitTimer = 0; } @@ -283,9 +283,9 @@ struct MANGOS_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI { switch (urand(0, 2)) { - case 0: m_creature->SummonCreature(NPC_HEARTHEN_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); break; - case 1: m_creature->SummonCreature(NPC_SHARPSHOOTER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); break; - case 2: m_creature->SummonCreature(NPC_REAVER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); break; + case 0: m_creature->SummonCreature(NPC_HEARTHEN_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); break; + case 1: m_creature->SummonCreature(NPC_SHARPSHOOTER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); break; + case 2: m_creature->SummonCreature(NPC_REAVER_GUARD, AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 20000); break; } } diff --git a/scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp b/scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp index 84acfe256..24fbd10d5 100644 --- a/scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp +++ b/scripts/outland/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,7 +25,7 @@ EndScriptData */ #include "shattered_halls.h" instance_shattered_halls::instance_shattered_halls(Map* pMap) : ScriptedInstance(pMap), - m_uiExecutionTimer(55*MINUTE*IN_MILLISECONDS), + m_uiExecutionTimer(55 * MINUTE* IN_MILLISECONDS), m_uiTeam(0), m_uiExecutionStage(0) { @@ -43,12 +43,12 @@ void instance_shattered_halls::OnPlayerEnter(Player* pPlayer) if (instance->IsRegularDifficulty() || m_uiTeam) return; - m_uiTeam = pPlayer->GetTeam(); + m_uiTeam = pPlayer->GetTeam(); - if (m_uiTeam == ALLIANCE) + if (m_uiTeam == ALLIANCE) pPlayer->SummonCreature(aSoldiersLocs[1].m_uiAllianceEntry, aSoldiersLocs[1].m_fX, aSoldiersLocs[1].m_fY, aSoldiersLocs[1].m_fZ, aSoldiersLocs[1].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); - else - pPlayer->SummonCreature(aSoldiersLocs[0].m_uiHordeEntry, aSoldiersLocs[0].m_fX, aSoldiersLocs[0].m_fY, aSoldiersLocs[0].m_fZ, aSoldiersLocs[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + else + pPlayer->SummonCreature(aSoldiersLocs[0].m_uiHordeEntry, aSoldiersLocs[0].m_fX, aSoldiersLocs[0].m_fY, aSoldiersLocs[0].m_fZ, aSoldiersLocs[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); } void instance_shattered_halls::OnObjectCreate(GameObject* pGo) @@ -91,7 +91,7 @@ void instance_shattered_halls::OnCreatureCreate(Creature* pCreature) void instance_shattered_halls::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { case TYPE_NETHEKURSE: m_auiEncounter[uiType] = uiData; @@ -123,8 +123,8 @@ void instance_shattered_halls::SetData(uint32 uiType, uint32 uiData) for (uint8 i = 2; i < 5; ++i) pPlayer->SummonCreature(m_uiTeam == ALLIANCE ? aSoldiersLocs[i].m_uiAllianceEntry : aSoldiersLocs[i].m_uiHordeEntry, aSoldiersLocs[i].m_fX, aSoldiersLocs[i].m_fY, aSoldiersLocs[i].m_fZ, aSoldiersLocs[i].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); - // Summon the executioner for 80 min; ToDo: set the flags in DB - if (Creature* pExecutioner = pPlayer->SummonCreature(NPC_EXECUTIONER, afExecutionerLoc[0], afExecutionerLoc[1], afExecutionerLoc[2], afExecutionerLoc[3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 80*MINUTE*IN_MILLISECONDS, true)) + // Summon the executioner; Note: according to wowhead he shouldn't be targetable until Kargath encounter is finished + if (Creature* pExecutioner = pPlayer->SummonCreature(NPC_EXECUTIONER, afExecutionerLoc[0], afExecutionerLoc[1], afExecutionerLoc[2], afExecutionerLoc[3], TEMPSUMMON_DEAD_DESPAWN, 0, true)) pExecutioner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); // cast the execution spell @@ -133,9 +133,21 @@ void instance_shattered_halls::SetData(uint32 uiType, uint32 uiData) } if (uiData == DONE) { - // Allow playes to complete the quest only after the executioner is dead + // If the officer is already killed, then skip the quest completion + if (m_uiExecutionStage) + break; + + // Complete quest 9524 or 9525 if (Creature* pOfficer = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_OFFICER_ALLIANCE : NPC_OFFICER_HORDE)) - pOfficer->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER); + { + Map::PlayerList const& lPlayers = instance->GetPlayers(); + + for (Map::PlayerList::const_iterator itr = lPlayers.begin(); itr != lPlayers.end(); ++itr) + { + if (Player* pPlayer = itr->getSource()) + pPlayer->KilledMonsterCredit(pOfficer->GetEntry(), pOfficer->GetObjectGuid()); + } + } } break; } @@ -167,7 +179,7 @@ void instance_shattered_halls::Load(const char* chrIn) std::istringstream loadStream(chrIn); loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for(uint8 i = 0; i < MAX_ENCOUNTER; ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { if (m_auiEncounter[i] == IN_PROGRESS) m_auiEncounter[i] = NOT_STARTED; @@ -176,7 +188,7 @@ void instance_shattered_halls::Load(const char* chrIn) OUT_LOAD_INST_DATA_COMPLETE; } -uint32 instance_shattered_halls::GetData(uint32 uiType) +uint32 instance_shattered_halls::GetData(uint32 uiType) const { if (uiType < MAX_ENCOUNTER) return m_auiEncounter[uiType]; @@ -205,6 +217,22 @@ void instance_shattered_halls::OnCreatureEvade(Creature* pCreature) SetData(TYPE_EXECUTION, IN_PROGRESS); } +bool instance_shattered_halls::CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const +{ + switch (uiInstanceConditionId) + { + case INSTANCE_CONDITION_ID_NORMAL_MODE: // No soldier alive + case INSTANCE_CONDITION_ID_HARD_MODE: // One soldier alive + case INSTANCE_CONDITION_ID_HARD_MODE_2: // Two soldier alive + case INSTANCE_CONDITION_ID_HARD_MODE_3: // Three soldier alive + return uiInstanceConditionId == uint32(INSTANCE_CONDITION_ID_HARD_MODE_3 - m_uiExecutionStage); + } + + script_error_log("instance_shattered_halls::CheckConditionCriteriaMeet called with unsupported Id %u. Called with param plr %s, src %s, condition source type %u", + uiInstanceConditionId, pPlayer ? pPlayer->GetGuidStr().c_str() : "NULL", pConditionSource ? pConditionSource->GetGuidStr().c_str() : "NULL", conditionSourceType); + return false; +} + void instance_shattered_halls::Update(uint32 uiDiff) { if (m_auiEncounter[TYPE_EXECUTION] != IN_PROGRESS) @@ -212,7 +240,7 @@ void instance_shattered_halls::Update(uint32 uiDiff) if (m_uiExecutionTimer < uiDiff) { - switch(m_uiExecutionStage) + switch (m_uiExecutionStage) { case 0: // Kill the officer @@ -224,14 +252,14 @@ void instance_shattered_halls::Update(uint32 uiDiff) // Set timer for the next execution DoCastGroupDebuff(SPELL_KARGATH_EXECUTIONER_2); - m_uiExecutionTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiExecutionTimer = 10 * MINUTE * IN_MILLISECONDS; break; case 1: if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_SOLDIER_ALLIANCE_2 : NPC_SOLDIER_HORDE_2)) pSoldier->DealDamage(pSoldier, pSoldier->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); DoCastGroupDebuff(SPELL_KARGATH_EXECUTIONER_3); - m_uiExecutionTimer = 15*MINUTE*IN_MILLISECONDS; + m_uiExecutionTimer = 15 * MINUTE * IN_MILLISECONDS; break; case 2: if (Creature* pSoldier = GetSingleCreatureFromStorage(m_uiTeam == ALLIANCE ? NPC_SOLDIER_ALLIANCE_3 : NPC_SOLDIER_HORDE_3)) @@ -265,9 +293,9 @@ InstanceData* GetInstanceData_instance_shattered_halls(Map* pMap) return new instance_shattered_halls(pMap); } -bool AreaTrigger_at_shattered_halls(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_shattered_halls(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { - if (pPlayer->isGameMaster() || pPlayer->isDead()) + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) return false; instance_shattered_halls* pInstance = (instance_shattered_halls*)pPlayer->GetInstanceData(); diff --git a/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h b/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h index fc193b1b6..610711f4f 100644 --- a/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h +++ b/scripts/outland/hellfire_citadel/shattered_halls/shattered_halls.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -39,7 +39,7 @@ enum SAY_KARGATH_EXECUTE_ALLY = -1540049, SAY_KARGATH_EXECUTE_HORDE = -1540050, - //AT_NETHEKURSE = 4524, // Area trigger used for the execution event + // AT_NETHEKURSE = 4524, // Area trigger used for the execution event }; struct SpawnLocation @@ -59,33 +59,35 @@ static SpawnLocation aSoldiersLocs[] = {NPC_OFFICER_ALLIANCE, NPC_OFFICER_HORDE, 138.241f, -84.198f, 1.907f, 0.055f} }; -class MANGOS_DLL_DECL instance_shattered_halls : public ScriptedInstance +class instance_shattered_halls : public ScriptedInstance { public: instance_shattered_halls(Map* pMap); - void Initialize(); + void Initialize() override; - void OnPlayerEnter(Player* pPlayer); + void OnPlayerEnter(Player* pPlayer) override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; - void OnCreatureDeath(Creature* pCreature); + void OnCreatureDeath(Creature* pCreature) override; void OnCreatureEvade(Creature* pCreature); - void OnCreatureEnterCombat(Creature* pCreature); + void OnCreatureEnterCombat(Creature* pCreature) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - const char* Save() { return m_strInstData.c_str(); } - void Load(const char* chrIn); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; - void Update(uint32 uiDiff); + bool CheckConditionCriteriaMeet(Player const* pPlayer, uint32 uiInstanceConditionId, WorldObject const* pConditionSource, uint32 conditionSourceType) const override; - void DoCastGroupDebuff(uint32 uiSpellId); + void Update(uint32 uiDiff) override; private: + void DoCastGroupDebuff(uint32 uiSpellId); + uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string m_strInstData; diff --git a/scripts/outland/hellfire_peninsula.cpp b/scripts/outland/hellfire_peninsula.cpp index 3bef663fd..f493c93b7 100644 --- a/scripts/outland/hellfire_peninsula.cpp +++ b/scripts/outland/hellfire_peninsula.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Hellfire_Peninsula SD%Complete: 100 -SDComment: Quest support: 9375, 9410, 9418, 10838 +SDComment: Quest support: 9375, 9410, 9418, 10286, 10629, 10838, 10935. SDCategory: Hellfire Peninsula EndScriptData */ @@ -25,55 +25,63 @@ EndScriptData */ npc_aeranas npc_ancestral_wolf npc_demoniac_scryer -npc_tracy_proudwell npc_wounded_blood_elf +npc_fel_guard_hound +npc_anchorite_barada +npc_colonel_jules +npc_magister_aledis EndContentData */ #include "precompiled.h" #include "escort_ai.h" +#include "pet_ai.h" /*###### ## npc_aeranas ######*/ -#define SAY_SUMMON -1000138 -#define SAY_FREE -1000139 +enum +{ + SAY_SUMMON = -1000138, + SAY_FREE = -1000139, -#define FACTION_HOSTILE 16 -#define FACTION_FRIENDLY 35 + FACTION_HOSTILE = 16, + FACTION_FRIENDLY = 35, -#define SPELL_ENVELOPING_WINDS 15535 -#define SPELL_SHOCK 12553 + SPELL_ENVELOPING_WINDS = 15535, + SPELL_SHOCK = 12553, +}; -struct MANGOS_DLL_DECL npc_aeranasAI : public ScriptedAI +struct npc_aeranasAI : public ScriptedAI { npc_aeranasAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 Faction_Timer; - uint32 EnvelopingWinds_Timer; - uint32 Shock_Timer; + uint32 m_uiFactionTimer; + uint32 m_uiEnvelopingWindsTimer; + uint32 m_uiShockTimer; - void Reset() + void Reset() override { - Faction_Timer = 8000; - EnvelopingWinds_Timer = 9000; - Shock_Timer = 5000; + m_uiFactionTimer = 8000; + m_uiEnvelopingWindsTimer = 9000; + m_uiShockTimer = 5000; m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - m_creature->setFaction(FACTION_FRIENDLY); DoScriptText(SAY_SUMMON, m_creature); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - if (Faction_Timer) + if (m_uiFactionTimer) { - if (Faction_Timer <= diff) + if (m_uiFactionTimer <= uiDiff) { - m_creature->setFaction(FACTION_HOSTILE); - Faction_Timer = 0; - }else Faction_Timer -= diff; + m_creature->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_COMBAT_STOP); + m_uiFactionTimer = 0; + } + else + m_uiFactionTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -81,7 +89,6 @@ struct MANGOS_DLL_DECL npc_aeranasAI : public ScriptedAI if (m_creature->GetHealthPercent() < 30.0f) { - m_creature->setFaction(FACTION_FRIENDLY); m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); @@ -90,17 +97,21 @@ struct MANGOS_DLL_DECL npc_aeranasAI : public ScriptedAI return; } - if (Shock_Timer < diff) + if (m_uiShockTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SHOCK); - Shock_Timer = 10000; - }else Shock_Timer -= diff; + DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHOCK); + m_uiShockTimer = 10000; + } + else + m_uiShockTimer -= uiDiff; - if (EnvelopingWinds_Timer < diff) + if (m_uiEnvelopingWindsTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ENVELOPING_WINDS); - EnvelopingWinds_Timer = 25000; - }else EnvelopingWinds_Timer -= diff; + DoCastSpellIfCan(m_creature->getVictim(), SPELL_ENVELOPING_WINDS); + m_uiEnvelopingWindsTimer = 25000; + } + else + m_uiEnvelopingWindsTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -126,26 +137,26 @@ enum NPC_RYGA = 17123 }; -struct MANGOS_DLL_DECL npc_ancestral_wolfAI : public npc_escortAI +struct npc_ancestral_wolfAI : public npc_escortAI { npc_ancestral_wolfAI(Creature* pCreature) : npc_escortAI(pCreature) { if (pCreature->GetOwner() && pCreature->GetOwner()->GetTypeId() == TYPEID_PLAYER) Start(false, (Player*)pCreature->GetOwner()); else - error_log("SD2: npc_ancestral_wolf can not obtain owner or owner is not a player."); + script_error_log("npc_ancestral_wolf can not obtain owner or owner is not a player."); Reset(); } - void Reset() + void Reset() override { m_creature->CastSpell(m_creature, SPELL_ANCESTRAL_WOLF_BUFF, true); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: DoScriptText(EMOTE_WOLF_LIFT_HEAD, m_creature); @@ -180,22 +191,22 @@ enum QUEST_DEMONIAC = 10838, NPC_HELLFIRE_WARDLING = 22259, - NPC_BUTTRESS = 22267, //the 4x nodes - NPC_SPAWNER = 22260, //just a dummy, not used + NPC_BUTTRESS = 22267, // the 4x nodes + NPC_SPAWNER = 22260, // just a dummy, not used MAX_BUTTRESS = 4, - TIME_TOTAL = MINUTE*10*IN_MILLISECONDS, + TIME_TOTAL = MINUTE * 10 * IN_MILLISECONDS, - SPELL_SUMMONED_DEMON = 7741, //visual spawn-in for demon - SPELL_DEMONIAC_VISITATION = 38708, //create item + SPELL_SUMMONED_DEMON = 7741, // visual spawn-in for demon + SPELL_DEMONIAC_VISITATION = 38708, // create item - SPELL_BUTTRESS_APPERANCE = 38719, //visual on 4x bunnies + the flying ones - SPELL_SUCKER_CHANNEL = 38721, //channel to the 4x nodes + SPELL_BUTTRESS_APPERANCE = 38719, // visual on 4x bunnies + the flying ones + SPELL_SUCKER_CHANNEL = 38721, // channel to the 4x nodes SPELL_SUCKER_DESPAWN_MOB = 38691 }; -//script is basic support, details like end event are not implemented -struct MANGOS_DLL_DECL npc_demoniac_scryerAI : public ScriptedAI +// script is basic support, details like end event are not implemented +struct npc_demoniac_scryerAI : public ScriptedAI { npc_demoniac_scryerAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -212,11 +223,11 @@ struct MANGOS_DLL_DECL npc_demoniac_scryerAI : public ScriptedAI uint32 m_uiSpawnButtressTimer; uint32 m_uiButtressCount; - void Reset() {} + void Reset() override {} - //we don't want anything to happen when attacked - void AttackedBy(Unit* pEnemy) {} - void AttackStart(Unit* pEnemy) {} + // we don't want anything to happen when attacked + void AttackedBy(Unit* /*pEnemy*/) override {} + void AttackStart(Unit* /*pEnemy*/) override {} void DoSpawnButtress() { @@ -224,11 +235,11 @@ struct MANGOS_DLL_DECL npc_demoniac_scryerAI : public ScriptedAI float fAngle = 0.0f; - switch(m_uiButtressCount) + switch (m_uiButtressCount) { case 1: fAngle = 0.0f; break; - case 2: fAngle = M_PI_F+M_PI_F/2; break; - case 3: fAngle = M_PI_F/2; break; + case 2: fAngle = M_PI_F + M_PI_F / 2; break; + case 3: fAngle = M_PI_F / 2; break; case 4: fAngle = M_PI_F; break; } @@ -244,10 +255,10 @@ struct MANGOS_DLL_DECL npc_demoniac_scryerAI : public ScriptedAI float fX, fY, fZ; m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); - m_creature->SummonCreature(NPC_HELLFIRE_WARDLING, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + m_creature->SummonCreature(NPC_HELLFIRE_WARDLING, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_HELLFIRE_WARDLING) { @@ -264,13 +275,13 @@ struct MANGOS_DLL_DECL npc_demoniac_scryerAI : public ScriptedAI } } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { if (pTarget->GetEntry() == NPC_HELLFIRE_WARDLING && pSpell->Id == SPELL_SUCKER_DESPAWN_MOB) ((Creature*)pTarget)->ForcedDespawn(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_bIsComplete || !m_creature->isAlive()) return; @@ -330,7 +341,7 @@ bool GossipHello_npc_demoniac_scryer(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_demoniac_scryer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_demoniac_scryer(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { @@ -342,78 +353,36 @@ bool GossipSelect_npc_demoniac_scryer(Player* pPlayer, Creature* pCreature, uint } /*###### -## npc_tracy_proudwell +## npc_wounded_blood_elf ######*/ -#define GOSSIP_TEXT_REDEEM_MARKS "I have marks to redeem!" -#define GOSSIP_TRACY_PROUDWELL_ITEM1 "I heard that your dog Fei Fei took Klatu's prayer beads..." -#define GOSSIP_TRACY_PROUDWELL_ITEM2 "" - enum { - GOSSIP_TEXTID_TRACY_PROUDWELL1 = 10689, - QUEST_DIGGING_FOR_PRAYER_BEADS = 10916 -}; - -bool GossipHello_npc_tracy_proudwell(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_REDEEM_MARKS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if (pPlayer->GetQuestStatus(QUEST_DIGGING_FOR_PRAYER_BEADS) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TRACY_PROUDWELL_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_tracy_proudwell(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_TRACY_PROUDWELL_ITEM2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXTID_TRACY_PROUDWELL1, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - break; - } - - return true; -} - -/*###### -## npc_wounded_blood_elf -######*/ + SAY_ELF_START = -1000117, + SAY_ELF_SUMMON1 = -1000118, + SAY_ELF_RESTING = -1000119, + SAY_ELF_SUMMON2 = -1000120, + SAY_ELF_COMPLETE = -1000121, + SAY_ELF_AGGRO = -1000122, -#define SAY_ELF_START -1000117 -#define SAY_ELF_SUMMON1 -1000118 -#define SAY_ELF_RESTING -1000119 -#define SAY_ELF_SUMMON2 -1000120 -#define SAY_ELF_COMPLETE -1000121 -#define SAY_ELF_AGGRO -1000122 + NPC_WINDWALKER = 16966, + NPC_TALONGUARD = 16967, -#define QUEST_ROAD_TO_FALCON_WATCH 9375 + QUEST_ROAD_TO_FALCON_WATCH = 9375, +}; -struct MANGOS_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI +struct npc_wounded_blood_elfAI : public npc_escortAI { npc_wounded_blood_elfAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} - void WaypointReached(uint32 i) + void WaypointReached(uint32 uiPointId) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch (i) + switch (uiPointId) { case 0: DoScriptText(SAY_ELF_START, m_creature, pPlayer); @@ -421,8 +390,8 @@ struct MANGOS_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI case 9: DoScriptText(SAY_ELF_SUMMON1, m_creature, pPlayer); // Spawn two Haal'eshi Talonguard - DoSpawnCreature(16967, -15, -15, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - DoSpawnCreature(16967, -17, -17, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + DoSpawnCreature(NPC_WINDWALKER, -15, -15, 0, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + DoSpawnCreature(NPC_WINDWALKER, -17, -17, 0, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); break; case 13: DoScriptText(SAY_ELF_RESTING, m_creature, pPlayer); @@ -430,8 +399,8 @@ struct MANGOS_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI case 14: DoScriptText(SAY_ELF_SUMMON2, m_creature, pPlayer); // Spawn two Haal'eshi Windwalker - DoSpawnCreature(16966, -15, -15, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - DoSpawnCreature(16966, -17, -17, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + DoSpawnCreature(NPC_WINDWALKER, -15, -15, 0, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); + DoSpawnCreature(NPC_WINDWALKER, -17, -17, 0, 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000); break; case 27: DoScriptText(SAY_ELF_COMPLETE, m_creature, pPlayer); @@ -441,17 +410,17 @@ struct MANGOS_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI } } - void Reset() { } + void Reset() override { } - void Aggro(Unit* who) + void Aggro(Unit* /*pWho*/) override { if (HasEscortState(STATE_ESCORT_ESCORTING)) DoScriptText(SAY_ELF_AGGRO, m_creature); } - void JustSummoned(Creature* summoned) + void JustSummoned(Creature* pSummoned) override { - summoned->AI()->AttackStart(m_creature); + pSummoned->AI()->AttackStart(m_creature); } }; @@ -465,7 +434,7 @@ bool QuestAccept_npc_wounded_blood_elf(Player* pPlayer, Creature* pCreature, con if (pQuest->GetQuestId() == QUEST_ROAD_TO_FALCON_WATCH) { // Change faction so mobs attack - pCreature->setFaction(FACTION_ESCORT_H_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); if (npc_wounded_blood_elfAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -474,6 +443,559 @@ bool QuestAccept_npc_wounded_blood_elf(Player* pPlayer, Creature* pCreature, con return true; } +/*###### +## npc_fel_guard_hound +######*/ + +enum +{ + SPELL_CREATE_POODAD = 37688, + SPELL_FAKE_DOG_SPART = 37692, + SPELL_INFORM_DOG = 37689, + + NPC_DERANGED_HELBOAR = 16863, +}; + +struct npc_fel_guard_houndAI : public ScriptedPetAI +{ + npc_fel_guard_houndAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } + + uint32 m_uiPoodadTimer; + + bool m_bIsPooActive; + + void Reset() override + { + m_uiPoodadTimer = 0; + m_bIsPooActive = false; + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (DoCastSpellIfCan(m_creature, SPELL_FAKE_DOG_SPART) == CAST_OK) + m_uiPoodadTimer = 2000; + } + + // Function to allow the boar to move to target + void DoMoveToCorpse(Unit* pBoar) + { + if (!pBoar) + return; + + m_bIsPooActive = true; + m_creature->GetMotionMaster()->MovePoint(1, pBoar->GetPositionX(), pBoar->GetPositionY(), pBoar->GetPositionZ()); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPoodadTimer) + { + if (m_uiPoodadTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CREATE_POODAD) == CAST_OK) + { + m_uiPoodadTimer = 0; + m_bIsPooActive = false; + } + } + else + m_uiPoodadTimer -= uiDiff; + } + + if (!m_bIsPooActive) + ScriptedPetAI::UpdateAI(uiDiff); + } +}; + +CreatureAI* GetAI_npc_fel_guard_hound(Creature* pCreature) +{ + return new npc_fel_guard_houndAI(pCreature); +} + +bool EffectDummyCreature_npc_fel_guard_hound(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_INFORM_DOG && uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetEntry() == NPC_DERANGED_HELBOAR) + { + if (npc_fel_guard_houndAI* pHoundAI = dynamic_cast(pCreatureTarget->AI())) + pHoundAI->DoMoveToCorpse(pCaster); + } + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_anchorite_barada +######*/ + +enum +{ + SAY_EXORCISM_1 = -1000981, + SAY_EXORCISM_2 = -1000982, + SAY_EXORCISM_3 = -1000983, + SAY_EXORCISM_4 = -1000984, + SAY_EXORCISM_5 = -1000985, + SAY_EXORCISM_6 = -1000986, + + SPELL_BARADA_COMMANDS = 39277, + SPELL_BARADA_FALTERS = 39278, + + SPELL_JULES_THREATENS = 39284, + SPELL_JULES_GOES_UPRIGHT = 39294, + SPELL_JULES_VOMITS = 39295, + SPELL_JULES_RELEASE_DARKNESS = 39306, // periodic trigger missing spell 39305 + + NPC_ANCHORITE_BARADA = 22431, + NPC_COLONEL_JULES = 22432, + NPC_DARKNESS_RELEASED = 22507, // summoned by missing spell 39305 + + GOSSIP_ITEM_EXORCISM = -3000111, + QUEST_ID_EXORCISM = 10935, + + TEXT_ID_CLEANSED = 10706, + TEXT_ID_POSSESSED = 10707, + TEXT_ID_ANCHORITE = 10683, +}; + +static const DialogueEntry aExorcismDialogue[] = +{ + {SAY_EXORCISM_1, NPC_ANCHORITE_BARADA, 3000}, + {SAY_EXORCISM_2, NPC_ANCHORITE_BARADA, 2000}, + {QUEST_ID_EXORCISM, 0, 0}, // start wp movemnet + {SAY_EXORCISM_3, NPC_COLONEL_JULES, 3000}, + {SPELL_BARADA_COMMANDS, 0, 10000}, + {SAY_EXORCISM_4, NPC_ANCHORITE_BARADA, 10000}, + {SAY_EXORCISM_5, NPC_COLONEL_JULES, 10000}, + {SPELL_BARADA_FALTERS, 0, 2000}, + {SPELL_JULES_THREATENS, 0, 15000}, // start levitating + {NPC_COLONEL_JULES, 0, 15000}, + {NPC_ANCHORITE_BARADA, 0, 15000}, + {NPC_COLONEL_JULES, 0, 15000}, + {NPC_ANCHORITE_BARADA, 0, 15000}, + {SPELL_JULES_GOES_UPRIGHT, 0, 3000}, + {SPELL_JULES_VOMITS, 0, 7000}, // start moving around the room + {NPC_COLONEL_JULES, 0, 10000}, + {NPC_ANCHORITE_BARADA, 0, 10000}, + {NPC_COLONEL_JULES, 0, 10000}, + {NPC_ANCHORITE_BARADA, 0, 10000}, + {NPC_COLONEL_JULES, 0, 10000}, + {NPC_ANCHORITE_BARADA, 0, 10000}, + {NPC_COLONEL_JULES, 0, 10000}, + {NPC_ANCHORITE_BARADA, 0, 10000}, + {NPC_DARKNESS_RELEASED, 0, 5000}, // event finished + {SAY_EXORCISM_6, NPC_ANCHORITE_BARADA, 3000}, + {TEXT_ID_CLEANSED, 0, 0}, + {0, 0, 0}, +}; + +static const int32 aAnchoriteTexts[3] = { -1000987, -1000988, -1000989 }; +static const int32 aColonelTexts[3] = { -1000990, -1000991, -1000992 }; + +// Note: script is highly dependent on DBscript implementation +struct npc_anchorite_baradaAI : public ScriptedAI, private DialogueHelper +{ + npc_anchorite_baradaAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aExorcismDialogue) + { + Reset(); + } + + bool m_bEventComplete; + bool m_bEventInProgress; + + ObjectGuid m_colonelGuid; + + void Reset() override + { + m_bEventComplete = false; + m_bEventInProgress = false; + } + + void AttackStart(Unit* pWho) override + { + // no attack during the exorcism + if (m_bEventInProgress) + return; + + ScriptedAI::AttackStart(pWho); + } + + void EnterEvadeMode() override + { + // no evade during the exorcism + if (m_bEventInProgress) + return; + + ScriptedAI::EnterEvadeMode(); + } + + bool IsExorcismComplete() { return m_bEventComplete; } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + // start the actuall exorcism + if (Creature* pColoner = GetClosestCreatureWithEntry(m_creature, NPC_COLONEL_JULES, 15.0f)) + m_colonelGuid = pColoner->GetObjectGuid(); + + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + + StartNextDialogueText(SAY_EXORCISM_1); + } + } + + void MovementInform(uint32 uiType, uint32 uiPointId) override + { + if (uiType != WAYPOINT_MOTION_TYPE) + return; + + switch (uiPointId) + { + case 3: + // pause wp and resume dialogue + m_creature->addUnitState(UNIT_STAT_WAYPOINT_PAUSED); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_bEventInProgress = true; + + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + m_creature->SetFacingToObject(pColonel); + pColonel->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + + StartNextDialogueText(SAY_EXORCISM_3); + break; + case 6: + // event completed - wait for player to get quest credit by gossip + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + m_creature->SetFacingToObject(pColonel); + m_creature->GetMotionMaster()->Clear(); + m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); + m_bEventComplete = true; + break; + } + } + + void JustDidDialogueStep(int32 iEntry) override + { + switch (iEntry) + { + case QUEST_ID_EXORCISM: + m_creature->GetMotionMaster()->MoveWaypoint(); + break; + case SPELL_BARADA_COMMANDS: + DoCastSpellIfCan(m_creature, SPELL_BARADA_COMMANDS); + break; + case SPELL_BARADA_FALTERS: + DoCastSpellIfCan(m_creature, SPELL_BARADA_FALTERS); + // start levitating + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + pColonel->SetLevitate(true); + pColonel->GetMotionMaster()->MovePoint(0, pColonel->GetPositionX(), pColonel->GetPositionY(), pColonel->GetPositionZ() + 2.0f); + } + break; + case SPELL_JULES_THREATENS: + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + pColonel->CastSpell(pColonel, SPELL_JULES_THREATENS, true); + pColonel->CastSpell(pColonel, SPELL_JULES_RELEASE_DARKNESS, true); + pColonel->SetFacingTo(0); + } + break; + case SPELL_JULES_GOES_UPRIGHT: + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + pColonel->InterruptNonMeleeSpells(false); + pColonel->CastSpell(pColonel, SPELL_JULES_GOES_UPRIGHT, false); + } + break; + case SPELL_JULES_VOMITS: + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + pColonel->CastSpell(pColonel, SPELL_JULES_VOMITS, true); + pColonel->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 3.0f, 5.0f); + } + break; + case NPC_COLONEL_JULES: + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + DoScriptText(aColonelTexts[urand(0, 2)], pColonel); + break; + case NPC_ANCHORITE_BARADA: + DoScriptText(aAnchoriteTexts[urand(0, 2)], m_creature); + break; + case NPC_DARKNESS_RELEASED: + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + pColonel->RemoveAurasDueToSpell(SPELL_JULES_THREATENS); + pColonel->RemoveAurasDueToSpell(SPELL_JULES_RELEASE_DARKNESS); + pColonel->RemoveAurasDueToSpell(SPELL_JULES_VOMITS); + pColonel->GetMotionMaster()->MoveTargetedHome(); + pColonel->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + } + break; + case TEXT_ID_CLEANSED: + if (Creature* pColonel = m_creature->GetMap()->GetCreature(m_colonelGuid)) + { + pColonel->RemoveAurasDueToSpell(SPELL_JULES_GOES_UPRIGHT); + pColonel->SetLevitate(false); + } + // resume wp movemnet + m_creature->RemoveAllAuras(); + m_creature->clearUnitState(UNIT_STAT_WAYPOINT_PAUSED); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + break; + } + } + + Creature* GetSpeakerByEntry(uint32 uiEntry) override + { + switch (uiEntry) + { + case NPC_ANCHORITE_BARADA: return m_creature; + case NPC_COLONEL_JULES: return m_creature->GetMap()->GetCreature(m_colonelGuid); + + default: + return NULL; + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_anchorite_barada(Creature* pCreature) +{ + return new npc_anchorite_baradaAI(pCreature); +} + +bool GossipHello_npc_anchorite_barada(Player* pPlayer, Creature* pCreature) +{ + // check if quest is active but not completed + if (pPlayer->IsCurrentQuest(QUEST_ID_EXORCISM, 1)) + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_EXORCISM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_ANCHORITE, pCreature->GetObjectGuid()); + return true; +} + +bool GossipSelect_npc_anchorite_barada(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) +{ + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_EVENT, pPlayer, pCreature); + pPlayer->CLOSE_GOSSIP_MENU(); + } + + return true; +} + +/*###### +## npc_colonel_jules +######*/ + +bool GossipHello_npc_colonel_jules(Player* pPlayer, Creature* pCreature) +{ + // quest already completed + if (pPlayer->GetQuestStatus(QUEST_ID_EXORCISM) == QUEST_STATUS_COMPLETE) + { + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_CLEANSED, pCreature->GetObjectGuid()); + return true; + } + // quest active but not complete + else if (pPlayer->IsCurrentQuest(QUEST_ID_EXORCISM, 1)) + { + Creature* pAnchorite = GetClosestCreatureWithEntry(pCreature, NPC_ANCHORITE_BARADA, 15.0f); + if (!pAnchorite) + return true; + + if (npc_anchorite_baradaAI* pAnchoriteAI = dynamic_cast(pAnchorite->AI())) + { + // event complete - give credit and reset + if (pAnchoriteAI->IsExorcismComplete()) + { + // kill credit + pPlayer->RewardPlayerAndGroupAtEvent(pCreature->GetEntry(), pCreature); + + // reset Anchorite and Colonel + pAnchorite->AI()->EnterEvadeMode(); + pCreature->AI()->EnterEvadeMode(); + + pAnchorite->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_CLEANSED, pCreature->GetObjectGuid()); + return true; + } + } + } + + pPlayer->SEND_GOSSIP_MENU(TEXT_ID_POSSESSED, pCreature->GetObjectGuid()); + return true; +} + +bool EffectDummyCreature_npc_colonel_jules(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_JULES_RELEASE_DARKNESS && uiEffIndex == EFFECT_INDEX_0 && pCreatureTarget->GetEntry() == NPC_COLONEL_JULES) + { + Creature* pAnchorite = GetClosestCreatureWithEntry(pCreatureTarget, NPC_ANCHORITE_BARADA, 15.0f); + if (!pAnchorite) + return false; + + // get random point around the Anchorite + float fX, fY, fZ; + pCreatureTarget->GetNearPoint(pCreatureTarget, fX, fY, fZ, 5.0f, 10.0f, frand(0, M_PI_F / 2)); + + // spawn a Darkness Released npc and move around the room + if (Creature* pDarkness = pCreatureTarget->SummonCreature(NPC_DARKNESS_RELEASED, 0, 0, 0, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 20000)) + pDarkness->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_magister_aledis +######*/ + +enum +{ + SAY_ALEDIS_DEFEAT = -1001172, + + SPELL_PYROBLAST = 33975, + SPELL_FROST_NOVA = 11831, + SPELL_FIREBALL = 20823, +}; + +struct npc_magister_aledisAI : public ScriptedAI +{ + npc_magister_aledisAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_bIsDefeated = false; + Reset(); + } + + uint32 m_uiPyroblastTimer; + uint32 m_uiFrostNovaTimer; + uint32 m_uiFireballTimer; + + bool m_bIsDefeated; + + void Reset() override + { + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + m_uiPyroblastTimer = urand(10000, 14000); + m_uiFrostNovaTimer = 0; + m_uiFireballTimer = 1000; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, false)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 10.0f); + } + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + + if (!m_bIsDefeated) + m_creature->LoadCreatureAddon(true); + + if (m_creature->isAlive()) + { + if (!m_bIsDefeated) + { + m_creature->SetWalk(true); + m_creature->GetMotionMaster()->MoveWaypoint(); + } + else + m_creature->GetMotionMaster()->MoveIdle(); + } + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bIsDefeated && m_creature->GetHealthPercent() < 25.0f) + { + // evade when defeated; faction is reset automatically + m_bIsDefeated = true; + EnterEvadeMode(); + + m_creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + DoScriptText(SAY_ALEDIS_DEFEAT, m_creature); + m_creature->ForcedDespawn(60000); + return; + } + + if (m_uiPyroblastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PYROBLAST) == CAST_OK) + m_uiPyroblastTimer = urand(18000, 21000); + } + else + m_uiPyroblastTimer -= uiDiff; + + if (m_uiFireballTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIREBALL) == CAST_OK) + m_uiFireballTimer = urand(3000, 4000); + } + else + m_uiFireballTimer -= uiDiff; + + if (m_uiFrostNovaTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FROST_NOVA) == CAST_OK) + m_uiFrostNovaTimer = urand(12000, 16000); + } + else + m_uiFrostNovaTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_magister_aledis(Creature* pCreature) +{ + return new npc_magister_aledisAI(pCreature); +} + void AddSC_hellfire_peninsula() { Script* pNewScript; @@ -495,15 +1017,33 @@ void AddSC_hellfire_peninsula() pNewScript->pGossipSelect = &GossipSelect_npc_demoniac_scryer; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_tracy_proudwell"; - pNewScript->pGossipHello = &GossipHello_npc_tracy_proudwell; - pNewScript->pGossipSelect = &GossipSelect_npc_tracy_proudwell; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_wounded_blood_elf"; pNewScript->GetAI = &GetAI_npc_wounded_blood_elf; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_wounded_blood_elf; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_fel_guard_hound"; + pNewScript->GetAI = &GetAI_npc_fel_guard_hound; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_fel_guard_hound; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_anchorite_barada"; + pNewScript->GetAI = &GetAI_npc_anchorite_barada; + pNewScript->pGossipHello = &GossipHello_npc_anchorite_barada; + pNewScript->pGossipSelect = &GossipSelect_npc_anchorite_barada; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_colonel_jules"; + pNewScript->pGossipHello = &GossipHello_npc_colonel_jules; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_colonel_jules; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_magister_aledis"; + pNewScript->GetAI = &GetAI_npc_magister_aledis; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/nagrand.cpp b/scripts/outland/nagrand.cpp index 40c5ced22..de3d6debf 100644 --- a/scripts/outland/nagrand.cpp +++ b/scripts/outland/nagrand.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,16 +17,15 @@ /* ScriptData SDName: Nagrand SD%Complete: 90 -SDComment: Quest support: 9868, 9918, 9991, 10044, 10085, 10172, 10646. TextId's unknown for altruis_the_sufferer and greatmother_geyah (npc_text) +SDComment: Quest support: 9868, 9879, 9918, 10085, 10646, 11090. SDCategory: Nagrand EndScriptData */ /* ContentData mob_lump -npc_altruis_the_sufferer -npc_greatmother_geyah -npc_maghar_captive +npc_nagrand_captive npc_creditmarker_visit_with_ancestors +npc_rethhedron EndContentData */ #include "precompiled.h" @@ -48,7 +47,7 @@ enum FACTION_FRIENDLY = 35 }; -struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI +struct mob_lumpAI : public ScriptedAI { mob_lumpAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -60,16 +59,13 @@ struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI uint32 m_uiSpearThrowTimer; bool m_bReset; - void Reset() + void Reset() override { - m_uiResetTimer = MINUTE*IN_MILLISECONDS; + m_uiResetTimer = MINUTE * IN_MILLISECONDS; m_uiSpearThrowTimer = 2000; - - if (m_creature->getFaction() != m_creature->GetCreatureInfo()->faction_A) - m_creature->setFaction(m_creature->GetCreatureInfo()->faction_A); } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -80,18 +76,18 @@ struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDealer, uint32& uiDamage) + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override { - if (m_creature->GetHealth() < uiDamage || (m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() < 30) + if (m_creature->GetHealth() < uiDamage || (m_creature->GetHealth() - uiDamage) * 100 / m_creature->GetMaxHealth() < 30) { - uiDamage = 0; //Take 0 damage + uiDamage = 0; // Take 0 damage m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); // should get unit_flags UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE at faction change, but unclear why/for what reason, skipped (no flags expected as default) - m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME); m_creature->SetStandState(UNIT_STAND_STATE_SIT); DoScriptText(SAY_LUMP_DEFEAT, m_creature); @@ -100,7 +96,7 @@ struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (m_creature->HasAura(SPELL_VISUAL_SLEEP, EFFECT_INDEX_0)) m_creature->RemoveAurasDueToSpell(SPELL_VISUAL_SLEEP); @@ -111,7 +107,7 @@ struct MANGOS_DLL_DECL mob_lumpAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_LUMP_AGGRO_1 : SAY_LUMP_AGGRO_2, m_creature, pWho); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Check if we waiting for a reset if (m_bReset) @@ -148,183 +144,7 @@ CreatureAI* GetAI_mob_lump(Creature* pCreature) } /*###### -## npc_altruis_the_sufferer -######*/ - -enum -{ - QUEST_SURVEY = 9991, - QUEST_PUPIL = 10646, - - TAXI_PATH_ID = 532 -}; - -bool GossipHello_npc_altruis_the_sufferer(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - //gossip before obtaining Survey the Land - if (pPlayer->GetQuestStatus(QUEST_SURVEY) == QUEST_STATUS_NONE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I see twisted steel and smell sundered earth.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+10); - - //gossip when Survey the Land is incomplete (technically, after the flight) - if (pPlayer->GetQuestStatus(QUEST_SURVEY) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Well...?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+20); - - //wowwiki.com/Varedis - if (pPlayer->GetQuestStatus(QUEST_PUPIL) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] Story about Illidan's Pupil", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+30); - - pPlayer->SEND_GOSSIP_MENU(9419, pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_altruis_the_sufferer(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+10: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Legion?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - pPlayer->SEND_GOSSIP_MENU(9420, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "And now?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - pPlayer->SEND_GOSSIP_MENU(9421, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+12: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "How do you see them now?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - pPlayer->SEND_GOSSIP_MENU(9422, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+13: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Forge camps?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); - pPlayer->SEND_GOSSIP_MENU(9423, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+14: - pPlayer->SEND_GOSSIP_MENU(9424, pCreature->GetObjectGuid()); - break; - - case GOSSIP_ACTION_INFO_DEF+20: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Ok.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 21); - pPlayer->SEND_GOSSIP_MENU(9427, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+21: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(QUEST_SURVEY); - break; - - case GOSSIP_ACTION_INFO_DEF+30: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "[PH] Story done", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 31); - pPlayer->SEND_GOSSIP_MENU(384, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+31: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->AreaExploredOrEventHappens(QUEST_PUPIL); - break; - } - return true; -} - -bool QuestAccept_npc_altruis_the_sufferer(Player* pPlayer, Creature* pCreature, const Quest* pQuest) -{ - if (!pPlayer->GetQuestRewardStatus(QUEST_SURVEY)) //Survey the Land - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID); - } - return true; -} - -/*###### -## npc_greatmother_geyah -######*/ - -//all the textId's for the below is unknown, but i do believe the gossip item texts are proper. -bool GossipHello_npc_greatmother_geyah(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->GetQuestStatus(10044) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Hello, Greatmother. Garrosh told me that you wanted to speak with me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - } - else if (pPlayer->GetQuestStatus(10172) == QUEST_STATUS_INCOMPLETE) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Garrosh is beyond redemption, Greatmother. I fear that in helping the Mag'har, I have convinced Garrosh that he is unfit to lead.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - } - else - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_greatmother_geyah(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF + 1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "You raised all of the orcs here, Greatmother?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Do you believe that?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What can be done? I have tried many different things. I have done my best to help the people of Nagrand. Each time I have approached Garrosh, he has dismissed me.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Left? How can you choose to leave?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "What is this duty?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Is there anything I can do for you, Greatmother?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 7: - pPlayer->AreaExploredOrEventHappens(10044); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - - case GOSSIP_ACTION_INFO_DEF + 10: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I have done all that I could, Greatmother. I thank you for your kind words.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 11: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Greatmother, you are the mother of Durotan?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 12); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 12: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Greatmother, I never had the honor. Durotan died long before my time, but his heroics are known to all on my world. The orcs of Azeroth reside in a place known as Durotar, named after your son. And ... (You take a moment to breathe and think through what you are about to tell the Greatmother.)", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 13); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 13: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "It is my Warchief, Greatmother. The leader of my people. From my world. He ... He is the son of Durotan. He is your grandchild.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 14); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 14: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "I will return to Azeroth at once, Greatmother.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 15); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF + 15: - pPlayer->AreaExploredOrEventHappens(10172); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - } - return true; -} - -/*##### -## npc_maghar_captive +## npc_nagrand_captive #####*/ enum @@ -337,12 +157,22 @@ enum SAY_MAG_SHOCK = -1000487, SAY_MAG_COMPLETE = -1000488, + SAY_KUR_START = -1001001, + SAY_KUR_AMBUSH_1 = -1001002, + SAY_KUR_AMBUSH_2 = -1001003, + SAY_KUR_COMPLETE_1 = -1001004, + SAY_KUR_COMPLETE_2 = -1001005, + SPELL_CHAIN_LIGHTNING = 16006, SPELL_EARTHBIND_TOTEM = 15786, SPELL_FROST_SHOCK = 12548, SPELL_HEALING_WAVE = 12491, QUEST_TOTEM_KARDASH_H = 9868, + QUEST_TOTEM_KARDASH_A = 9879, + + NPC_KURENAI_CAPTIVE = 18209, + NPC_MAGHAR_CAPTIVE = 18210, NPC_MURK_RAIDER = 18203, NPC_MURK_BRUTE = 18211, @@ -350,56 +180,92 @@ enum NPC_MURK_PUTRIFIER = 18202 }; -static float m_afAmbushA[]= {-1568.805786f, 8533.873047f, 1.958f}; -static float m_afAmbushB[]= {-1491.554321f, 8506.483398f, 1.248f}; +static float m_afAmbushA[] = { -1568.805786f, 8533.873047f, 1.958f}; +static float m_afAmbushB[] = { -1491.554321f, 8506.483398f, 1.248f}; -struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI +struct npc_nagrand_captiveAI : public npc_escortAI { - npc_maghar_captiveAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + npc_nagrand_captiveAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } uint32 m_uiChainLightningTimer; uint32 m_uiHealTimer; uint32 m_uiFrostShockTimer; - void Reset() + void Reset() override { m_uiChainLightningTimer = 1000; m_uiHealTimer = 0; m_uiFrostShockTimer = 6000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - m_creature->CastSpell(m_creature, SPELL_EARTHBIND_TOTEM, false); + DoCastSpellIfCan(m_creature, SPELL_EARTHBIND_TOTEM); } - void WaypointReached(uint32 uiPointId) + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override { - switch(uiPointId) + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + if (m_creature->GetEntry() == NPC_MAGHAR_CAPTIVE) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFactionTemporary(FACTION_ESCORT_H_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + + DoScriptText(SAY_MAG_START, m_creature); + + m_creature->SummonCreature(NPC_MURK_RAIDER, m_afAmbushA[0] + 2.5f, m_afAmbushA[1] - 2.5f, m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_MURK_PUTRIFIER, m_afAmbushA[0] - 2.5f, m_afAmbushA[1] + 2.5f, m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_MURK_BRUTE, m_afAmbushA[0], m_afAmbushA[1], m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + } + else if (m_creature->GetEntry() == NPC_KURENAI_CAPTIVE) + { + m_creature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + + DoScriptText(SAY_KUR_START, m_creature); + + m_creature->SummonCreature(NPC_MURK_RAIDER, -1509.606f, 8484.284f, -3.841f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_MURK_PUTRIFIER, -1532.475f, 8454.706f, -4.102f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_MURK_BRUTE, -1525.484f, 8475.383f, -2.482f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + } + + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) { case 7: - DoScriptText(SAY_MAG_MORE, m_creature); + if (m_creature->GetEntry() == NPC_MAGHAR_CAPTIVE) + DoScriptText(SAY_MAG_MORE, m_creature); + else if (m_creature->GetEntry() == NPC_KURENAI_CAPTIVE) + DoScriptText(urand(0, 1) ? SAY_KUR_AMBUSH_1 : SAY_KUR_AMBUSH_2, m_creature); - if (Creature* pTemp = m_creature->SummonCreature(NPC_MURK_PUTRIFIER, m_afAmbushB[0], m_afAmbushB[1], m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000)) + if (Creature* pTemp = m_creature->SummonCreature(NPC_MURK_PUTRIFIER, m_afAmbushB[0], m_afAmbushB[1], m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000)) DoScriptText(SAY_MAG_MORE_REPLY, pTemp); - m_creature->SummonCreature(NPC_MURK_PUTRIFIER, m_afAmbushB[0]-2.5f, m_afAmbushB[1]-2.5f, m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_MURK_PUTRIFIER, m_afAmbushB[0] - 2.5f, m_afAmbushB[1] - 2.5f, m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); - m_creature->SummonCreature(NPC_MURK_SCAVENGER, m_afAmbushB[0]+2.5f, m_afAmbushB[1]+2.5f, m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - m_creature->SummonCreature(NPC_MURK_SCAVENGER, m_afAmbushB[0]+2.5f, m_afAmbushB[1]-2.5f, m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_MURK_SCAVENGER, m_afAmbushB[0] + 2.5f, m_afAmbushB[1] + 2.5f, m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_MURK_SCAVENGER, m_afAmbushB[0] + 2.5f, m_afAmbushB[1] - 2.5f, m_afAmbushB[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 16: - DoScriptText(SAY_MAG_COMPLETE, m_creature); + if (m_creature->GetEntry() == NPC_MAGHAR_CAPTIVE) + DoScriptText(SAY_MAG_COMPLETE, m_creature); + else if (m_creature->GetEntry() == NPC_KURENAI_CAPTIVE) + DoScriptText(urand(0, 1) ? SAY_KUR_COMPLETE_1 : SAY_KUR_COMPLETE_2, m_creature); if (Player* pPlayer = GetPlayerForEscort()) - pPlayer->GroupEventHappens(QUEST_TOTEM_KARDASH_H, m_creature); + pPlayer->GroupEventHappens(m_creature->GetEntry() == NPC_MAGHAR_CAPTIVE ? QUEST_TOTEM_KARDASH_H : QUEST_TOTEM_KARDASH_A, m_creature); SetRun(); break; } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_MURK_BRUTE) DoScriptText(SAY_MAG_NO_ESCAPE, pSummoned); @@ -411,7 +277,7 @@ struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI pSummoned->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); } - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* /*pTarget*/, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_CHAIN_LIGHTNING) { @@ -422,15 +288,15 @@ struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiChainLightningTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING); - m_uiChainLightningTimer = urand(7000, 14000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiChainLightningTimer = urand(7000, 14000); } else m_uiChainLightningTimer -= uiDiff; @@ -439,8 +305,8 @@ struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI { if (m_uiHealTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_HEALING_WAVE); - m_uiHealTimer = 5000; + if (DoCastSpellIfCan(m_creature, SPELL_HEALING_WAVE) == CAST_OK) + m_uiHealTimer = 5000; } else m_uiHealTimer -= uiDiff; @@ -448,8 +314,8 @@ struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI if (m_uiFrostShockTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK); - m_uiFrostShockTimer = urand(7500, 15000); + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK) == CAST_OK) + m_uiFrostShockTimer = urand(7500, 15000); } else m_uiFrostShockTimer -= uiDiff; @@ -458,30 +324,20 @@ struct MANGOS_DLL_DECL npc_maghar_captiveAI : public npc_escortAI } }; -bool QuestAccept_npc_maghar_captive(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool QuestAccept_npc_nagrand_captive(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - if (pQuest->GetQuestId() == QUEST_TOTEM_KARDASH_H) + if (pQuest->GetQuestId() == QUEST_TOTEM_KARDASH_H || pQuest->GetQuestId() == QUEST_TOTEM_KARDASH_A) { - if (npc_maghar_captiveAI* pEscortAI = dynamic_cast(pCreature->AI())) - { - pCreature->SetStandState(UNIT_STAND_STATE_STAND); - pCreature->setFaction(FACTION_ESCORT_H_NEUTRAL_ACTIVE); - - pEscortAI->Start(false, pPlayer, pQuest); - - DoScriptText(SAY_MAG_START, pCreature); - - pCreature->SummonCreature(NPC_MURK_RAIDER, m_afAmbushA[0]+2.5f, m_afAmbushA[1]-2.5f, m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - pCreature->SummonCreature(NPC_MURK_PUTRIFIER, m_afAmbushA[0]-2.5f, m_afAmbushA[1]+2.5f, m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - pCreature->SummonCreature(NPC_MURK_BRUTE, m_afAmbushA[0], m_afAmbushA[1], m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - } + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; } - return true; + + return false; } -CreatureAI* GetAI_npc_maghar_captive(Creature* pCreature) +CreatureAI* GetAI_npc_nagrand_captive(Creature* pCreature) { - return new npc_maghar_captiveAI(pCreature); + return new npc_nagrand_captiveAI(pCreature); } /*###### @@ -493,13 +349,13 @@ enum QUEST_VISIT_WITH_ANCESTORS = 10085 }; -struct MANGOS_DLL_DECL npc_creditmarker_visit_with_ancestorsAI : public ScriptedAI +struct npc_creditmarker_visit_with_ancestorsAI : public ScriptedAI { npc_creditmarker_visit_with_ancestorsAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 30.0f)) { @@ -523,9 +379,173 @@ CreatureAI* GetAI_npc_creditmarker_visit_with_ancestors(Creature* pCreature) } /*###### -## AddSC +## npc_rethhedron ######*/ +enum +{ + SAY_LOW_HP = -1000966, + SAY_EVENT_END = -1000967, + + SPELL_CRIPPLE = 41281, + SPELL_SHADOW_BOLT = 41280, + SPELL_ABYSSAL_TOSS = 41283, // summon npc 23416 at target position + SPELL_ABYSSAL_IMPACT = 41284, + // SPELL_GROUND_AIR_PULSE = 41270, // spell purpose unk + // SPELL_AGGRO_CHECK = 41285, // spell purpose unk + // SPELL_AGGRO_BURST = 41286, // spell purpose unk + + SPELL_COSMETIC_LEGION_RING = 41339, + SPELL_QUEST_COMPLETE = 41340, + + NPC_SPELLBINDER = 22342, + NPC_RETHHEDRONS_TARGET = 23416, + + POINT_ID_PORTAL_FRONT = 0, + POINT_ID_PORTAL = 1, +}; + +static const float afRethhedronPos[2][3] = +{ + { -1502.39f, 9772.33f, 200.421f}, + { -1557.93f, 9834.34f, 200.949f} +}; + +struct npc_rethhedronAI : public ScriptedAI +{ + npc_rethhedronAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiCrippleTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiAbyssalTossTimer; + uint32 m_uiDelayTimer; + + bool m_bLowHpYell; + bool m_bEventFinished; + + void Reset() override + { + m_uiCrippleTimer = urand(5000, 9000); + m_uiShadowBoltTimer = urand(1000, 3000); + m_uiAbyssalTossTimer = 0; + m_uiDelayTimer = 0; + + m_bLowHpYell = false; + m_bEventFinished = false; + } + + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 30.0f); + } + } + + void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage) override + { + // go to epilog at 10% health + if (!m_bEventFinished && m_creature->GetHealthPercent() < 10.0f) + { + m_creature->InterruptNonMeleeSpells(false); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PORTAL_FRONT, afRethhedronPos[0][0], afRethhedronPos[0][1], afRethhedronPos[0][2]); + m_bEventFinished = true; + } + + // npc is not allowed to die + if (m_creature->GetHealth() < uiDamage) + uiDamage = 0; + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + if (uiPointId == POINT_ID_PORTAL_FRONT) + { + DoScriptText(SAY_EVENT_END, m_creature); + m_creature->GetMotionMaster()->MoveIdle(); + m_uiDelayTimer = 2000; + } + else if (uiPointId == POINT_ID_PORTAL) + { + DoCastSpellIfCan(m_creature, SPELL_COSMETIC_LEGION_RING, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_QUEST_COMPLETE, CAST_TRIGGERED); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->ForcedDespawn(2000); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_RETHHEDRONS_TARGET) + pSummoned->CastSpell(pSummoned, SPELL_ABYSSAL_IMPACT, true); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiDelayTimer) + { + if (m_uiDelayTimer <= uiDiff) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_PORTAL, afRethhedronPos[1][0], afRethhedronPos[1][1], afRethhedronPos[1][2]); + m_uiDelayTimer = 0; + } + else + m_uiDelayTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_bEventFinished) + return; + + if (m_uiCrippleTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CRIPPLE) == CAST_OK) + m_uiCrippleTimer = urand(20000, 30000); + } + else + m_uiCrippleTimer -= uiDiff; + + if (m_uiShadowBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT) == CAST_OK) + m_uiShadowBoltTimer = urand(3000, 5000); + } + else + m_uiShadowBoltTimer -= uiDiff; + + if (m_uiAbyssalTossTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ABYSSAL_TOSS) == CAST_OK) + m_uiAbyssalTossTimer = urand(500, 2000); + } + else + m_uiAbyssalTossTimer -= uiDiff; + + if (!m_bLowHpYell && m_creature->GetHealthPercent() < 40.0f) + { + DoScriptText(SAY_LOW_HP, m_creature); + m_bLowHpYell = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_rethhedron(Creature* pCreature) +{ + return new npc_rethhedronAI(pCreature); +} + void AddSC_nagrand() { Script* pNewScript; @@ -536,26 +556,18 @@ void AddSC_nagrand() pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_altruis_the_sufferer"; - pNewScript->pGossipHello = &GossipHello_npc_altruis_the_sufferer; - pNewScript->pGossipSelect = &GossipSelect_npc_altruis_the_sufferer; - pNewScript->pQuestAcceptNPC = &QuestAccept_npc_altruis_the_sufferer; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_greatmother_geyah"; - pNewScript->pGossipHello = &GossipHello_npc_greatmother_geyah; - pNewScript->pGossipSelect = &GossipSelect_npc_greatmother_geyah; + pNewScript->Name = "npc_nagrand_captive"; + pNewScript->GetAI = &GetAI_npc_nagrand_captive; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_nagrand_captive; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_maghar_captive"; - pNewScript->GetAI = &GetAI_npc_maghar_captive; - pNewScript->pQuestAcceptNPC = &QuestAccept_npc_maghar_captive; + pNewScript->Name = "npc_creditmarker_visit_with_ancestors"; + pNewScript->GetAI = &GetAI_npc_creditmarker_visit_with_ancestors; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_creditmarker_visit_with_ancestors"; - pNewScript->GetAI = &GetAI_npc_creditmarker_visit_with_ancestors; + pNewScript->Name = "npc_rethhedron"; + pNewScript->GetAI = &GetAI_npc_rethhedron; pNewScript->RegisterSelf(); } diff --git a/scripts/outland/netherstorm.cpp b/scripts/outland/netherstorm.cpp index 13526d09f..9d5a0ab6d 100644 --- a/scripts/outland/netherstorm.cpp +++ b/scripts/outland/netherstorm.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Netherstorm SD%Complete: 80 -SDComment: Quest support: 10438, 10299, 10321, 10322, 10323, 10329, 10330, 10337, 10338, 10365(Shutting Down Manaforge), 10198, 10191, 10924 +SDComment: Quest support: 10191, 10198, 10299, 10310, 10321, 10322, 10323, 10329, 10330, 10337, 10338, 10365(Shutting Down Manaforge), 10406, 10425, 10438, 10924. SDCategory: Netherstorm EndScriptData */ @@ -25,9 +25,13 @@ EndScriptData */ npc_manaforge_control_console go_manaforge_control_console npc_commander_dawnforge -npc_protectorate_nether_drake npc_bessy npc_maxx_a_million +npc_zeppit +npc_protectorate_demolitionist +npc_captured_vanguard +npc_drijya +npc_dimensius EndContentData */ #include "precompiled.h" @@ -77,7 +81,7 @@ enum SPELL_INTERRUPT_2 = 35176, // ACID mobs should cast this (Manaforge Ara-version) }; -struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI +struct npc_manaforge_control_consoleAI : public ScriptedAI { npc_manaforge_control_consoleAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -88,7 +92,7 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI uint32 m_uiPhase; bool m_bWave; - void Reset() + void Reset() override { m_playerGuid.Clear(); m_consoleGuid.Clear(); @@ -98,15 +102,15 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI m_bWave = false; } - /*void SpellHit(Unit *caster, const SpellEntry *spell) + /*void SpellHit(Unit *caster, const SpellEntry *spell) override { - //we have no way of telling the creature was hit by spell -> got aura applied after 10-12 seconds - //then no way for the mobs to actually stop the shutdown as intended. + // we have no way of telling the creature was hit by spell -> got aura applied after 10-12 seconds + // then no way for the mobs to actually stop the shutdown as intended. if (spell->Id == SPELL_INTERRUPT_1) ... }*/ - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(EMOTE_ABORT, m_creature); @@ -114,7 +118,7 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI if (pPlayer) { - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case NPC_BNAAR_C_CONSOLE: pPlayer->FailQuest(QUEST_SHUTDOWN_BNAAR_ALDOR); @@ -143,52 +147,52 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI { Creature* pAdd = NULL; - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_BNAAR_C_CONSOLE: if (urand(0, 1)) { - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2933.68f, 4162.55f, 164.00f, 1.60f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2933.68f, 4162.55f, 164.00f, 1.60f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2927.36f, 4212.97f, 164.00f); } else { - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2927.36f, 4212.97f, 164.00f, 4.94f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2927.36f, 4212.97f, 164.00f, 4.94f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2933.68f, 4162.55f, 164.00f); } m_uiWaveTimer = 30000; break; case NPC_CORUU_C_CONSOLE: - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2445.21f, 2765.26f, 134.49f, 3.93f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2445.21f, 2765.26f, 134.49f, 3.93f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2424.21f, 2740.15f, 133.81f); - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2429.86f, 2731.85f, 134.53f, 1.31f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2429.86f, 2731.85f, 134.53f, 1.31f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2435.37f, 2766.04f, 133.81f); m_uiWaveTimer = 20000; break; case NPC_DURO_C_CONSOLE: - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2986.80f, 2205.36f, 165.37f, 3.74f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2986.80f, 2205.36f, 165.37f, 3.74f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2985.15f, 2197.32f, 164.79f); - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2952.91f, 2191.20f, 165.32f, 0.22f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2952.91f, 2191.20f, 165.32f, 0.22f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2060.01f, 2185.27f, 164.67f); m_uiWaveTimer = 15000; break; case NPC_ARA_C_CONSOLE: if (urand(0, 1)) { - if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 4035.11f, 4038.97f, 194.27f, 2.57f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 4035.11f, 4038.97f, 194.27f, 2.57f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4003.42f, 4040.19f, 193.49f); - if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 4033.66f, 4036.79f, 194.28f, 2.57f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 4033.66f, 4036.79f, 194.28f, 2.57f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4003.42f, 4040.19f, 193.49f); - if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 4037.13f, 4037.30f, 194.23f, 2.57f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 4037.13f, 4037.30f, 194.23f, 2.57f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4003.42f, 4040.19f, 193.49f); } else { - if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 3099.59f, 4049.30f, 194.22f, 0.05f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 3099.59f, 4049.30f, 194.22f, 0.05f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4028.01f, 4035.17f, 193.59f); - if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 3999.72f, 4046.75f, 194.22f, 0.05f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 3999.72f, 4046.75f, 194.22f, 0.05f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4028.01f, 4035.17f, 193.59f); - if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 3996.81f, 4048.26f, 194.22f, 0.05f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_TECH, 3996.81f, 4048.26f, 194.22f, 0.05f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4028.01f, 4035.17f, 193.59f); } m_uiWaveTimer = 15000; @@ -200,38 +204,38 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI { Creature* pAdd = NULL; - switch(pCreature->GetEntry()) + switch (pCreature->GetEntry()) { case NPC_BNAAR_C_CONSOLE: - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2946.52f, 4201.42f, 163.47f, 3.54f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2946.52f, 4201.42f, 163.47f, 3.54f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2927.49f, 4192.81f, 163.00f); break; case NPC_CORUU_C_CONSOLE: - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2453.88f, 2737.85f, 133.27f, 2.59f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2453.88f, 2737.85f, 133.27f, 2.59f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2433.96f, 2751.53f, 133.85f); - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2441.62f, 2735.32f, 134.49f, 1.97f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2441.62f, 2735.32f, 134.49f, 1.97f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2433.96f, 2751.53f, 133.85f); - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2450.73f, 2754.50f, 134.49f, 3.29f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2450.73f, 2754.50f, 134.49f, 3.29f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2433.96f, 2751.53f, 133.85f); break; case NPC_DURO_C_CONSOLE: - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2956.18f, 2202.85f, 165.32f, 5.45f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2956.18f, 2202.85f, 165.32f, 5.45f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2972.27f, 2193.22f, 164.48f); - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2975.30f, 2211.50f, 165.32f, 4.55f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_TECH, 2975.30f, 2211.50f, 165.32f, 4.55f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2972.27f, 2193.22f, 164.48f); - if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_PROT, 2965.02f, 2217.45f, 164.16f, 4.96f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_SUNFURY_PROT, 2965.02f, 2217.45f, 164.16f, 4.96f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 2972.27f, 2193.22f, 164.48f); break; case NPC_ARA_C_CONSOLE: - if (pAdd = m_creature->SummonCreature(NPC_ARA_ENGI, 3994.51f, 4020.46f, 192.18f, 0.91f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_ENGI, 3994.51f, 4020.46f, 192.18f, 0.91f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4008.35f, 4035.04f, 192.70f); - if (pAdd = m_creature->SummonCreature(NPC_ARA_GORKLONN, 4021.56f, 4059.35f, 193.59f, 4.44f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000)) + if (pAdd = m_creature->SummonCreature(NPC_ARA_GORKLONN, 4021.56f, 4059.35f, 193.59f, 4.44f, TEMPSUMMON_TIMED_OOC_DESPAWN, 120000)) pAdd->GetMotionMaster()->MovePoint(0, 4016.62f, 4039.89f, 193.46f); break; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiEventTimer < uiDiff) { @@ -247,7 +251,7 @@ struct MANGOS_DLL_DECL npc_manaforge_control_consoleAI : public ScriptedAI return; } - switch(m_uiPhase) + switch (m_uiPhase) { case 1: DoScriptText(EMOTE_START, m_creature, pPlayer); @@ -318,31 +322,31 @@ bool GOUse_go_manaforge_control_console(Player* pPlayer, GameObject* pGo) Creature* pManaforge = NULL; - switch(pGo->GetAreaId()) + switch (pGo->GetAreaId()) { case 3726: // b'naar if ((pPlayer->GetQuestStatus(QUEST_SHUTDOWN_BNAAR_ALDOR) == QUEST_STATUS_INCOMPLETE - || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_BNAAR_SCRYERS) == QUEST_STATUS_INCOMPLETE) - && pPlayer->HasItemCount(ITEM_BNAAR_ACESS_CRYSTAL, 1)) - pManaforge = pPlayer->SummonCreature(NPC_BNAAR_C_CONSOLE, 2918.95f, 4189.98f, 161.88f, 0.34f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000); + || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_BNAAR_SCRYERS) == QUEST_STATUS_INCOMPLETE) + && pPlayer->HasItemCount(ITEM_BNAAR_ACESS_CRYSTAL, 1)) + pManaforge = pPlayer->SummonCreature(NPC_BNAAR_C_CONSOLE, 2918.95f, 4189.98f, 161.88f, 0.34f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 125000); break; case 3730: // coruu if ((pPlayer->GetQuestStatus(QUEST_SHUTDOWN_CORUU_ALDOR) == QUEST_STATUS_INCOMPLETE - || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_CORUU_SCRYERS) == QUEST_STATUS_INCOMPLETE) - && pPlayer->HasItemCount(ITEM_CORUU_ACESS_CRYSTAL, 1)) - pManaforge = pPlayer->SummonCreature(NPC_CORUU_C_CONSOLE, 2426.77f, 2750.38f, 133.24f, 2.14f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000); + || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_CORUU_SCRYERS) == QUEST_STATUS_INCOMPLETE) + && pPlayer->HasItemCount(ITEM_CORUU_ACESS_CRYSTAL, 1)) + pManaforge = pPlayer->SummonCreature(NPC_CORUU_C_CONSOLE, 2426.77f, 2750.38f, 133.24f, 2.14f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 125000); break; case 3734: // duro if ((pPlayer->GetQuestStatus(QUEST_SHUTDOWN_DURO_ALDOR) == QUEST_STATUS_INCOMPLETE - || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_DURO_SCRYERS) == QUEST_STATUS_INCOMPLETE) - && pPlayer->HasItemCount(ITEM_DURO_ACESS_CRYSTAL, 1)) - pManaforge = pPlayer->SummonCreature(NPC_DURO_C_CONSOLE, 2976.48f, 2183.29f, 163.20f, 1.85f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000); + || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_DURO_SCRYERS) == QUEST_STATUS_INCOMPLETE) + && pPlayer->HasItemCount(ITEM_DURO_ACESS_CRYSTAL, 1)) + pManaforge = pPlayer->SummonCreature(NPC_DURO_C_CONSOLE, 2976.48f, 2183.29f, 163.20f, 1.85f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 125000); break; case 3722: // ara if ((pPlayer->GetQuestStatus(QUEST_SHUTDOWN_ARA_ALDOR) == QUEST_STATUS_INCOMPLETE - || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_ARA_SCRYERS) == QUEST_STATUS_INCOMPLETE) - && pPlayer->HasItemCount(ITEM_ARA_ACESS_CRYSTAL, 1)) - pManaforge = pPlayer->SummonCreature(NPC_ARA_C_CONSOLE, 4013.71f, 4028.76f, 192.10f, 1.25f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000); + || pPlayer->GetQuestStatus(QUEST_SHUTDOWN_ARA_SCRYERS) == QUEST_STATUS_INCOMPLETE) + && pPlayer->HasItemCount(ITEM_ARA_ACESS_CRYSTAL, 1)) + pManaforge = pPlayer->SummonCreature(NPC_ARA_C_CONSOLE, 4013.71f, 4028.76f, 192.10f, 1.25f, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 125000); break; } @@ -386,9 +390,9 @@ enum NPC_PATHALEON_THE_CALCULATOR_IMAGE = 21504 }; -struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI +struct npc_commander_dawnforgeAI : public ScriptedAI { - npc_commander_dawnforgeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset (); } + npc_commander_dawnforgeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } ObjectGuid m_playerGuid; ObjectGuid m_ardonisGuid; @@ -399,7 +403,7 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI uint32 m_uiPhaseTimer; bool m_bIsEvent; - void Reset() + void Reset() override { m_playerGuid.Clear(); m_ardonisGuid.Clear(); @@ -411,7 +415,7 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI m_bIsEvent = false; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_PATHALEON_THE_CALCULATOR_IMAGE) m_pathaleonGuid = pSummoned->GetObjectGuid(); @@ -474,7 +478,7 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI return false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Is event even running? if (!m_bIsEvent) @@ -532,7 +536,7 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI m_uiPhaseTimer = 6000; break; case 6: - switch(m_uiPhaseSubphase) + switch (m_uiPhaseSubphase) { case 0: TurnToPathaleonsImage(); @@ -548,7 +552,7 @@ struct MANGOS_DLL_DECL npc_commander_dawnforgeAI : public ScriptedAI } break; case 7: - switch(m_uiPhaseSubphase) + switch (m_uiPhaseSubphase) { case 0: DoScriptText(SAY_PATHALEON_THE_CALCULATOR_IMAGE_2, pPathaleon); @@ -596,7 +600,7 @@ CreatureAI* GetAI_npc_commander_dawnforge(Creature* pCreature) return new npc_commander_dawnforgeAI(pCreature); } -bool AreaTrigger_at_commander_dawnforge(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_commander_dawnforge(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { // if player lost aura or not have at all, we should not try start event. if (!pPlayer->HasAura(SPELL_SUNFURY_DISGUISE, EFFECT_INDEX_0)) @@ -618,39 +622,6 @@ bool AreaTrigger_at_commander_dawnforge(Player* pPlayer, AreaTriggerEntry const* return false; } -/*###### -## npc_protectorate_nether_drake -######*/ - -enum -{ - QUEST_NETHER_WINGS = 10438, - ITEM_PH_DISRUPTOR = 29778, - TAXI_PATH_ID = 627 //(possibly 627+628(152->153->154->155)) -}; - -#define GOSSIP_ITEM_FLY_ULTRIS "Fly me to Ultris" - -bool GossipHello_npc_protectorate_nether_drake(Player* pPlayer, Creature* pCreature) -{ - // On Nethery Wings - if (pPlayer->GetQuestStatus(QUEST_NETHER_WINGS) == QUEST_STATUS_INCOMPLETE && pPlayer->HasItemCount(ITEM_PH_DISRUPTOR, 1)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FLY_ULTRIS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -bool GossipSelect_npc_protectorate_nether_drake(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID); - } - return true; -} - /*###### ## npc_bessy ######*/ @@ -664,22 +635,22 @@ enum NPC_SEVERED_SPIRIT = 19881 }; -struct MANGOS_DLL_DECL npc_bessyAI : public npc_escortAI +struct npc_bessyAI : public npc_escortAI { npc_bessyAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 3: - m_creature->SummonCreature(NPC_TORMENTED_SOUL, 2449.67f, 2183.11f, 96.85f, 6.20f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - m_creature->SummonCreature(NPC_TORMENTED_SOUL, 2449.53f, 2184.43f, 96.36f, 6.27f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - m_creature->SummonCreature(NPC_TORMENTED_SOUL, 2449.85f, 2186.34f, 97.57f, 6.08f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_TORMENTED_SOUL, 2449.67f, 2183.11f, 96.85f, 6.20f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_TORMENTED_SOUL, 2449.53f, 2184.43f, 96.36f, 6.27f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_TORMENTED_SOUL, 2449.85f, 2186.34f, 97.57f, 6.08f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 7: - m_creature->SummonCreature(NPC_SEVERED_SPIRIT, 2309.64f, 2186.24f, 92.25f, 6.06f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - m_creature->SummonCreature(NPC_SEVERED_SPIRIT, 2309.25f, 2183.46f, 91.75f, 6.22f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_SEVERED_SPIRIT, 2309.64f, 2186.24f, 92.25f, 6.06f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); + m_creature->SummonCreature(NPC_SEVERED_SPIRIT, 2309.25f, 2183.46f, 91.75f, 6.22f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 12: if (Player* pPlayer = GetPlayerForEscort()) @@ -688,20 +659,19 @@ struct MANGOS_DLL_DECL npc_bessyAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void Reset() {} + void Reset() override {} }; bool QuestAccept_npc_bessy(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_COWS_COME_HOME) { - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); - pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_NON_ATTACKABLE); if (npc_bessyAI* pBessyAI = dynamic_cast(pCreature->AI())) pBessyAI->Start(true, pPlayer, pQuest); @@ -711,7 +681,7 @@ bool QuestAccept_npc_bessy(Player* pPlayer, Creature* pCreature, const Quest* pQ CreatureAI* GetAI_npc_bessy(Creature* pCreature) { - return new npc_bessyAI(pCreature); + return new npc_bessyAI(pCreature); } /*###### @@ -730,7 +700,7 @@ enum SAY_ALLEY_FINISH = -1000624 }; -struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI +struct npc_maxx_a_million_escortAI : public npc_escortAI { npc_maxx_a_million_escortAI(Creature* pCreature) : npc_escortAI(pCreature) {Reset();} @@ -739,7 +709,7 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI ObjectGuid m_alleyGuid; ObjectGuid m_lastDraeneiMachineGuid; - void Reset() + void Reset() override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -750,23 +720,16 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI // Reset fields, that were changed on escort-start m_creature->HandleEmote(EMOTE_STATE_STUN); - // Faction is reset with npc_escortAI::JustRespawned(); - - // Unclear how these flags are set/removed in relation to the faction change at start of escort. - // Workaround here, so that the flags are removed during escort (and while not in evade mode) - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE + UNIT_FLAG_PASSIVE); } - else - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); } - void WaypointReached(uint32 uiPoint) + void WaypointReached(uint32 uiPoint) override { switch (uiPoint) { case 1: // turn 90 degrees , towards doorway. - m_creature->SetFacingTo(m_creature->GetOrientation() + (M_PI_F/2)); + m_creature->SetFacingTo(m_creature->GetOrientation() + (M_PI_F / 2)); DoScriptText(SAY_START, m_creature); m_uiSubEventTimer = 3000; m_uiSubEvent = 1; @@ -796,7 +759,7 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI } } - void WaypointStart(uint32 uiPoint) + void WaypointStart(uint32 uiPoint) override { switch (uiPoint) { @@ -808,7 +771,7 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -819,7 +782,7 @@ struct MANGOS_DLL_DECL npc_maxx_a_million_escortAI : public npc_escortAI switch (m_uiSubEvent) { case 1: // Wait time before Say - if (Creature* pAlley = GetClosestCreatureWithEntry(m_creature, NPC_BOT_SPECIALIST_ALLEY, INTERACTION_DISTANCE*2)) + if (Creature* pAlley = GetClosestCreatureWithEntry(m_creature, NPC_BOT_SPECIALIST_ALLEY, INTERACTION_DISTANCE * 2)) { m_alleyGuid = pAlley->GetObjectGuid(); DoScriptText(SAY_ALLEY_FAREWELL, pAlley); @@ -866,11 +829,9 @@ bool QuestAccept_npc_maxx_a_million(Player* pPlayer, Creature* pCreature, const if (npc_maxx_a_million_escortAI* pEscortAI = dynamic_cast(pCreature->AI())) { // Set Faction to Escort Faction - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_OOC_NOT_ATTACK | TEMPFACTION_TOGGLE_PASSIVE); // Set emote-state to 0 (is EMOTE_STATE_STUN by default) pCreature->HandleEmote(EMOTE_ONESHOT_NONE); - // Remove unit_flags (see comment in JustReachedHome) - pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE + UNIT_FLAG_PASSIVE); pEscortAI->Start(false, pPlayer, pQuest, true); } @@ -889,13 +850,13 @@ enum SPELL_GATHER_WARP_BLOOD = 39244, // for quest 10924 }; -struct MANGOS_DLL_DECL npc_zeppitAI : public ScriptedPetAI +struct npc_zeppitAI : public ScriptedPetAI { npc_zeppitAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void OwnerKilledUnit(Unit* pVictim) + void OwnerKilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetEntry() == NPC_WARP_CHASER) { @@ -914,6 +875,676 @@ CreatureAI* GetAI_npc_zeppit(Creature* pCreature) return new npc_zeppitAI(pCreature); } +/*###### +## npc_protectorate_demolitionist +######*/ + +enum +{ + SAY_INTRO = -1000891, + SAY_ATTACKED_1 = -1000892, + SAY_ATTACKED_2 = -1000893, + SAY_STAGING_GROUNDS = -1000894, + SAY_TOXIC_HORROR = -1000895, + SAY_SALHADAAR = -1000896, + SAY_DISRUPTOR = -1000897, + SAY_NEXUS_PROTECT = -1000898, + SAY_FINISH_1 = -1000899, + SAY_FINISH_2 = -1000900, + + SPELL_ETHEREAL_TELEPORT = 34427, + SPELL_PROTECTORATE = 35679, // dummy aura applied on player + + NPC_NEXUS_STALKER = 20474, + NPC_ARCHON = 20458, + + FACTION_FRIENDLY = 35, + + QUEST_ID_DELIVERING_MESSAGE = 10406, +}; + +struct npc_protectorate_demolitionistAI : public npc_escortAI +{ + npc_protectorate_demolitionistAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiEventTimer; + uint8 m_uiEventStage; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiEventTimer = 0; + m_uiEventStage = 0; + } + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(urand(0, 1) ? SAY_ATTACKED_1 : SAY_ATTACKED_2, m_creature); + } + + // No attack done by this npc + void AttackStart(Unit* /*pWho*/) override { } + + void MoveInLineOfSight(Unit* pWho) override + { + if (HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + // Star the escort + if (pWho->GetTypeId() == TYPEID_PLAYER) + { + if (pWho->HasAura(SPELL_PROTECTORATE) && ((Player*)pWho)->GetQuestStatus(QUEST_ID_DELIVERING_MESSAGE) == QUEST_STATUS_INCOMPLETE) + { + if (m_creature->IsWithinDistInMap(pWho, 10.0f)) + { + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); + Start(false, (Player*)pWho); + } + } + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_NEXUS_STALKER) + DoScriptText(SAY_NEXUS_PROTECT, pSummoned); + else if (pSummoned->GetEntry() == NPC_ARCHON) + pSummoned->CastSpell(pSummoned, SPELL_ETHEREAL_TELEPORT, true); + + pSummoned->AI()->AttackStart(m_creature); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + DoScriptText(SAY_INTRO, m_creature); + break; + case 3: + DoScriptText(SAY_STAGING_GROUNDS, m_creature); + break; + case 4: + DoScriptText(SAY_TOXIC_HORROR, m_creature); + break; + case 9: + DoScriptText(SAY_SALHADAAR, m_creature); + break; + case 12: + DoScriptText(SAY_DISRUPTOR, m_creature); + SetEscortPaused(true); + m_uiEventTimer = 5000; + break; + case 13: + DoScriptText(SAY_FINISH_2, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + { + m_creature->SetFacingToObject(pPlayer); + pPlayer->GroupEventHappens(QUEST_ID_DELIVERING_MESSAGE, m_creature); + } + SetEscortPaused(true); + m_uiEventTimer = 6000; + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (m_uiEventTimer) + { + if (m_uiEventTimer <= uiDiff) + { + switch (m_uiEventStage) + { + case 0: + m_creature->SummonCreature(NPC_ARCHON, 3875.69f, 2308.72f, 115.80f, 1.48f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_uiEventTimer = 4000; + break; + case 1: + m_creature->SummonCreature(NPC_NEXUS_STALKER, 3884.06f, 2325.22f, 111.37f, 3.45f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_creature->SummonCreature(NPC_NEXUS_STALKER, 3861.54f, 2320.44f, 111.48f, 0.32f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); + m_uiEventTimer = 9000; + break; + case 2: + DoScriptText(SAY_FINISH_1, m_creature); + SetRun(); + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + case 3: + if (DoCastSpellIfCan(m_creature, SPELL_ETHEREAL_TELEPORT, CAST_TRIGGERED) == CAST_OK) + m_creature->ForcedDespawn(1000); + m_uiEventTimer = 0; + break; + } + ++m_uiEventStage; + } + else + m_uiEventTimer -= uiDiff; + } + + // ToDo: research if the npc uses spells or melee for combat + } +}; + +CreatureAI* GetAI_npc_protectorate_demolitionist(Creature* pCreature) +{ + return new npc_protectorate_demolitionistAI(pCreature); +} + +/*###### +## npc_captured_vanguard +######*/ + +enum +{ + SAY_VANGUARD_INTRO = -1000901, + SAY_VANGUARD_START = -1000902, + SAY_VANGUARD_FINISH = -1000903, + EMOTE_VANGUARD_FINISH = -1000904, + + SPELL_GLAIVE = 36500, + SPELL_HAMSTRING = 31553, + + NPC_COMMANDER_AMEER = 20448, + + QUEST_ID_ESCAPE_STAGING_GROUNDS = 10425, +}; + +struct npc_captured_vanguardAI : public npc_escortAI +{ + npc_captured_vanguardAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiGlaiveTimer; + uint32 m_uiHamstringTimer; + + void Reset() override + { + m_uiGlaiveTimer = urand(4000, 8000); + m_uiHamstringTimer = urand(8000, 13000); + } + + void JustReachedHome() override + { + // Happens only if the player helps the npc in the fight - otherwise he dies + DoScriptText(SAY_VANGUARD_INTRO, m_creature); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 15: + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_ESCAPE_STAGING_GROUNDS, m_creature); + break; + case 16: + DoScriptText(SAY_VANGUARD_FINISH, m_creature); + SetRun(); + break; + case 17: + if (Creature* pAmeer = GetClosestCreatureWithEntry(m_creature, NPC_COMMANDER_AMEER, 5.0f)) + DoScriptText(EMOTE_VANGUARD_FINISH, m_creature, pAmeer); + break; + case 18: + if (DoCastSpellIfCan(m_creature, SPELL_ETHEREAL_TELEPORT, CAST_TRIGGERED) == CAST_OK) + m_creature->ForcedDespawn(1000); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiGlaiveTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_GLAIVE) == CAST_OK) + m_uiGlaiveTimer = urand(5000, 9000); + } + else + m_uiGlaiveTimer -= uiDiff; + + if (m_uiHamstringTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMSTRING) == CAST_OK) + m_uiHamstringTimer = urand(10000, 16000); + } + else + m_uiHamstringTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_captured_vanguard(Creature* pCreature) +{ + return new npc_captured_vanguardAI(pCreature); +} + +bool QuestAccept_npc_captured_vanguard(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_ESCAPE_STAGING_GROUNDS) + { + if (npc_captured_vanguardAI* pEscortAI = dynamic_cast(pCreature->AI())) + pEscortAI->Start(false, pPlayer, pQuest); + + DoScriptText(SAY_VANGUARD_START, pCreature, pPlayer); + } + + return true; +} + +/*###### +## npc_drijya +######*/ + +enum +{ + SAY_DRIJYA_START = -1000968, + SAY_DRIJYA_1 = -1000969, + SAY_DRIJYA_2 = -1000970, + SAY_DRIJYA_3 = -1000971, + SAY_DRIJYA_4 = -1000972, + SAY_DRIJYA_5 = -1000973, + SAY_DRIJYA_6 = -1000974, + SAY_DRIJYA_7 = -1000975, + SAY_DRIJYA_COMPLETE = -1000976, + + SPELL_SUMMON_SMOKE = 42456, // summon temp GO 185318 + SPELL_SUMMON_FIRE = 42467, // summon temp GO 185319 + SPELL_EXPLOSION_VISUAL = 42458, + + NPC_EXPLODE_TRIGGER = 20296, + NPC_TERROR_IMP = 20399, + NPC_LEGION_TROOPER = 20402, + NPC_LEGION_DESTROYER = 20403, + + // GO_SMOKE = 185318, + // GO_FIRE = 185317, // not sure if this one is used + // GO_BIG_FIRE = 185319, + + QUEST_ID_WARP_GATE = 10310, + + MAX_TROOPERS = 9, + MAX_IMPS = 6, +}; + +struct npc_drijyaAI : public npc_escortAI +{ + npc_drijyaAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint8 m_uiSpawnCount; + uint32 m_uiSpawnImpTimer; + uint32 m_uiSpawnTrooperTimer; + uint32 m_uiSpawnDestroyerTimer; + uint32 m_uiDestroyingTimer; + + ObjectGuid m_explodeTriggerGuid; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiSpawnCount = 0; + m_uiSpawnImpTimer = 0; + m_uiSpawnTrooperTimer = 0; + m_uiSpawnDestroyerTimer = 0; + m_uiDestroyingTimer = 0; + } + } + + void AttackedBy(Unit* pWho) override + { + if (pWho->GetEntry() == NPC_TERROR_IMP || pWho->GetEntry() == NPC_LEGION_TROOPER || pWho->GetEntry() == NPC_LEGION_DESTROYER) + { + if (urand(0, 1)) + DoScriptText(SAY_DRIJYA_3, m_creature); + } + } + + void DoSpawnCreature(uint32 uiEntry) + { + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_explodeTriggerGuid)) + m_creature->SummonCreature(uiEntry, pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), pTrigger->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 10000); + } + + void JustSummoned(Creature* pSummoned) override + { + switch (pSummoned->GetEntry()) + { + case NPC_TERROR_IMP: + case NPC_LEGION_TROOPER: + case NPC_LEGION_DESTROYER: + pSummoned->AI()->AttackStart(m_creature); + break; + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + DoScriptText(SAY_DRIJYA_START, m_creature); + SetRun(); + break; + case 1: + DoScriptText(SAY_DRIJYA_1, m_creature); + break; + case 5: + DoScriptText(SAY_DRIJYA_2, m_creature); + break; + case 7: + SetEscortPaused(true); + m_uiDestroyingTimer = 60000; + m_uiSpawnImpTimer = 15000; + m_uiSpawnCount = 0; + m_creature->HandleEmoteCommand(EMOTE_STATE_WORK); + if (Creature* pTrigger = GetClosestCreatureWithEntry(m_creature, NPC_EXPLODE_TRIGGER, 30.0f)) + m_explodeTriggerGuid = pTrigger->GetObjectGuid(); + break; + case 8: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOKE) == CAST_OK) + { + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + + DoScriptText(SAY_DRIJYA_4, m_creature); + } + break; + case 12: + SetEscortPaused(true); + m_uiDestroyingTimer = 60000; + m_uiSpawnTrooperTimer = 15000; + m_uiSpawnCount = 0; + m_creature->HandleEmoteCommand(EMOTE_STATE_WORK); + break; + case 13: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOKE) == CAST_OK) + { + if (Player* pPlayer = GetPlayerForEscort()) + m_creature->SetFacingToObject(pPlayer); + + DoScriptText(SAY_DRIJYA_5, m_creature); + } + break; + case 17: + SetEscortPaused(true); + m_uiDestroyingTimer = 60000; + m_uiSpawnDestroyerTimer = 15000; + m_creature->HandleEmoteCommand(EMOTE_STATE_WORK); + break; + case 18: + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_SMOKE) == CAST_OK) + { + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_explodeTriggerGuid)) + m_creature->SetFacingToObject(pTrigger); + + DoScriptText(SAY_DRIJYA_6, m_creature); + } + break; + case 19: + if (Creature* pTrigger = m_creature->GetMap()->GetCreature(m_explodeTriggerGuid)) + { + pTrigger->CastSpell(pTrigger, SPELL_SUMMON_FIRE, true); + pTrigger->CastSpell(pTrigger, SPELL_EXPLOSION_VISUAL, true); + } + break; + case 20: + DoScriptText(SAY_DRIJYA_7, m_creature); + break; + case 23: + SetRun(false); + break; + case 27: + if (Player* pPlayer = GetPlayerForEscort()) + { + DoScriptText(SAY_DRIJYA_COMPLETE, m_creature, pPlayer); + pPlayer->GroupEventHappens(QUEST_ID_WARP_GATE, m_creature); + } + break; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue), true); + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (m_uiSpawnImpTimer) + { + if (m_uiSpawnImpTimer <= uiDiff) + { + DoSpawnCreature(NPC_TERROR_IMP); + ++m_uiSpawnCount; + + if (m_uiSpawnCount == MAX_IMPS) + m_uiSpawnImpTimer = 0; + else + m_uiSpawnImpTimer = 3500; + } + else + m_uiSpawnImpTimer -= uiDiff; + } + + if (m_uiSpawnTrooperTimer) + { + if (m_uiSpawnTrooperTimer <= uiDiff) + { + DoSpawnCreature(NPC_LEGION_TROOPER); + ++m_uiSpawnCount; + + if (m_uiSpawnCount == MAX_TROOPERS) + m_uiSpawnTrooperTimer = 0; + else + m_uiSpawnTrooperTimer = 3500; + } + else + m_uiSpawnTrooperTimer -= uiDiff; + } + + if (m_uiSpawnDestroyerTimer) + { + if (m_uiSpawnDestroyerTimer <= uiDiff) + { + DoSpawnCreature(NPC_LEGION_DESTROYER); + m_uiSpawnDestroyerTimer = 0; + } + else + m_uiSpawnDestroyerTimer -= uiDiff; + } + + if (m_uiDestroyingTimer) + { + if (m_uiDestroyingTimer <= uiDiff) + { + SetEscortPaused(false); + m_creature->HandleEmoteCommand(EMOTE_STATE_NONE); + m_uiDestroyingTimer = 0; + } + else + m_uiDestroyingTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_drijya(Creature* pCreature) +{ + return new npc_drijyaAI(pCreature); +} + +bool QuestAccept_npc_drijya(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_WARP_GATE) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + +/*###### +## npc_dimensius +######*/ + +enum +{ + SAY_AGGRO = -1001170, + SAY_SUMMON = -1001171, + + SPELL_DIMENSIUS_FEEDING = 37450, + SPELL_SHADOW_SPIRAL = 37500, + SPELL_SHADOW_VAULT = 37412, + + NPC_SPAWN_OF_DIMENSIUS = 21780, + NPC_CAPTAIN_SAEED = 20985, + MODEL_ID_DIMENSIUS_CLOUD = 20011, +}; + +// order based on the increasing range of damage +static const uint32 auiShadowRainSpells[5] = { 37399, 37405, 37397, 37396, 37409 }; + +struct npc_dimensiusAI : public Scripted_NoMovementAI +{ + npc_dimensiusAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + uint32 m_uiSpiralTimer; + uint32 m_uiVaultTimer; + uint32 m_uiRainTimer; + uint8 m_uiRainIndex; + uint8 m_uiSpawnsDead; + + bool m_bSpawnsFeeding; + + void Reset() override + { + m_uiSpiralTimer = 1000; + m_uiVaultTimer = urand(5000, 10000); + m_uiRainTimer = 0; + m_uiRainIndex = urand(0, 4); + m_uiSpawnsDead = 0; + + m_bSpawnsFeeding = false; + + m_creature->SetDisplayId(MODEL_ID_DIMENSIUS_CLOUD); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PASSIVE); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SPAWN_OF_DIMENSIUS) + pSummoned->CastSpell(m_creature, SPELL_DIMENSIUS_FEEDING, true); + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_SPAWN_OF_DIMENSIUS) + { + // interrupt the shadow rain when all spawns are dead + ++m_uiSpawnsDead; + if (m_uiSpawnsDead == 4) + { + m_creature->InterruptNonMeleeSpells(false); + m_uiRainTimer = 0; + } + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* /*pInvoker*/, uint32 /*uiMiscValue*/) override + { + // event is sent by dbscript + if (eventType == AI_EVENT_CUSTOM_EVENTAI_B && pSender->GetEntry() == NPC_CAPTAIN_SAEED) + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PASSIVE); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (!m_bSpawnsFeeding && m_creature->GetHealthPercent() < 75.0f) + { + DoScriptText(SAY_SUMMON, m_creature); + + float fX, fY, fZ; + for (uint8 i = 0; i < 4; ++i) + { + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, 30.0f, i * (M_PI_F / 2)); + m_creature->SummonCreature(NPC_SPAWN_OF_DIMENSIUS, fX, fY, fZ, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 120000); + } + + m_uiRainTimer = 5000; + m_bSpawnsFeeding = true; + } + + if (m_uiRainTimer) + { + if (m_uiRainTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, auiShadowRainSpells[m_uiRainIndex], CAST_INTERRUPT_PREVIOUS) == CAST_OK) + { + m_uiRainIndex = urand(0, 4); + m_uiRainTimer = 5000; + } + } + else + m_uiRainTimer -= uiDiff; + + return; + } + + if (m_uiSpiralTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_SPIRAL) == CAST_OK) + m_uiSpiralTimer = urand(3000, 4000); + } + } + else + m_uiSpiralTimer -= uiDiff; + + if (m_uiVaultTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_VAULT) == CAST_OK) + m_uiVaultTimer = urand(20000, 30000); + } + } + else + m_uiVaultTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_dimensius(Creature* pCreature) +{ + return new npc_dimensiusAI(pCreature); +} + void AddSC_netherstorm() { Script* pNewScript; @@ -930,7 +1561,7 @@ void AddSC_netherstorm() pNewScript = new Script; pNewScript->Name = "npc_commander_dawnforge"; - pNewScript->GetAI = GetAI_npc_commander_dawnforge; + pNewScript->GetAI = &GetAI_npc_commander_dawnforge; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -938,13 +1569,6 @@ void AddSC_netherstorm() pNewScript->pAreaTrigger = &AreaTrigger_at_commander_dawnforge; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_protectorate_nether_drake"; - pNewScript->pGossipHello = &GossipHello_npc_protectorate_nether_drake; - pNewScript->pGossipSelect = &GossipSelect_npc_protectorate_nether_drake; - pNewScript->RegisterSelf(); - - pNewScript = new Script; pNewScript->Name = "npc_bessy"; pNewScript->GetAI = &GetAI_npc_bessy; @@ -961,4 +1585,26 @@ void AddSC_netherstorm() pNewScript->Name = "npc_zeppit"; pNewScript->GetAI = &GetAI_npc_zeppit; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_protectorate_demolitionist"; + pNewScript->GetAI = &GetAI_npc_protectorate_demolitionist; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_captured_vanguard"; + pNewScript->GetAI = &GetAI_npc_captured_vanguard; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_captured_vanguard; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_drijya"; + pNewScript->GetAI = &GetAI_npc_drijya; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_drijya; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_dimensius"; + pNewScript->GetAI = &GetAI_npc_dimensius; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/shadowmoon_valley.cpp b/scripts/outland/shadowmoon_valley.cpp index 57c836a09..a5ee9668c 100644 --- a/scripts/outland/shadowmoon_valley.cpp +++ b/scripts/outland/shadowmoon_valley.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Shadowmoon_Valley SD%Complete: 100 -SDComment: Quest support: 10781, 10804, 10854, 10458, 10480, 10481, 10588, 11020. Vendor Drake Dealer Hurlunk. +SDComment: Quest support: 10451, 10458, 10480, 10481, 10514, 10540, 10588, 10781, 10804, 10854, 11020. SDCategory: Shadowmoon Valley EndScriptData */ @@ -25,8 +25,6 @@ EndScriptData */ mob_mature_netherwing_drake mob_enslaved_netherwing_drake npc_dragonmaw_peon -npc_drake_dealer_hurlunk -npc_karynaku npc_wilda mob_torloth npc_lord_illidan_stormrage @@ -34,6 +32,8 @@ npc_totem_of_spirits event_spell_soul_captured_credit go_crystal_prison npc_spawned_oronok_tornheart +npc_domesticated_felboar +npc_veneratus_spawn_node EndContentData */ #include "precompiled.h" @@ -51,112 +51,108 @@ enum SPELL_PLACE_CARCASS = 38439, SPELL_JUST_EATEN = 38502, SPELL_NETHER_BREATH = 38467, - POINT_ID = 1, QUEST_KINDNESS = 10804, - NPC_EVENT_PINGER = 22131 + NPC_EVENT_PINGER = 22131, + + GO_FLAYER_CARCASS = 185155, }; -struct MANGOS_DLL_DECL mob_mature_netherwing_drakeAI : public ScriptedAI +struct mob_mature_netherwing_drakeAI : public ScriptedAI { mob_mature_netherwing_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } ObjectGuid m_playerGuid; - bool bCanEat; - bool bIsEating; - - uint32 EatTimer; - uint32 CastTimer; + uint32 m_uiEatTimer; + uint32 m_uiCreditTimer; + uint32 m_uiCastTimer; - void Reset() + void Reset() override { m_playerGuid.Clear(); - bCanEat = false; - bIsEating = false; - - EatTimer = 5000; - CastTimer = 5000; + m_uiEatTimer = 0; + m_uiCreditTimer = 0; + m_uiCastTimer = 5000; } - void SpellHit(Unit* pCaster, SpellEntry const* pSpell) + void SpellHit(Unit* pCaster, SpellEntry const* pSpell) override { - if (bCanEat || bIsEating) + if (m_uiEatTimer || m_uiCreditTimer) return; if (pCaster->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_PLACE_CARCASS && !m_creature->HasAura(SPELL_JUST_EATEN)) { m_playerGuid = pCaster->GetObjectGuid(); - bCanEat = true; + m_uiEatTimer = 5000; } } - void MovementInform(uint32 type, uint32 id) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - if (type != POINT_MOTION_TYPE) + if (uiMoveType != POINT_MOTION_TYPE) return; - if (id == POINT_ID) + if (uiPointId) { - bIsEating = true; - EatTimer = 7000; + m_uiCreditTimer = 7000; + m_creature->SetLevitate(false); m_creature->HandleEmote(EMOTE_ONESHOT_ATTACKUNARMED); + m_creature->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); } } - void UpdateAI(const uint32 diff) + void JustReachedHome() override { - if (bCanEat || bIsEating) + m_creature->GetMotionMaster()->Clear(); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiEatTimer) { - if (EatTimer < diff) + if (m_uiEatTimer <= uiDiff) { - if (bCanEat && !bIsEating) + if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_FLAYER_CARCASS, 80.0f)) { - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) - { - GameObject* pGo = pPlayer->GetGameObject(SPELL_PLACE_CARCASS); + if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) + m_creature->GetMotionMaster()->MovementExpired(); - // Workaround for broken function GetGameObject - if (!pGo) - { - const SpellEntry* pSpell = GetSpellStore()->LookupEntry(SPELL_PLACE_CARCASS); + m_creature->GetMotionMaster()->MoveIdle(); - uint32 uiGameobjectEntry = pSpell->EffectMiscValue[EFFECT_INDEX_0]; + float fX, fY, fZ; + pGo->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); - pGo = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2*INTERACTION_DISTANCE); - } - - if (pGo) - { - if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) - m_creature->GetMotionMaster()->MovementExpired(); - - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->StopMoving(); + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + m_uiEatTimer = 0; + } + else + m_uiEatTimer -= uiDiff; - float fX, fY, fZ; - pGo->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); + return; + } - m_creature->GetMotionMaster()->MovePoint(POINT_ID, fX, fY, fZ); - } - } - bCanEat = false; - } - else if (bIsEating) - { - DoCastSpellIfCan(m_creature, SPELL_JUST_EATEN); - DoScriptText(SAY_JUST_EATEN, m_creature); + if (m_uiCreditTimer) + { + if (m_uiCreditTimer <= uiDiff) + { + DoCastSpellIfCan(m_creature, SPELL_JUST_EATEN); + DoScriptText(SAY_JUST_EATEN, m_creature); - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) - pPlayer->KilledMonsterCredit(NPC_EVENT_PINGER, m_creature->GetObjectGuid()); + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + pPlayer->KilledMonsterCredit(NPC_EVENT_PINGER, m_creature->GetObjectGuid()); - Reset(); - m_creature->GetMotionMaster()->Clear(); - } + Reset(); + m_creature->SetLevitate(true); + m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); + m_creature->GetMotionMaster()->MoveTargetedHome(); + m_uiCreditTimer = 0; } else - EatTimer -= diff; + m_uiCreditTimer -= uiDiff; return; } @@ -164,11 +160,13 @@ struct MANGOS_DLL_DECL mob_mature_netherwing_drakeAI : public ScriptedAI if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (CastTimer < diff) + if (m_uiCastTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_NETHER_BREATH); - CastTimer = 5000; - }else CastTimer -= diff; + m_uiCastTimer = 5000; + } + else + m_uiCastTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -185,7 +183,6 @@ CreatureAI* GetAI_mob_mature_netherwing_drake(Creature* pCreature) enum { - FACTION_DEFAULT = 62, FACTION_FRIENDLY = 1840, // Not sure if this is correct, it was taken off of Mordenai. SPELL_HIT_FORCE_OF_NELTHARAKU = 38762, @@ -196,36 +193,29 @@ enum NPC_ESCAPE_DUMMY = 21348 }; -struct MANGOS_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI +struct mob_enslaved_netherwing_drakeAI : public ScriptedAI { mob_enslaved_netherwing_drakeAI(Creature* pCreature) : ScriptedAI(pCreature) { - Tapped = false; + m_uiFlyTimer = 0; Reset(); } ObjectGuid m_playerGuid; - uint32 FlyTimer; - bool Tapped; + uint32 m_uiFlyTimer; - void Reset() - { - if (!Tapped) - m_creature->setFaction(FACTION_DEFAULT); + void Reset() override { } - FlyTimer = 2500; - } - - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (pSpell->Id == SPELL_HIT_FORCE_OF_NELTHARAKU && !Tapped) + if (pSpell->Id == SPELL_HIT_FORCE_OF_NELTHARAKU && !m_uiFlyTimer) { if (Player* pPlayer = pCaster->GetCharmerOrOwnerPlayerOrPlayerItself()) { - Tapped = true; + m_uiFlyTimer = 2500; m_playerGuid = pPlayer->GetObjectGuid(); - m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_RESPAWN); if (Creature* pDragonmaw = GetClosestCreatureWithEntry(m_creature, NPC_DRAGONMAW_SUBJUGATOR, 50.0f)) AttackStart(pDragonmaw); @@ -233,25 +223,23 @@ struct MANGOS_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI } } - void MovementInform(uint32 type, uint32 id) + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { - if (type != POINT_MOTION_TYPE) + if (uiMoveType != POINT_MOTION_TYPE) return; - if (id == 1) + if (uiPointId) m_creature->ForcedDespawn(); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { - if (Tapped) + if (m_uiFlyTimer) { - if (FlyTimer <= diff) + if (m_uiFlyTimer <= uiDiff) { - Tapped = false; - if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { if (pPlayer->GetQuestStatus(QUEST_FORCE_OF_NELT) == QUEST_STATUS_INCOMPLETE) @@ -259,23 +247,26 @@ struct MANGOS_DLL_DECL mob_enslaved_netherwing_drakeAI : public ScriptedAI DoCastSpellIfCan(pPlayer, SPELL_FORCE_OF_NELTHARAKU, CAST_TRIGGERED); m_playerGuid.Clear(); - float dx, dy, dz; + float fX, fY, fZ; - if (Creature* EscapeDummy = GetClosestCreatureWithEntry(m_creature, NPC_ESCAPE_DUMMY, 30.0f)) - EscapeDummy->GetPosition(dx, dy, dz); + // Get an escape position + if (Creature* pEscapeDummy = GetClosestCreatureWithEntry(m_creature, NPC_ESCAPE_DUMMY, 50.0f)) + pEscapeDummy->GetPosition(fX, fY, fZ); else { - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20, dx, dy, dz); - dz += 25; + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 20.0f, fX, fY, fZ); + fZ += 25; } - m_creature->GetMotionMaster()->MovePoint(1, dx, dy, dz); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } } + m_uiFlyTimer = 0; } else - FlyTimer -= diff; + m_uiFlyTimer -= uiDiff; } + return; } @@ -306,7 +297,7 @@ enum POINT_DEST = 1 }; -struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI +struct npc_dragonmaw_peonAI : public ScriptedAI { npc_dragonmaw_peonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -315,7 +306,7 @@ struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI uint32 m_uiMoveTimer; uint32 m_uiEatTimer; - void Reset() + void Reset() override { m_playerGuid.Clear(); m_uiPoisonTimer = 0; @@ -336,7 +327,7 @@ struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI return true; } - void MovementInform(uint32 uiType, uint32 uiPointId) + void MovementInform(uint32 uiType, uint32 uiPointId) override { if (uiType != POINT_MOTION_TYPE) return; @@ -346,7 +337,7 @@ struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI m_uiEatTimer = 2000; m_uiPoisonTimer = 3000; - switch(urand(0, 4)) + switch (urand(0, 4)) { case 0: DoScriptText(SAY_PEON_1, m_creature); break; case 1: DoScriptText(SAY_PEON_2, m_creature); break; @@ -357,7 +348,7 @@ struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiMoveTimer) { @@ -375,7 +366,7 @@ struct MANGOS_DLL_DECL npc_dragonmaw_peonAI : public ScriptedAI uint32 uiGameobjectEntry = pSpell->EffectMiscValue[EFFECT_INDEX_0]; // this can fail, but very low chance - pMutton = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2*INTERACTION_DISTANCE); + pMutton = GetClosestGameObjectWithEntry(pPlayer, uiGameobjectEntry, 2 * INTERACTION_DISTANCE); } if (pMutton) @@ -428,7 +419,7 @@ CreatureAI* GetAI_npc_dragonmaw_peon(Creature* pCreature) return new npc_dragonmaw_peonAI(pCreature); } -bool EffectDummyCreature_npc_dragonmaw_peon(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_dragonmaw_peon(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiEffIndex != EFFECT_INDEX_1 || uiSpellId != SPELL_SERVING_MUTTON || pCaster->GetTypeId() != TYPEID_PLAYER) return false; @@ -447,46 +438,6 @@ bool EffectDummyCreature_npc_dragonmaw_peon(Unit* pCaster, uint32 uiSpellId, Spe return false; } -/*###### -## npc_drake_dealer_hurlunk -######*/ - -bool GossipHello_npc_drake_dealer_hurlunk(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isVendor() && pPlayer->GetReputationRank(1015) == REP_EXALTED) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_drake_dealer_hurlunk(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - -/*#### -# npc_karynaku -####*/ - -enum -{ - QUEST_ALLY_OF_NETHER = 10870, - TAXI_PATH_ID = 649 -}; - -bool QuestAccept_npc_karynaku(Player* pPlayer, Creature* pCreature, const Quest* pQuest) -{ - if (pQuest->GetQuestId() == QUEST_ALLY_OF_NETHER) - pPlayer->ActivateTaxiPathTo(TAXI_PATH_ID); - - return true; -} - /*###### # npc_wilda ######*/ @@ -494,13 +445,15 @@ bool QuestAccept_npc_karynaku(Player* pPlayer, Creature* pCreature, const Quest* enum { SAY_WIL_START = -1000381, - SAY_WIL_AGGRO1 = -1000382, - SAY_WIL_AGGRO2 = -1000383, - SAY_WIL_PROGRESS1 = -1000384, - SAY_WIL_PROGRESS2 = -1000385, + SAY_WIL_AGGRO_1 = -1000382, + SAY_WIL_AGGRO_2 = -1000383, + SAY_WIL_FREE_SPIRITS = -1000384, SAY_WIL_FIND_EXIT = -1000386, - SAY_WIL_PROGRESS4 = -1000387, - SAY_WIL_PROGRESS5 = -1000388, + SAY_WIL_PROGRESS_1 = -1000385, + SAY_WIL_PROGRESS_2 = -1000387, + SAY_WIL_PROGRESS_3 = -1000388, + SAY_WIL_PROGRESS_4 = -1001168, + SAY_WIL_PROGRESS_5 = -1001169, SAY_WIL_JUST_AHEAD = -1000389, SAY_WIL_END = -1000390, @@ -508,133 +461,182 @@ enum SPELL_EARTHBING_TOTEM = 15786, SPELL_FROST_SHOCK = 12548, SPELL_HEALING_WAVE = 12491, + SPELL_WATER_BUBBLE = 35929, QUEST_ESCAPE_COILSCAR = 10451, NPC_COILSKAR_ASSASSIN = 21044, - FACTION_EARTHEN = 1726 //guessed + NPC_CAPTURED_WATER_SPIRIT = 21029, }; -//this script needs verification -struct MANGOS_DLL_DECL npc_wildaAI : public npc_escortAI +struct npc_wildaAI : public npc_escortAI { - npc_wildaAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + npc_wildaAI(Creature* pCreature) : npc_escortAI(pCreature) + { + // the creature is floating in a prison; no quest available first; + // the floating prison setup and quest flag restore is handled by DB + m_creature->SetLevitate(true); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + Reset(); + } uint32 m_uiHealingTimer; + uint32 m_uiShockTimer; + uint32 m_uiLightningTimer; - void Reset() + void Reset() override { m_uiHealingTimer = 0; + m_uiShockTimer = 1000; + m_uiLightningTimer = 2000; } - void WaypointReached(uint32 uiPointId) + void Aggro(Unit* pWho) override { - Player* pPlayer = GetPlayerForEscort(); + if (roll_chance_i(30)) + DoCastSpellIfCan(m_creature, SPELL_EARTHBING_TOTEM); + } - if (!pPlayer) - return; + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 10.0f); + } + } - switch(uiPointId) + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) { - case 13: - DoScriptText(SAY_WIL_PROGRESS1, m_creature, pPlayer); - DoSpawnAssassin(); - break; - case 14: - DoSpawnAssassin(); - break; - case 15: - DoScriptText(SAY_WIL_FIND_EXIT, m_creature, pPlayer); - break; - case 19: - DoRandomSay(); - break; - case 20: - DoSpawnAssassin(); - break; + case 8: case 26: - DoRandomSay(); - break; - case 27: - DoSpawnAssassin(); - break; - case 33: - DoRandomSay(); - break; - case 34: + case 30: + case 32: + case 39: + case 43: + case 51: DoSpawnAssassin(); break; - case 37: - DoRandomSay(); - break; - case 38: - DoSpawnAssassin(); + case 13: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_WIL_FREE_SPIRITS, m_creature, pPlayer); + DoFreeSpirits(); break; - case 39: - DoScriptText(SAY_WIL_JUST_AHEAD, m_creature, pPlayer); + case 14: + DoScriptText(SAY_WIL_FIND_EXIT, m_creature); break; - case 43: - DoRandomSay(); + case 15: + DoSpawnAssassin(2); break; - case 44: - DoSpawnAssassin(); + case 40: + if (Player* pPlayer = GetPlayerForEscort()) + DoScriptText(SAY_WIL_JUST_AHEAD, m_creature, pPlayer); break; - case 50: - DoScriptText(SAY_WIL_END, m_creature, pPlayer); - pPlayer->GroupEventHappens(QUEST_ESCAPE_COILSCAR, m_creature); + case 52: + if (Player* pPlayer = GetPlayerForEscort()) + { + DoDespawnSpirits(); + m_creature->SetFacingToObject(pPlayer); + DoScriptText(SAY_WIL_END, m_creature, pPlayer); + pPlayer->GroupEventHappens(QUEST_ESCAPE_COILSCAR, m_creature); + } break; } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_COILSKAR_ASSASSIN) - pSummoned->AI()->AttackStart(m_creature); - } - - //this is very unclear, random say without no real relevance to script/event - void DoRandomSay() - { - switch(urand(0, 2)) { - case 0: DoScriptText(SAY_WIL_PROGRESS2, m_creature); break; - case 1: DoScriptText(SAY_WIL_PROGRESS4, m_creature); break; - case 2: DoScriptText(SAY_WIL_PROGRESS5, m_creature); break; + if (Player* pPlayer = GetPlayerForEscort()) + pSummoned->AI()->AttackStart(pPlayer); } } - void DoSpawnAssassin() + // wrapper to spawn assassin and do text + void DoSpawnAssassin(uint8 uiCount = 1) { - //unknown where they actually appear + // unknown where they actually appear float fX, fY, fZ; - m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 15.0f, fX, fY, fZ); + for (uint8 i = 0; i < uiCount; ++i) + { + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 10.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_COILSKAR_ASSASSIN, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 10000); + } - m_creature->SummonCreature(NPC_COILSKAR_ASSASSIN, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + // random chance to yell + if (roll_chance_i(20)) + return; + + // random text when assassin is summoned + switch (urand(0, 6)) + { + case 0: DoScriptText(SAY_WIL_PROGRESS_1, m_creature); break; + case 1: DoScriptText(SAY_WIL_PROGRESS_2, m_creature); break; + case 2: DoScriptText(SAY_WIL_PROGRESS_3, m_creature); break; + case 3: DoScriptText(SAY_WIL_PROGRESS_4, m_creature); break; + case 4: DoScriptText(SAY_WIL_PROGRESS_5, m_creature); break; + case 5: DoScriptText(SAY_WIL_AGGRO_1, m_creature); break; + case 6: DoScriptText(SAY_WIL_AGGRO_2, m_creature); break; + } } - void Aggro(Unit* pWho) + // free the water spirits + void DoFreeSpirits() { - //don't always use - if (urand(0, 4)) + std::list lSpiritsInRange; + GetCreatureListWithEntryInGrid(lSpiritsInRange, m_creature, NPC_CAPTURED_WATER_SPIRIT, 50.0f); + + if (lSpiritsInRange.empty()) return; - //only aggro text if not player - if (pWho->GetTypeId() != TYPEID_PLAYER) + // all spirits follow + for (std::list::const_iterator itr = lSpiritsInRange.begin(); itr != lSpiritsInRange.end(); ++itr) { - //appears to be random - switch(urand(0, 3)) - { - case 0: DoScriptText(SAY_WIL_AGGRO1, m_creature, pWho); break; - case 1: DoScriptText(SAY_WIL_AGGRO2, m_creature, pWho); break; - } + (*itr)->RemoveAurasDueToSpell(SPELL_WATER_BUBBLE); + (*itr)->GetMotionMaster()->MoveFollow(m_creature, m_creature->GetDistance(*itr) * 0.25f, M_PI_F / 2 + m_creature->GetAngle(*itr)); + (*itr)->SetLevitate(false); } } - void UpdateEscortAI(const uint32 uiDiff) + void DoDespawnSpirits() + { + std::list lSpiritsInRange; + GetCreatureListWithEntryInGrid(lSpiritsInRange, m_creature, NPC_CAPTURED_WATER_SPIRIT, 50.0f); + + if (lSpiritsInRange.empty()) + return; + + // all spirits follow + for (std::list::const_iterator itr = lSpiritsInRange.begin(); itr != lSpiritsInRange.end(); ++itr) + (*itr)->ForcedDespawn(6000); + } + + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //TODO: add more abilities + if (m_uiLightningTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING) == CAST_OK) + m_uiLightningTimer = 4000; + } + else + m_uiLightningTimer -= uiDiff; + + if (m_uiShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_SHOCK) == CAST_OK) + m_uiShockTimer = 10000; + } + else + m_uiShockTimer -= uiDiff; + if (m_creature->GetHealthPercent() <= 30.0f) { if (m_uiHealingTimer < uiDiff) @@ -660,7 +662,8 @@ bool QuestAccept_npc_wilda(Player* pPlayer, Creature* pCreature, const Quest* pQ if (pQuest->GetQuestId() == QUEST_ESCAPE_COILSCAR) { DoScriptText(SAY_WIL_START, pCreature, pPlayer); - pCreature->setFaction(FACTION_EARTHEN); + pCreature->SetFactionTemporary(FACTION_ESCORT_A_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + pCreature->SetLevitate(false); if (npc_wildaAI* pEscortAI = dynamic_cast(pCreature->AI())) pEscortAI->Start(false, pPlayer, pQuest); @@ -713,7 +716,7 @@ struct TorlothCinematic uint32 uiTimer; }; -static TorlothCinematic TorlothAnim[]= +static TorlothCinematic TorlothAnim[] = { {SAY_TORLOTH_DIALOGUE1, TORLOTH, 2000}, {SAY_ILLIDAN_DIALOGUE, LORD_ILLIDAN, 7000}, @@ -732,24 +735,24 @@ struct Location float fOrient; }; -static Location SpawnLocation[]= +static Location SpawnLocation[] = { - {-4615.8556f, 1342.2532f, 139.9f, 1.612f}, // Illidari Soldier - {-4598.9365f, 1377.3182f, 139.9f, 3.917f}, // Illidari Soldier - {-4598.4697f, 1360.8999f, 139.9f, 2.427f}, // Illidari Soldier - {-4589.3599f, 1369.1061f, 139.9f, 3.165f}, // Illidari Soldier - {-4608.3477f, 1386.0076f, 139.9f, 4.108f}, // Illidari Soldier - {-4633.1889f, 1359.8033f, 139.9f, 0.949f}, // Illidari Soldier - {-4623.5791f, 1351.4574f, 139.9f, 0.971f}, // Illidari Soldier - {-4607.2988f, 1351.6099f, 139.9f, 2.416f}, // Illidari Soldier - {-4633.7764f, 1376.0417f, 139.9f, 5.608f}, // Illidari Soldier - {-4600.2461f, 1369.1240f, 139.9f, 3.056f}, // Illidari Mind Breaker - {-4631.7808f, 1367.9459f, 139.9f, 0.020f}, // Illidari Mind Breaker - {-4600.2461f, 1369.1240f, 139.9f, 3.056f}, // Illidari Highlord - {-4631.7808f, 1367.9459f, 139.9f, 0.020f}, // Illidari Highlord - {-4615.5586f, 1353.0031f, 139.9f, 1.540f}, // Illidari Highlord - {-4616.4736f, 1384.2170f, 139.9f, 4.971f}, // Illidari Highlord - {-4627.1240f, 1378.8752f, 139.9f, 2.544f} // Torloth The Magnificent + { -4615.8556f, 1342.2532f, 139.9f, 1.612f}, // Illidari Soldier + { -4598.9365f, 1377.3182f, 139.9f, 3.917f}, // Illidari Soldier + { -4598.4697f, 1360.8999f, 139.9f, 2.427f}, // Illidari Soldier + { -4589.3599f, 1369.1061f, 139.9f, 3.165f}, // Illidari Soldier + { -4608.3477f, 1386.0076f, 139.9f, 4.108f}, // Illidari Soldier + { -4633.1889f, 1359.8033f, 139.9f, 0.949f}, // Illidari Soldier + { -4623.5791f, 1351.4574f, 139.9f, 0.971f}, // Illidari Soldier + { -4607.2988f, 1351.6099f, 139.9f, 2.416f}, // Illidari Soldier + { -4633.7764f, 1376.0417f, 139.9f, 5.608f}, // Illidari Soldier + { -4600.2461f, 1369.1240f, 139.9f, 3.056f}, // Illidari Mind Breaker + { -4631.7808f, 1367.9459f, 139.9f, 0.020f}, // Illidari Mind Breaker + { -4600.2461f, 1369.1240f, 139.9f, 3.056f}, // Illidari Highlord + { -4631.7808f, 1367.9459f, 139.9f, 0.020f}, // Illidari Highlord + { -4615.5586f, 1353.0031f, 139.9f, 1.540f}, // Illidari Highlord + { -4616.4736f, 1384.2170f, 139.9f, 4.971f}, // Illidari Highlord + { -4627.1240f, 1378.8752f, 139.9f, 2.544f} // Torloth The Magnificent }; struct WaveData @@ -762,7 +765,7 @@ struct WaveData int32 iTextId; }; -static WaveData WavesInfo[]= +static WaveData WavesInfo[] = { // Illidari Soldier {9, 0, NPC_ILLIDARI_SOLDIER, 10000, 7000, SAY_ILLIDAN_SUMMON1}, @@ -785,7 +788,7 @@ enum SPELL_SPELL_REFLECTION = 33961 }; -struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI +struct mob_torlothAI : public ScriptedAI { mob_torlothAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} @@ -798,7 +801,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI uint8 m_uiAnimationCount; uint32 m_uiAnimationTimer; - void Reset() + void Reset() override { m_lordIllidanGuid.Clear(); m_playerGuid.Clear(); @@ -814,7 +817,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI SetCombatMovement(false); } - void EnterEvadeMode() + void EnterEvadeMode() override { m_creature->ForcedDespawn(); } @@ -839,7 +842,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI m_uiAnimationTimer = TorlothAnim[m_uiAnimationCount].uiTimer; - switch(m_uiAnimationCount) + switch (m_uiAnimationCount) { case 0: m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); @@ -872,7 +875,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI ++m_uiAnimationCount; } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (Player* pPlayer = pKiller->GetCharmerOrOwnerPlayerOrPlayerItself()) { @@ -886,7 +889,7 @@ struct MANGOS_DLL_DECL mob_torlothAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (m_uiAnimationCount < 7) { @@ -938,7 +941,7 @@ CreatureAI* GetAI_mob_torloth(Creature* pCreature) # npc_lord_illidan_stormrage #####*/ -struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovementAI +struct npc_lord_illidan_stormrageAI : public Scripted_NoMovementAI { npc_lord_illidan_stormrageAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) {Reset();} @@ -953,7 +956,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement bool m_bEventFailed; bool m_bWaveAnnounced; - void Reset() + void Reset() override { m_playerGuid.Clear(); @@ -982,7 +985,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement uint8 uiFelguardCount = 0; uint8 uiDreadlordCount = 0; - for(uint8 i = 0; i < uiCount; ++i) + for (uint8 i = 0; i < uiCount; ++i) { float fLocX, fLocY, fLocZ, fOrient; fLocX = SpawnLocation[uiLocIndex + i].fLocX; @@ -996,7 +999,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement if (m_uiWaveCount) // only in first wave continue; - if (!urand(0,2) && uiFelguardCount < 2) + if (!urand(0, 2) && uiFelguardCount < 2) { pSpawn->SetDisplayId(MODEL_ID_FELGUARD); ++uiFelguardCount; @@ -1019,7 +1022,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement m_uiAnnounceTimer = WavesInfo[m_uiWaveCount].uiYellTimer; } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // increment mob count ++m_uiMobCount; @@ -1046,7 +1049,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement } } - void SummonedCreatureDespawn(Creature* pCreature) + void SummonedCreatureDespawn(Creature* /*pCreature*/) override { // decrement mob count --m_uiMobCount; @@ -1067,7 +1070,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement uint8 uiDeadMemberCount = 0; uint8 uiFailedMemberCount = 0; - for(GroupReference* pRef = pEventGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pEventGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { if (Player* pMember = pRef->getSource()) { @@ -1098,7 +1101,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement if (pEventGroup->GetMembersCount() == uiDeadMemberCount) { - for(GroupReference* pRef = pEventGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) + for (GroupReference* pRef = pEventGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next()) { if (Player* pMember = pRef->getSource()) { @@ -1117,7 +1120,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_playerGuid || !m_bEventStarted) return; @@ -1151,7 +1154,7 @@ struct MANGOS_DLL_DECL npc_lord_illidan_stormrageAI : public Scripted_NoMovement } }; -CreatureAI* GetAI_npc_lord_illidan_stormrage(Creature* (pCreature)) +CreatureAI* GetAI_npc_lord_illidan_stormrage(Creature * (pCreature)) { return new npc_lord_illidan_stormrageAI(pCreature); } @@ -1159,7 +1162,7 @@ CreatureAI* GetAI_npc_lord_illidan_stormrage(Creature* (pCreature)) /*##### # go_crystal_prison : GameObject that begins the event and hands out quest ######*/ -bool GOQuestAccept_GO_crystal_prison(Player* pPlayer, GameObject* pGo, Quest const* pQuest) +bool GOQuestAccept_GO_crystal_prison(Player* pPlayer, GameObject* /*pGo*/, Quest const* pQuest) { if (pQuest->GetQuestId() == QUEST_BATTLE_OF_THE_CRIMSON_WATCH) if (Creature* pLordIllidan = GetClosestCreatureWithEntry(pPlayer, NPC_LORD_ILLIDAN, 50.0)) @@ -1182,40 +1185,84 @@ enum // quest 10458, 10480, 10481 SPELL_ELEMENTAL_SIEVE = 36035, - NPC_TOTEM_OF_SPIRITS = 21071, - NPC_EARTH_SPIRIT = 21050, // to be killed - NPC_FIERY_SPIRIT = 21061, - NPC_WATER_SPIRIT = 21059, - NPC_AIR_SPIRIT = 21060, + SPELL_CALL_TO_THE_SPIRITS = 36206, + SPELL_EARTH_CAPTURED = 36025, // dummies (having visual effects) SPELL_FIERY_CAPTURED = 36115, SPELL_WATER_CAPTURED = 36170, SPELL_AIR_CAPTURED = 36181, + SPELL_EARTH_CAPTURED_CREDIT = 36108, // event 13513 SPELL_FIERY_CAPTURED_CREDIT = 36117, // event 13514 SPELL_WATER_CAPTURED_CREDIT = 36171, // event 13515 SPELL_AIR_CAPTURED_CREDIT = 36182, // event 13516 - EVENT_EARTH = 13513, - EVENT_FIERY = 13514, - EVENT_WATER = 13515, - EVENT_AIR = 13516, + + NPC_TOTEM_OF_SPIRITS = 21071, + NPC_EARTH_SPIRIT = 21050, // to be killed + NPC_FIERY_SPIRIT = 21061, + NPC_WATER_SPIRIT = 21059, + NPC_AIR_SPIRIT = 21060, + + NPC_EARTHEN_SOUL = 21073, // invisible souls summoned by the totem + NPC_FIERY_SOUL = 21097, + NPC_WATERY_SOUL = 21109, + NPC_AIRY_SOUL = 21116, + NPC_CREDIT_MARKER_EARTH = 21092, // quest objective npc's NPC_CREDIT_MARKER_FIERY = 21094, NPC_CREDIT_MARKER_WATER = 21095, NPC_CREDIT_MARKER_AIR = 21096, + + EVENT_EARTH = 13513, // credit events + EVENT_FIERY = 13514, + EVENT_WATER = 13515, + EVENT_AIR = 13516, }; -struct MANGOS_DLL_DECL npc_totem_of_spiritsAI : public ScriptedPetAI +struct npc_totem_of_spiritsAI : public ScriptedPetAI { npc_totem_of_spiritsAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void MoveInLineOfSight(Unit* pWho) {} - void UpdateAI(const uint32 uiDiff) {} - void AttackedBy(Unit* pAttacker) {} + void UpdateAI(const uint32 /*uiDiff*/) override {} + void AttackedBy(Unit* /*pAttacker*/) override {} - void OwnerKilledUnit(Unit* pVictim) + void MoveInLineOfSight(Unit* pWho) override + { + if (pWho->GetTypeId() != TYPEID_UNIT) + return; + + // Use the LoS function to check for the souls in range due to the fact that pets do not support SummonedMovementInform() + uint32 uiEntry = pWho->GetEntry(); + if (uiEntry == NPC_EARTHEN_SOUL || uiEntry == NPC_FIERY_SOUL || uiEntry == NPC_WATERY_SOUL || uiEntry == NPC_AIRY_SOUL) + { + // Only when it's close to the totem + if (!pWho->IsWithinDistInMap(m_creature, 1.5f)) + return; + + switch (uiEntry) + { + case NPC_EARTHEN_SOUL: + pWho->CastSpell(m_creature, SPELL_EARTH_CAPTURED, true); + break; + case NPC_FIERY_SOUL: + pWho->CastSpell(m_creature, SPELL_FIERY_CAPTURED, true); + break; + case NPC_WATERY_SOUL: + pWho->CastSpell(m_creature, SPELL_WATER_CAPTURED, true); + break; + case NPC_AIRY_SOUL: + pWho->CastSpell(m_creature, SPELL_AIR_CAPTURED, true); + break; + } + + // Despawn the spirit soul after it's captured + ((Creature*)pWho)->ForcedDespawn(); + } + } + + void OwnerKilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() != TYPEID_UNIT) return; @@ -1226,6 +1273,14 @@ struct MANGOS_DLL_DECL npc_totem_of_spiritsAI : public ScriptedPetAI if (uiEntry == NPC_EARTH_SPIRIT || uiEntry == NPC_FIERY_SPIRIT || uiEntry == NPC_WATER_SPIRIT || uiEntry == NPC_AIR_SPIRIT) pVictim->CastSpell(pVictim, SPELL_ELEMENTAL_SIEVE, true); } + + void JustSummoned(Creature* pSummoned) override + { + // After summoning the spirit soul, make it move towards the totem + float fX, fY, fZ; + m_creature->GetContactPoint(pSummoned, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } }; CreatureAI* GetAI_npc_totem_of_spirits(Creature* pCreature) @@ -1233,31 +1288,31 @@ CreatureAI* GetAI_npc_totem_of_spirits(Creature* pCreature) return new npc_totem_of_spiritsAI(pCreature); } -bool EffectDummyCreature_npc_totem_of_spirits(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_npc_totem_of_spirits(Unit* /*pCaster*/, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { if (uiEffIndex != EFFECT_INDEX_0) return false; - switch(uiSpellId) + switch (uiSpellId) { case SPELL_EARTH_CAPTURED: { - pCaster->CastSpell(pCaster, SPELL_EARTH_CAPTURED_CREDIT, true); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_EARTH_CAPTURED_CREDIT, true); return true; } case SPELL_FIERY_CAPTURED: { - pCaster->CastSpell(pCaster, SPELL_FIERY_CAPTURED_CREDIT, true); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_FIERY_CAPTURED_CREDIT, true); return true; } case SPELL_WATER_CAPTURED: { - pCaster->CastSpell(pCaster, SPELL_WATER_CAPTURED_CREDIT, true); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_WATER_CAPTURED_CREDIT, true); return true; } case SPELL_AIR_CAPTURED: { - pCaster->CastSpell(pCaster, SPELL_AIR_CAPTURED_CREDIT, true); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_AIR_CAPTURED_CREDIT, true); return true; } } @@ -1285,27 +1340,23 @@ bool EffectAuraDummy_npc_totem_of_spirits(const Aura* pAura, bool bApply) if (!pCreature || !pCreature->IsPet() || !pCaster) return true; - // Need to expect the enraged elementals to be caster of aura - switch(pCaster->GetEntry()) + // Summon the soul of the spirit and cast the visual + uint32 uiSoulEntry = 0; + switch (pCaster->GetEntry()) { - case NPC_EARTH_SPIRIT: - pCreature->CastSpell(pCreature, SPELL_EARTH_CAPTURED, true); - break; - case NPC_FIERY_SPIRIT: - pCreature->CastSpell(pCreature, SPELL_FIERY_CAPTURED, true); - break; - case NPC_WATER_SPIRIT: - pCreature->CastSpell(pCreature, SPELL_WATER_CAPTURED, true); - break; - case NPC_AIR_SPIRIT: - pCreature->CastSpell(pCreature, SPELL_AIR_CAPTURED, true); - break; + case NPC_EARTH_SPIRIT: uiSoulEntry = NPC_EARTHEN_SOUL; break; + case NPC_FIERY_SPIRIT: uiSoulEntry = NPC_FIERY_SOUL; break; + case NPC_WATER_SPIRIT: uiSoulEntry = NPC_WATERY_SOUL; break; + case NPC_AIR_SPIRIT: uiSoulEntry = NPC_AIRY_SOUL; break; } + pCreature->CastSpell(pCreature, SPELL_CALL_TO_THE_SPIRITS, true); + pCreature->SummonCreature(uiSoulEntry, pCaster->GetPositionX(), pCaster->GetPositionY(), pCaster->GetPositionZ(), 0, TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, 10000); + return true; } -bool ProcessEventId_event_spell_soul_captured_credit(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_spell_soul_captured_credit(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool bIsStart) { if (bIsStart && pSource->GetTypeId() == TYPEID_UNIT) { @@ -1314,7 +1365,7 @@ bool ProcessEventId_event_spell_soul_captured_credit(uint32 uiEventId, Object* p if (!pOwner) return true; - switch(uiEventId) + switch (uiEventId) { case EVENT_EARTH: pOwner->KilledMonsterCredit(NPC_CREDIT_MARKER_EARTH); @@ -1358,17 +1409,17 @@ enum GOSSIP_TEXT_ID_ORONOK = 10421, // spells - some are already defined above - //SPELL_CHAIN_LIGHTNING = 16006, + // SPELL_CHAIN_LIGHTNING = 16006, SPELL_EARTHBIND_TOTEM = 15786, - //SPELL_FROST_SHOCK = 12548, - //SPELL_HEALING_WAVE = 12491, + // SPELL_FROST_SHOCK = 12548, + // SPELL_HEALING_WAVE = 12491, // npcs NPC_ORONOK_TORN_HEART = 21685, NPC_GROMTOR_SON_OF_ORONOK = 21687, NPC_BORAK_SON_OF_ORONOK = 21686, NPC_CYRUKH_THE_FIRELORD = 21181, - //NPC_EARTH_SPIRIT = 21050, + // NPC_EARTH_SPIRIT = 21050, NPC_REDEEMED_SPIRIT_OF_EARTH = 21739, NPC_REDEEMED_SPIRIT_OF_FIRE = 21740, NPC_REDEEMED_SPIRIT_OF_AIR = 21738, @@ -1410,16 +1461,16 @@ struct EventLocations const static EventLocations aDamnationLocations[] = { - {-3605.09f, 1885.47f, 47.24f, 1.81f}, // 0 fire spirit summon loc - {-3600.68f, 1886.58f, 47.24f, 1.81f}, // 1 earth spirit summon loc - {-3597.19f, 1887.46f, 47.24f, 1.77f}, // 2 water spirit summon loc - {-3593.18f, 1888.27f, 47.24f, 1.77f}, // 3 air spirit summon loc - {-3595.36f, 1869.78f, 47.24f}, // 4 fight ready move loc - {-3635.90f, 1860.94f, 52.93f}, // 5 elementals move loc - {-3599.71f, 1897.94f, 47.24f} // 6 epilogue move loc + { -3605.09f, 1885.47f, 47.24f, 1.81f}, // 0 fire spirit summon loc + { -3600.68f, 1886.58f, 47.24f, 1.81f}, // 1 earth spirit summon loc + { -3597.19f, 1887.46f, 47.24f, 1.77f}, // 2 water spirit summon loc + { -3593.18f, 1888.27f, 47.24f, 1.77f}, // 3 air spirit summon loc + { -3595.36f, 1869.78f, 47.24f}, // 4 fight ready move loc + { -3635.90f, 1860.94f, 52.93f}, // 5 elementals move loc + { -3599.71f, 1897.94f, 47.24f} // 6 epilogue move loc }; -struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, private DialogueHelper +struct npc_spawned_oronok_tornheartAI : public ScriptedAI, private DialogueHelper { npc_spawned_oronok_tornheartAI(Creature* pCreature) : ScriptedAI(pCreature), DialogueHelper(aOutroDialogue) @@ -1442,7 +1493,7 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva bool m_bHasAttackStart; - void Reset() + void Reset() override { m_uiLightningTimer = 15000; m_uiTotemTimer = 10000; @@ -1452,9 +1503,9 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva m_bHasAttackStart = false; } - void JustDidDialogueStep(int32 iEntry) + void JustDidDialogueStep(int32 iEntry) override { - switch(iEntry) + switch (iEntry) { case NPC_CYRUKH_THE_FIRELORD: // Set them in motion @@ -1463,12 +1514,12 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva if (Creature* pBorak = GetClosestCreatureWithEntry(m_creature, NPC_BORAK_SON_OF_ORONOK, 10.0f)) { m_borakGuid = pBorak->GetObjectGuid(); - pBorak->GetMotionMaster()->MoveFollow(m_creature, 5.0f, -M_PI_F/2); + pBorak->GetMotionMaster()->MoveFollow(m_creature, 5.0f, -M_PI_F / 2); } if (Creature* pGromtor = GetClosestCreatureWithEntry(m_creature, NPC_GROMTOR_SON_OF_ORONOK, 10.0f)) { m_gromtorGuid = pGromtor->GetObjectGuid(); - pGromtor->GetMotionMaster()->MoveFollow(m_creature, 5.0f, M_PI_F/2); + pGromtor->GetMotionMaster()->MoveFollow(m_creature, 5.0f, M_PI_F / 2); } break; case NPC_EARTHMENDER_TORLOK: @@ -1492,7 +1543,7 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva case NPC_ORONOK_TORN_HEART: if (GameObject* pMark = GetClosestGameObjectWithEntry(m_creature, GO_MARK_OF_KAELTHAS, 30.0f)) { - pMark->SetRespawnTime(5*MINUTE); + pMark->SetRespawnTime(5 * MINUTE); pMark->Refresh(); } if (Creature* pBorak = m_creature->GetMap()->GetCreature(m_borakGuid)) @@ -1504,7 +1555,7 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva } } - Creature* GetSpeakerByEntry(uint32 uiEntry) + Creature* GetSpeakerByEntry(uint32 uiEntry) override { switch (uiEntry) { @@ -1518,7 +1569,7 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (!m_bHasAttackStart && pWho->GetEntry() == NPC_EARTH_SPIRIT) { @@ -1533,7 +1584,7 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { @@ -1546,9 +1597,9 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva } } - void EnterEvadeMode() + void EnterEvadeMode() override { - m_creature->RemoveAllAuras(); + m_creature->RemoveAllAurasOnEvade(); m_creature->DeleteThreatList(); m_creature->CombatStop(true); m_creature->LoadCreatureAddon(true); @@ -1567,12 +1618,12 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva } else { - error_log("SD2: Npc %u couldn't be found or something really bad happened. Epilogue event for quest %u will stop.", NPC_CYRUKH_THE_FIRELORD, QUEST_CIPHER_OF_DAMNATION); + script_error_log("Npc %u couldn't be found or something really bad happened. Epilogue event for quest %u will stop.", NPC_CYRUKH_THE_FIRELORD, QUEST_CIPHER_OF_DAMNATION); m_creature->GetMotionMaster()->MoveTargetedHome(); } } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE) return; @@ -1598,7 +1649,7 @@ struct MANGOS_DLL_DECL npc_spawned_oronok_tornheartAI : public ScriptedAI, priva } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); @@ -1653,7 +1704,7 @@ bool GossipHello_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreatu { if (pPlayer->GetQuestStatus(QUEST_CIPHER_OF_DAMNATION) == QUEST_STATUS_INCOMPLETE) { - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_FIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(GOSSIP_TEXT_ID_ORONOK, pCreature->GetObjectGuid()); } else @@ -1662,9 +1713,9 @@ bool GossipHello_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreatu return true; } -bool GossipSelect_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { // Note: this movement expects MMaps. DoScriptText(SAY_ORONOK_ELEMENTS, pCreature); @@ -1677,6 +1728,170 @@ bool GossipSelect_npc_spawned_oronok_tornheart(Player* pPlayer, Creature* pCreat return true; } +/*###### +## npc_domesticated_felboar +######*/ + +enum +{ + EMOTE_SNIFF_AIR = -1000907, + EMOTE_START_DIG = -1000908, + EMOTE_SQUEAL = -1000909, + + SPELL_SHADOWMOON_TUBER = 36462, + SPELL_SPECIAL_UNARMED = 33334, + SPELL_TUBER_WHISTLE = 36652, + + NPC_DOMESTICATED_FELBOAR = 21195, + NPC_SHADOWMOON_TUBER_NODE = 21347, + GO_SHADOWMOON_TUBER_MOUND = 184701, +}; + +struct npc_domesticated_felboarAI : public ScriptedAI +{ + npc_domesticated_felboarAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiTuberTimer; + uint8 m_uiTuberStage; + + void Reset() override + { + m_uiTuberTimer = 0; + m_uiTuberStage = 0; + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + if (DoCastSpellIfCan(m_creature, SPELL_SPECIAL_UNARMED) == CAST_OK) + { + DoScriptText(EMOTE_START_DIG, m_creature); + m_uiTuberTimer = 2000; + } + } + + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 /*uiMiscValue*/) override + { + if (eventType == AI_EVENT_START_EVENT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(EMOTE_SNIFF_AIR, m_creature); + + float fX, fY, fZ; + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MoveIdle(); + pSender->GetContactPoint(m_creature, fX, fY, fZ); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiTuberTimer) + { + if (m_uiTuberTimer <= uiDiff) + { + switch (m_uiTuberStage) + { + case 0: + if (DoCastSpellIfCan(m_creature, SPELL_SPECIAL_UNARMED) == CAST_OK) + m_uiTuberTimer = 2000; + break; + case 1: + if (DoCastSpellIfCan(m_creature, SPELL_SHADOWMOON_TUBER) == CAST_OK) + { + // Despawn current tuber + if (GameObject* pTuber = GetClosestGameObjectWithEntry(m_creature, GO_SHADOWMOON_TUBER_MOUND, 3.0f)) + pTuber->SetLootState(GO_JUST_DEACTIVATED); + + DoScriptText(EMOTE_SQUEAL, m_creature); + m_uiTuberTimer = 2000; + } + break; + case 2: + EnterEvadeMode(); + break; + } + ++m_uiTuberStage; + } + else + m_uiTuberTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_domesticated_felboar(Creature* pCreature) +{ + return new npc_domesticated_felboarAI(pCreature); +} + +bool EffectDummyCreature_npc_shadowmoon_tuber_node(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_TUBER_WHISTLE && uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() == NPC_SHADOWMOON_TUBER_NODE) + { + // Check if tuber mound exists or it's spawned + GameObject* pTuber = GetClosestGameObjectWithEntry(pCreatureTarget, GO_SHADOWMOON_TUBER_MOUND, 1.0f); + if (!pTuber || !pTuber->isSpawned()) + return true; + + // Call nearby felboar + if (Creature* pBoar = GetClosestCreatureWithEntry(pCreatureTarget, NPC_DOMESTICATED_FELBOAR, 40.0f)) + pCreatureTarget->AI()->SendAIEvent(AI_EVENT_START_EVENT, pCaster, pBoar); + } + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## npc_veneratus_spawn_node +######*/ + +enum +{ + SAY_VENERATUS_SPAWN = -1000579, + + NPC_VENERATUS = 20427, + NPC_SPIRIT_HUNTER = 21332, +}; + +struct npc_veneratus_spawn_nodeAI : public Scripted_NoMovementAI +{ + npc_veneratus_spawn_nodeAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + + void MoveInLineOfSight(Unit* pWho) override + { + // Check for the spirit hunter in order to spawn Veneratus; this will replace missing spells 36614 (dummy periodic spell) and 36616 (summon spell) + if (pWho->GetEntry() == NPC_SPIRIT_HUNTER && m_creature->IsWithinDistInMap(pWho, 40.0f) && m_creature->IsWithinLOSInMap(pWho)) + { + DoScriptText(SAY_VENERATUS_SPAWN, pWho); + DoSpawnCreature(NPC_VENERATUS, 0, 0, 0, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 uiDiff) override { } +}; + +CreatureAI* GetAI_npc_veneratus_spawn_node(Creature* pCreature) +{ + return new npc_veneratus_spawn_nodeAI(pCreature); +} + void AddSC_shadowmoon_valley() { Script* pNewScript; @@ -1697,17 +1912,6 @@ void AddSC_shadowmoon_valley() pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_dragonmaw_peon; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_drake_dealer_hurlunk"; - pNewScript->pGossipHello = &GossipHello_npc_drake_dealer_hurlunk; - pNewScript->pGossipSelect = &GossipSelect_npc_drake_dealer_hurlunk; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_karynaku"; - pNewScript->pQuestAcceptNPC = &QuestAccept_npc_karynaku; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_wilda"; pNewScript->GetAI = &GetAI_npc_wilda; @@ -1747,4 +1951,19 @@ void AddSC_shadowmoon_valley() pNewScript->pGossipHello = &GossipHello_npc_spawned_oronok_tornheart; pNewScript->pGossipSelect = &GossipSelect_npc_spawned_oronok_tornheart; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_domesticated_felboar"; + pNewScript->GetAI = &GetAI_npc_domesticated_felboar; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_shadowmoon_tuber_node"; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_shadowmoon_tuber_node; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_veneratus_spawn_node"; + pNewScript->GetAI = &GetAI_npc_veneratus_spawn_node; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/shattrath_city.cpp b/scripts/outland/shattrath_city.cpp index 73bc27eda..2fc668af5 100644 --- a/scripts/outland/shattrath_city.cpp +++ b/scripts/outland/shattrath_city.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Shattrath_City SD%Complete: 100 -SDComment: Quest support: 10004, 10231. Flask vendors +SDComment: Quest support: 10004, 10231. SDCategory: Shattrath City EndScriptData */ @@ -26,7 +26,6 @@ npc_dirty_larry npc_ishanah npc_khadgars_servant npc_salsalabim -npc_shattrathflaskvendors EndContentData */ #include "precompiled.h" @@ -46,7 +45,7 @@ enum GOSSIP_ITEM_BOOK = -3000105, }; -struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI +struct npc_dirty_larryAI : public ScriptedAI { npc_dirty_larryAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -66,7 +65,7 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI uint32 m_uiSayTimer; uint32 m_uiStep; - void Reset() + void Reset() override { m_creature->SetUInt32Value(UNIT_NPC_FLAGS, m_uiNpcFlags); @@ -80,7 +79,7 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI m_uiSayTimer = 1000; m_uiStep = 0; - //expect database to have correct faction (1194) and then only unit flags set/remove needed + // expect database to have correct faction (1194) and then only unit flags set/remove needed m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); } @@ -151,7 +150,7 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI return 0; } - switch(uiStep) + switch (uiStep) { case 1: DoScriptText(SAY_START, m_creature, pPlayer); @@ -175,7 +174,7 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI } } - void AttackedBy(Unit* pAttacker) + void AttackedBy(Unit* pAttacker) override { if (m_creature->getVictim()) return; @@ -186,12 +185,12 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI AttackStart(pAttacker); } - void DamageTaken(Unit* pDoneBy, uint32& uiDamage) + void DamageTaken(Unit* /*pDoneBy*/, uint32& uiDamage) override { if (uiDamage < m_creature->GetHealth()) return; - //damage will kill, this is pretty much the same as 1%HP left + // damage will kill, this is pretty much the same as 1%HP left if (bEvent) { uiDamage = 0; @@ -208,7 +207,7 @@ struct MANGOS_DLL_DECL npc_dirty_larryAI : public ScriptedAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { if (bEvent && !bActiveAttack) { @@ -231,15 +230,15 @@ bool GossipHello_npc_dirty_larry(Player* pPlayer, Creature* pCreature) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); if (pPlayer->GetQuestStatus(QUEST_WHAT_BOOK) == QUEST_STATUS_INCOMPLETE) - pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BOOK, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BOOK, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); return true; } -bool GossipSelect_npc_dirty_larry(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_dirty_larry(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { if (npc_dirty_larryAI* pLarryAI = dynamic_cast(pCreature->AI())) pLarryAI->StartEvent(pPlayer); @@ -309,14 +308,14 @@ enum QUEST_CITY_LIGHT = 10211 }; -struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI +struct npc_khadgars_servantAI : public npc_escortAI { npc_khadgars_servantAI(Creature* pCreature) : npc_escortAI(pCreature) { if (pCreature->GetOwner() && pCreature->GetOwner()->GetTypeId() == TYPEID_PLAYER) Start(false, (Player*)pCreature->GetOwner()); else - error_log("SD2: npc_khadgars_servant can not obtain owner or owner is not a player."); + script_error_log("npc_khadgars_servant can not obtain owner or owner is not a player."); Reset(); } @@ -326,7 +325,7 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI uint32 m_uiTalkCount; uint32 m_uiRandomTalkCooldown; - void Reset() + void Reset() override { m_uiTalkTimer = 2500; m_uiTalkCount = 0; @@ -334,11 +333,11 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI m_uiRandomTalkCooldown = 0; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_uiRandomTalkCooldown && pWho->GetTypeId() == TYPEID_UNIT && m_creature->IsWithinDistInMap(pWho, 10.0f)) { - switch(pWho->GetEntry()) + switch (pWho->GetEntry()) { case NPC_HAGGARD: if (Player* pPlayer = GetPlayerForEscort()) @@ -359,17 +358,17 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { if (uiPointId == 2) DoScriptText(SAY_KHAD_SERV_0, m_creature); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { m_uiPointId = uiPointId; - switch(uiPointId) + switch (uiPointId) { case 0: if (Creature* pKhadgar = GetClosestCreatureWithEntry(m_creature, NPC_KHADGAR, 10.0f)) @@ -394,7 +393,7 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_uiRandomTalkCooldown) { @@ -416,11 +415,11 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI if (!pPlayer) return; - switch(m_uiPointId) + switch (m_uiPointId) { - case 5: //to lower city + case 5: // to lower city { - switch(m_uiTalkCount) + switch (m_uiTalkCount) { case 1: DoScriptText(SAY_KHAD_SERV_1, m_creature, pPlayer); @@ -438,9 +437,9 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } break; } - case 24: //in lower city + case 24: // in lower city { - switch(m_uiTalkCount) + switch (m_uiTalkCount) { case 5: if (Creature* pShanir = GetClosestCreatureWithEntry(m_creature, NPC_SHANIR, 15.0f)) @@ -458,9 +457,9 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } break; } - case 50: //outside + case 50: // outside { - switch(m_uiTalkCount) + switch (m_uiTalkCount) { case 8: DoScriptText(SAY_KHAD_SERV_8, m_creature, pPlayer); @@ -478,9 +477,9 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } break; } - case 63: //scryer + case 63: // scryer { - switch(m_uiTalkCount) + switch (m_uiTalkCount) { case 12: DoScriptText(SAY_KHAD_SERV_12, m_creature, pPlayer); @@ -492,9 +491,9 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } break; } - case 74: //aldor + case 74: // aldor { - switch(m_uiTalkCount) + switch (m_uiTalkCount) { case 14: DoScriptText(SAY_KHAD_SERV_14, m_creature, pPlayer); @@ -512,9 +511,9 @@ struct MANGOS_DLL_DECL npc_khadgars_servantAI : public npc_escortAI } break; } - case 75: //a'dal + case 75: // a'dal { - switch(m_uiTalkCount) + switch (m_uiTalkCount) { case 18: DoScriptText(SAY_KHAD_SERV_18, m_creature, pPlayer); @@ -550,49 +549,55 @@ CreatureAI* GetAI_npc_khadgars_servant(Creature* pCreature) # npc_salsalabim ######*/ -#define FACTION_HOSTILE_SA 90 -#define FACTION_FRIENDLY_SA 35 -#define QUEST_10004 10004 +enum +{ + FACTION_HOSTILE_SA = 90, + QUEST_10004 = 10004, -#define SPELL_MAGNETIC_PULL 31705 + SPELL_MAGNETIC_PULL = 31705, +}; -struct MANGOS_DLL_DECL npc_salsalabimAI : public ScriptedAI +struct npc_salsalabimAI : public ScriptedAI { npc_salsalabimAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - uint32 MagneticPull_Timer; + uint32 m_uiMagneticPullTimer; - void Reset() + void Reset() override { - MagneticPull_Timer = 15000; - m_creature->setFaction(FACTION_FRIENDLY_SA); + m_uiMagneticPullTimer = 15000; } - void DamageTaken(Unit *done_by, uint32 &damage) + void DamageTaken(Unit* pDoneBy, uint32& uiDamage) override { - if (done_by->GetTypeId() == TYPEID_PLAYER) - if ((m_creature->GetHealth()-damage)*100 / m_creature->GetMaxHealth() < 20) + if (pDoneBy->GetTypeId() == TYPEID_PLAYER) { - ((Player*)done_by)->GroupEventHappens(QUEST_10004,m_creature); - damage = 0; - EnterEvadeMode(); + if (m_creature->GetHealthPercent() < 20.0f) + { + ((Player*)pDoneBy)->GroupEventHappens(QUEST_10004, m_creature); + uiDamage = 0; + EnterEvadeMode(); + } } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (MagneticPull_Timer < diff) + if (m_uiMagneticPullTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_MAGNETIC_PULL); - MagneticPull_Timer = 15000; - }else MagneticPull_Timer -= diff; + DoCastSpellIfCan(m_creature->getVictim(), SPELL_MAGNETIC_PULL); + m_uiMagneticPullTimer = 15000; + } + else + m_uiMagneticPullTimer -= uiDiff; DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI_npc_salsalabim(Creature* pCreature) { return new npc_salsalabimAI(pCreature); @@ -602,70 +607,20 @@ bool GossipHello_npc_salsalabim(Player* pPlayer, Creature* pCreature) { if (pPlayer->GetQuestStatus(QUEST_10004) == QUEST_STATUS_INCOMPLETE) { - pCreature->setFaction(FACTION_HOSTILE_SA); + pCreature->SetFactionTemporary(FACTION_HOSTILE_SA, TEMPFACTION_RESTORE_REACH_HOME); pCreature->AI()->AttackStart(pPlayer); } else { if (pCreature->isQuestGiver()) pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - } - return true; -} -/* -################################################## -Shattrath City Flask Vendors provides flasks to people exalted with 3 factions: -Haldor the Compulsive -Arcanist Xorith -Both sell special flasks for use in Outlands 25man raids only, -purchasable for one Mark of Illidari each -Purchase requires exalted reputation with Scryers/Aldor, Cenarion Expedition and The Sha'tar -################################################## -*/ - -bool GossipHello_npc_shattrathflaskvendors(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->GetEntry() == 23484) - { - // Aldor vendor - if (pCreature->isVendor() && (pPlayer->GetReputationRank(932) == REP_EXALTED) && (pPlayer->GetReputationRank(935) == REP_EXALTED) && (pPlayer->GetReputationRank(942) == REP_EXALTED)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(11085, pCreature->GetObjectGuid()); - } - else - { - pPlayer->SEND_GOSSIP_MENU(11083, pCreature->GetObjectGuid()); - } - } - - if (pCreature->GetEntry() == 23483) - { - // Scryers vendor - if (pCreature->isVendor() && (pPlayer->GetReputationRank(934) == REP_EXALTED) && (pPlayer->GetReputationRank(935) == REP_EXALTED) && (pPlayer->GetReputationRank(942) == REP_EXALTED)) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(11085, pCreature->GetObjectGuid()); - } - else - { - pPlayer->SEND_GOSSIP_MENU(11084, pCreature->GetObjectGuid()); - } + pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); } return true; } -bool GossipSelect_npc_shattrathflaskvendors(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - void AddSC_shattrath_city() { Script* pNewScript; @@ -687,10 +642,4 @@ void AddSC_shattrath_city() pNewScript->GetAI = &GetAI_npc_salsalabim; pNewScript->pGossipHello = &GossipHello_npc_salsalabim; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_shattrathflaskvendors"; - pNewScript->pGossipHello = &GossipHello_npc_shattrathflaskvendors; - pNewScript->pGossipSelect = &GossipSelect_npc_shattrathflaskvendors; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp b/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp index d268f321d..99bbbb9cb 100644 --- a/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp +++ b/scripts/outland/tempest_keep/arcatraz/arcatraz.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -48,11 +48,11 @@ enum SAY_ICEBLOCK = -1552019, SAY_LOWHP = -1552020, SAY_DEATH = -1552021, - SAY_COMPLETE = -1552022, SPELL_CONJURE_WATER = 36879, SPELL_ARCANE_INTELLECT = 36880, SPELL_ICE_ARMOR = 36881, + SPELL_DRINK = 30024, SPELL_ARCANE_MISSILES = 33833, SPELL_CONE_OF_COLD = 12611, @@ -60,64 +60,79 @@ enum SPELL_FIREBALL = 14034, SPELL_FROSTBOLT = 15497, SPELL_PYROBLAST = 33975, + SPELL_ICE_BLOCK = 36911, + + POINT_ID_CENTER = 1, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {NPC_MILLHOUSE, 0, 2000}, + {SAY_INTRO_1, NPC_MILLHOUSE, 10000}, + {TYPE_WARDEN_2, 0, 10000}, + {SAY_INTRO_2, NPC_MILLHOUSE, 18000}, + {SAY_WATER, NPC_MILLHOUSE, 7000}, + {SAY_BUFFS, NPC_MILLHOUSE, 6000}, + {SPELL_ICE_ARMOR, 0, 1000}, + {SAY_DRINK, NPC_MILLHOUSE, 7000}, + {SAY_READY, NPC_MILLHOUSE, 6000}, + {POINT_ID_CENTER, 0, 0}, + {0, 0, 0}, }; -struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI +static const float fRoomCenterCoords[3] = {445.8804f, -158.7055f, 43.06898f}; + +struct npc_millhouse_manastormAI : public ScriptedAI, private DialogueHelper { - npc_millhouse_manastormAI(Creature* pCreature) : ScriptedAI(pCreature) + npc_millhouse_manastormAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + InitializeDialogueHelper(m_pInstance); Reset(); + m_attackDistance = 25.0f; } ScriptedInstance* m_pInstance; - uint32 m_uiEventProgressTimer; - uint32 m_uiPhase; - bool m_bInitFinished; bool m_bHasLowHp; - uint32 m_uiPyroblastTimer; uint32 m_uiFireballTimer; + uint32 m_uiFrostBoltTimer; + uint32 m_uiFireBlastTimer; + uint32 m_uiConeColtTimer; + uint32 m_uiArcaneMissileTimer; - void Reset() + void Reset() override { - m_uiEventProgressTimer = 2000; - m_bHasLowHp = false; - m_bInitFinished = false; - m_uiPhase = 1; - - m_uiPyroblastTimer = 1000; - m_uiFireballTimer = 2500; - - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_WARDEN_2) == DONE) - m_bInitFinished = true; - - if (m_pInstance->GetData(TYPE_HARBINGERSKYRISS) == DONE) - DoScriptText(SAY_COMPLETE, m_creature); - } + m_bHasLowHp = false; + m_uiPyroblastTimer = urand(6000, 9000); + m_uiFireballTimer = urand(2500, 4000); + m_uiFrostBoltTimer = urand(3000, 5000); + m_uiFireBlastTimer = urand(6000, 14000); + m_uiConeColtTimer = urand(7000, 12000); + m_uiArcaneMissileTimer = urand(5000, 8000); + + StartNextDialogueText(NPC_MILLHOUSE); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { if (m_creature->Attack(pWho, true)) { m_creature->AddThreat(pWho); m_creature->SetInCombatWith(pWho); pWho->SetInCombatWith(m_creature); - - m_creature->GetMotionMaster()->MoveChase(pWho, 25.0f); + HandleMovementOnAttackStart(pWho); } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pVictim) + void JustDied(Unit* /*pVictim*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -126,55 +141,52 @@ struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI ->FailQuest();*/ } - void UpdateAI(const uint32 uiDiff) + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + // Boss should evade in the center of the room + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(1, fRoomCenterCoords[0], fRoomCenterCoords[1], fRoomCenterCoords[2]); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void JustDidDialogueStep(int32 iEntry) override { - if (!m_bInitFinished) + switch (iEntry) { - if (m_uiEventProgressTimer < uiDiff) - { - if (m_uiPhase < 8) - { - switch(m_uiPhase) - { - case 1: - DoScriptText(SAY_INTRO_1, m_creature); - m_uiEventProgressTimer = 18000; - break; - case 2: - DoScriptText(SAY_INTRO_2, m_creature); - m_uiEventProgressTimer = 18000; - break; - case 3: - DoScriptText(SAY_WATER, m_creature); - DoCastSpellIfCan(m_creature, SPELL_CONJURE_WATER); - m_uiEventProgressTimer = 7000; - break; - case 4: - DoScriptText(SAY_BUFFS, m_creature); - DoCastSpellIfCan(m_creature, SPELL_ICE_ARMOR); - m_uiEventProgressTimer = 7000; - break; - case 5: - DoScriptText(SAY_DRINK, m_creature); - DoCastSpellIfCan(m_creature, SPELL_ARCANE_INTELLECT); - m_uiEventProgressTimer = 7000; - break; - case 6: - DoScriptText(SAY_READY, m_creature); - m_uiEventProgressTimer = 6000; - break; - case 7: - if (m_pInstance) - m_pInstance->SetData(TYPE_WARDEN_2, DONE); - m_bInitFinished = true; - break; - } - ++m_uiPhase; - } - } - else - m_uiEventProgressTimer -= uiDiff; + case TYPE_WARDEN_2: + if (m_pInstance) + m_pInstance->SetData(TYPE_WARDEN_2, DONE); + break; + case SAY_WATER: + DoCastSpellIfCan(m_creature, SPELL_CONJURE_WATER); + break; + case SAY_BUFFS: + DoCastSpellIfCan(m_creature, SPELL_ARCANE_INTELLECT); + break; + case SPELL_ICE_ARMOR: + DoCastSpellIfCan(m_creature, SPELL_ICE_ARMOR); + break; + case SAY_DRINK: + DoCastSpellIfCan(m_creature, SPELL_DRINK); + break; + case POINT_ID_CENTER: + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, fRoomCenterCoords[0], fRoomCenterCoords[1], fRoomCenterCoords[2]); + break; } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -189,12 +201,12 @@ struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PYROBLAST) == CAST_OK) { - m_uiPyroblastTimer = 40000; - DoScriptText(SAY_PYRO, m_creature); + m_uiPyroblastTimer = 40000; + DoScriptText(SAY_PYRO, m_creature); } } else - m_uiPyroblastTimer -=uiDiff; + m_uiPyroblastTimer -= uiDiff; if (m_uiFireballTimer < uiDiff) { @@ -202,7 +214,39 @@ struct MANGOS_DLL_DECL npc_millhouse_manastormAI : public ScriptedAI m_uiFireballTimer = 4000; } else - m_uiFireballTimer -=uiDiff; + m_uiFireballTimer -= uiDiff; + + if (m_uiFrostBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROSTBOLT) == CAST_OK) + m_uiFrostBoltTimer = urand(4000, 6000); + } + else + m_uiFrostBoltTimer -= uiDiff; + + if (m_uiConeColtTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_CONE_OF_COLD) == CAST_OK) + m_uiConeColtTimer = urand(7000, 12000); + } + else + m_uiConeColtTimer -= uiDiff; + + if (m_uiFireBlastTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FIRE_BLAST) == CAST_OK) + m_uiFireBlastTimer = urand(5000, 16000); + } + else + m_uiFireBlastTimer -= uiDiff; + + if (m_uiArcaneMissileTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_MISSILES) == CAST_OK) + m_uiArcaneMissileTimer = urand(5000, 8000); + } + else + m_uiArcaneMissileTimer -= uiDiff; DoMeleeAttackIfReady(); } @@ -219,47 +263,11 @@ CreatureAI* GetAI_npc_millhouse_manastorm(Creature* pCreature) enum { - YELL_INTRO1 = -1552023, - YELL_INTRO2 = -1552024, - YELL_RELEASE1 = -1552025, - YELL_RELEASE2A = -1552026, - YELL_RELEASE2B = -1552027, - YELL_RELEASE3 = -1552028, - YELL_RELEASE4 = -1552029, - YELL_WELCOME = -1552030, - - // phase 2(acid mobs) - ENTRY_TRICKSTER = 20905, - ENTRY_PH_HUNTER = 20906, - // phase 3 - ENTRY_MILLHOUSE = 20977, - // phase 4(acid mobs) - ENTRY_AKKIRIS = 20908, - ENTRY_SULFURON = 20909, - // phase 5(acid mobs) - ENTRY_TW_DRAK = 20910, - ENTRY_BL_DRAK = 20911, - // phase 6 - ENTRY_SKYRISS = 20912, - - SPELL_TARGET_ALPHA = 36856, - SPELL_TARGET_BETA = 36854, - SPELL_TARGET_DELTA = 36857, - SPELL_TARGET_GAMMA = 36858, - SPELL_TARGET_OMEGA = 36852, SPELL_BUBBLE_VISUAL = 36849, + SPELL_SIMPLE_TELEPORT = 12980, }; -static const float aSummonPosition[5][4] = -{ - {478.326f, -148.505f, 42.56f, 3.19f}, // Trickster or Phase Hunter - {413.292f, -148.378f, 42.56f, 6.27f}, // Millhouse - {420.179f, -174.396f, 42.58f, 0.02f}, // Akkiris or Sulfuron - {471.795f, -174.58f, 42.58f, 3.06f}, // Twilight or Blackwing Drakonaar - {445.763f, -191.639f, 44.64f, 1.60f} // Skyriss -}; - -struct MANGOS_DLL_DECL npc_warden_mellicharAI : public ScriptedAI +struct npc_warden_mellicharAI : public ScriptedAI { npc_warden_mellicharAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -269,207 +277,68 @@ struct MANGOS_DLL_DECL npc_warden_mellicharAI : public ScriptedAI ScriptedInstance* m_pInstance; - bool m_bIsEventRunning; - bool m_bCanSpawnNextWave; + uint32 m_uiIntroTimer; + ObjectGuid m_targetPlayerGuid; - uint32 m_uiEventProgressTimer; - uint32 m_uiPhase; - - void Reset() + void Reset() override { - m_bIsEventRunning = false; - m_bCanSpawnNextWave = false; - - m_uiEventProgressTimer = 22000; - m_uiPhase = 1; - - m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NON_ATTACKABLE); - DoCastSpellIfCan(m_creature,SPELL_TARGET_OMEGA); - - if (m_pInstance) - m_pInstance->SetData(TYPE_HARBINGERSKYRISS,NOT_STARTED); + m_uiIntroTimer = 5000; + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void AttackStart(Unit* pWho) {} + void AttackStart(Unit* /*pWho*/) override {} - void MoveInLineOfSight(Unit* pWho) + void Aggro(Unit* pWho) override { - if (m_bIsEventRunning) - return; - - if (pWho->GetTypeId() != TYPEID_PLAYER) - return; - - if (!m_creature->getVictim() && pWho->isTargetableForAttack() && (m_creature->IsHostileTo(pWho)) && pWho->isInAccessablePlaceFor(m_creature)) - { - if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(pWho)/10; - if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) - Aggro(pWho); - } - } + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetFacingToObject(pWho); + m_targetPlayerGuid = pWho->GetObjectGuid(); - void Aggro(Unit* pWho) - { - DoScriptText(YELL_INTRO1, m_creature); DoCastSpellIfCan(m_creature, SPELL_BUBBLE_VISUAL); + // In theory the Seal Sphere should protect the npc from being attacked, but because LoS isn't enabled for Gameobjects we have to use this workaround + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + if (m_pInstance) - { m_pInstance->SetData(TYPE_HARBINGERSKYRISS, IN_PROGRESS); - - if (GameObject* pSphere = m_pInstance->GetSingleGameObjectFromStorage(GO_SEAL_SPHERE)) - pSphere->SetGoState(GO_STATE_READY); - - m_bIsEventRunning = true; - } } - bool CanProgress() + void JustSummoned(Creature* pSummoned) override { - if (m_pInstance) + pSummoned->CastSpell(pSummoned, SPELL_SIMPLE_TELEPORT, false); + + if (pSummoned->GetEntry() != NPC_MILLHOUSE && pSummoned->GetEntry() != NPC_SKYRISS) { - if (m_uiPhase == 7 && m_pInstance->GetData(TYPE_WARDEN_4) == DONE) - return true; - if (m_uiPhase == 6 && m_pInstance->GetData(TYPE_WARDEN_3) == DONE) - return true; - if (m_uiPhase == 5 && m_pInstance->GetData(TYPE_WARDEN_2) == DONE) - return true; - if (m_uiPhase == 4) - return true; - if (m_uiPhase == 3 && m_pInstance->GetData(TYPE_WARDEN_1) == DONE) - return true; - if (m_uiPhase == 2 && m_pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS) - return true; - if (m_uiPhase == 1 && m_pInstance->GetData(TYPE_HARBINGERSKYRISS) == IN_PROGRESS) - return true; - - return false; + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_targetPlayerGuid)) + pSummoned->AI()->AttackStart(pTarget); } - return false; } - void DoPrepareForPhase() + void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) { - m_creature->InterruptNonMeleeSpells(true); - m_creature->RemoveSpellsCausingAura(SPELL_AURA_DUMMY); - - switch(m_uiPhase) + if (Creature* pSkyriss = m_pInstance->GetSingleCreatureFromStorage(NPC_SKYRISS)) { - case 2: - DoCastSpellIfCan(m_creature, SPELL_TARGET_ALPHA); - m_pInstance->SetData(TYPE_WARDEN_1, IN_PROGRESS); - break; - case 3: - DoCastSpellIfCan(m_creature, SPELL_TARGET_BETA); - m_pInstance->SetData(TYPE_WARDEN_2, IN_PROGRESS); - break; - case 5: - DoCastSpellIfCan(m_creature, SPELL_TARGET_DELTA); - m_pInstance->SetData(TYPE_WARDEN_3, IN_PROGRESS); - break; - case 6: - DoCastSpellIfCan(m_creature, SPELL_TARGET_GAMMA); - m_pInstance->SetData(TYPE_WARDEN_4, IN_PROGRESS); - break; - case 7: - m_pInstance->SetData(TYPE_WARDEN_5, IN_PROGRESS); - break; + if (Unit* pTarget = m_creature->GetMap()->GetUnit(m_targetPlayerGuid)) + pSkyriss->AI()->AttackStart(pTarget); } - m_bCanSpawnNextWave = true; } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_bIsEventRunning) - return; - - if (m_uiEventProgressTimer < uiDiff) + // Set the visual intro on OOC timer + if (m_uiIntroTimer) { - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_HARBINGERSKYRISS) == FAIL) - Reset(); - } - - if (m_bCanSpawnNextWave) + if (m_uiIntroTimer <= uiDiff) { - //continue beam omega pod, unless we are about to summon skyriss - if (m_uiPhase != 7) - DoCastSpellIfCan(m_creature, SPELL_TARGET_OMEGA); - - switch (m_uiPhase) - { - case 2: - m_creature->SummonCreature(urand(0, 1) ? ENTRY_TRICKSTER : ENTRY_PH_HUNTER, aSummonPosition[0][0], aSummonPosition[0][1], aSummonPosition[0][2], aSummonPosition[0][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - break; - case 3: - m_creature->SummonCreature(ENTRY_MILLHOUSE, aSummonPosition[1][0], aSummonPosition[1][1], aSummonPosition[1][2], aSummonPosition[1][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - break; - case 4: - DoScriptText(YELL_RELEASE2B, m_creature); - break; - case 5: - m_creature->SummonCreature(urand(0, 1) ? ENTRY_AKKIRIS : ENTRY_SULFURON, aSummonPosition[2][0], aSummonPosition[2][1], aSummonPosition[2][2], aSummonPosition[2][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - break; - case 6: - m_creature->SummonCreature(urand(0, 1) ? ENTRY_TW_DRAK : ENTRY_BL_DRAK, aSummonPosition[3][0], aSummonPosition[3][1], aSummonPosition[3][2], aSummonPosition[3][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - break; - case 7: - m_creature->SummonCreature(ENTRY_SKYRISS, aSummonPosition[4][0], aSummonPosition[4][1], aSummonPosition[4][2], aSummonPosition[4][3], TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - DoScriptText(YELL_WELCOME, m_creature); - break; - } - m_bCanSpawnNextWave = false; - ++m_uiPhase; - } - if (CanProgress()) - { - switch(m_uiPhase) - { - case 1: - DoScriptText(YELL_INTRO2, m_creature); - m_uiEventProgressTimer = 10000; - ++m_uiPhase; - break; - case 2: - DoScriptText(YELL_RELEASE1, m_creature); - DoPrepareForPhase(); - m_uiEventProgressTimer = 7000; - break; - case 3: - DoScriptText(YELL_RELEASE2A, m_creature); - DoPrepareForPhase(); - m_uiEventProgressTimer = 10000; - break; - case 4: - DoPrepareForPhase(); - m_uiEventProgressTimer = 15000; - break; - case 5: - DoScriptText(YELL_RELEASE3, m_creature); - DoPrepareForPhase(); - m_uiEventProgressTimer = 15000; - break; - case 6: - DoScriptText(YELL_RELEASE4, m_creature); - DoPrepareForPhase(); - m_uiEventProgressTimer = 15000; - break; - case 7: - DoPrepareForPhase(); - m_uiEventProgressTimer = 15000; - break; - } + DoCastSpellIfCan(m_creature, SPELL_TARGET_OMEGA); + m_uiIntroTimer = 0; } + else + m_uiIntroTimer -= uiDiff; } - else - m_uiEventProgressTimer -= uiDiff; } }; @@ -478,33 +347,6 @@ CreatureAI* GetAI_npc_warden_mellichar(Creature* pCreature) return new npc_warden_mellicharAI(pCreature); } -/*##### -# mob_zerekethvoidzone (this script probably not needed in future -> `creature_template_addon`.`auras`='36120 0') -#####*/ - -enum -{ - SPELL_VOID_ZONE_DAMAGE = 36120, -}; - -struct MANGOS_DLL_DECL mob_zerekethvoidzoneAI : public ScriptedAI -{ - mob_zerekethvoidzoneAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - - void Reset() - { - m_creature->SetUInt32Value(UNIT_NPC_FLAGS, 0); - m_creature->setFaction(16); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - DoCastSpellIfCan(m_creature, SPELL_VOID_ZONE_DAMAGE); - } -}; -CreatureAI* GetAI_mob_zerekethvoidzoneAI(Creature* pCreature) -{ - return new mob_zerekethvoidzoneAI(pCreature); -} - void AddSC_arcatraz() { Script* pNewScript; @@ -518,9 +360,4 @@ void AddSC_arcatraz() pNewScript->Name = "npc_warden_mellichar"; pNewScript->GetAI = &GetAI_npc_warden_mellichar; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_zerekethvoidzone"; - pNewScript->GetAI = &GetAI_mob_zerekethvoidzoneAI; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/arcatraz/arcatraz.h b/scripts/outland/tempest_keep/arcatraz/arcatraz.h index c781d1f88..1c80f6825 100644 --- a/scripts/outland/tempest_keep/arcatraz/arcatraz.h +++ b/scripts/outland/tempest_keep/arcatraz/arcatraz.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,11 +7,13 @@ enum { - MAX_ENCOUNTER = 9, + MAX_ENCOUNTER = 10, + MAX_WARDENS = 7, + TYPE_ENTRANCE = 0, TYPE_ZEREKETH = 1, - TYPE_DALLIAH = 2, // Handled in ACID (20885 - Dalliah the Doomsayer) - TYPE_SOCCOTHRATES = 3, // Handled in ACID (20886 - Wrath-Scryer Soccothrates) + TYPE_DALLIAH = 2, + TYPE_SOCCOTHRATES = 3, TYPE_HARBINGERSKYRISS = 4, // Handled with ACID (FAIL of 20905, 20906, 20908, 20909, 20910, 20911) TYPE_WARDEN_1 = 5, // Handled with ACID (20905 - Blazing Trickster, 20906 - Phase-Hunter) TYPE_WARDEN_2 = 6, @@ -19,7 +21,30 @@ enum TYPE_WARDEN_4 = 8, // Handled with ACID (20910 - Twilight Drakonaar, 20911 - Blackwing Drakonaar) TYPE_WARDEN_5 = 9, + NPC_DALLIAH = 20885, + NPC_SOCCOTHRATES = 20886, NPC_MELLICHAR = 20904, // Skyriss will kill this unit + NPC_PRISON_APHPA_POD = 21436, + NPC_PRISON_BETA_POD = 21437, + NPC_PRISON_DELTA_POD = 21438, + NPC_PRISON_GAMMA_POD = 21439, + NPC_PRISON_BOSS_POD = 21440, + + // intro event related + NPC_PROTEAN_NIGHTMARE = 20864, + NPC_PROTEAN_HORROR = 20865, + NPC_ARCATRAZ_WARDEN = 20859, + NPC_ARCATRAZ_DEFENDER = 20857, + + // Harbinger Skyriss event related (trash mobs are scripted in ACID) + NPC_BLAZING_TRICKSTER = 20905, // phase 1 + NPC_PHASE_HUNTER = 20906, + NPC_MILLHOUSE = 20977, // phase 2 + NPC_AKKIRIS = 20908, // phase 3 + NPC_SULFURON = 20909, + NPC_TW_DRAKONAAR = 20910, // phase 4 + NPC_BL_DRAKONAAR = 20911, + NPC_SKYRISS = 20912, // phase 5 GO_CORE_SECURITY_FIELD_ALPHA = 184318, // Door opened when Wrath-Scryer Soccothrates dies GO_CORE_SECURITY_FIELD_BETA = 184319, // Door opened when Dalliah the Doomsayer dies @@ -29,23 +54,61 @@ enum GO_POD_DELTA = 183964, // Pod third boss wave GO_POD_GAMMA = 183962, // Pod fourth boss wave GO_POD_OMEGA = 183965, // Pod fifth boss wave + + SPELL_TARGET_OMEGA = 36852, // Visual spell used by Mellichar +}; + +struct SpawnLocation +{ + float m_fX, m_fY, m_fZ, m_fO; +}; + +static const SpawnLocation aSummonPosition[5] = +{ + {478.326f, -148.505f, 42.56f, 3.19f}, // Trickster or Phase Hunter + {413.292f, -148.378f, 42.56f, 6.27f}, // Millhouse + {420.179f, -174.396f, 42.58f, 0.02f}, // Akkiris or Sulfuron + {471.795f, -174.58f, 42.58f, 3.06f}, // Twilight or Blackwing Drakonaar + {445.763f, -191.639f, 44.64f, 1.60f} // Skyriss }; -class MANGOS_DLL_DECL instance_arcatraz : public ScriptedInstance +static const float aDalliahStartPos[4] = {118.6038f, 96.84682f, 22.44115f, 1.012f}; +static const float aSoccotharesStartPos[4] = {122.1035f, 192.7203f, 22.44115f, 5.235f}; + +static const float aEntranceMoveLoc[3] = {82.020f, 0.306f, -11.026f}; +static const float aEntranceSpawnLoc[4] = {173.471f, -0.138f, -10.101f, 3.123f}; + +class instance_arcatraz : public ScriptedInstance, private DialogueHelper { public: instance_arcatraz(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; - void OnObjectCreate(GameObject* pGo); - void OnCreatureCreate(Creature* pCreature); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; private: + void JustDidDialogueStep(int32 iEntry) override; + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiResetDelayTimer; + uint32 m_uiEntranceEventTimer; + uint8 m_uiKilledWardens; + + GuidList m_lSkyrissEventMobsGuidList; }; #endif diff --git a/scripts/outland/tempest_keep/arcatraz/boss_dalliah.cpp b/scripts/outland/tempest_keep/arcatraz/boss_dalliah.cpp new file mode 100644 index 000000000..16910ad0a --- /dev/null +++ b/scripts/outland/tempest_keep/arcatraz/boss_dalliah.cpp @@ -0,0 +1,217 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: boss_dalliah +SD%Complete: 100 +SDComment: +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +#include "precompiled.h" +#include "arcatraz.h" + +enum +{ + SAY_AGGRO = -1552031, + SAY_SOCCOTHRATES_TAUNT_1 = -1552040, + SAY_SOCCOTHRATES_TAUNT_2 = -1552041, + SAY_SOCCOTHRATES_TAUNT_3 = -1552042, + SAY_HEAL_1 = -1552032, + SAY_HEAL_2 = -1552033, + SAY_KILL_1 = -1552034, + SAY_KILL_2 = -1552035, + SAY_WHIRLWIND_1 = -1552036, + SAY_WHIRLWIND_2 = -1552037, + SAY_DEATH = -1552038, + + SPELL_GIFT_DOOMSAYER = 36173, + SPELL_GIFT_DOOMSAYER_H = 39009, + SPELL_HEAL = 36144, + SPELL_HEAL_H = 39013, + SPELL_WHIRLWIND = 36142, + SPELL_SHADOW_WAVE = 39016, // heroic spell only +}; + +struct boss_dalliahAI : public ScriptedAI +{ + boss_dalliahAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiGiftDoomsayerTimer; + uint32 m_uiHealTimer; + uint32 m_uiWhirlwindTimer; + uint32 m_uiShadowWaveTimer; + + bool m_bHasTaunted; + + void Reset() override + { + m_uiGiftDoomsayerTimer = urand(4000, 7000); + m_uiHealTimer = 0; + m_uiWhirlwindTimer = 15000; + m_uiShadowWaveTimer = urand(9000, 13000); + + m_bHasTaunted = false; + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DALLIAH, IN_PROGRESS); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); + } + + void JustDied(Unit* /*pWho*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DALLIAH, DONE); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + // should evade to the attack position + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(1, aDalliahStartPos[0], aDalliahStartPos[1], aDalliahStartPos[2]); + + if (m_pInstance) + m_pInstance->SetData(TYPE_DALLIAH, FAIL); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + // Adjust orientation + if (uiPointId) + m_creature->SetFacingTo(aDalliahStartPos[3]); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiGiftDoomsayerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_GIFT_DOOMSAYER : SPELL_GIFT_DOOMSAYER_H) == CAST_OK) + m_uiGiftDoomsayerTimer = urand(14000, 19000); + } + else + m_uiGiftDoomsayerTimer -= uiDiff; + + if (m_uiWhirlwindTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_WHIRLWIND) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_WHIRLWIND_1 : SAY_WHIRLWIND_2, m_creature); + m_uiWhirlwindTimer = urand(25000, 30000); + m_uiHealTimer = urand(6000, 10000); + } + } + else + m_uiWhirlwindTimer -= uiDiff; + + if (m_uiHealTimer) + { + if (m_uiHealTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_HEAL : SPELL_HEAL_H) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_HEAL_1 : SAY_HEAL_2, m_creature); + m_uiHealTimer = 0; + } + } + else + m_uiHealTimer -= uiDiff; + } + + if (!m_bIsRegularMode) + { + if (m_uiShadowWaveTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SHADOW_WAVE) == CAST_OK) + m_uiShadowWaveTimer = urand(13000, 17000); + } + } + else + m_uiShadowWaveTimer -= uiDiff; + } + + if (!m_bHasTaunted && m_creature->GetHealthPercent() < 25.0f) + { + // Taunt if Soccothares isn't dead yet + if (m_pInstance && m_pInstance->GetData(TYPE_SOCCOTHRATES) != DONE) + { + if (Creature* pSoccothares = m_pInstance->GetSingleCreatureFromStorage(NPC_SOCCOTHRATES)) + { + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_SOCCOTHRATES_TAUNT_1, pSoccothares); break; + case 1: DoScriptText(SAY_SOCCOTHRATES_TAUNT_2, pSoccothares); break; + case 2: DoScriptText(SAY_SOCCOTHRATES_TAUNT_3, pSoccothares); break; + } + } + } + + m_bHasTaunted = true; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_dalliah(Creature* pCreature) +{ + return new boss_dalliahAI(pCreature); +} + +void AddSC_boss_dalliah() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_dalliah"; + pNewScript->GetAI = &GetAI_boss_dalliah; + pNewScript->RegisterSelf(); +} diff --git a/scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp b/scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp index 1d3f71468..861047e28 100644 --- a/scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp +++ b/scripts/outland/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,23 +16,16 @@ /* ScriptData SDName: Boss_Harbinger_Skyriss -SD%Complete: 45 -SDComment: CombatAI not fully implemented. Timers will need adjustments. On wipe despawn all, and let warden_mellichar respawn after ~1min +SD%Complete: 95 +SDComment: Timers will need adjustments. SDCategory: Tempest Keep, The Arcatraz EndScriptData */ -/* ContentData -boss_harbinger_skyriss -boss_harbinger_skyriss_illusion -- TODO implement or move to ACID -EndContentData */ - #include "precompiled.h" #include "arcatraz.h" enum { - SAY_INTRO = -1552000, - SAY_AGGRO = -1552001, SAY_KILL_1 = -1552002, SAY_KILL_2 = -1552003, SAY_MIND_1 = -1552004, @@ -52,140 +45,73 @@ enum SPELL_33_ILLUSION = 36932, // Summons 21467 }; -struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI +struct boss_harbinger_skyrissAI : public ScriptedAI { boss_harbinger_skyrissAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - m_bIntroFinished = false; Reset(); } ScriptedInstance* m_pInstance; bool m_bIsRegularMode; - bool m_bIntroFinished; - bool m_bDidSplitImage33; - bool m_bDidSplitImage66; - - uint32 m_uiIntroPhase; - uint32 m_uiIntroTimer; + uint8 m_uiSplitPhase; uint32 m_uiMindRendTimer; uint32 m_uiFearTimer; uint32 m_uiDominationTimer; uint32 m_uiManaBurnTimer; - void Reset() + void Reset() override { - m_bDidSplitImage33 = false; - m_bDidSplitImage66 = false; - - m_uiIntroPhase = 1; - m_uiIntroTimer = 5000; - m_uiMindRendTimer = 3000; - m_uiFearTimer = 15000; + m_uiSplitPhase = 1; + m_uiMindRendTimer = 3000; + m_uiFearTimer = 15000; m_uiDominationTimer = 30000; - m_uiManaBurnTimer = 25000; - } - - void MoveInLineOfSight(Unit* pWho) - { - if (!m_bIntroFinished) - return; - - ScriptedAI::MoveInLineOfSight(pWho); + m_uiManaBurnTimer = 25000; } - void AttackStart(Unit* pWho) + void JustDied(Unit* /*pKiller*/) override { - if (!m_bIntroFinished) - return; + DoScriptText(SAY_DEATH, m_creature); - ScriptedAI::AttackStart(pWho); + if (m_pInstance) + m_pInstance->SetData(TYPE_HARBINGERSKYRISS, DONE); } - void JustDied(Unit* pKiller) + void JustReachedHome() override { - DoScriptText(SAY_DEATH, m_creature); - if (m_pInstance) - m_pInstance->SetData(TYPE_HARBINGERSKYRISS, DONE); + m_pInstance->SetData(TYPE_HARBINGERSKYRISS, FAIL); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { - //won't yell killing pet/other unit + // won't yell killing pet/other unit if (pVictim->GetTypeId() != TYPEID_PLAYER) return; DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { - pSummoned->AI()->AttackStart(m_creature->getVictim()); + if (m_creature->getVictim()) + pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void DoSplit() + void UpdateAI(const uint32 uiDiff) override { - DoScriptText(SAY_IMAGE, m_creature); - - DoCastSpellIfCan(m_creature, m_bDidSplitImage33 ? SPELL_33_ILLUSION : SPELL_66_ILLUSION, CAST_INTERRUPT_PREVIOUS); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_bIntroFinished && !m_creature->isInCombat()) - { - if (!m_pInstance) - return; - - if (m_uiIntroTimer < uiDiff) - { - switch(m_uiIntroPhase) - { - case 1: - DoScriptText(SAY_INTRO, m_creature); - if (GameObject* pSphere = m_pInstance->GetSingleGameObjectFromStorage(GO_SEAL_SPHERE)) - pSphere->SetGoState(GO_STATE_ACTIVE); - ++m_uiIntroPhase; - m_uiIntroTimer = 25000; - break; - case 2: - DoScriptText(SAY_AGGRO, m_creature); - if (Creature* pMellic = m_pInstance->GetSingleCreatureFromStorage(NPC_MELLICHAR)) - { - // should have a better way to do this. possibly spell exist. - pMellic->SetDeathState(JUST_DIED); - pMellic->SetHealth(0); - } - ++m_uiIntroPhase; - m_uiIntroTimer = 3000; - break; - case 3: - m_bIntroFinished = true; - // TODO - Let Attack here, or change Unit_flag - break; - } - } - else - m_uiIntroTimer -=uiDiff; - } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (!m_bDidSplitImage66 && m_creature->GetHealthPercent() <= 66.0f) + // Check if creature is below 66% or 33%; Also don't allow it to split the third time + if (m_creature->GetHealthPercent() < 100 - 33 * m_uiSplitPhase && m_creature->GetHealthPercent() > 5.0f) { - m_bDidSplitImage66 = true; - DoSplit(); - } - - if (!m_bDidSplitImage33 && m_creature->GetHealthPercent() <= 33.0f) - { - m_bDidSplitImage33 = true; - DoSplit(); + DoCastSpellIfCan(m_creature, m_uiSplitPhase == 1 ? SPELL_66_ILLUSION : SPELL_33_ILLUSION, CAST_INTERRUPT_PREVIOUS); + DoScriptText(SAY_IMAGE, m_creature); + ++m_uiSplitPhase; } if (m_uiMindRendTimer < uiDiff) @@ -198,7 +124,7 @@ struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI m_uiMindRendTimer = 8000; } else - m_uiMindRendTimer -=uiDiff; + m_uiMindRendTimer -= uiDiff; if (m_uiFearTimer < uiDiff) { @@ -213,22 +139,21 @@ struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI } } else - m_uiFearTimer -=uiDiff; + m_uiFearTimer -= uiDiff; if (m_uiDominationTimer < uiDiff) { - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1); - if (!pTarget) - pTarget = m_creature->getVictim(); - - if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_DOMINATION : SPELL_DOMINATION_H) == CAST_OK) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_PLAYER)) { - DoScriptText(urand(0, 1) ? SAY_MIND_1 : SAY_MIND_2, m_creature); - m_uiDominationTimer = urand(16000, 32000); + if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_DOMINATION : SPELL_DOMINATION_H) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_MIND_1 : SAY_MIND_2, m_creature); + m_uiDominationTimer = urand(16000, 32000); + } } } else - m_uiDominationTimer -=uiDiff; + m_uiDominationTimer -= uiDiff; if (!m_bIsRegularMode) { @@ -242,7 +167,7 @@ struct MANGOS_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI m_uiManaBurnTimer = urand(16000, 32000); } else - m_uiManaBurnTimer -=uiDiff; + m_uiManaBurnTimer -= uiDiff; } DoMeleeAttackIfReady(); @@ -254,32 +179,6 @@ CreatureAI* GetAI_boss_harbinger_skyriss(Creature* pCreature) return new boss_harbinger_skyrissAI(pCreature); } -enum -{ - SPELL_MIND_REND_IMAGE = 36929, - SPELL_MIND_REND_IMAGE_H = 39021, -}; - -struct MANGOS_DLL_DECL boss_harbinger_skyriss_illusionAI : public ScriptedAI -{ - boss_harbinger_skyriss_illusionAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; - - void Reset() { } -}; - -CreatureAI* GetAI_boss_harbinger_skyriss_illusion(Creature* pCreature) -{ - return new boss_harbinger_skyriss_illusionAI(pCreature); -} - void AddSC_boss_harbinger_skyriss() { Script* pNewScript; @@ -288,9 +187,4 @@ void AddSC_boss_harbinger_skyriss() pNewScript->Name = "boss_harbinger_skyriss"; pNewScript->GetAI = &GetAI_boss_harbinger_skyriss; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "boss_harbinger_skyriss_illusion"; - pNewScript->GetAI = &GetAI_boss_harbinger_skyriss_illusion; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/arcatraz/boss_soccothrates.cpp b/scripts/outland/tempest_keep/arcatraz/boss_soccothrates.cpp new file mode 100644 index 000000000..1cd54e78c --- /dev/null +++ b/scripts/outland/tempest_keep/arcatraz/boss_soccothrates.cpp @@ -0,0 +1,252 @@ +/* This file is part of the ScriptDev2 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 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 + */ + +/* ScriptData +SDName: boss_soccothrates +SD%Complete: 80 +SDComment: Spell Felfire Line Up and Wrath-Scryer's Felfire npc are summoning are NYI and they need additional research. +SDCategory: Tempest Keep, The Arcatraz +EndScriptData */ + +#include "precompiled.h" +#include "arcatraz.h" + +enum +{ + // Intro yells + SAY_SOCCOTHRATES_INTRO_1 = -1552049, + SAY_DALLIAH_INTRO_2 = -1552050, + SAY_SOCCOTHRATES_INTRO_3 = -1552051, + SAY_DALLIAH_INTRO_4 = -1552052, + SAY_SOCCOTHRATES_INTRO_5 = -1552053, + SAY_DALLIAH_INTRO_6 = -1552054, + SAY_SOCCOTHRATES_INTRO_7 = -1552055, + + SAY_AGGRO = -1552048, + SAY_KILL = -1552047, + SAY_DEATH = -1552046, + SAY_CHARGE_1 = -1552044, + SAY_CHARGE_2 = -1552045, + + SPELL_IMMOLATION = 36051, + SPELL_IMMOLATION_H = 39007, + SPELL_KNOCK_AWAY = 36512, + SPELL_FELFIRE_LINE_UP = 35770, // dummy spell - should summon a line of npcs - 20978 to the target + SPELL_CHARGE_TARGETING = 36038, // summons 21030 on target + SPELL_CHARGE = 35754, // script target on 21030; also dummy effect area effect target on 20978 - makes the target cast 35769 + SPELL_FELFIRE_SHOCK = 35759, + SPELL_FELFIRE_SHOCK_H = 39006, +}; + +static const DialogueEntry aIntroDialogue[] = +{ + {SAY_SOCCOTHRATES_INTRO_1, NPC_SOCCOTHRATES, 3000}, + {SAY_DALLIAH_INTRO_2, NPC_DALLIAH, 2000}, + {SAY_SOCCOTHRATES_INTRO_3, NPC_SOCCOTHRATES, 4000}, + {SAY_DALLIAH_INTRO_4, NPC_DALLIAH, 5000}, + {SAY_SOCCOTHRATES_INTRO_5, NPC_SOCCOTHRATES, 3000}, + {SAY_DALLIAH_INTRO_6, NPC_DALLIAH, 3000}, + {SAY_SOCCOTHRATES_INTRO_7, NPC_SOCCOTHRATES, 0}, + {0, 0, 0}, +}; + +struct boss_soccothratesAI : public ScriptedAI, private DialogueHelper +{ + boss_soccothratesAI(Creature* pCreature) : ScriptedAI(pCreature), + DialogueHelper(aIntroDialogue) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); + InitializeDialogueHelper(m_pInstance); + m_bHasYelledIntro = false; + Reset(); + } + + ScriptedInstance* m_pInstance; + bool m_bIsRegularMode; + + uint32 m_uiKnockAwayTimer; + uint32 m_uiFelfireShockTimer; + uint32 m_uiFelfireLineupTimer; + uint32 m_uiChargeTimer; + + bool m_bHasYelledIntro; + + void Reset() override + { + m_uiFelfireShockTimer = urand(10000, 13000); + m_uiKnockAwayTimer = urand(22000, 25000); + m_uiFelfireLineupTimer = 0; + m_uiChargeTimer = 0; + + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_IMMOLATION : SPELL_IMMOLATION_H); + } + + void Aggro(Unit* /*pWho*/) override + { + DoScriptText(SAY_AGGRO, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SOCCOTHRATES, IN_PROGRESS); + } + + void MoveInLineOfSight(Unit* pWho) override + { + if (!m_bHasYelledIntro && pWho->GetTypeId() == TYPEID_PLAYER && m_creature->IsWithinDistInMap(pWho, 75.0f) && m_creature->IsWithinLOSInMap(pWho)) + { + StartNextDialogueText(SAY_SOCCOTHRATES_INTRO_1); + m_bHasYelledIntro = true; + } + + ScriptedAI::MoveInLineOfSight(pWho); + } + + void KilledUnit(Unit* /*pVictim*/) override + { + DoScriptText(SAY_KILL, m_creature); + } + + void JustDied(Unit* /*pWho*/) override + { + DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SOCCOTHRATES, DONE); + } + + void EnterEvadeMode() override + { + m_creature->RemoveAllAurasOnEvade(); + m_creature->DeleteThreatList(); + m_creature->CombatStop(true); + m_creature->LoadCreatureAddon(true); + + // should evade to the attack position + if (m_creature->isAlive()) + m_creature->GetMotionMaster()->MovePoint(1, aSoccotharesStartPos[0], aSoccotharesStartPos[1], aSoccotharesStartPos[2]); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SOCCOTHRATES, FAIL); + + m_creature->SetLootRecipient(NULL); + + Reset(); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE) + return; + + // Adjust orientation + if (uiPointId) + m_creature->SetFacingTo(aSoccotharesStartPos[3]); + } + + void JustDidDialogueStep(int32 iEntry) override + { + // Move each of them to their places + if (iEntry == SAY_SOCCOTHRATES_INTRO_7) + { + m_creature->GetMotionMaster()->MovePoint(1, aSoccotharesStartPos[0], aSoccotharesStartPos[1], aSoccotharesStartPos[2]); + + if (m_pInstance) + { + if (Creature* pDalliah = m_pInstance->GetSingleCreatureFromStorage(NPC_DALLIAH)) + pDalliah->GetMotionMaster()->MovePoint(1, aDalliahStartPos[0], aDalliahStartPos[1], aDalliahStartPos[2]); + } + } + } + + void UpdateAI(const uint32 uiDiff) override + { + DialogueUpdate(uiDiff); + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiFelfireShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_FELFIRE_SHOCK : SPELL_FELFIRE_SHOCK_H) == CAST_OK) + m_uiFelfireShockTimer = urand(35000, 45000); + } + else + m_uiFelfireShockTimer -= uiDiff; + + if (m_uiKnockAwayTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_KNOCK_AWAY) == CAST_OK) + { + m_uiKnockAwayTimer = urand(30000, 35000); + m_uiFelfireLineupTimer = 3000; + } + } + else + m_uiKnockAwayTimer -= uiDiff; + + // Prepare the boss for charging + if (m_uiFelfireLineupTimer) + { + if (m_uiFelfireLineupTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE_TARGETING) == CAST_OK) + { + // ToDo: the Wrath-Scryer's Felfire npcs should be summoned at this point and aligned to the chosen target! + DoCastSpellIfCan(m_creature, SPELL_FELFIRE_LINE_UP, CAST_TRIGGERED); + DoScriptText(urand(0, 1) ? SAY_CHARGE_1 : SAY_CHARGE_2, m_creature); + + m_uiChargeTimer = 1500; + m_uiFelfireLineupTimer = 0; + } + } + } + else + m_uiFelfireLineupTimer -= uiDiff; + } + + // Charge the target + if (m_uiChargeTimer) + { + if (m_uiChargeTimer <= uiDiff) + { + // Note: this spell will also light up the Wrath-Scryer's Felfire npcs + if (DoCastSpellIfCan(m_creature, SPELL_CHARGE) == CAST_OK) + m_uiChargeTimer = 0; + } + else + m_uiChargeTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_boss_soccothrates(Creature* pCreature) +{ + return new boss_soccothratesAI(pCreature); +} + +void AddSC_boss_soccothrates() +{ + Script* pNewScript; + + pNewScript = new Script; + pNewScript->Name = "boss_soccothrates"; + pNewScript->GetAI = &GetAI_boss_soccothrates; + pNewScript->RegisterSelf(); +} diff --git a/scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp b/scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp index ac48e1a71..158fa9a46 100644 --- a/scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp +++ b/scripts/outland/tempest_keep/arcatraz/instance_arcatraz.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -31,64 +31,210 @@ EndScriptData */ 4 - Harbinger Skyriss event, 5 sub-events */ -instance_arcatraz::instance_arcatraz(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } +enum +{ + SAY_SOCCOTHRATES_AGGRO = -1552039, + SAY_SOCCOTHRATES_DEATH = -1552043, + + YELL_MELLICHAR_INTRO1 = -1552023, + YELL_MELLICHAR_INTRO2 = -1552024, + YELL_MELLICHAR_RELEASE1 = -1552025, + YELL_MELLICHAR_RELEASE2 = -1552026, + YELL_MELLICHAR_RELEASE3 = -1552027, + YELL_MELLICHAR_RELEASE4 = -1552028, + YELL_MELLICHAR_RELEASE5 = -1552029, + YELL_MELLICAR_WELCOME = -1552030, + SAY_SKYRISS_INTRO = -1552000, + SAY_SKYRISS_AGGRO = -1552001, + SAY_MILLHOUSE_COMPLETE = -1552022, + + // Spells used by Mellichar during the dialogue + SPELL_TARGET_BETA = 36854, + SPELL_TARGET_ALPHA = 36856, + SPELL_TARGET_DELTA = 36857, + SPELL_TARGET_GAMMA = 36858, + SPELL_SIMPLE_TELEPORT = 12980, + SPELL_MIND_REND = 36859, +}; + +static const DialogueEntry aArcatrazDialogue[] = +{ + // Soccothares taunts + {TYPE_DALLIAH, 0, 5000}, + {SAY_SOCCOTHRATES_AGGRO, NPC_SOCCOTHRATES, 0}, + {TYPE_SOCCOTHRATES, 0, 5000}, + {SAY_SOCCOTHRATES_DEATH, NPC_SOCCOTHRATES, 0}, + // Skyriss event + {YELL_MELLICHAR_INTRO1, NPC_MELLICHAR, 22000}, + {YELL_MELLICHAR_INTRO2, NPC_MELLICHAR, 7000}, + {SPELL_TARGET_ALPHA, 0, 7000}, + {YELL_MELLICHAR_RELEASE1, NPC_MELLICHAR, 0}, + {YELL_MELLICHAR_RELEASE2, NPC_MELLICHAR, 7000}, + {SPELL_TARGET_BETA, 0, 7000}, + {TYPE_WARDEN_2, 0, 0}, + {YELL_MELLICHAR_RELEASE3, NPC_MELLICHAR, 7000}, + {SPELL_TARGET_DELTA, 0, 7000}, + {TYPE_WARDEN_3, 0, 0}, + {YELL_MELLICHAR_RELEASE4, NPC_MELLICHAR, 7000}, + {SPELL_TARGET_GAMMA, 0, 7000}, + {TYPE_WARDEN_4, 0, 0}, + {YELL_MELLICHAR_RELEASE5, NPC_MELLICHAR, 8000}, + {TYPE_WARDEN_5, 0, 5000}, + {SAY_SKYRISS_INTRO, NPC_SKYRISS, 25000}, + {YELL_MELLICAR_WELCOME, NPC_MELLICHAR, 3000}, + {SAY_SKYRISS_AGGRO, NPC_SKYRISS, 0}, + {0, 0, 0}, +}; + +instance_arcatraz::instance_arcatraz(Map* pMap) : ScriptedInstance(pMap), DialogueHelper(aArcatrazDialogue), + m_uiResetDelayTimer(0), + m_uiEntranceEventTimer(0), + m_uiKilledWardens(0) +{ + Initialize(); +} void instance_arcatraz::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + InitializeDialogueHelper(this); +} + +void instance_arcatraz::OnPlayerEnter(Player* /*pPlayer*/) +{ + // Check encounter states + if (GetData(TYPE_ENTRANCE) == DONE || GetData(TYPE_ENTRANCE) == IN_PROGRESS) + return; + + SetData(TYPE_ENTRANCE, IN_PROGRESS); + m_uiEntranceEventTimer = 1000; } void instance_arcatraz::OnObjectCreate(GameObject* pGo) { - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_CORE_SECURITY_FIELD_ALPHA: + if (m_auiEncounter[2] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; case GO_CORE_SECURITY_FIELD_BETA: + if (m_auiEncounter[1] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; case GO_SEAL_SPHERE: case GO_POD_ALPHA: case GO_POD_BETA: case GO_POD_DELTA: case GO_POD_GAMMA: case GO_POD_OMEGA: - m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); break; + default: + return; } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); } void instance_arcatraz::OnCreatureCreate(Creature* pCreature) { - if (pCreature->GetEntry() == NPC_MELLICHAR) - m_mNpcEntryGuidStore[NPC_MELLICHAR] = pCreature->GetObjectGuid(); + switch (pCreature->GetEntry()) + { + case NPC_SKYRISS: + case NPC_MILLHOUSE: + m_lSkyrissEventMobsGuidList.push_back(pCreature->GetObjectGuid()); + // no break here because we want them in both lists + case NPC_PRISON_APHPA_POD: + case NPC_PRISON_BETA_POD: + case NPC_PRISON_DELTA_POD: + case NPC_PRISON_GAMMA_POD: + case NPC_PRISON_BOSS_POD: + case NPC_MELLICHAR: + case NPC_DALLIAH: + case NPC_SOCCOTHRATES: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_BLAZING_TRICKSTER: + case NPC_PHASE_HUNTER: + case NPC_AKKIRIS: + case NPC_SULFURON: + case NPC_TW_DRAKONAAR: + case NPC_BL_DRAKONAAR: + m_lSkyrissEventMobsGuidList.push_back(pCreature->GetObjectGuid()); + break; + } } void instance_arcatraz::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { + case TYPE_ENTRANCE: case TYPE_ZEREKETH: - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_DALLIAH: + if (uiData == IN_PROGRESS) + { + // Soccothares taunts after Dalliah gets aggro + if (GetData(TYPE_SOCCOTHRATES) != DONE) + StartNextDialogueText(TYPE_DALLIAH); + } if (uiData == DONE) + { DoUseDoorOrButton(GO_CORE_SECURITY_FIELD_BETA); - m_auiEncounter[1] = uiData; + + // Soccothares taunts after Dalliah dies + if (GetData(TYPE_SOCCOTHRATES) != DONE) + StartNextDialogueText(TYPE_SOCCOTHRATES); + } + m_auiEncounter[uiType] = uiData; break; case TYPE_SOCCOTHRATES: if (uiData == DONE) DoUseDoorOrButton(GO_CORE_SECURITY_FIELD_ALPHA); - m_auiEncounter[2] = uiData; + m_auiEncounter[uiType] = uiData; break; case TYPE_HARBINGERSKYRISS: - if (uiData == NOT_STARTED || uiData == FAIL) + if (uiData == FAIL) { - m_auiEncounter[4] = NOT_STARTED; - m_auiEncounter[5] = NOT_STARTED; - m_auiEncounter[6] = NOT_STARTED; - m_auiEncounter[7] = NOT_STARTED; - m_auiEncounter[8] = NOT_STARTED; + SetData(TYPE_WARDEN_1, NOT_STARTED); + SetData(TYPE_WARDEN_2, NOT_STARTED); + SetData(TYPE_WARDEN_3, NOT_STARTED); + SetData(TYPE_WARDEN_4, NOT_STARTED); + SetData(TYPE_WARDEN_5, NOT_STARTED); + + // Reset event in 1 min + if (Creature* pMellichar = GetSingleCreatureFromStorage(NPC_MELLICHAR)) + pMellichar->ForcedDespawn(); + m_uiResetDelayTimer = 60000; + + // Despawn all the summons manually + for (GuidList::const_iterator itr = m_lSkyrissEventMobsGuidList.begin(); itr != m_lSkyrissEventMobsGuidList.end(); ++itr) + { + if (Creature* pTemp = instance->GetCreature(*itr)) + pTemp->ForcedDespawn(); + } + + // Reset these objects, because they doesn't reset automatically + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_POD_BETA)) + pGo->ResetDoorOrButton(); + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_POD_OMEGA)) + pGo->ResetDoorOrButton(); + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_SEAL_SPHERE)) + pGo->ResetDoorOrButton(); + } + if (uiData == IN_PROGRESS) + { + StartNextDialogueText(YELL_MELLICHAR_INTRO1); + DoUseDoorOrButton(GO_SEAL_SPHERE); + } + if (uiData == DONE) + { + if (Creature* pMillhouse = GetSingleCreatureFromStorage(NPC_MILLHOUSE)) + DoScriptText(SAY_MILLHOUSE_COMPLETE, pMillhouse); } m_auiEncounter[3] = uiData; break; @@ -96,48 +242,221 @@ void instance_arcatraz::SetData(uint32 uiType, uint32 uiData) case TYPE_WARDEN_1: if (uiData == IN_PROGRESS) DoUseDoorOrButton(GO_POD_ALPHA); - m_auiEncounter[4] = uiData; + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE2); + m_auiEncounter[uiType] = uiData; break; case TYPE_WARDEN_2: if (uiData == IN_PROGRESS) DoUseDoorOrButton(GO_POD_BETA); - m_auiEncounter[5] = uiData; + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE3); + m_auiEncounter[uiType] = uiData; break; case TYPE_WARDEN_3: if (uiData == IN_PROGRESS) DoUseDoorOrButton(GO_POD_DELTA); - m_auiEncounter[6] = uiData; + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE4); + m_auiEncounter[uiType] = uiData; break; case TYPE_WARDEN_4: if (uiData == IN_PROGRESS) DoUseDoorOrButton(GO_POD_GAMMA); - m_auiEncounter[7] = uiData; + if (uiData == DONE) + StartNextDialogueText(YELL_MELLICHAR_RELEASE5); + m_auiEncounter[uiType] = uiData; break; case TYPE_WARDEN_5: if (uiData == IN_PROGRESS) DoUseDoorOrButton(GO_POD_OMEGA); - m_auiEncounter[8] = uiData; + m_auiEncounter[uiType] = uiData; + break; + } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_arcatraz::GetData(uint32 uiType) const +{ + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; + + return 0; +} + +void instance_arcatraz::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_arcatraz::JustDidDialogueStep(int32 iEntry) +{ + Creature* pMellichar = GetSingleCreatureFromStorage(NPC_MELLICHAR); + if (!pMellichar) + return; + + switch (iEntry) + { + case SPELL_TARGET_ALPHA: + pMellichar->CastSpell(pMellichar, SPELL_TARGET_ALPHA, false); + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_APHPA_POD)) + pMellichar->SetFacingToObject(pTarget); + SetData(TYPE_WARDEN_1, IN_PROGRESS); + break; + case YELL_MELLICHAR_RELEASE1: + pMellichar->SummonCreature(urand(0, 1) ? NPC_BLAZING_TRICKSTER : NPC_PHASE_HUNTER, aSummonPosition[0].m_fX, aSummonPosition[0].m_fY, aSummonPosition[0].m_fZ, aSummonPosition[0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + break; + case YELL_MELLICHAR_RELEASE2: + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_BETA_POD)) + pMellichar->SetFacingToObject(pTarget); + break; + case SPELL_TARGET_BETA: + pMellichar->CastSpell(pMellichar, SPELL_TARGET_BETA, false); + SetData(TYPE_WARDEN_2, IN_PROGRESS); + break; + case TYPE_WARDEN_2: + pMellichar->SummonCreature(NPC_MILLHOUSE, aSummonPosition[1].m_fX, aSummonPosition[1].m_fY, aSummonPosition[1].m_fZ, aSummonPosition[1].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + break; + case SPELL_TARGET_DELTA: + pMellichar->CastSpell(pMellichar, SPELL_TARGET_DELTA, false); + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_DELTA_POD)) + pMellichar->SetFacingToObject(pTarget); + SetData(TYPE_WARDEN_3, IN_PROGRESS); + break; + case TYPE_WARDEN_3: + pMellichar->SummonCreature(urand(0, 1) ? NPC_AKKIRIS : NPC_SULFURON, aSummonPosition[2].m_fX, aSummonPosition[2].m_fY, aSummonPosition[2].m_fZ, aSummonPosition[2].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + pMellichar->CastSpell(pMellichar, SPELL_TARGET_OMEGA, false); + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_BOSS_POD)) + pMellichar->SetFacingToObject(pTarget); + break; + case YELL_MELLICHAR_RELEASE4: + pMellichar->InterruptNonMeleeSpells(false); + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_GAMMA_POD)) + pMellichar->SetFacingToObject(pTarget); + break; + case SPELL_TARGET_GAMMA: + pMellichar->CastSpell(pMellichar, SPELL_TARGET_GAMMA, false); + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_GAMMA_POD)) + pMellichar->SetFacingToObject(pTarget); + SetData(TYPE_WARDEN_4, IN_PROGRESS); + break; + case TYPE_WARDEN_4: + pMellichar->SummonCreature(urand(0, 1) ? NPC_TW_DRAKONAAR : NPC_BL_DRAKONAAR, aSummonPosition[3].m_fX, aSummonPosition[3].m_fY, aSummonPosition[3].m_fZ, aSummonPosition[3].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); + pMellichar->CastSpell(pMellichar, SPELL_TARGET_OMEGA, false); + if (Creature* pTarget = GetSingleCreatureFromStorage(NPC_PRISON_BOSS_POD)) + pMellichar->SetFacingToObject(pTarget); + break; + case YELL_MELLICHAR_RELEASE5: + pMellichar->InterruptNonMeleeSpells(false); + SetData(TYPE_WARDEN_5, IN_PROGRESS); + break; + case TYPE_WARDEN_5: + if (Creature* pSkyriss = pMellichar->SummonCreature(NPC_SKYRISS, aSummonPosition[4].m_fX, aSummonPosition[4].m_fY, aSummonPosition[4].m_fZ, aSummonPosition[4].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + pSkyriss->CastSpell(pSkyriss, SPELL_SIMPLE_TELEPORT, false); + break; + case YELL_MELLICAR_WELCOME: + if (Creature* pSkyriss = GetSingleCreatureFromStorage(NPC_SKYRISS)) + pSkyriss->CastSpell(pSkyriss, SPELL_MIND_REND, false); + break; + case SAY_SKYRISS_AGGRO: + // Kill Mellichar and start combat + if (Creature* pSkyriss = GetSingleCreatureFromStorage(NPC_SKYRISS)) + { + pSkyriss->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + pMellichar->DealDamage(pMellichar, pMellichar->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + } + DoUseDoorOrButton(GO_SEAL_SPHERE); break; } } -uint32 instance_arcatraz::GetData(uint32 uiType) +void instance_arcatraz::OnCreatureDeath(Creature* pCreature) { - switch(uiType) + if (pCreature->GetEntry() == NPC_ARCATRAZ_WARDEN || pCreature->GetEntry() == NPC_ARCATRAZ_DEFENDER) { - case TYPE_HARBINGERSKYRISS: return m_auiEncounter[3]; - case TYPE_WARDEN_1: return m_auiEncounter[4]; - case TYPE_WARDEN_2: return m_auiEncounter[5]; - case TYPE_WARDEN_3: return m_auiEncounter[6]; - case TYPE_WARDEN_4: return m_auiEncounter[7]; - case TYPE_WARDEN_5: return m_auiEncounter[8]; + ++m_uiKilledWardens; - default: - return 0; + // Stop the intro spawns when the wardens are killed + if (m_uiKilledWardens == MAX_WARDENS) + { + SetData(TYPE_ENTRANCE, DONE); + m_uiEntranceEventTimer = 0; + } + } +} + +void instance_arcatraz::Update(uint32 uiDiff) +{ + DialogueUpdate(uiDiff); + + if (m_uiResetDelayTimer) + { + if (m_uiResetDelayTimer <= uiDiff) + { + if (Creature* pMellichar = GetSingleCreatureFromStorage(NPC_MELLICHAR)) + pMellichar->Respawn(); + m_uiResetDelayTimer = 0; + } + else + m_uiResetDelayTimer -= uiDiff; + } + + if (m_uiEntranceEventTimer) + { + if (m_uiEntranceEventTimer <= uiDiff) + { + Player* pPlayer = GetPlayerInMap(); + if (!pPlayer) + return; + + uint32 uiEntry = urand(0, 10) ? NPC_PROTEAN_HORROR : NPC_PROTEAN_NIGHTMARE; + + // Summon and move the intro creatures into combat positions + if (Creature* pTemp = pPlayer->SummonCreature(uiEntry, aEntranceSpawnLoc[0], aEntranceSpawnLoc[1], aEntranceSpawnLoc[2], aEntranceSpawnLoc[3], TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000)) + { + pTemp->SetWalk(false); + pTemp->GetMotionMaster()->MovePoint(0, aEntranceMoveLoc[0], aEntranceMoveLoc[1], aEntranceMoveLoc[2]); + } + m_uiEntranceEventTimer = urand(0, 10) ? urand(2000, 3500) : urand(5000, 7000); + } + else + m_uiEntranceEventTimer -= uiDiff; } } diff --git a/scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp b/scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp index 33f28452e..3136c44e8 100644 --- a/scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp +++ b/scripts/outland/tempest_keep/botanica/boss_high_botanist_freywinn.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,7 +43,7 @@ enum NPC_FRAYER_PROTECTOR = 19953, }; -struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI +struct boss_high_botanist_freywinnAI : public ScriptedAI { boss_high_botanist_freywinnAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -54,7 +54,7 @@ struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI uint8 m_uiFrayerAddsCount; bool m_bCanMoveFree; - void Reset() + void Reset() override { m_uiSummonSeedlingTimer = 6000; m_uiTreeFormTimer = 30000; @@ -64,12 +64,12 @@ struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI m_bCanMoveFree = true; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FRAYER_PROTECTOR) ++m_uiFrayerAddsCount; @@ -79,7 +79,7 @@ struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FRAYER_PROTECTOR) { @@ -104,7 +104,7 @@ struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI // Wrapper to summon one seedling void DoSummonSeedling() { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoCastSpellIfCan(m_creature, SPELL_PLANT_WHITE); break; case 1: DoCastSpellIfCan(m_creature, SPELL_PLANT_GREEN); break; @@ -113,17 +113,17 @@ struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI } } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_KILL_1 : SAY_KILL_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -132,7 +132,7 @@ struct MANGOS_DLL_DECL boss_high_botanist_freywinnAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_TRANQUILITY) == CAST_OK) { - // Note: This should remove only negative auras + // Note: This should remove only negative auras m_creature->RemoveAllAuras(); DoCastSpellIfCan(m_creature, SPELL_TREE_FORM, CAST_TRIGGERED); diff --git a/scripts/outland/tempest_keep/botanica/boss_laj.cpp b/scripts/outland/tempest_keep/botanica/boss_laj.cpp index ddd921626..0a35dd542 100644 --- a/scripts/outland/tempest_keep/botanica/boss_laj.cpp +++ b/scripts/outland/tempest_keep/botanica/boss_laj.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -23,58 +23,63 @@ EndScriptData */ #include "precompiled.h" -#define EMOTE_SUMMON -1553006 - -#define SPELL_ALLERGIC_REACTION 34697 -#define SPELL_TELEPORT_SELF 34673 - -#define SPELL_SUMMON_LASHER_1 34681 -#define SPELL_SUMMON_FLAYER_1 34682 -#define SPELL_SUMMON_LASHER_2 34684 -#define SPELL_SUMMON_FLAYER_2 34685 -#define SPELL_SUMMON_LASHER_3 34686 -#define SPELL_SUMMON_FLAYER_4 34687 -#define SPELL_SUMMON_LASHER_4 34688 -#define SPELL_SUMMON_FLAYER_3 34690 - -#define MODEL_DEFAULT 13109 -#define MODEL_ARCANE 14213 -#define MODEL_FIRE 13110 -#define MODEL_FROST 14112 -#define MODEL_NATURE 14214 +enum +{ + EMOTE_SUMMON = -1553006, + + SPELL_ALLERGIC_REACTION = 34697, + SPELL_TELEPORT_SELF = 34673, + SPELL_TRASH = 3391, + + SPELL_SUMMON_LASHER_1 = 34681, + SPELL_SUMMON_FLAYER_1 = 34682, + SPELL_SUMMON_LASHER_2 = 34684, + SPELL_SUMMON_FLAYER_2 = 34685, + SPELL_SUMMON_LASHER_3 = 34686, + SPELL_SUMMON_FLAYER_4 = 34687, + SPELL_SUMMON_LASHER_4 = 34688, + SPELL_SUMMON_FLAYER_3 = 34690, + + MODEL_ID_DEFAULT = 13109, + MODEL_ID_ARCANE = 14213, + MODEL_ID_FIRE = 13110, + MODEL_ID_FROST = 14112, + MODEL_ID_NATURE = 14214, +}; -struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI +struct boss_lajAI : public ScriptedAI { boss_lajAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - bool CanSummon; - uint32 Teleport_Timer; - uint32 Summon_Timer; - uint32 Transform_Timer; - uint32 Allergic_Timer; + uint32 m_uiTeleportTimer; + uint32 m_uiSummonTimer; + uint32 m_uiTransformTimer; + uint32 m_uiAllergicTimer; + uint32 m_uiTrashTimer; - void Reset() + void Reset() override { - m_creature->SetDisplayId(MODEL_DEFAULT); + m_creature->SetDisplayId(MODEL_ID_DEFAULT); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); - CanSummon = false; - Teleport_Timer = 20000; - Summon_Timer = 2500; - Transform_Timer = 30000; - Allergic_Timer = 5000; + m_uiTeleportTimer = urand(17000, 26000); + m_uiSummonTimer = 0; + m_uiTransformTimer = 30000; + m_uiAllergicTimer = urand(8500, 30000); + m_uiTrashTimer = urand(3600, 5000); } void DoTransform() { - switch(urand(0, 4)) + // Random transform into a different form + switch (urand(0, 4)) { case 0: - m_creature->SetDisplayId(MODEL_DEFAULT); + m_creature->SetDisplayId(MODEL_ID_DEFAULT); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, true); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, false); @@ -82,7 +87,7 @@ struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); break; case 1: - m_creature->SetDisplayId(MODEL_ARCANE); + m_creature->SetDisplayId(MODEL_ID_ARCANE); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, false); @@ -90,7 +95,7 @@ struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); break; case 2: - m_creature->SetDisplayId(MODEL_FIRE); + m_creature->SetDisplayId(MODEL_ID_FIRE); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); @@ -98,7 +103,7 @@ struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); break; case 3: - m_creature->SetDisplayId(MODEL_FROST); + m_creature->SetDisplayId(MODEL_ID_FROST); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, false); @@ -106,7 +111,7 @@ struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); break; case 4: - m_creature->SetDisplayId(MODEL_NATURE); + m_creature->SetDisplayId(MODEL_ID_NATURE); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_SHADOW, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, false); m_creature->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, false); @@ -118,7 +123,7 @@ struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI void DoSummons() { - switch(urand(0, 3)) + switch (urand(0, 3)) { case 0: DoCastSpellIfCan(m_creature, SPELL_SUMMON_LASHER_1, CAST_TRIGGERED); @@ -137,42 +142,70 @@ struct MANGOS_DLL_DECL boss_lajAI : public ScriptedAI DoCastSpellIfCan(m_creature, SPELL_SUMMON_FLAYER_4, CAST_TRIGGERED); break; } - CanSummon = false; } - void UpdateAI(const uint32 diff) + void JustSummoned(Creature* pSummoned) override + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + pSummoned->AI()->AttackStart(pTarget); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (CanSummon) + if (m_uiSummonTimer) { - if (Summon_Timer < diff) + if (m_uiSummonTimer <= uiDiff) { - DoScriptText(EMOTE_SUMMON, m_creature); + // Summon adds and restart chasing the victim DoSummons(); - Summon_Timer = 2500; - }else Summon_Timer -= diff; + DoScriptText(EMOTE_SUMMON, m_creature); + + if (m_creature->getVictim()) + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + m_uiSummonTimer = 0; + } + else + m_uiSummonTimer -= uiDiff; } - if (Allergic_Timer < diff) + if (m_uiAllergicTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_ALLERGIC_REACTION); - Allergic_Timer = urand(25000, 40000); - }else Allergic_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ALLERGIC_REACTION) == CAST_OK) + m_uiAllergicTimer = urand(21000, 32000); + } + else + m_uiAllergicTimer -= uiDiff; - if (Teleport_Timer < diff) + if (m_uiTeleportTimer < uiDiff) { - DoCastSpellIfCan(m_creature,SPELL_TELEPORT_SELF); - Teleport_Timer = urand(30000, 40000); - CanSummon = true; - }else Teleport_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_TELEPORT_SELF) == CAST_OK) + { + m_creature->GetMotionMaster()->MoveIdle(); + m_uiTeleportTimer = urand(25000, 33000); + m_uiSummonTimer = 4000; + } + } + else + m_uiTeleportTimer -= uiDiff; - if (Transform_Timer < diff) + if (m_uiTransformTimer < uiDiff) { DoTransform(); - Transform_Timer = urand(25000, 40000); - }else Transform_Timer -= diff; + m_uiTransformTimer = urand(25000, 40000); + } + else + m_uiTransformTimer -= uiDiff; + + if (m_uiTrashTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_TRASH) == CAST_OK) + m_uiTrashTimer = urand(10000, 24000); + } + else + m_uiTrashTimer -= uiDiff; DoMeleeAttackIfReady(); } diff --git a/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp b/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp index 5fdc733d5..96be58896 100644 --- a/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp +++ b/scripts/outland/tempest_keep/botanica/boss_warp_splinter.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -45,9 +45,9 @@ enum }; // Summon Saplings spells (too many to declare them above) -static const uint32 aSaplingsSummonSpells[10] = {34727,34730,34731,34732,34733,34734,34735,34736,34737,34739}; +static const uint32 aSaplingsSummonSpells[10] = {34727, 34730, 34731, 34732, 34733, 34734, 34735, 34736, 34737, 34739}; -struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI +struct boss_warp_splinterAI : public ScriptedAI { boss_warp_splinterAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -67,29 +67,29 @@ struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI std::vector m_vSummonSpells; - void Reset() + void Reset() override { - m_uiWarStompTimer = 20000; - m_uiSummonTreantsTimer = 15000; - m_uiArcaneVolleyTimer = urand(20000, 25000); + m_uiWarStompTimer = urand(6000, 7000); + m_uiSummonTreantsTimer = urand(25000, 35000); + m_uiArcaneVolleyTimer = urand(12000, 14500); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SAPLING) pSummoned->GetMotionMaster()->MoveFollow(m_creature, 0, 0); @@ -107,7 +107,7 @@ struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI DoScriptText(urand(0, 1) ? SAY_SUMMON_1 : SAY_SUMMON_2, m_creature); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -116,7 +116,7 @@ struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI if (m_uiWarStompTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WAR_STOMP) == CAST_OK) - m_uiWarStompTimer = urand(25000, 30000); + m_uiWarStompTimer = urand(17000, 38000); } else m_uiWarStompTimer -= uiDiff; @@ -125,7 +125,7 @@ struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI if (m_uiArcaneVolleyTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_ARCANE_VOLLEY : SPELL_ARCANE_VOLLEY_H) == CAST_OK) - m_uiArcaneVolleyTimer = urand(20000, 35000); + m_uiArcaneVolleyTimer = urand(16000, 38000); } else m_uiArcaneVolleyTimer -= uiDiff; @@ -134,7 +134,7 @@ struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI if (m_uiSummonTreantsTimer < uiDiff) { SummonTreants(); - m_uiSummonTreantsTimer = 45000; + m_uiSummonTreantsTimer = urand(37000, 55000); } else m_uiSummonTreantsTimer -= uiDiff; @@ -146,18 +146,18 @@ struct MANGOS_DLL_DECL boss_warp_splinterAI : public ScriptedAI /*##### # mob_treant (Sapling) #####*/ -struct MANGOS_DLL_DECL npc_saplingAI : public ScriptedAI +struct npc_saplingAI : public ScriptedAI { - npc_saplingAI (Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + npc_saplingAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() + void Reset() override { // ToDo: This one may need further reserch - //m_creature->SetSpeedRate(MOVE_RUN, 0.5f); + // m_creature->SetSpeedRate(MOVE_RUN, 0.5f); } - void MoveInLineOfSight(Unit* pWho) { } - void UpdateAI(const uint32 uiDiff) + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; diff --git a/scripts/outland/tempest_keep/the_eye/boss_alar.cpp b/scripts/outland/tempest_keep/the_eye/boss_alar.cpp index d12f562e4..a0cd5e948 100644 --- a/scripts/outland/tempest_keep/the_eye/boss_alar.cpp +++ b/scripts/outland/tempest_keep/the_eye/boss_alar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: boss_alar -SD%Complete: 70 -SDComment: Dive Bomb event NYI +SD%Complete: 90 +SDComment: Boss movement should be improved. SDCategory: Tempest Keep, The Eye EndScriptData */ @@ -38,8 +38,8 @@ enum SPELL_DIVE_BOMB_VISUAL = 35367, // visual transform to fire ball SPELL_DIVE_BOMB = 35181, // dive bomb damage spell SPELL_BOMB_REBIRTH = 35369, // used after the dive bomb - to transform back to phoenis - SPELL_CHARGE = 35412, // used while in Dive Bomb form - to charge a target - //SPELL_SUMMON_ADDS = 18814, // summons 3*19551 - Not sure if the spell is the right id + SPELL_CHARGE = 35412, // charge a random target + // SPELL_SUMMON_ADDS = 18814, // summons 3*19551 - Not sure if the spell is the right id SPELL_BERSERK = 27680, // this spell is used only during phase II NPC_EMBER_OF_ALAR = 19551, // scripted in Acid @@ -55,6 +55,7 @@ enum PHASE_ONE = 1, PHASE_REBIRTH = 2, PHASE_TWO = 3, + PHASE_DIVE_BOMB = 4, }; struct EventLocation @@ -77,7 +78,7 @@ static const EventLocation aCenterLocation[] = {331.0, 0.01f, -2.39f}, }; -struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI +struct boss_alarAI : public ScriptedAI { boss_alarAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -96,11 +97,13 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI uint32 m_uiFlameQuillsTimer; uint32 m_uiFlamePatchTimer; uint32 m_uiDiveBombTimer; + uint32 m_uiChargeTimer; + uint32 m_uiRebirthTimer; uint32 m_uiMeltArmorTimer; bool m_bCanSummonEmber; - void Reset() + void Reset() override { // Start phase one and move to the closest platform m_uiPhase = PHASE_ONE; @@ -109,19 +112,21 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI m_uiRangeCheckTimer = 0; m_uiCurrentPlatformId = 0; m_uiPlatformMoveTimer = 35000; - m_uiFlameQuillsTimer = 170000; // at the 5th platform + m_uiFlameQuillsTimer = 170000; // at the 5th platform - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; // only after phase 2 starts + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; // only after phase 2 starts m_uiFlamePatchTimer = 20000; m_uiDiveBombTimer = 30000; m_uiMeltArmorTimer = 10000; + m_uiChargeTimer = 20000; + m_uiRebirthTimer = 0; m_bCanSummonEmber = true; } - void Aggro (Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if(m_pInstance) + if (m_pInstance) m_pInstance->SetData(TYPE_ALAR, IN_PROGRESS); // The boss will always move to the first platform from the left side; also set the movement to idle to stop the DB movement @@ -129,19 +134,19 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI m_creature->GetMotionMaster()->MovePoint(POINT_ID_PLATFORM, aPlatformLocation[m_uiCurrentPlatformId].m_fX, aPlatformLocation[m_uiCurrentPlatformId].m_fY, aPlatformLocation[m_uiCurrentPlatformId].m_fZ); } - void JustReachedHome() + void JustReachedHome() override { - if(m_pInstance) + if (m_pInstance) m_pInstance->SetData(TYPE_ALAR, FAIL); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - if(m_pInstance) + if (m_pInstance) m_pInstance->SetData(TYPE_ALAR, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FLAME_PATCH) pSummoned->CastSpell(pSummoned, SPELL_FLAME_PATCH, true); @@ -152,7 +157,7 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI } } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { // drain 3% of boss health when the ember dies if (pSummoned->GetEntry() == NPC_EMBER_OF_ALAR) @@ -163,7 +168,7 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI } } - void EnterEvadeMode() + void EnterEvadeMode() override { // Don't evade if the boss has the ember blast invisibility aura if (m_creature->HasAura(SPELL_EMBER_BLAST)) @@ -172,7 +177,7 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI ScriptedAI::EnterEvadeMode(); } - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { if (uiMotionType != POINT_MOTION_TYPE) return; @@ -180,11 +185,19 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI switch (uiPointId) { case POINT_ID_QUILLS: - if (DoCastSpellIfCan(m_creature, SPELL_FLAME_QUILLS) == CAST_OK) + if (m_uiPhase == PHASE_ONE) { - // Set the platform id so the boss will move to the last or the first platform - m_uiCurrentPlatformId = urand(0, 1) ? 2 : 3; - m_uiPlatformMoveTimer = 10000; + if (DoCastSpellIfCan(m_creature, SPELL_FLAME_QUILLS) == CAST_OK) + { + // Set the platform id so the boss will move to the last or the first platform + m_uiCurrentPlatformId = urand(0, 1) ? 2 : 3; + m_uiPlatformMoveTimer = 10000; + } + } + else if (m_uiPhase == PHASE_DIVE_BOMB) + { + if (DoCastSpellIfCan(m_creature, SPELL_DIVE_BOMB_VISUAL) == CAST_OK) + m_uiDiveBombTimer = 5000; } break; case POINT_ID_PLATFORM: @@ -216,7 +229,7 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI } } - void DamageTaken(Unit* pKiller, uint32& uiDamage) + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override { // Only init fake in phase one if (m_uiPhase != PHASE_ONE) @@ -251,9 +264,9 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if(!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Platform phase @@ -300,7 +313,7 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI if (m_uiBerserkTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) - m_uiBerserkTimer = 10*MINUTE*IN_MILLISECONDS; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; } else m_uiBerserkTimer -= uiDiff; @@ -323,6 +336,79 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI } else m_uiMeltArmorTimer -= uiDiff; + + if (m_uiChargeTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CHARGE) == CAST_OK) + m_uiChargeTimer = 20000; + } + } + else + m_uiChargeTimer -= uiDiff; + + if (m_uiDiveBombTimer) + { + if (m_uiDiveBombTimer <= uiDiff) + { + SetCombatMovement(false); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_QUILLS, aCenterLocation[0].m_fX, aCenterLocation[0].m_fY, aCenterLocation[0].m_fZ); + m_uiPhase = PHASE_DIVE_BOMB; + m_uiRangeCheckTimer = 0; + m_uiDiveBombTimer = 0; + } + else + m_uiDiveBombTimer -= uiDiff; + } + } + // Dive Bomb event + else if (m_uiPhase == PHASE_DIVE_BOMB) + { + if (m_uiDiveBombTimer) + { + if (m_uiDiveBombTimer <= uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_DIVE_BOMB) == CAST_OK) + { + m_creature->Relocate(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ()); + m_uiRebirthTimer = 2000; + m_uiDiveBombTimer = 0; + } + } + } + else + m_uiDiveBombTimer -= uiDiff; + } + + if (m_uiRebirthTimer) + { + if (m_uiRebirthTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BOMB_REBIRTH) == CAST_OK) + { + m_creature->RemoveAurasDueToSpell(SPELL_DIVE_BOMB_VISUAL); + SetCombatMovement(true, true); + + // Spawn 2 Embers of Alar + float fX, fY, fZ; + for (uint8 i = 0; i < 2; ++i) + { + m_creature->GetRandomPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 5.0f, fX, fY, fZ); + m_creature->SummonCreature(NPC_EMBER_OF_ALAR, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + + m_uiPhase = PHASE_TWO; + m_uiRangeCheckTimer = 2000; + m_uiDiveBombTimer = 30000; + m_uiRebirthTimer = 0; + } + } + else + m_uiRebirthTimer -= uiDiff; + } } // only cast flame buffet when not in motion @@ -342,9 +428,9 @@ struct MANGOS_DLL_DECL boss_alarAI : public ScriptedAI } }; -CreatureAI* GetAI_boss_alar(Creature *pCreature) +CreatureAI* GetAI_boss_alar(Creature* pCreature) { - return new boss_alarAI (pCreature); + return new boss_alarAI(pCreature); } void AddSC_boss_alar() diff --git a/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp b/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp index 6fe82e5ee..054b11d5e 100644 --- a/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp +++ b/scripts/outland/tempest_keep/the_eye/boss_astromancer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,8 +16,8 @@ /* ScriptData SDName: Boss_Astromancer -SD%Complete: 80 -SDComment: +SD%Complete: 90 +SDComment: Check if the split phase has some spells involved SDCategory: Tempest Keep, The Eye EndScriptData */ @@ -39,49 +39,52 @@ enum SPELL_ARCANE_MISSILES = 33031, SPELL_WRATH_OF_THE_ASTROMANCER = 42783, SPELL_BLINDING_LIGHT = 33009, - SPELL_FEAR = 34322, + SPELL_PSYHIC_SCREAM = 34322, + SPELL_SOLARIAN_TRANSFORM = 39117, SPELL_VOID_BOLT = 39329, + SPELL_MARK_OF_SOLARIAN = 33023, // acts as an enrage spell + // SPELL_ROTATE_ASTROMANCER = 33283, // purpose unk - SPELL_SPOTLIGHT = 25824, - NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT = 18928, - + // summoned creatures NPC_SOLARIUM_AGENT = 18925, NPC_SOLARIUM_PRIEST = 18806, + NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT = 18928, + // NPC_ASTROMANCER_TRIGGER = 18932, // purpose unk - MODEL_HUMAN = 18239, - MODEL_VOIDWALKER = 18988, + // summoned spells + SPELL_SPOTLIGHT = 25824, // visual aura on the spotlights SPELL_SOLARIUM_GREAT_HEAL = 33387, SPELL_SOLARIUM_HOLY_SMITE = 25054, SPELL_SOLARIUM_ARCANE_TORRENT = 33390, - WV_ARMOR = 31000 + WV_ARMOR = 31000, // ToDo: this value need to be checked + + MAX_SPOTLIGHTS = 3, + MAX_AGENTS = 4, }; -const float CENTER_X = 432.909f; -const float CENTER_Y = -373.424f; -const float CENTER_Z = 17.9608f; -const float CENTER_O = 1.06421f; -const float SMALL_PORTAL_RADIUS = 12.6f; -const float LARGE_PORTAL_RADIUS = 26.0f; -const float PORTAL_Z = 17.005f; +// Spells used to summon the Spotlights on 2.4.3 - Astromancer Split +// The boss had to choose 2 large radius split spells and 1 small radius split +// Large radius spotlight: 33189,33281,33282,33347,33348,33349,33350,33351 +// Small radius spotlight: 33352,33353,33354,33355 + +static const float fRoomCenter[4] = {432.909f, -373.424f, 17.9608f, 1.06421f}; +static const float fSpotlightRadius[2] = {13.0f, 25.0f}; enum Phases { - PHASE_NORMAL = 1, - PHASE_SUMMON_AGENTS = 2, - PHASE_SUMMON_PRIESTS = 3, - PHASE_VOID = 4, + PHASE_NORMAL = 1, + PHASE_SPLIT = 2, + PHASE_VOID = 3, }; -struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI +struct boss_high_astromancer_solarianAI : public ScriptedAI { boss_high_astromancer_solarianAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_uiDefaultArmor = m_creature->GetArmor(); - m_fDefaultSize = m_creature->GetFloatValue(OBJECT_FIELD_SCALE_X); Reset(); } @@ -92,49 +95,45 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI uint32 m_uiBlindingLightTimer; uint32 m_uiFearTimer; uint32 m_uiVoidBoltTimer; - uint32 m_uiPhaseOneTimer; - uint32 m_uiPhaseTwoTimer; - uint32 m_uiPhaseThreeTimer; - uint32 m_uiAppearDelayTimer; + uint32 m_uiSplitTimer; + uint32 m_uiSummonAgentsTimer; + uint32 m_uiSummonPriestsTimer; + uint32 m_uiDelayTimer; uint32 m_uiDefaultArmor; - float m_fDefaultSize; - - bool m_bIsAppearDelay; - Phases m_Phase; - float m_aPortals[3][3]; + GuidVector m_vSpotLightsGuidVector; - void Reset() + void Reset() override { - m_uiArcaneMissilesTimer = 2000; - m_uiWrathOfTheAstromancerTimer = 15000; - m_uiBlindingLightTimer = 41000; - m_uiFearTimer = 20000; - m_uiVoidBoltTimer = 10000; - m_uiPhaseOneTimer = 50000; - m_uiPhaseTwoTimer = 8000; - m_uiPhaseThreeTimer = 15000; - m_uiAppearDelayTimer = 2000; - m_bIsAppearDelay = false; - m_Phase = PHASE_NORMAL; - - if (m_pInstance) - m_pInstance->SetData(TYPE_SOLARIAN, NOT_STARTED); + m_uiArcaneMissilesTimer = 0; + m_uiWrathOfTheAstromancerTimer = urand(15000, 25000); + m_uiBlindingLightTimer = 35000; + m_uiFearTimer = 20000; + m_uiVoidBoltTimer = 10000; + m_uiSplitTimer = 50000; + m_uiSummonAgentsTimer = 0; + m_uiSummonPriestsTimer = 0; + m_uiDelayTimer = 0; + m_Phase = PHASE_NORMAL; + + // The vector will store the summoned spotlights + m_vSpotLightsGuidVector.reserve(MAX_SPOTLIGHTS); m_creature->SetArmor(m_uiDefaultArmor); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, m_fDefaultSize); - m_creature->SetDisplayId(MODEL_HUMAN); + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); SetCombatMovement(true); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { - switch(urand(0, 2)) + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + switch (urand(0, 2)) { case 0: DoScriptText(SAY_KILL1, m_creature); break; case 1: DoScriptText(SAY_KILL2, m_creature); break; @@ -142,18 +141,15 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI } } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, m_fDefaultSize); - m_creature->SetDisplayId(MODEL_HUMAN); - DoScriptText(SAY_DEATH, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_SOLARIAN, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -161,13 +157,21 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI m_pInstance->SetData(TYPE_SOLARIAN, IN_PROGRESS); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SOLARIAN, FAIL); + } + + void JustSummoned(Creature* pSummoned) override { switch (pSummoned->GetEntry()) { case NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT: + // Note: this should be moved to database pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); pSummoned->CastSpell(pSummoned, SPELL_SPOTLIGHT, false); + m_vSpotLightsGuidVector.push_back(pSummoned->GetObjectGuid()); break; case NPC_SOLARIUM_AGENT: case NPC_SOLARIUM_PRIEST: @@ -177,22 +181,14 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI } } - float Portal_X(float fRadius) + void DoSummonSpotlight(float fRadius, float fAngle, uint8 uiRandPoint) { - if (urand(0, 1)) - fRadius = -fRadius; - - return (fRadius * (float)(rand()%100)/100.0f + CENTER_X); - } - - float Portal_Y(float fX, float fRadius) - { - float fZ = urand(0, 1) ? 1.0f : -1.0f; - - return (fZ * sqrt(fRadius*fRadius - (fX - CENTER_X)*(fX - CENTER_X)) + CENTER_Y); + float fX, fY, fZ; + m_creature->GetNearPoint(m_creature, fX, fY, fZ, 0, fRadius, fAngle * uiRandPoint); + m_creature->SummonCreature(NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT, fX, fY, fZ, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -200,48 +196,58 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI // When Solarian reaches 20% she will transform into a huge void walker. if (m_Phase != PHASE_VOID && m_creature->GetHealthPercent() < 20.0f) { - m_Phase = PHASE_VOID; - - // To make sure she behaves like expected - m_bIsAppearDelay = false; - if (!IsCombatMovement()) + if (DoCastSpellIfCan(m_creature, SPELL_SOLARIAN_TRANSFORM) == CAST_OK) { - SetCombatMovement(true); - m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); - } - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); + DoScriptText(SAY_VOIDA, m_creature); + m_uiDelayTimer = 2000; - DoScriptText(SAY_VOIDA, m_creature); - DoScriptText(SAY_VOIDB, m_creature); + m_creature->SetArmor(WV_ARMOR); + m_Phase = PHASE_VOID; - m_creature->SetArmor(WV_ARMOR); - m_creature->SetDisplayId(MODEL_VOIDWALKER); - m_creature->SetFloatValue(OBJECT_FIELD_SCALE_X, m_fDefaultSize*2.5f); + if (m_creature->GetVisibility() != VISIBILITY_ON) + m_creature->SetVisibility(VISIBILITY_ON); + + // Stop the combat for a small delay + SetCombatMovement(false); + m_creature->GetMotionMaster()->MoveIdle(); + } } - if (m_bIsAppearDelay) + // Handle delays between combat phases + if (m_uiDelayTimer) { - if (m_uiAppearDelayTimer < uiDiff) + if (m_uiDelayTimer <= uiDiff) { - m_bIsAppearDelay = false; - - if (m_Phase == PHASE_SUMMON_AGENTS) + if (m_Phase == PHASE_SPLIT) { - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // select two different numbers between 0 and 7 so we will get different spawn points for the spotlights + uint8 uiPos1 = urand(0, 7); + uint8 uiPos2 = (uiPos1 + urand(1, 7)) % 8; + + // summon 3 spotlights + m_vSpotLightsGuidVector.clear(); + DoSummonSpotlight(fSpotlightRadius[0], M_PI_F / 2, urand(0, 3)); + DoSummonSpotlight(fSpotlightRadius[1], M_PI_F / 4, uiPos1); + DoSummonSpotlight(fSpotlightRadius[1], M_PI_F / 4, uiPos2); + m_creature->SetVisibility(VISIBILITY_OFF); + + DoScriptText(urand(0, 1) ? SAY_SUMMON1 : SAY_SUMMON2, m_creature); + m_uiSummonAgentsTimer = 6000; } - // Let move and attack again - else if (!IsCombatMovement()) + else if (m_Phase == PHASE_VOID) { + DoScriptText(SAY_VOIDB, m_creature); + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); } - m_uiAppearDelayTimer = 2000; + m_uiDelayTimer = 0; } else - m_uiAppearDelayTimer -= uiDiff; + m_uiDelayTimer -= uiDiff; // Combat is still on hold return; @@ -256,8 +262,8 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI // Target the tank ? if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_WRATH_OF_THE_ASTROMANCER, SELECT_FLAG_PLAYER)) { - if (DoCastSpellIfCan(pTarget, SPELL_WRATH_OF_THE_ASTROMANCER, CAST_INTERRUPT_PREVIOUS) == CAST_OK) - m_uiWrathOfTheAstromancerTimer = 25000; + if (DoCastSpellIfCan(pTarget, SPELL_WRATH_OF_THE_ASTROMANCER) == CAST_OK) + m_uiWrathOfTheAstromancerTimer = urand(15000, 25000); } else m_uiWrathOfTheAstromancerTimer = 10000; @@ -269,13 +275,13 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI if (m_uiBlindingLightTimer < uiDiff) { // She casts this spell every 45 seconds. It is a kind of Moonfire spell, which she strikes down on the whole raid simultaneously. It hits everyone in the raid for 2280 to 2520 arcane damage. - if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BLINDING_LIGHT) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_BLINDING_LIGHT) == CAST_OK) m_uiBlindingLightTimer = 45000; } else m_uiBlindingLightTimer -= uiDiff; - // Arcane Missiles Timer - TODO - check timer, if this spell is cast always, CombatMovement should be disabled here + // Arcane Missiles Timer if (m_uiArcaneMissilesTimer < uiDiff) { // Solarian casts Arcane Missiles on on random targets in the raid. @@ -288,112 +294,88 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI DoCastSpellIfCan(pTarget, SPELL_ARCANE_MISSILES); } - m_uiArcaneMissilesTimer = 5000; + m_uiArcaneMissilesTimer = urand(3000, 4000); } else m_uiArcaneMissilesTimer -= uiDiff; // Phase 1 Timer - if (m_uiPhaseOneTimer < uiDiff) + if (m_uiSplitTimer < uiDiff) { - m_Phase = PHASE_SUMMON_AGENTS; + // ToDo: the timer of this ability is around 45-50 seconds. Please check if this is correct! + DoCastSpellIfCan(m_creature, SPELL_MARK_OF_SOLARIAN, CAST_INTERRUPT_PREVIOUS); + m_Phase = PHASE_SPLIT; // After these 50 seconds she portals to the middle of the room and disappears, leaving 3 light portals behind. - m_creature->GetMotionMaster()->Clear(); - m_creature->StopMoving(); - m_creature->AttackStop(); - + // ToDo: check if there are some spells involved in this event! + m_creature->GetMotionMaster()->MoveIdle(); SetCombatMovement(false); + m_creature->NearTeleportTo(fRoomCenter[0], fRoomCenter[1], fRoomCenter[2], fRoomCenter[3], true); - m_creature->NearTeleportTo(CENTER_X, CENTER_Y, CENTER_Z, CENTER_O, true); - - for(int i = 0; i <= 2; ++i) - { - if (!i) - { - m_aPortals[i][0] = Portal_X(SMALL_PORTAL_RADIUS); - m_aPortals[i][1] = Portal_Y(m_aPortals[i][0], SMALL_PORTAL_RADIUS); - m_aPortals[i][2] = CENTER_Z; - } - else - { - m_aPortals[i][0] = Portal_X(LARGE_PORTAL_RADIUS); - m_aPortals[i][1] = Portal_Y(m_aPortals[i][0], LARGE_PORTAL_RADIUS); - m_aPortals[i][2] = PORTAL_Z; - } - } - - if ((abs(int(m_aPortals[2][0]) - int(m_aPortals[1][0])) < 7) && (abs(int(m_aPortals[2][1]) - int(m_aPortals[1][1])) < 7)) - { - int i = 1; - if (abs(int(CENTER_X) + int(26.0f) - int(m_aPortals[2][0])) < 7) - i = -1; - - m_aPortals[2][0] = m_aPortals[2][0]+7*i; - m_aPortals[2][1] = Portal_Y(m_aPortals[2][0], LARGE_PORTAL_RADIUS); - } - - for (int i = 0; i <= 2; ++i) - m_creature->SummonCreature(NPC_ASTROMANCER_SOLARIAN_SPOTLIGHT, m_aPortals[i][0], m_aPortals[i][1], m_aPortals[i][2], CENTER_O, TEMPSUMMON_TIMED_DESPAWN, m_uiPhaseTwoTimer+m_uiPhaseThreeTimer+m_uiAppearDelayTimer+1700); - - m_bIsAppearDelay = true; - m_uiPhaseOneTimer = 48000; // 2s for appearDelay - + m_uiDelayTimer = 1000; + m_uiSplitTimer = 50000; // Do nothing more, if phase switched return; } else - m_uiPhaseOneTimer -= uiDiff; + m_uiSplitTimer -= uiDiff; DoMeleeAttackIfReady(); break; - case PHASE_SUMMON_AGENTS: - // Check Phase 2 Timer - if (m_uiPhaseTwoTimer < uiDiff) + case PHASE_SPLIT: + + // Summon 4 Agents on each portal + if (m_uiSummonAgentsTimer) { - //10 seconds after Solarian disappears, 12 mobs spawn out of the three portals. - m_Phase = PHASE_SUMMON_PRIESTS; - for (int i = 0; i <= 2; ++i) + if (m_uiSummonAgentsTimer <= uiDiff) { - for (int j = 1; j <= 4; ++j) - m_creature->SummonCreature(NPC_SOLARIUM_AGENT, m_aPortals[i][0], m_aPortals[i][1], m_aPortals[i][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); + for (uint8 i = 0; i < MAX_SPOTLIGHTS; ++i) + { + if (Creature* pSpotlight = m_creature->GetMap()->GetCreature(m_vSpotLightsGuidVector[i])) + { + for (uint8 j = 0; j < MAX_AGENTS; ++j) + m_creature->SummonCreature(NPC_SOLARIUM_AGENT, pSpotlight->GetPositionX(), pSpotlight->GetPositionY(), pSpotlight->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + } + m_uiSummonAgentsTimer = 0; + m_uiSummonPriestsTimer = 15000; } - - DoScriptText(SAY_SUMMON1, m_creature); - - m_uiPhaseTwoTimer = 8000; // 2s for appearDelay + else + m_uiSummonAgentsTimer -= uiDiff; } - else - m_uiPhaseTwoTimer -= uiDiff; - - break; - case PHASE_SUMMON_PRIESTS: - // Check Phase 3 Timer - if (m_uiPhaseThreeTimer < uiDiff) + if (m_uiSummonPriestsTimer) { - m_Phase = PHASE_NORMAL; - - // 15 seconds later Solarian reappears out of one of the 3 portals. Simultaneously, 2 healers appear in the two other portals. - int i = irand(0, 2); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMap()->CreatureRelocation(m_creature, m_aPortals[i][0], m_aPortals[i][1], m_aPortals[i][2], CENTER_O); - - for (int j = 0; j <= 2; ++j) - if (j != i) - m_creature->SummonCreature(NPC_SOLARIUM_PRIEST, m_aPortals[j][0], m_aPortals[j][1], m_aPortals[j][2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetVisibility(VISIBILITY_ON); - - DoScriptText(SAY_SUMMON2, m_creature); - - m_bIsAppearDelay = true; - m_uiPhaseThreeTimer = 15000; + if (m_uiSummonPriestsTimer < uiDiff) + { + m_Phase = PHASE_NORMAL; + // Randomize the portals + std::random_shuffle(m_vSpotLightsGuidVector.begin(), m_vSpotLightsGuidVector.end()); + // Summon 2 priests + for (uint8 i = 0; i < 2; ++i) + { + if (Creature* pSpotlight = m_creature->GetMap()->GetCreature(m_vSpotLightsGuidVector[i])) + m_creature->SummonCreature(NPC_SOLARIUM_PRIEST, pSpotlight->GetPositionX(), pSpotlight->GetPositionY(), pSpotlight->GetPositionZ(), 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } + // Teleport the boss at the last portal + if (Creature* pSpotlight = m_creature->GetMap()->GetCreature(m_vSpotLightsGuidVector[2])) + m_creature->NearTeleportTo(pSpotlight->GetPositionX(), pSpotlight->GetPositionY(), pSpotlight->GetPositionZ(), pSpotlight->GetOrientation(), true); + + SetCombatMovement(true); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim()); + + // Set as visible and reset spells timers + m_creature->SetVisibility(VISIBILITY_ON); + m_uiArcaneMissilesTimer = 0; + m_uiSummonPriestsTimer = 0; + m_uiBlindingLightTimer = 35000; + m_uiWrathOfTheAstromancerTimer = urand(15000, 25000); + } + else + m_uiSummonPriestsTimer -= uiDiff; } - else - m_uiPhaseThreeTimer -= uiDiff; break; @@ -401,7 +383,7 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI // Fear Timer if (m_uiFearTimer < uiDiff) { - if (DoCastSpellIfCan(m_creature, SPELL_FEAR) == CAST_OK) + if (DoCastSpellIfCan(m_creature, SPELL_PSYHIC_SCREAM) == CAST_OK) m_uiFearTimer = 20000; } else @@ -422,51 +404,43 @@ struct MANGOS_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI } }; -struct MANGOS_DLL_DECL mob_solarium_priestAI : public ScriptedAI +struct mob_solarium_priestAI : public ScriptedAI { - mob_solarium_priestAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); - } - - ScriptedInstance* m_pInstance; + mob_solarium_priestAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } uint32 m_uiHealTimer; uint32 m_uiHolySmiteTimer; uint32 m_uiAoESilenceTimer; - void Reset() + void Reset() override { m_uiHealTimer = 9000; m_uiHolySmiteTimer = 1; m_uiAoESilenceTimer = 15000; } - void UpdateAI(const uint32 uiDiff) + void AttackStart(Unit* pWho) override + { + if (m_creature->Attack(pWho, true)) + { + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 25.0f); + } + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiHealTimer < uiDiff) { - Creature* pTarget = NULL; - - switch(urand(0, 1)) + if (Unit* pTarget = DoSelectLowestHpFriendly(50.0f)) { - case 0: - if (m_pInstance) - pTarget = m_pInstance->GetSingleCreatureFromStorage(NPC_ASTROMANCER); - break; - case 1: - pTarget = m_creature; - break; - } - - if (pTarget) - { - DoCastSpellIfCan(pTarget, SPELL_SOLARIUM_GREAT_HEAL); - m_uiHealTimer = 9000; + if (DoCastSpellIfCan(pTarget, SPELL_SOLARIUM_GREAT_HEAL) == CAST_OK) + m_uiHealTimer = 9000; } } else @@ -474,16 +448,19 @@ struct MANGOS_DLL_DECL mob_solarium_priestAI : public ScriptedAI if (m_uiHolySmiteTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SOLARIUM_HOLY_SMITE); - m_uiHolySmiteTimer = 4000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_SOLARIUM_HOLY_SMITE) == CAST_OK) + m_uiHolySmiteTimer = 4000; + } } else m_uiHolySmiteTimer -= uiDiff; if (m_uiAoESilenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SOLARIUM_ARCANE_TORRENT); - m_uiAoESilenceTimer = 13000; + if (DoCastSpellIfCan(m_creature, SPELL_SOLARIUM_ARCANE_TORRENT) == CAST_OK) + m_uiAoESilenceTimer = 13000; } else m_uiAoESilenceTimer -= uiDiff; diff --git a/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp b/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp index b4fb4a08f..20be2ab7b 100644 --- a/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp +++ b/scripts/outland/tempest_keep/the_eye/boss_kaelthas.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,18 +16,18 @@ /* ScriptData SDName: Boss_Kaelthas -SD%Complete: 60 -SDComment: SQL, weapon scripts, mind control, need correct spells(interruptible/uninterruptible), phoenix spawn location & animation, phoenix behaviour & spawn during gravity lapse +SD%Complete: 80 +SDComment: Timers; Transition phase is incomplete, some spells are unk. SDCategory: Tempest Keep, The Eye EndScriptData */ #include "precompiled.h" #include "the_eye.h" -#include "WorldPacket.h" enum { - //kael'thas Speech + // ***** Event yells ******** + // kael'thas Speech SAY_INTRO = -1550016, SAY_INTRO_CAPERNIAN = -1550017, SAY_INTRO_TELONICUS = -1550018, @@ -47,25 +47,28 @@ enum SAY_SUMMON_PHOENIX1 = -1550032, SAY_SUMMON_PHOENIX2 = -1550033, SAY_DEATH = -1550034, + EMOTE_PYROBLAST = -1550044, - //Thaladred the Darkener speech + // Thaladred the Darkener speech SAY_THALADRED_AGGRO = -1550035, SAY_THALADRED_DEATH = -1550036, EMOTE_THALADRED_GAZE = -1550037, - //Lord Sanguinar speech + // Lord Sanguinar speech SAY_SANGUINAR_AGGRO = -1550038, SAY_SANGUINAR_DEATH = -1550039, - //Grand Astromancer Capernian speech + // Grand Astromancer Capernian speech SAY_CAPERNIAN_AGGRO = -1550040, SAY_CAPERNIAN_DEATH = -1550041, - //Master Engineer Telonicus speech + // Master Engineer Telonicus speech SAY_TELONICUS_AGGRO = -1550042, SAY_TELONICUS_DEATH = -1550043, - //Phase 2 spells + // ***** Kaelthas spells ******** + // Phase 2 spells + SPELL_KAEL_PHASE_2 = 36709, // not sure if this is used in the right way SPELL_SUMMON_WEAPONS = 36976, SPELL_SUMMON_WEAPONA = 36958, SPELL_SUMMON_WEAPONB = 36959, @@ -74,1180 +77,930 @@ enum SPELL_SUMMON_WEAPONE = 36962, SPELL_SUMMON_WEAPONF = 36963, SPELL_SUMMON_WEAPONG = 36964, - SPELL_RES_VISUAL = 24171, + SPELL_RESURRECTION = 36450, - //Phase 4 spells - SPELL_FIREBALL = 22088, //wrong but works with CastCustomSpell + // Phase 4 spells + SPELL_FIREBALL = 36805, SPELL_PYROBLAST = 36819, - SPELL_FLAME_STRIKE = 36735, // summons + SPELL_FLAME_STRIKE = 36735, // summons 21369 SPELL_FLAME_STRIKE_DUMMY = 36730, SPELL_ARCANE_DISRUPTION = 36834, SPELL_SHOCK_BARRIER = 36815, - SPELL_PHOENIX_ANIMATION = 36723, + SPELL_PHOENIX_ANIMATION = 36723, // summons 21362 SPELL_MIND_CONTROL = 32830, - //Phase 5 spells + // Phase 5 spells + SPELL_GAIN_POWER = 36091, SPELL_EXPLODE = 36092, + // SPELL_EXPLODE_1 = 36354, // it's not very clear what all these spells should do + SPELL_EXPLODE_2 = 36373, + // SPELL_EXPLODE_3 = 36375, + // SPELL_EXPLODE_4 = 36376, + // SPELL_KAEL_STUN = 36185, // purpose unk SPELL_FULLPOWER = 36187, - SPELL_KNOCKBACK = 11027, - SPELL_GRAVITY_LAPSE = 34480, - SPELL_GRAVITY_LAPSE_AURA = 39432, - SPELL_NETHER_BEAM = 35873, - - //Thaladred the Darkener spells - SPELL_PSYCHIC_BLOW = 10689, + SPELL_GRAVITY_LAPSE = 35941, + SPELL_GRAVITY_LAPSE_KNOCKBACK = 34480, // cast by players - damage effect + SPELL_GRAVITY_LAPSE_AURA = 39432, // cast by players - fly effect + SPELL_NETHER_BEAM = 35869, // triggers 35873 on target + SPELL_NETHER_VAPOR_SUMMON = 35865, // script effect - probably related to 35879 + + // ***** Advisors spells ******** + // Thaladred the Darkener spells + SPELL_PSYCHIC_BLOW = 36966, SPELL_SILENCE = 30225, - //Lord Sanguinar spells - SPELL_BELLOWING_ROAR = 40636, - //Grand Astromancer Capernian spells + SPELL_REND = 36965, + + // Lord Sanguinar spells + SPELL_BELLOWING_ROAR = 44863, + // Grand Astromancer Capernian spells SPELL_CAPERNIAN_FIREBALL = 36971, SPELL_CONFLAGRATION = 37018, - SPELL_ARCANE_EXPLOSION = 36970, - //Master Engineer Telonicus spells + SPELL_ARCANE_BURST = 36970, + + // Master Engineer Telonicus spells SPELL_BOMB = 37036, SPELL_REMOTE_TOY = 37027, - //Nether Vapor spell - SPELL_NETHER_VAPOR = 35859, - //Phoenix spell + + // ***** Other summons spells ******** + // Nether Vapor spell + SPELL_NETHER_VAPOR = 35858, + // Phoenix spell SPELL_BURN = 36720, SPELL_EMBER_BLAST = 34341, - SPELL_REBIRTH = 41587, + SPELL_REBIRTH = 35369, - //Creature IDs + // ***** Creature Entries ******** NPC_FLAME_STRIKE_TRIGGER = 21369, NPC_PHOENIX = 21362, NPC_PHOENIX_EGG = 21364, - - //Phoenix egg and phoenix model - MODEL_ID_PHOENIX = 19682, - MODEL_ID_PHOENIX_EGG = 20245, - - MAX_ADVISORS = 4 + NPC_NETHER_VAPOR = 21002, + + // ***** Other ******** + PHASE_0_NOT_BEGUN = 0, + PHASE_1_ADVISOR = 1, + PHASE_2_WEAPON = 2, + PHASE_3_ADVISOR_ALL = 3, + PHASE_4_SOLO = 4, + PHASE_5_WAITING = 5, + PHASE_6_FLYING = 6, + PHASE_7_GRAVITY = 7, + + POINT_ID_CENTER = 1, + POINT_ID_AIR = 2, + + MAX_WEAPONS = 7, + MAX_MIND_CONTROL = 3, }; -static const uint32 aAdvisors[MAX_ADVISORS] = {NPC_THALADRED, NPC_SANGUINAR, NPC_CAPERNIAN, NPC_TELONICUS}; - -uint32 m_auiSpellSummonWeapon[]= +static const uint32 m_auiSpellSummonWeapon[MAX_WEAPONS] = { SPELL_SUMMON_WEAPONA, SPELL_SUMMON_WEAPONB, SPELL_SUMMON_WEAPONC, SPELL_SUMMON_WEAPOND, SPELL_SUMMON_WEAPONE, SPELL_SUMMON_WEAPONF, SPELL_SUMMON_WEAPONG }; -const float CAPERNIAN_DISTANCE = 20.0f; //she casts away from the target -const float KAEL_VISIBLE_RANGE = 50.0f; +// teleport spells for gravity lapse event +static const uint32 m_auiSpellGravityLapseTeleport[] = +{ + 35966, 35967, 35968, 35969, 35970, 35971, 35972, 35973, 35974, 35975, 35976, 35977, 35978, 35979, 35980, + 35981, 35982, 35983, 35984, 35985, 35986, 35987, 35988, 35989, 35990 +}; -const float afGravityPos[3] = {795.0f, 0.0f, 70.0f}; +static const float aCenterPos[3] = {795.00f, -0.46f, 48.72f}; -#define TIME_PHASE_2_3 120000 -#define TIME_PHASE_3_4 180000 +/*###### +## boss_kaelthas +######*/ -//Base AI for Advisors -struct MANGOS_DLL_DECL advisorbase_ai : public ScriptedAI +struct boss_kaelthasAI : public ScriptedAI { - advisorbase_ai(Creature* pCreature) : ScriptedAI(pCreature) + boss_kaelthasAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bDoubled_Health = false; Reset(); } - protected: - int32 m_iAdvisor_Speech; - public: ScriptedInstance* m_pInstance; - bool m_bFakeDeath; - bool m_bDoubled_Health; - uint32 m_uiDelayRes_Timer; - ObjectGuid m_delayResTargetGuid; - void Reset() - { - if (m_bDoubled_Health) - { - m_creature->SetMaxHealth(m_creature->GetMaxHealth() / 2); - m_bDoubled_Health = false; - } + uint32 m_uiFireballTimer; + uint32 m_uiArcaneDisruptionTimer; + uint32 m_uiPhoenixTimer; + uint32 m_uiFlameStrikeTimer; - m_bFakeDeath = false; - m_uiDelayRes_Timer = 0; - m_delayResTargetGuid.Clear(); + uint32 m_uiPyroblastTimer; + uint32 m_uiShockBarrierTimer; + uint32 m_uiMindControlTimer; + uint32 m_uiExplodeTimer; - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - //reset encounter - if (m_pInstance && (m_pInstance->GetData(TYPE_KAELTHAS_PHASE) == PHASE_1_ADVISOR || m_pInstance->GetData(TYPE_KAELTHAS_PHASE) == PHASE_3_ADVISOR_ALL)) - { - if (Creature* pKaelthas = m_pInstance->GetSingleCreatureFromStorage(NPC_KAELTHAS)) - pKaelthas->AI()->EnterEvadeMode(); - } - } + uint32 m_uiGravityLapseTimer; + uint32 m_uiGravityExpireTimer; + uint32 m_uiNetherBeamTimer; + uint32 m_uiNetherVaporTimer; + uint8 m_uiGravityIndex; - void MoveInLineOfSight(Unit* pWho) - { - if (!pWho || m_bFakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::MoveInLineOfSight(pWho); - } + uint32 m_uiPhaseTimer; + uint8 m_uiPhase; + uint8 m_uiPhaseSubphase; - void AttackStart(Unit* pWho) + void Reset() override { - if (!pWho || m_bFakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - ScriptedAI::AttackStart(pWho); - } + // Phases + m_uiPhase = PHASE_0_NOT_BEGUN; + m_uiPhaseTimer = 23000; + m_uiPhaseSubphase = 0; + + // Spells + m_uiFireballTimer = urand(1000, 3000); + m_uiArcaneDisruptionTimer = 45000; + m_uiPhoenixTimer = 50000; + m_uiFlameStrikeTimer = 30000; + + m_uiShockBarrierTimer = 60000; + m_uiMindControlTimer = 40000; + m_uiPyroblastTimer = 0; + m_uiExplodeTimer = 0; + + m_uiGravityLapseTimer = 12000; + m_uiGravityExpireTimer = 0; + m_uiNetherBeamTimer = 8000; + m_uiNetherVaporTimer = 10000; + m_uiGravityIndex = 0; - void Revive(Unit* Target) - { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - // double health for phase 3 - m_creature->SetMaxHealth(m_creature->GetMaxHealth() * 2); - m_bDoubled_Health = true; - m_creature->SetHealth(m_creature->GetMaxHealth()); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - DoCastSpellIfCan(m_creature, SPELL_RES_VISUAL); - m_uiDelayRes_Timer = 2000; + SetCombatMovement(true); } - void JustDied(Unit* pKiller) + void GetAIInformation(ChatHandler& reader) override { - if (m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS_PHASE) == PHASE_3_ADVISOR_ALL) - DoScriptText(m_iAdvisor_Speech, m_creature); + reader.PSendSysMessage("Kael'thas is currently in phase %u", m_uiPhase); } - void DamageTaken(Unit* pKiller, uint32 &damage) + // Custom Move in LoS function + void MoveInLineOfSight(Unit* pWho) override { - if (damage < m_creature->GetHealth()) - return; - - //Prevent glitch if in fake death - if (m_bFakeDeath && m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS_PHASE) != PHASE_0_NOT_BEGUN) + if (m_uiPhase == PHASE_0_NOT_BEGUN && pWho->GetTypeId() == TYPEID_PLAYER && !((Player*)pWho)->isGameMaster() && + m_creature->IsWithinDistInMap(pWho, m_creature->GetAttackDistance(pWho)) && m_creature->IsWithinLOSInMap(pWho)) { - damage = 0; - return; - } + DoScriptText(SAY_INTRO, m_creature); + m_uiPhase = PHASE_1_ADVISOR; - //Don't really die in phase 1 & 3, only die after that - if (m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS_PHASE) != PHASE_0_NOT_BEGUN) - { - //prevent death - damage = 0; - m_bFakeDeath = true; - - m_creature->InterruptNonMeleeSpells(false); - m_creature->SetHealth(0); - m_creature->StopMoving(); - m_creature->ClearComboPointHolders(); - m_creature->RemoveAllAurasOnDeath(); - m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->ClearAllReactives(); - m_creature->SetTargetGuid(ObjectGuid()); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - JustDied(pKiller); + // Set the player in combat with the boss + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho); - if (m_creature->getVictim()) - m_delayResTargetGuid = m_creature->getVictim()->GetObjectGuid(); + if (m_pInstance) + m_pInstance->SetData(TYPE_KAELTHAS, IN_PROGRESS); } } - void UpdateAI(const uint32 uiDiff) + void AttackStart(Unit* pWho) override { - if (m_uiDelayRes_Timer) + if (m_creature->Attack(pWho, true)) { - if (m_uiDelayRes_Timer <= uiDiff) - { - m_uiDelayRes_Timer = 0; - m_bFakeDeath = false; - - Unit* pTarget = m_creature->GetMap()->GetUnit(m_delayResTargetGuid); - - if (!pTarget || !pTarget->isAlive()) - pTarget = m_creature->getVictim(); - - if (!pTarget) - return; - - DoResetThreat(); - AttackStart(pTarget); - // In case of same target as before, AttackStart and Attack won't set the target guid. - m_creature->SetTargetGuid(pTarget->GetObjectGuid()); - - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveChase(pTarget); - } - else - m_uiDelayRes_Timer -= uiDiff; + m_creature->AddThreat(pWho); + m_creature->SetInCombatWith(pWho); + pWho->SetInCombatWith(m_creature); + DoStartMovement(pWho, 25.0f); } } -}; - -//Kael'thas AI -struct MANGOS_DLL_DECL boss_kaelthasAI : public ScriptedAI -{ - boss_kaelthasAI(Creature* pCreature) : ScriptedAI(pCreature) + void KilledUnit(Unit* /*pUnit*/) override { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - Reset(); + switch (urand(0, 2)) + { + case 0: DoScriptText(SAY_SLAY1, m_creature); break; + case 1: DoScriptText(SAY_SLAY2, m_creature); break; + case 2: DoScriptText(SAY_SLAY3, m_creature); break; + } } - ScriptedInstance* m_pInstance; - - uint32 m_uiFireball_Timer; - uint32 m_uiArcaneDisruption_Timer; - uint32 m_uiPhoenix_Timer; - uint32 m_uiShockBarrier_Timer; - uint32 m_uiGravityLapse_Timer; - uint32 m_uiGravityLapse_Phase; - uint32 m_uiNetherBeam_Timer; - uint32 m_uiNetherVapor_Timer; - uint32 m_uiFlameStrike_Timer; - uint32 m_uiMindControl_Timer; - uint32 m_uiPhase; - uint32 m_uiPhaseSubphase; //generic - uint32 m_uiPhase_Timer; //generic timer - uint32 m_uiPyrosCasted; - - bool m_bInGravityLapse; - bool m_bIsCastingFireball; - bool m_bChainPyros; - - void Reset() + void JustDied(Unit* /*pKiller*/) override { - m_uiFireball_Timer = urand(5000, 15000); - m_uiArcaneDisruption_Timer = 45000; - m_uiMindControl_Timer = 40000; - m_uiPhoenix_Timer = 50000; - m_uiShockBarrier_Timer = 60000; - m_uiFlameStrike_Timer = 30000; - m_uiGravityLapse_Timer = 20000; - m_uiGravityLapse_Phase = 0; - m_uiNetherBeam_Timer = 8000; - m_uiNetherVapor_Timer = 10000; - m_uiPyrosCasted = 0; - m_uiPhase = 0; - m_bInGravityLapse = false; - m_bIsCastingFireball = false; - m_bChainPyros = false; - - if (m_creature->isInCombat()) - PrepareAdvisors(); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoScriptText(SAY_DEATH, m_creature); if (m_pInstance) - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_0_NOT_BEGUN); + m_pInstance->SetData(TYPE_KAELTHAS, DONE); } - void PrepareAdvisors() + void JustReachedHome() override { - if (!m_pInstance) - return; - - for(uint8 i = 0; i < MAX_ADVISORS; ++i) - { - if (Creature* pCreature = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[i])) - { - pCreature->Respawn(); - pCreature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pCreature->setFaction(m_creature->getFaction()); - pCreature->AI()->EnterEvadeMode(); - } - } + if (m_pInstance) + m_pInstance->SetData(TYPE_KAELTHAS, FAIL); } - void StartEvent() + void JustSummoned(Creature* pSummoned) override { - if (!m_pInstance) - return; - - bool bAdivsorsFound = true; - for (uint8 i = 0; i < MAX_ADVISORS; ++i) - { - if (!m_pInstance->GetSingleCreatureFromStorage(aAdvisors[i])) - bAdivsorsFound = false; - } - - if (!bAdivsorsFound) - { - error_log("SD2: Kael'Thas One or more advisors missing, Skipping Phases 1-3"); - - DoScriptText(SAY_PHASE4_INTRO2, m_creature); - - m_uiPhase = PHASE_4_SOLO; - - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_4_SOLO); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - AttackStart(pTarget); - - } + if (pSummoned->GetEntry() == NPC_FLAME_STRIKE_TRIGGER) + pSummoned->CastSpell(pSummoned, SPELL_FLAME_STRIKE_DUMMY, false, NULL, NULL, m_creature->GetObjectGuid()); + else if (pSummoned->GetEntry() == NPC_NETHER_VAPOR) + pSummoned->CastSpell(pSummoned, SPELL_NETHER_VAPOR, false, NULL, NULL, m_creature->GetObjectGuid()); + // Start combat for Weapons of Phoenix else - { - PrepareAdvisors(); - - DoScriptText(SAY_INTRO, m_creature); - - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_1_ADVISOR); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - m_uiPhaseSubphase = 0; - m_uiPhase_Timer = 23000; - m_uiPhase = PHASE_1_ADVISOR; - } + pSummoned->SetInCombatWithZone(); } - void MoveInLineOfSight(Unit* pWho) + void SpellHit(Unit* /*pCaster*/, const SpellEntry* pSpell) override { - if (pWho->isTargetableForAttack() && - m_creature->IsHostileTo(pWho) && pWho->isInAccessablePlaceFor(m_creature)) + // Handle summon weapons event + if (pSpell->Id == SPELL_SUMMON_WEAPONS) { - if (!m_creature->CanFly() && m_creature->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = m_creature->GetAttackDistance(pWho); - if (m_creature->IsWithinDistInMap(pWho, attackRadius) && m_creature->IsWithinLOSInMap(pWho)) - { - if (!m_creature->getVictim() && m_uiPhase >= PHASE_4_SOLO) - { - pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(pWho); - } - else if (m_creature->GetMap()->IsDungeon()) - { - if (m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS_PHASE) == PHASE_0_NOT_BEGUN && !m_uiPhase) - StartEvent(); + for (uint8 i = 0; i < MAX_WEAPONS; ++i) + DoCastSpellIfCan(m_creature, m_auiSpellSummonWeapon[i], CAST_TRIGGERED); - pWho->SetInCombatWith(m_creature); - m_creature->AddThreat(pWho); - } - } + m_uiPhase = PHASE_2_WEAPON; + m_uiPhaseTimer = 120000; } } - void Aggro(Unit* pWho) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { - if (m_pInstance && m_pInstance->GetData(TYPE_KAELTHAS_PHASE) == PHASE_0_NOT_BEGUN && !m_uiPhase) - StartEvent(); - } - - void KilledUnit(Unit* pUnit) - { - switch(urand(0, 2)) + // Handle gravity lapse teleport - each player hit has his own teleport spell + if (pSpell->Id == SPELL_GRAVITY_LAPSE && pTarget->GetTypeId() == TYPEID_PLAYER) { - case 0: DoScriptText(SAY_SLAY1, m_creature); break; - case 1: DoScriptText(SAY_SLAY2, m_creature); break; - case 2: DoScriptText(SAY_SLAY3, m_creature); break; + DoCastSpellIfCan(pTarget, m_auiSpellGravityLapseTeleport[m_uiGravityIndex], CAST_TRIGGERED); + pTarget->CastSpell(pTarget, SPELL_GRAVITY_LAPSE_KNOCKBACK, true, NULL, NULL, m_creature->GetObjectGuid()); + pTarget->CastSpell(pTarget, SPELL_GRAVITY_LAPSE_AURA, true, NULL, NULL, m_creature->GetObjectGuid()); + ++m_uiGravityIndex; } } - void JustSummoned(Creature* pSummoned) + void MovementInform(uint32 uiMotionType, uint32 uiPointId) override { - if (pSummoned->GetEntry() == NPC_FLAME_STRIKE_TRIGGER) - { - pSummoned->CastSpell(pSummoned, SPELL_FLAME_STRIKE_DUMMY, false, NULL, NULL, m_creature->GetObjectGuid()); + if (uiMotionType != POINT_MOTION_TYPE || !uiPointId) return; - } - if (pSummoned->GetEntry() == NPC_PHOENIX) + if (uiPointId == POINT_ID_CENTER) { - return; + if (m_uiPhase == PHASE_5_WAITING) + { + // ToDo: also start channeling to the giant crystals nearby + m_creature->SetLevitate(true); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_AIR, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ() + 30.0f, false); + m_uiPhaseTimer = 0; + m_uiPhase = PHASE_6_FLYING; + } + else if (m_uiPhase == PHASE_6_FLYING) + { + SetCombatMovement(true); + m_creature->SetLevitate(false); + m_creature->InterruptNonMeleeSpells(false); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim(), 25.0f); + m_uiShockBarrierTimer = 10000; + m_uiPhase = PHASE_7_GRAVITY; + } + } + if (uiPointId == POINT_ID_AIR) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLODE_2) == CAST_OK) + { + // ToDo: start channeling some additional crystals + // Also it's not very clear which other spells should be used here (which modifies his scale) + m_uiExplodeTimer = 8000; + } } - - // if not phoenix or trigger, then it's one of the 7 weapons - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - pSummoned->AI()->AttackStart(pTarget); } - void JustDied(Unit* pKiller) + void AdvisorDefeated(uint32 uiEntry) { - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - DoScriptText(SAY_DEATH, m_creature); + if (m_uiPhase != PHASE_1_ADVISOR) + return; - if (m_pInstance) + // Handle phase 1 end + if (uiEntry == NPC_TELONICUS) { - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_6_COMPLETE); - - for (uint8 i = 0; i < MAX_ADVISORS; ++i) - { - if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[i])) - pAdvisor->DealDamage(pAdvisor, pAdvisor->GetMaxHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - } + if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_WEAPONS) == CAST_OK) + DoScriptText(SAY_PHASE2_WEAPON, m_creature); } + else + m_uiPhaseTimer = 1000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Phase 1 switch (m_uiPhase) { + // ***** Advisors phase ******** case PHASE_1_ADVISOR: { - Unit* pTarget = NULL; - Creature* pAdvisor = NULL; + if (!m_uiPhaseTimer) + return; - //Subphase switch - switch(m_uiPhaseSubphase) + if (m_uiPhaseTimer <= uiDiff) { - //Subphase 1 - Start - case 0: - if (m_uiPhase_Timer < uiDiff) - { - DoScriptText(SAY_INTRO_THALADRED, m_creature); - - //start advisor within 7 seconds - m_uiPhase_Timer = 7000; - ++m_uiPhaseSubphase; - } - else - m_uiPhase_Timer -= uiDiff; + if (!m_pInstance) + return; - break; - - //Subphase 1 - Unlock advisor - case 1: - if (m_uiPhase_Timer < uiDiff) - { - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[0]); + switch (m_uiPhaseSubphase) + { + case 0: + DoScriptText(SAY_INTRO_THALADRED, m_creature); + m_uiPhaseTimer = 7000; + break; - if (pAdvisor) + case 1: + if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(NPC_THALADRED)) { pAdvisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pAdvisor->setFaction(m_creature->getFaction()); - - pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget) - pAdvisor->AI()->AttackStart(pTarget); + pAdvisor->SetInCombatWithZone(); } + m_uiPhaseTimer = 0; + break; - ++m_uiPhaseSubphase; - } - else - m_uiPhase_Timer -= uiDiff; - - break; - - //Subphase 2 - Start - case 2: - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[0]); - - if (pAdvisor && (pAdvisor->getStandState() == UNIT_STAND_STATE_DEAD)) - { + case 2: DoScriptText(SAY_INTRO_SANGUINAR, m_creature); + m_uiPhaseTimer = 12500; + break; - //start advisor within 12.5 seconds - m_uiPhase_Timer = 12500; - ++m_uiPhaseSubphase; - } - break; - - //Subphase 2 - Unlock advisor - case 3: - if (m_uiPhase_Timer < uiDiff) - { - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[1]); - - if (pAdvisor) + case 3: + if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(NPC_SANGUINAR)) { pAdvisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pAdvisor->setFaction(m_creature->getFaction()); - - pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget) - pAdvisor->AI()->AttackStart(pTarget); + pAdvisor->SetInCombatWithZone(); } + m_uiPhaseTimer = 0; + break; - ++m_uiPhaseSubphase; - } - else - m_uiPhase_Timer -= uiDiff; - - break; - - //Subphase 3 - Start - case 4: - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[1]); - - if (pAdvisor && (pAdvisor->getStandState() == UNIT_STAND_STATE_DEAD)) - { + case 4: DoScriptText(SAY_INTRO_CAPERNIAN, m_creature); + m_uiPhaseTimer = 7000; + break; - //start advisor within 7 seconds - m_uiPhase_Timer = 7000; - ++m_uiPhaseSubphase; - } - break; - - //Subphase 3 - Unlock advisor - case 5: - if (m_uiPhase_Timer < uiDiff) - { - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[2]); - - if (pAdvisor) + case 5: + if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(NPC_CAPERNIAN)) { pAdvisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pAdvisor->setFaction(m_creature->getFaction()); - - pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget) - pAdvisor->AI()->AttackStart(pTarget); + pAdvisor->SetInCombatWithZone(); } + m_uiPhaseTimer = 0; + break; - ++m_uiPhaseSubphase; - } - else - m_uiPhase_Timer -= uiDiff; - - break; - - //Subphase 4 - Start - case 6: - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[2]); - - if (pAdvisor && (pAdvisor->getStandState() == UNIT_STAND_STATE_DEAD)) - { + case 6: DoScriptText(SAY_INTRO_TELONICUS, m_creature); + m_uiPhaseTimer = 8400; + break; - //start advisor within 8.4 seconds - m_uiPhase_Timer = 8400; - ++m_uiPhaseSubphase; - } - break; - - //Subphase 4 - Unlock advisor - case 7: - if (m_uiPhase_Timer < uiDiff) - { - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[3]); - - if (pAdvisor) + case 7: + if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(NPC_TELONICUS)) { pAdvisor->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - pAdvisor->setFaction(m_creature->getFaction()); - - pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - if (pTarget) - pAdvisor->AI()->AttackStart(pTarget); + pAdvisor->SetInCombatWithZone(); } + m_uiPhaseTimer = 0; + break; + } - m_uiPhase_Timer = 3000; - ++m_uiPhaseSubphase; - }else m_uiPhase_Timer -= uiDiff; - break; - - //End of phase 1 - case 8: - if (m_pInstance) - pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[3]); - - if (pAdvisor && (pAdvisor->getStandState() == UNIT_STAND_STATE_DEAD)) - { - m_uiPhase = PHASE_2_WEAPON; - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_2_WEAPON); - - DoScriptText(SAY_PHASE2_WEAPON, m_creature); - - m_uiPhaseSubphase = 0; - m_uiPhase_Timer = 3500; - DoCastSpellIfCan(m_creature, SPELL_SUMMON_WEAPONS); - } - break; + ++m_uiPhaseSubphase; } + else + m_uiPhaseTimer -= uiDiff; break; } + // ***** Weapons phase ******** case PHASE_2_WEAPON: { - if (m_uiPhaseSubphase == 0) - { - if (m_uiPhase_Timer < uiDiff) - { - m_uiPhaseSubphase = 1; - }else m_uiPhase_Timer -= uiDiff; - } - - //Spawn weapons - if (m_uiPhaseSubphase == 1) - { - m_creature->CastSpell(m_creature, SPELL_SUMMON_WEAPONS, false); - - uint8 uiMaxWeapon = sizeof(m_auiSpellSummonWeapon)/sizeof(uint32); - - for (uint32 i = 0; i < uiMaxWeapon; ++i) - m_creature->CastSpell(m_creature,m_auiSpellSummonWeapon[i],true); - - m_uiPhaseSubphase = 2; - m_uiPhase_Timer = TIME_PHASE_2_3; - } - - if (m_uiPhaseSubphase == 2) + if (m_uiPhaseTimer < uiDiff) { - if (m_uiPhase_Timer < uiDiff) + // Switch to next phase, no matter if the weapons are killed or not + if (DoCastSpellIfCan(m_creature, SPELL_RESURRECTION) == CAST_OK) { DoScriptText(SAY_PHASE3_ADVANCE, m_creature); - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_3_ADVISOR_ALL); - m_uiPhase = PHASE_3_ADVISOR_ALL; m_uiPhaseSubphase = 0; + m_uiPhaseTimer = 180000; + m_uiPhase = PHASE_3_ADVISOR_ALL; } - else - m_uiPhase_Timer -= uiDiff; } + else + m_uiPhaseTimer -= uiDiff; break; } + // ***** All advisors phase ******** case PHASE_3_ADVISOR_ALL: { - if (m_uiPhaseSubphase == 0) - { - //Respawn advisors - Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); - - for (uint32 i = 0; i < MAX_ADVISORS; ++i) - { - if (m_pInstance) - { - if (Creature* pAdvisor = m_pInstance->GetSingleCreatureFromStorage(aAdvisors[i])) - { - if (advisorbase_ai* pAdvisorAI = dynamic_cast(pAdvisor->AI())) - pAdvisorAI->Revive(pTarget); - } - } - } - - m_uiPhaseSubphase = 1; - m_uiPhase_Timer = TIME_PHASE_3_4; - } - - if (m_uiPhase_Timer < uiDiff) + if (m_uiPhaseTimer < uiDiff) { DoScriptText(SAY_PHASE4_INTRO2, m_creature); - m_uiPhase = PHASE_4_SOLO; - - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_4_SOLO); - - // Sometimes people can collect Aggro in Phase 1-3. Reset threat before releasing Kael. - DoResetThreat(); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - AttackStart(pTarget); - - m_uiPhase_Timer = 30000; + DoResetThreat(); + m_creature->SetInCombatWithZone(); + m_uiPhase = PHASE_4_SOLO; + m_uiPhaseTimer = 30000; } else - m_uiPhase_Timer -= uiDiff; + m_uiPhaseTimer -= uiDiff; break; } + // ***** Solo phases ******** case PHASE_4_SOLO: - case 5: - case 6: + case PHASE_7_GRAVITY: { - //Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiFireball_Timer - if (!m_bInGravityLapse && !m_bChainPyros && m_uiPhase != 5) + if (m_uiGravityExpireTimer) { - if (m_uiFireball_Timer < uiDiff) + if (m_uiNetherBeamTimer < uiDiff) { - if (!m_bIsCastingFireball) - { - if (!m_creature->IsNonMeleeSpellCasted(false)) - { - //interruptable - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); - int32 uiDmg = irand(20000, 25000); - m_creature->CastCustomSpell(m_creature->getVictim(), SPELL_FIREBALL, &uiDmg, 0, 0, false); - m_bIsCastingFireball = true; - m_uiFireball_Timer = 2500; - } - } - else - { - //apply resistance - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); - m_bIsCastingFireball = false; - m_uiFireball_Timer = urand(5000, 15000); - } + if (DoCastSpellIfCan(m_creature, SPELL_NETHER_BEAM) == CAST_OK) + m_uiNetherBeamTimer = urand(2000, 4000); } else - m_uiFireball_Timer -= uiDiff; + m_uiNetherBeamTimer -= uiDiff; - //m_uiArcaneDisruption_Timer - if (m_uiArcaneDisruption_Timer < uiDiff) + // Switch to the other spells after gravity lapse expired + if (m_uiGravityExpireTimer <= uiDiff) + m_uiGravityExpireTimer = 0; + else + m_uiGravityExpireTimer -= uiDiff; + } + else + { + if (m_uiFireballTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_DISRUPTION, CAST_TRIGGERED); - m_uiArcaneDisruption_Timer = 60000; + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_FIREBALL) == CAST_OK) + m_uiFireballTimer = urand(3000, 5000); + } } else - m_uiArcaneDisruption_Timer -= uiDiff; + m_uiFireballTimer -= uiDiff; - //m_uiFlameStrike_Timer - if (m_uiFlameStrike_Timer < uiDiff) + if (m_uiArcaneDisruptionTimer < uiDiff) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_FLAME_STRIKE); - - m_uiFlameStrike_Timer = 30000; + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_DISRUPTION) == CAST_OK) + m_uiArcaneDisruptionTimer = 60000; } else - m_uiFlameStrike_Timer -= uiDiff; + m_uiArcaneDisruptionTimer -= uiDiff; - if (m_uiMindControl_Timer < uiDiff) + if (m_uiFlameStrikeTimer < uiDiff) { - if (m_creature->getThreatManager().getThreatList().size() >= 2) - for (uint32 i = 0; i < 3; ++i) + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - debug_log("SD2: Kael'Thas mind control not supported."); - //DoCastSpellIfCan(pUnit, SPELL_MIND_CONTROL); + if (DoCastSpellIfCan(pTarget, SPELL_FLAME_STRIKE) == CAST_OK) + m_uiFlameStrikeTimer = 30000; } - - m_uiMindControl_Timer = 60000; } else - m_uiMindControl_Timer -= uiDiff; - } + m_uiFlameStrikeTimer -= uiDiff; - // Summon Phoenix - if (m_uiPhoenix_Timer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_PHOENIX_ANIMATION) == CAST_OK) + if (m_uiPhoenixTimer < uiDiff) { - DoScriptText(urand(0, 1) ? SAY_SUMMON_PHOENIX1 : SAY_SUMMON_PHOENIX2, m_creature); - m_uiPhoenix_Timer = 60000; + if (DoCastSpellIfCan(m_creature, SPELL_PHOENIX_ANIMATION) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_SUMMON_PHOENIX1 : SAY_SUMMON_PHOENIX2, m_creature); + m_uiPhoenixTimer = 60000; + } } + else + m_uiPhoenixTimer -= uiDiff; } - else - m_uiPhoenix_Timer -= uiDiff; - //Phase 4 specific spells + DoMeleeAttackIfReady(); + + // ***** Phase 4 specific actions ******** if (m_uiPhase == PHASE_4_SOLO) { if (m_creature->GetHealthPercent() < 50.0f) { - m_pInstance->SetData(TYPE_KAELTHAS_PHASE, PHASE_5_GRAVITY); - m_uiPhase = PHASE_5_GRAVITY; - m_uiPhase_Timer = 10000; - + // ToDo: should he cast something here? + m_creature->InterruptNonMeleeSpells(false); DoScriptText(SAY_PHASE5_NUTS, m_creature); - m_creature->StopMoving(); + SetCombatMovement(false); m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, aCenterPos[0], aCenterPos[1], aCenterPos[2]); - m_creature->NearTeleportTo(afGravityPos[0], afGravityPos[1], afGravityPos[2], 0.0f); - - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature, SPELL_FULLPOWER); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_uiPhase = PHASE_5_WAITING; } - //m_uiShockBarrier_Timer - if (m_uiShockBarrier_Timer < uiDiff) + if (m_uiShockBarrierTimer < uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SHOCK_BARRIER); - m_bChainPyros = true; - m_uiPyrosCasted = 0; - m_uiShockBarrier_Timer = 60000; + if (DoCastSpellIfCan(m_creature, SPELL_SHOCK_BARRIER) == CAST_OK) + { + m_uiPyroblastTimer = 1000; + m_uiShockBarrierTimer = 60000; + } } else - m_uiShockBarrier_Timer -= uiDiff; + m_uiShockBarrierTimer -= uiDiff; - //Chain Pyros (3 of them max) - if (m_bChainPyros && !m_creature->IsNonMeleeSpellCasted(false)) + if (m_uiPyroblastTimer) { - if (m_uiPyrosCasted < 3) + if (m_uiPyroblastTimer <= uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PYROBLAST); - ++m_uiPyrosCasted; + if (DoCastSpellIfCan(m_creature, SPELL_PYROBLAST) == CAST_OK) + { + DoScriptText(EMOTE_PYROBLAST, m_creature); + m_uiPyroblastTimer = 0; + } } else - { - m_bChainPyros = false; - m_uiFireball_Timer = 2500; - m_uiArcaneDisruption_Timer = 60000; - } + m_uiPyroblastTimer -= uiDiff; } - } - if (m_uiPhase == PHASE_5_GRAVITY) - { - if (m_uiPhase_Timer < uiDiff) + if (m_uiMindControlTimer < uiDiff) { - m_creature->InterruptNonMeleeSpells(false); - m_creature->RemoveAurasDueToSpell(SPELL_FULLPOWER); - - DoCastSpellIfCan(m_creature, SPELL_EXPLODE); - - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - m_uiPhase = 6; - AttackStart(m_creature->getVictim()); + for (uint8 i = 0; i < MAX_MIND_CONTROL; ++i) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, SPELL_MIND_CONTROL, SELECT_FLAG_PLAYER)) + DoCastSpellIfCan(pTarget, SPELL_MIND_CONTROL); + } + m_uiMindControlTimer = 60000; } else - m_uiPhase_Timer -= uiDiff; + m_uiMindControlTimer -= uiDiff; } - //Phase 5 - if (m_uiPhase == 6) + // ***** Phase 7 specific actions ******** + if (m_uiPhase == PHASE_7_GRAVITY) { - - //m_uiGravityLapse_Timer - if (m_uiGravityLapse_Timer < uiDiff) + if (m_uiGravityLapseTimer < uiDiff) { - switch(m_uiGravityLapse_Phase) + if (DoCastSpellIfCan(m_creature, SPELL_GRAVITY_LAPSE) == CAST_OK) { - case 0: - { - m_creature->StopMoving(); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->MonsterMoveWithSpeed(afGravityPos[0], afGravityPos[1], afGravityPos[2], 28.f); - - // 1) Kael'thas will portal the whole raid right into his body - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) - { - Unit* pUnit = m_creature->GetMap()->GetUnit(*i); - - if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER) - { - //Use work around packet to prevent player from being dropped from combat - DoTeleportPlayer(pUnit, afGravityPos[0], afGravityPos[1], afGravityPos[2], pUnit->GetOrientation()); - } - } - - m_uiGravityLapse_Timer = 500; - ++m_uiGravityLapse_Phase; - m_bInGravityLapse = true; - m_uiShockBarrier_Timer = 1000; - m_uiNetherBeam_Timer = 5000; - break; - } - case 1: - { - DoScriptText(urand(0, 1) ? SAY_GRAVITYLAPSE1 : SAY_GRAVITYLAPSE2, m_creature); - - // 2) At that point he will put a Gravity Lapse debuff on everyone - std::vector vGuids; - m_creature->FillGuidsListFromThreatList(vGuids); - for (std::vector::const_iterator i = vGuids.begin();i != vGuids.end(); ++i) - { - if (Unit* pUnit = m_creature->GetMap()->GetUnit(*i)) - { - m_creature->CastSpell(pUnit, SPELL_KNOCKBACK, true); - //Gravity lapse - needs an exception in Spell system to work - - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE, true, NULL, NULL, m_creature->GetObjectGuid()); - pUnit->CastSpell(pUnit, SPELL_GRAVITY_LAPSE_AURA, true, NULL, NULL, m_creature->GetObjectGuid()); - } - } - m_uiGravityLapse_Timer = 10000; - ++m_uiGravityLapse_Phase; - break; - } - case 2: - //Cast nether vapor aura on self - m_creature->InterruptNonMeleeSpells(false); - DoCastSpellIfCan(m_creature, SPELL_NETHER_VAPOR); - - m_uiGravityLapse_Timer = 20000; - ++m_uiGravityLapse_Phase; - break; - - case 3: - { - //Remove flight - m_creature->RemoveAurasDueToSpell(SPELL_NETHER_VAPOR); - m_bInGravityLapse = false; - m_uiGravityLapse_Timer = 60000; - m_uiGravityLapse_Phase = 0; - AttackStart(m_creature->getVictim()); - break; - } + DoScriptText(urand(0, 1) ? SAY_GRAVITYLAPSE1 : SAY_GRAVITYLAPSE2, m_creature);; + m_uiGravityIndex = 0; + m_uiNetherBeamTimer = 8000; + m_uiNetherVaporTimer = 4000; + m_uiGravityExpireTimer = 30000; + m_uiGravityLapseTimer = 90000; } } else - m_uiGravityLapse_Timer -= uiDiff; + m_uiGravityLapseTimer -= uiDiff; - if (m_bInGravityLapse) + if (m_uiShockBarrierTimer < uiDiff) { - //m_uiShockBarrier_Timer - if (m_uiShockBarrier_Timer < uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_SHOCK_BARRIER) == CAST_OK) + m_uiShockBarrierTimer = 20000; + } + else + m_uiShockBarrierTimer -= uiDiff; + + if (m_uiNetherVaporTimer) + { + if (m_uiNetherVaporTimer <= uiDiff) { - DoCastSpellIfCan(m_creature, SPELL_SHOCK_BARRIER); - m_uiShockBarrier_Timer = 20000; + if (DoCastSpellIfCan(m_creature, SPELL_NETHER_VAPOR_SUMMON) == CAST_OK) + m_uiNetherVaporTimer = 0; } else - m_uiShockBarrier_Timer -= uiDiff; - - //m_uiNetherBeam_Timer - if (m_uiNetherBeam_Timer < uiDiff) + m_uiNetherVaporTimer -= uiDiff; + } + } + } + // ***** Phase 5 - transition ******** + case PHASE_5_WAITING: + // Nothing here; wait for boss to arive at point + break; + // ***** Phase 6 - explode the bridge ******** + case PHASE_6_FLYING: + if (m_uiExplodeTimer) + { + if (m_uiExplodeTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_EXPLODE) == CAST_OK) { - if (Unit* pUnit = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pUnit, SPELL_NETHER_BEAM); - - m_uiNetherBeam_Timer = 4000; + if (m_pInstance) + { + m_pInstance->DoUseDoorOrButton(GO_KAEL_STATUE_LEFT); + m_pInstance->DoUseDoorOrButton(GO_KAEL_STATUE_RIGHT); + m_pInstance->DoUseDoorOrButton(GO_BRIDGE_WINDOW); + } + // Note: also Kael casts some other unk spells here + m_uiPhaseTimer = 5000; + m_uiExplodeTimer = 0; } - else - m_uiNetherBeam_Timer -= uiDiff; } + else + m_uiExplodeTimer -= uiDiff; } - if (!m_bInGravityLapse) - DoMeleeAttackIfReady(); - } + if (m_uiPhaseTimer) + { + if (m_uiPhaseTimer <= uiDiff) + { + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MovePoint(POINT_ID_CENTER, aCenterPos[0], aCenterPos[1], aCenterPos[2]); + m_uiPhaseTimer = 0; + } + else + m_uiPhaseTimer -= uiDiff; + } + break; } } }; -//Thaladred the Darkener AI -struct MANGOS_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai +bool EffectDummyCreature_kael_phase_2(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if (uiSpellId == SPELL_KAEL_PHASE_2 && uiEffIndex == EFFECT_INDEX_0) + { + if (boss_kaelthasAI* pKaelAI = dynamic_cast(pCreatureTarget->AI())) + pKaelAI->AdvisorDefeated(pCaster->GetEntry()); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + +/*###### +## advisor_base_ai +######*/ + +struct advisor_base_ai : public ScriptedAI { - boss_thaladred_the_darkenerAI(Creature* pCreature) : advisorbase_ai(pCreature) + advisor_base_ai(Creature* pCreature) : ScriptedAI(pCreature) { - m_iAdvisor_Speech = SAY_THALADRED_DEATH; + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); } - uint32 m_uiGaze_Timer; - uint32 m_uiSilence_Timer; - uint32 m_uiPsychicBlow_Timer; + ScriptedInstance* m_pInstance; + + bool m_bFakeDeath; + bool m_bCanFakeDeath; + + void Reset() override + { + m_bCanFakeDeath = true; + m_bFakeDeath = false; + + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } - void Reset() + void JustReachedHome() override { - m_uiGaze_Timer = 100; - m_uiSilence_Timer = 20000; - m_uiPsychicBlow_Timer = 10000; + // Reset Kael if needed + if (m_pInstance) + { + if (Creature* pKael = m_pInstance->GetSingleCreatureFromStorage(NPC_KAELTHAS)) + pKael->AI()->EnterEvadeMode(); - advisorbase_ai::Reset(); + m_pInstance->SetData(TYPE_KAELTHAS, FAIL); + } } - void Aggro(Unit* pWho) + void DamageTaken(Unit* /*pDoneby*/, uint32& uiDamage) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) + // Allow fake death only in the first phase + if (!m_bCanFakeDeath) + return; + + if (uiDamage < m_creature->GetHealth()) return; - if (!pWho || m_bFakeDeath) + // Make sure it won't die by accident + if (m_bFakeDeath) + { + uiDamage = 0; return; + } + + uiDamage = 0; + m_bFakeDeath = true; + + m_creature->InterruptNonMeleeSpells(true); + m_creature->SetHealth(0); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + DoCastSpellIfCan(m_creature, SPELL_KAEL_PHASE_2, CAST_TRIGGERED); + } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override + { + // Remove fake death + if (pSpell->Id == SPELL_RESURRECTION && pCaster->GetEntry() == NPC_KAELTHAS) + { + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + m_creature->GetMotionMaster()->Clear(); + if (m_creature->GetEntry() == NPC_CAPERNIAN) + DoStartMovement(m_creature->getVictim(), 20.0f); + else + DoStartMovement(m_creature->getVictim()); + m_bCanFakeDeath = false; + m_bFakeDeath = false; + } + } +}; +/*###### +## boss_thaladred_the_darkener +######*/ + +struct boss_thaladred_the_darkenerAI : public advisor_base_ai +{ + boss_thaladred_the_darkenerAI(Creature* pCreature) : advisor_base_ai(pCreature) { Reset(); } + + uint32 m_uiGazeTimer; + uint32 m_uiRendTimer; + uint32 m_uiSilenceTimer; + uint32 m_uiPsychicBlowTimer; + + void Reset() override + { + m_uiGazeTimer = 0; + m_uiRendTimer = urand(4000, 8000); + m_uiSilenceTimer = 5000; + m_uiPsychicBlowTimer = 25000; + + advisor_base_ai::Reset(); + } + + void Aggro(Unit* pWho) override + { DoScriptText(SAY_THALADRED_AGGRO, m_creature); - m_creature->AddThreat(pWho, 5000000.0f); + m_creature->TauntApply(pWho); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override { - advisorbase_ai::UpdateAI(uiDiff); + DoScriptText(SAY_THALADRED_DEATH, m_creature); + } - //Faking death, don't do anything - if (m_bFakeDeath) + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Don't use abilities during fake death + if (m_bFakeDeath) return; - //m_uiGaze_Timer - if (m_uiGaze_Timer < uiDiff) + if (m_uiGazeTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { DoResetThreat(); - m_creature->AddThreat(pTarget, 5000000.0f); + m_creature->TauntApply(pTarget); DoScriptText(EMOTE_THALADRED_GAZE, m_creature, pTarget); } - m_uiGaze_Timer = 8500; + m_uiGazeTimer = 10000; } else - m_uiGaze_Timer -= uiDiff; + m_uiGazeTimer -= uiDiff; - //m_uiSilence_Timer - if (m_uiSilence_Timer < uiDiff) + if (m_uiRendTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_SILENCE); - m_uiSilence_Timer = 20000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_REND) == CAST_OK) + m_uiRendTimer = urand(7000, 12000); } else - m_uiSilence_Timer -= uiDiff; + m_uiRendTimer -= uiDiff; - //m_uiPsychicBlow_Timer - if (m_uiPsychicBlow_Timer < uiDiff) + if (m_uiSilenceTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHIC_BLOW); - m_uiPsychicBlow_Timer = urand(20000, 25000); + if (DoCastSpellIfCan(m_creature, SPELL_SILENCE) == CAST_OK) + m_uiSilenceTimer = urand(7000, 13000); } else - m_uiPsychicBlow_Timer -= uiDiff; + m_uiSilenceTimer -= uiDiff; + + if (m_uiPsychicBlowTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_PSYCHIC_BLOW) == CAST_OK) + m_uiPsychicBlowTimer = urand(20000, 25000); + } + else + m_uiPsychicBlowTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Lord Sanguinar AI -struct MANGOS_DLL_DECL boss_lord_sanguinarAI : public advisorbase_ai +/*###### +## boss_lord_sanguinar +######*/ + +struct boss_lord_sanguinarAI : public advisor_base_ai { - boss_lord_sanguinarAI(Creature* pCreature) : advisorbase_ai(pCreature) - { - m_iAdvisor_Speech = SAY_SANGUINAR_DEATH; - } + boss_lord_sanguinarAI(Creature* pCreature) : advisor_base_ai(pCreature) { Reset(); } - uint32 m_uiFear_Timer; + uint32 m_uiFearTimer; - void Reset() + void Reset() override { - m_uiFear_Timer = 20000; - advisorbase_ai::Reset(); + m_uiFearTimer = 10000; + + advisor_base_ai::Reset(); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!pWho || m_bFakeDeath) - return; - DoScriptText(SAY_SANGUINAR_AGGRO, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override { - advisorbase_ai::UpdateAI(uiDiff); + DoScriptText(SAY_SANGUINAR_DEATH, m_creature); + } - //Faking death, don't do anything - if (m_bFakeDeath) + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Don't use abilities during fake death + if (m_bFakeDeath) return; - //m_uiFear_Timer - if (m_uiFear_Timer < uiDiff) + if (m_uiFearTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BELLOWING_ROAR); - m_uiFear_Timer = urand(25000, 35000); //approximately every 30 seconds + if (DoCastSpellIfCan(m_creature, SPELL_BELLOWING_ROAR) == CAST_OK) + m_uiFearTimer = 30000; } else - m_uiFear_Timer -= uiDiff; + m_uiFearTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Grand Astromancer Capernian AI -struct MANGOS_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_ai +/*###### +## boss_grand_astromancer_capernian +######*/ + +struct boss_grand_astromancer_capernianAI : public advisor_base_ai { - boss_grand_astromancer_capernianAI(Creature* pCreature) : advisorbase_ai(pCreature) - { - m_iAdvisor_Speech = SAY_CAPERNIAN_DEATH; - } + boss_grand_astromancer_capernianAI(Creature* pCreature) : advisor_base_ai(pCreature) { Reset(); } - uint32 m_uiFireball_Timer; - uint32 m_uiConflagration_Timer; - uint32 m_uiArcaneExplosion_Timer; - uint32 m_uiYell_Timer; - bool m_bYell; + uint32 m_uiFireballTimer; + uint32 m_uiConflagrationTimer; + uint32 m_uiArcaneExplosionTimer; - void Reset() + void Reset() override { - m_uiFireball_Timer = 2000; - m_uiConflagration_Timer = 20000; - m_uiArcaneExplosion_Timer = 5000; - m_uiYell_Timer = 2000; - m_bYell = false; + m_uiFireballTimer = 2000; + m_uiConflagrationTimer = 20000; + m_uiArcaneExplosionTimer = 5000; - advisorbase_ai::Reset(); + advisor_base_ai::Reset(); } - void AttackStart(Unit* pWho) + void AttackStart(Unit* pWho) override { - if (!pWho || m_bFakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - if (m_creature->Attack(pWho, true)) { m_creature->AddThreat(pWho); m_creature->SetInCombatWith(pWho); pWho->SetInCombatWith(m_creature); - m_creature->GetMotionMaster()->MoveChase(pWho, CAPERNIAN_DISTANCE); + m_creature->GetMotionMaster()->MoveChase(pWho, 20.0f); } } - void Aggro(Unit *pWho) + void Aggro(Unit* /*pWho*/) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!pWho || m_bFakeDeath) - return; + DoScriptText(SAY_CAPERNIAN_AGGRO, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override { - advisorbase_ai::UpdateAI(uiDiff); - - //Faking Death, don't do anything - if (m_bFakeDeath) - return; + DoScriptText(SAY_CAPERNIAN_DEATH, m_creature); + } - //Return since we have no target + void UpdateAI(const uint32 uiDiff) override + { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //m_uiYell_Timer - if (!m_bYell) - { - if (m_uiYell_Timer < uiDiff) - { - DoScriptText(SAY_CAPERNIAN_AGGRO, m_creature); - m_bYell = true; - } - else - m_uiYell_Timer -= uiDiff; - } + // Don't use abilities during fake death + if (m_bFakeDeath) + return; - //m_uiFireball_Timer - if (m_uiFireball_Timer < uiDiff) + if (m_uiFireballTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_CAPERNIAN_FIREBALL); - m_uiFireball_Timer = 4000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CAPERNIAN_FIREBALL) == CAST_OK) + m_uiFireballTimer = 4000; } else - m_uiFireball_Timer -= uiDiff; + m_uiFireballTimer -= uiDiff; - //m_uiConflagration_Timer - if (m_uiConflagration_Timer < uiDiff) + if (m_uiConflagrationTimer < uiDiff) { Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0); @@ -1256,182 +1009,226 @@ struct MANGOS_DLL_DECL boss_grand_astromancer_capernianAI : public advisorbase_a else DoCastSpellIfCan(m_creature->getVictim(), SPELL_CONFLAGRATION); - m_uiConflagration_Timer = urand(10000, 15000); + m_uiConflagrationTimer = urand(10000, 15000); } else - m_uiConflagration_Timer -= uiDiff; + m_uiConflagrationTimer -= uiDiff; - //m_uiArcaneExplosion_Timer - if (m_uiArcaneExplosion_Timer < uiDiff) + if (m_uiArcaneExplosionTimer < uiDiff) { - // if enemy is in melee range - if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, uint32(0), SELECT_FLAG_IN_MELEE_RANGE)) - DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION); - - m_uiArcaneExplosion_Timer = urand(4000, 6000); + if (m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0, SPELL_ARCANE_BURST, SELECT_FLAG_IN_MELEE_RANGE)) + { + if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_BURST) == CAST_OK) + m_uiArcaneExplosionTimer = urand(4000, 6000); + } } else - m_uiArcaneExplosion_Timer -= uiDiff; + m_uiArcaneExplosionTimer -= uiDiff; - //Do NOT deal any melee damage. + // Do NOT deal any melee damage. } }; -//Master Engineer Telonicus AI -struct MANGOS_DLL_DECL boss_master_engineer_telonicusAI : public advisorbase_ai +/*###### +## boss_master_engineer_telonicus +######*/ + +struct boss_master_engineer_telonicusAI : public advisor_base_ai { - boss_master_engineer_telonicusAI(Creature* pCreature) : advisorbase_ai(pCreature) - { - m_iAdvisor_Speech = SAY_TELONICUS_DEATH; - } + boss_master_engineer_telonicusAI(Creature* pCreature) : advisor_base_ai(pCreature) { Reset(); } - uint32 m_uiBomb_Timer; - uint32 m_uiRemoteToy_Timer; + uint32 m_uiBombTimer; + uint32 m_uiRemoteToyTimer; - void Reset() + void Reset() override { - m_uiBomb_Timer = 10000; - m_uiRemoteToy_Timer = 5000; + m_uiBombTimer = 10000; + m_uiRemoteToyTimer = 5000; - advisorbase_ai::Reset(); + advisor_base_ai::Reset(); } - void Aggro(Unit *pWho) + void Aggro(Unit* /*pWho*/) override { - if (m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - return; - - if (!pWho || m_bFakeDeath) - return; - DoScriptText(SAY_TELONICUS_AGGRO, m_creature); } - void UpdateAI(const uint32 uiDiff) + void JustDied(Unit* /*pKiller*/) override { - advisorbase_ai::UpdateAI(uiDiff); + DoScriptText(SAY_TELONICUS_DEATH, m_creature); + } - //Faking Death, do nothing - if (m_bFakeDeath) + void UpdateAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Don't use abilities during fake death + if (m_bFakeDeath) return; - //m_uiBomb_Timer - if (m_uiBomb_Timer < uiDiff) + if (m_uiBombTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_BOMB); - m_uiBomb_Timer = 25000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_BOMB) == CAST_OK) + m_uiBombTimer = 25000; } else - m_uiBomb_Timer -= uiDiff; + m_uiBombTimer -= uiDiff; - //m_uiRemoteToy_Timer - if (m_uiRemoteToy_Timer < uiDiff) + if (m_uiRemoteToyTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - DoCastSpellIfCan(pTarget, SPELL_REMOTE_TOY); - - m_uiRemoteToy_Timer = urand(10000, 15000); + { + if (DoCastSpellIfCan(pTarget, SPELL_REMOTE_TOY) == CAST_OK) + m_uiRemoteToyTimer = urand(10000, 15000); + } } else - m_uiRemoteToy_Timer -= uiDiff; + m_uiRemoteToyTimer -= uiDiff; DoMeleeAttackIfReady(); } }; -//Phoenix AI -struct MANGOS_DLL_DECL mob_phoenix_tkAI : public ScriptedAI +/*###### +## mob_phoenix_tk +######*/ + +struct mob_phoenix_tkAI : public ScriptedAI { mob_phoenix_tkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 m_uiCycle_Timer; + uint32 m_uiCycleTimer; - void Reset() + bool m_bFakeDeath; + + void Reset() override { - m_uiCycle_Timer = 2000; - m_creature->CastSpell(m_creature,SPELL_BURN,true); + m_uiCycleTimer = 2000; + m_bFakeDeath = false; } - void JustDied(Unit* pKiller) + void Aggro(Unit* /*pWho*/) override { - //is this spell in use anylonger? - //m_creature->CastSpell(m_creature,SPELL_EMBER_BLAST,true); - m_creature->SummonCreature(NPC_PHOENIX_EGG,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_TIMED_DESPAWN,16000); + DoCastSpellIfCan(m_creature, SPELL_BURN); } - void UpdateAI(const uint32 uiDiff) + void EnterEvadeMode() override { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + // Don't evade during ember blast + if (m_bFakeDeath) return; - if (m_uiCycle_Timer < uiDiff) - { - //spell Burn should possible do this, but it doesn't, so do this for now. - uint32 uiDmg = urand(4500,5500); + ScriptedAI::EnterEvadeMode(); + } - if (m_creature->GetHealth() > uiDmg) - m_creature->SetHealth(uint32(m_creature->GetHealth()-uiDmg)); + void DamageTaken(Unit* /*pKiller*/, uint32& uiDamage) override + { + if (uiDamage < m_creature->GetHealth()) + return; - m_uiCycle_Timer = 2000; + // Prevent glitch if in fake death + if (m_bFakeDeath) + { + uiDamage = 0; + return; } - else - m_uiCycle_Timer -= uiDiff; - DoMeleeAttackIfReady(); + // prevent death + uiDamage = 0; + DoSetFakeDeath(); } -}; - -//Phoenix Egg AI -struct MANGOS_DLL_DECL mob_phoenix_egg_tkAI : public ScriptedAI -{ - mob_phoenix_egg_tkAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiRebirth_Timer; - void Reset() + void DoSetFakeDeath() { - m_uiRebirth_Timer = 15000; + m_bFakeDeath = true; + + m_creature->InterruptNonMeleeSpells(false); + m_creature->SetHealth(1); + m_creature->StopMoving(); + m_creature->ClearComboPointHolders(); + m_creature->RemoveAllAurasOnDeath(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + m_creature->ClearAllReactives(); + m_creature->SetTargetGuid(ObjectGuid()); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + + // Spawn egg and make invisible + DoCastSpellIfCan(m_creature, SPELL_EMBER_BLAST, CAST_TRIGGERED); + m_creature->SummonCreature(NPC_PHOENIX_EGG, 0, 0, 0, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15000); } - //ignore any - void MoveInLineOfSight(Unit* pWho) { return; } - - void AttackStart(Unit* pWho) + void SummonedCreatureDespawn(Creature* /*pSummoned*/) override { - if (m_creature->Attack(pWho, false)) + // Remove fake death if the egg despawns after 15 secs + m_creature->RemoveAurasDueToSpell(SPELL_EMBER_BLAST); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (DoCastSpellIfCan(m_creature, SPELL_REBIRTH) == CAST_OK) { - m_creature->SetInCombatWith(pWho); - pWho->SetInCombatWith(m_creature); + m_creature->SetHealth(m_creature->GetMaxHealth()); + m_creature->GetMotionMaster()->Clear(); + DoStartMovement(m_creature->getVictim()); + m_bFakeDeath = false; - DoStartNoMovement(pWho); + DoCastSpellIfCan(m_creature, SPELL_BURN, CAST_TRIGGERED); } } - void JustSummoned(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* /*pSummoned*/) override { - pSummoned->AddThreat(m_creature->getVictim()); - pSummoned->CastSpell(pSummoned,SPELL_REBIRTH,false); + // Self kill if the egg is killed + if (m_bFakeDeath) + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - if (!m_uiRebirth_Timer) + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiRebirth_Timer <= uiDiff) + if (m_bFakeDeath) + return; + + // ToDo: research if this is correct and how can this be done by spell + if (m_uiCycleTimer < uiDiff) { - m_creature->SummonCreature(NPC_PHOENIX,m_creature->GetPositionX(),m_creature->GetPositionY(),m_creature->GetPositionZ(),m_creature->GetOrientation(),TEMPSUMMON_CORPSE_DESPAWN,5000); - m_uiRebirth_Timer = 0; + // spell Burn should possible do this, but it doesn't, so do this for now. + uint32 uiDmg = urand(4500, 5500); + if (uiDmg > m_creature->GetHealth()) + DoSetFakeDeath(); + else + m_creature->DealDamage(m_creature, uiDmg, 0, DOT, SPELL_SCHOOL_MASK_FIRE, NULL, false); + + m_uiCycleTimer = 2000; } else - m_uiRebirth_Timer -= uiDiff; + m_uiCycleTimer -= uiDiff; + + DoMeleeAttackIfReady(); } }; +/*###### +## mob_phoenix_egg_tk +######*/ + +// TODO Remove this 'script' when combat movement can be proper prevented from core-side +struct mob_phoenix_egg_tkAI : public Scripted_NoMovementAI +{ + mob_phoenix_egg_tkAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature) { Reset(); } + + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } + void AttackStart(Unit* /*pWho*/) override { } + void UpdateAI(const uint32 /*uiDiff*/) override { } +}; + CreatureAI* GetAI_boss_kaelthas(Creature* pCreature) { return new boss_kaelthasAI(pCreature); @@ -1474,6 +1271,7 @@ void AddSC_boss_kaelthas() pNewScript = new Script; pNewScript->Name = "boss_kaelthas"; pNewScript->GetAI = &GetAI_boss_kaelthas; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_kael_phase_2; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp b/scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp index 96817da4d..1e542b756 100644 --- a/scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp +++ b/scripts/outland/tempest_keep/the_eye/boss_void_reaver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,31 +16,33 @@ /* ScriptData SDName: Boss_Void_Reaver -SD%Complete: 90 -SDComment: Should reset if raid are out of room. +SD%Complete: 95 +SDComment: Small adjustments may be required SDCategory: Tempest Keep, The Eye EndScriptData */ #include "precompiled.h" #include "the_eye.h" -#define SAY_AGGRO -1550000 -#define SAY_SLAY1 -1550001 -#define SAY_SLAY2 -1550002 -#define SAY_SLAY3 -1550003 -#define SAY_DEATH -1550004 -#define SAY_POUNDING1 -1550005 -#define SAY_POUNDING2 -1550006 - -#define SPELL_POUNDING 34162 -#define SPELL_ARCANE_ORB_MISSILE 34172 -#define SPELL_KNOCK_AWAY 25778 -#define SPELL_BERSERK 26662 - -//Unknown function. If target not found, this will be created and used as dummy target instead? -//#define CREATURE_ORB_TARGET 19577 +enum +{ + SAY_AGGRO = -1550000, + SAY_SLAY1 = -1550001, + SAY_SLAY2 = -1550002, + SAY_SLAY3 = -1550003, + SAY_DEATH = -1550004, + SAY_POUNDING1 = -1550005, + SAY_POUNDING2 = -1550006, + + SPELL_POUNDING = 34162, + SPELL_ARCANE_ORB_MISSILE = 34172, + SPELL_KNOCK_AWAY = 25778, + SPELL_BERSERK = 26662, + + NPC_ARCANE_ORB_TARGET = 19577, +}; -struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI +struct boss_void_reaverAI : public ScriptedAI { boss_void_reaverAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -50,25 +52,25 @@ struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI ScriptedInstance* m_pInstance; - uint32 Pounding_Timer; - uint32 ArcaneOrb_Timer; - uint32 KnockAway_Timer; - uint32 Berserk_Timer; + uint32 m_uiPoundingTimer; + uint32 m_uiArcaneOrbTimer; + uint32 m_uiKnockAwayTimer; + uint32 m_uiBerserkTimer; - void Reset() + void Reset() override { - Pounding_Timer = 15000; - ArcaneOrb_Timer = 3000; - KnockAway_Timer = 30000; - Berserk_Timer = 600000; - - if (m_pInstance && m_creature->isAlive()) - m_pInstance->SetData(TYPE_VOIDREAVER, NOT_STARTED); + m_uiPoundingTimer = 13000; + m_uiArcaneOrbTimer = 3000; + m_uiKnockAwayTimer = 30000; + m_uiBerserkTimer = 10 * MINUTE * IN_MILLISECONDS; } - void KilledUnit(Unit *victim) + void KilledUnit(Unit* pVictim) override { - switch(urand(0, 2)) + if (pVictim->GetTypeId() != TYPEID_PLAYER) + return; + + switch (urand(0, 2)) { case 0: DoScriptText(SAY_SLAY1, m_creature); break; case 1: DoScriptText(SAY_SLAY2, m_creature); break; @@ -76,7 +78,7 @@ struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI } } - void JustDied(Unit *victim) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -84,7 +86,7 @@ struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI m_pInstance->SetData(TYPE_VOIDREAVER, DONE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); @@ -92,74 +94,90 @@ struct MANGOS_DLL_DECL boss_void_reaverAI : public ScriptedAI m_pInstance->SetData(TYPE_VOIDREAVER, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_VOIDREAVER, NOT_STARTED); + } + + void JustSummoned(Creature* pSummoned) override + { + // Cast the Arcane Orb missile on the npc, not on player + DoCastSpellIfCan(pSummoned, SPELL_ARCANE_ORB_MISSILE, CAST_TRIGGERED); + } + + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Pounding - if (Pounding_Timer < diff) + if (m_uiPoundingTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_POUNDING); - DoScriptText(urand(0, 1) ? SAY_POUNDING1 : SAY_POUNDING2, m_creature); - - Pounding_Timer = 15000; //cast time(3000) + cooldown time(12000) - }else Pounding_Timer -= diff; + if (DoCastSpellIfCan(m_creature, SPELL_POUNDING) == CAST_OK) + { + DoScriptText(urand(0, 1) ? SAY_POUNDING1 : SAY_POUNDING2, m_creature); + m_uiPoundingTimer = 14000; + } + } + else + m_uiPoundingTimer -= uiDiff; // Arcane Orb - if (ArcaneOrb_Timer < diff) + if (m_uiArcaneOrbTimer < uiDiff) { - Unit *target = NULL; - std::vector target_list; + // Search only for players which are not within 18 yards of the boss + std::vector suitableTargets; + ThreatList const& threatList = m_creature->getThreatManager().getThreatList(); - ThreatList const& tList = m_creature->getThreatManager().getThreatList(); - for (ThreatList::const_iterator itr = tList.begin();itr != tList.end(); ++itr) + for (ThreatList::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) { - target = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); - - // exclude pets & totems - if (!target || target->GetTypeId() != TYPEID_PLAYER) - continue; - - //18 yard radius minimum - if (target->IsWithinDist(m_creature, 18.0f, false)) - continue; - - target_list.push_back(target); + if (Unit* pTarget = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) + { + if (pTarget->GetTypeId() == TYPEID_PLAYER && !pTarget->IsWithinDist(m_creature, 18.0f)) + suitableTargets.push_back(pTarget); + } } - if (target_list.size()) - target = *(target_list.begin()+rand()%target_list.size()); + if (suitableTargets.empty()) + m_uiArcaneOrbTimer = 3000; else - target = m_creature->getVictim(); + { + Unit* pTarget = suitableTargets[urand(0, suitableTargets.size() - 1)]; - if (target) - DoCastSpellIfCan(target, SPELL_ARCANE_ORB_MISSILE); + if (pTarget) + m_creature->SummonCreature(NPC_ARCANE_ORB_TARGET, pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 0, TEMPSUMMON_CORPSE_DESPAWN, 0); - ArcaneOrb_Timer = 3000; - }else ArcaneOrb_Timer -= diff; + m_uiArcaneOrbTimer = 3000; + } + } + else + m_uiArcaneOrbTimer -= uiDiff; // Single Target knock back, reduces aggro - if (KnockAway_Timer < diff) + if (m_uiKnockAwayTimer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_KNOCK_AWAY); - - KnockAway_Timer = 30000; - }else KnockAway_Timer -= diff; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_KNOCK_AWAY) == CAST_OK) + m_uiKnockAwayTimer = 30000; + } + else + m_uiKnockAwayTimer -= uiDiff; - //Berserk - if (Berserk_Timer < diff) + // Berserk + if (m_uiBerserkTimer) { - if (m_creature->IsNonMeleeSpellCasted(false)) - m_creature->InterruptNonMeleeSpells(false); - - DoCastSpellIfCan(m_creature,SPELL_BERSERK); - Berserk_Timer = 600000; - }else Berserk_Timer -= diff; + if (m_uiBerserkTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) + m_uiBerserkTimer = 0; + } + else + m_uiBerserkTimer -= uiDiff; + } DoMeleeAttackIfReady(); - EnterEvadeIfOutOfCombatArea(diff); + EnterEvadeIfOutOfCombatArea(uiDiff); } }; diff --git a/scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp b/scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp index 4942d6dd5..262aa8bdf 100644 --- a/scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp +++ b/scripts/outland/tempest_keep/the_eye/instance_the_eye.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,9 +43,6 @@ bool instance_the_eye::IsEncounterInProgress() const return true; } - if (PHASE_1_ADVISOR <= m_uiKaelthasEventPhase && m_uiKaelthasEventPhase <= PHASE_5_GRAVITY) - return true; - return false; } @@ -58,12 +55,25 @@ void instance_the_eye::OnCreatureCreate(Creature* pCreature) case NPC_CAPERNIAN: case NPC_SANGUINAR: case NPC_KAELTHAS: - case NPC_ASTROMANCER: m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); break; } } +void instance_the_eye::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_ARCANE_DOOR_HORIZ_3: + case GO_ARCANE_DOOR_HORIZ_4: + case GO_KAEL_STATUE_LEFT: + case GO_KAEL_STATUE_RIGHT: + case GO_BRIDGE_WINDOW: + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); + break; + } +} + void instance_the_eye::SetData(uint32 uiType, uint32 uiData) { switch (uiType) @@ -73,27 +83,44 @@ void instance_the_eye::SetData(uint32 uiType, uint32 uiData) case TYPE_VOIDREAVER: m_auiEncounter[uiType] = uiData; break; + case TYPE_KAELTHAS: + // Don't set the same data twice + if (m_auiEncounter[uiType] == uiData) + break; + DoUseDoorOrButton(GO_ARCANE_DOOR_HORIZ_3); + DoUseDoorOrButton(GO_ARCANE_DOOR_HORIZ_4); + if (uiData == FAIL) + { + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_KAEL_STATUE_LEFT)) + pGo->ResetDoorOrButton(); + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_KAEL_STATUE_RIGHT)) + pGo->ResetDoorOrButton(); + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_BRIDGE_WINDOW)) + pGo->ResetDoorOrButton(); - case TYPE_KAELTHAS_PHASE: - m_uiKaelthasEventPhase = uiData; + // Respawn or reset the advisors + for (uint8 i = 0; i < MAX_ADVISORS; ++i) + { + if (Creature* pTemp = GetSingleCreatureFromStorage(aAdvisors[i])) + { + if (!pTemp->isAlive()) + pTemp->Respawn(); + else + pTemp->AI()->EnterEvadeMode(); + } + } + } + m_auiEncounter[uiType] = uiData; break; } } -uint32 instance_the_eye::GetData(uint32 uiType) +uint32 instance_the_eye::GetData(uint32 uiType) const { - switch(uiType) - { - case TYPE_ALAR: - case TYPE_SOLARIAN: - case TYPE_VOIDREAVER: - return m_auiEncounter[uiType]; - case TYPE_KAELTHAS_PHASE: - return m_uiKaelthasEventPhase; + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; - default: - return 0; - } + return 0; } InstanceData* GetInstanceData_instance_the_eye(Map* pMap) diff --git a/scripts/outland/tempest_keep/the_eye/the_eye.cpp b/scripts/outland/tempest_keep/the_eye/the_eye.cpp deleted file mode 100644 index 3fb1ed148..000000000 --- a/scripts/outland/tempest_keep/the_eye/the_eye.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: The_Eye -SD%Complete: 100 -SDComment: -SDCategory: Tempest Keep, The Eye -EndScriptData */ - -/* ContentData -mob_crystalcore_devastator -EndContentData */ - -#include "precompiled.h" -#include "the_eye.h" - -#define SPELL_COUNTERCHARGE 35035 -#define SPELL_KNOCKAWAY 22893 - -struct MANGOS_DLL_DECL mob_crystalcore_devastatorAI : public ScriptedAI -{ - mob_crystalcore_devastatorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 Knockaway_Timer; - uint32 Countercharge_Timer; - - void Reset() - { - Countercharge_Timer = 9000; - Knockaway_Timer = 25000; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Check if we have a current target - //Knockaway_Timer - if (Knockaway_Timer < diff) - { - m_creature->CastSpell(m_creature->getVictim(),SPELL_KNOCKAWAY, true); - - // current aggro target is knocked away pick new target - Unit* Target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 0); - - if (!Target || Target == m_creature->getVictim()) - Target = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1); - - if (Target) - m_creature->TauntApply(Target); - - Knockaway_Timer = 23000; - } - else Knockaway_Timer -= diff; - - //Countercharge_Timer - if (Countercharge_Timer < diff) - { - DoCastSpellIfCan(this->m_creature,SPELL_COUNTERCHARGE); - Countercharge_Timer = 45000; - }else Countercharge_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_crystalcore_devastator(Creature* pCreature) -{ - return new mob_crystalcore_devastatorAI(pCreature); -} - -void AddSC_the_eye() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "mob_crystalcore_devastator"; - pNewScript->GetAI = &GetAI_mob_crystalcore_devastator; - pNewScript->RegisterSelf(); -} diff --git a/scripts/outland/tempest_keep/the_eye/the_eye.h b/scripts/outland/tempest_keep/the_eye/the_eye.h index 1fd2bf0cd..5aa6e60aa 100644 --- a/scripts/outland/tempest_keep/the_eye/the_eye.h +++ b/scripts/outland/tempest_keep/the_eye/the_eye.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,46 +7,48 @@ enum { - MAX_ENCOUNTER = 3, + MAX_ENCOUNTER = 4, + MAX_ADVISORS = 4, TYPE_ALAR = 0, TYPE_SOLARIAN = 1, TYPE_VOIDREAVER = 2, + TYPE_KAELTHAS = 3, - TYPE_KAELTHAS_PHASE = 3, // not regular encounter, contains phase instead - - NPC_ASTROMANCER = 18805, + // NPC_ASTROMANCER = 18805, NPC_KAELTHAS = 19622, NPC_CAPERNIAN = 20062, NPC_SANGUINAR = 20060, NPC_TELONICUS = 20063, NPC_THALADRED = 20064, -}; -enum KaelPhases -{ - PHASE_0_NOT_BEGUN = 0, - PHASE_1_ADVISOR = 1, - PHASE_2_WEAPON = 2, - PHASE_3_ADVISOR_ALL = 3, - PHASE_4_SOLO = 4, - PHASE_5_GRAVITY = 5, - PHASE_6_COMPLETE = 6, + GO_ARCANE_DOOR_HORIZ_3 = 184325, // combat doors for Kael + GO_ARCANE_DOOR_HORIZ_4 = 184324, + // GO_RAID_DOOR_4 = 184329, // encounter doors - no longer used since 2.4.0 + // GO_RAID_DOOR_3 = 184327, + // GO_ARCANE_DOOR_VERT_3 = 184326, + // GO_ARCANE_DOOR_VERT_4 = 184328, + GO_KAEL_STATUE_LEFT = 184597, // cosmetic objects for Kael encounter + GO_KAEL_STATUE_RIGHT = 184596, + GO_BRIDGE_WINDOW = 184069, }; -class MANGOS_DLL_DECL instance_the_eye : public ScriptedInstance +static const uint32 aAdvisors[MAX_ADVISORS] = {NPC_CAPERNIAN, NPC_SANGUINAR, NPC_TELONICUS, NPC_THALADRED}; + +class instance_the_eye : public ScriptedInstance { public: instance_the_eye(Map* pMap); - void Initialize(); - bool IsEncounterInProgress() const; + void Initialize() override; + bool IsEncounterInProgress() const override; - void OnCreatureCreate(Creature* pCreature); + void OnCreatureCreate(Creature* pCreature) override; + void OnObjectCreate(GameObject* pGo) override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; // No Save or Load needed to current knowledge diff --git a/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp b/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp deleted file mode 100644 index 42a7a0e93..000000000 --- a/scripts/outland/tempest_keep/the_mechanar/boss_gatewatcher_ironhand.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* 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 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 - */ - -/* ScriptData -SDName: Boss_Gatewatcher_Ironhand -SD%Complete: 75 -SDComment: -SDCategory: Tempest Keep, The Mechanar -EndScriptData */ - -#include "precompiled.h" - -#define SAY_AGGRO_1 -1554006 -#define SAY_HAMMER_1 -1554007 -#define SAY_HAMMER_2 -1554008 -#define SAY_SLAY_1 -1554009 -#define SAY_SLAY_2 -1554010 -#define SAY_DEATH_1 -1554011 -#define EMOTE_HAMMER -1554012 - -#define SPELL_SHADOW_POWER 35322 -#define SPELL_SHADOW_POWER_H 39193 -#define SPELL_HAMMER_PUNCH 35326 -#define SPELL_JACKHAMMER 35327 -#define SPELL_JACKHAMMER_H 39194 -#define SPELL_STREAM_OF_MACHINE_FLUID 35311 - -struct MANGOS_DLL_DECL boss_gatewatcher_iron_handAI : public ScriptedAI -{ - boss_gatewatcher_iron_handAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; - - uint32 Shadow_Power_Timer; - uint32 Jackhammer_Timer; - uint32 Stream_of_Machine_Fluid_Timer; - - void Reset() - { - Shadow_Power_Timer = 25000; - Jackhammer_Timer = 45000; - Stream_of_Machine_Fluid_Timer = 55000; - } - - void Aggro(Unit *who) - { - DoScriptText(SAY_AGGRO_1, m_creature); - } - - void KilledUnit(Unit* victim) - { - if (urand(0, 1)) - return; - - DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); - } - - void JustDied(Unit* Killer) - { - DoScriptText(SAY_DEATH_1, m_creature); - - if (!m_pInstance) - return; - - //TODO: Add door check/open code - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //Shadow Power - if (Shadow_Power_Timer < diff) - { - DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SHADOW_POWER : SPELL_SHADOW_POWER_H); - Shadow_Power_Timer = urand(20000, 28000); - }else Shadow_Power_Timer -= diff; - - //Jack Hammer - if (Jackhammer_Timer < diff) - { - //TODO: expect cast this about 5 times in a row (?), announce it by emote only once - DoScriptText(EMOTE_HAMMER, m_creature); - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_JACKHAMMER : SPELL_JACKHAMMER_H); - - //chance to yell, but not same time as emote (after spell in fact casted) - if (urand(0, 4)) - DoScriptText(urand(0, 1) ? SAY_HAMMER_1 : SAY_HAMMER_2, m_creature); - - Jackhammer_Timer = 30000; - }else Jackhammer_Timer -= diff; - - //Stream of Machine Fluid - if (Stream_of_Machine_Fluid_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_STREAM_OF_MACHINE_FLUID); - Stream_of_Machine_Fluid_Timer = urand(35000, 50000); - }else Stream_of_Machine_Fluid_Timer -= diff; - - DoMeleeAttackIfReady(); - } -}; -CreatureAI* GetAI_boss_gatewatcher_iron_hand(Creature* pCreature) -{ - return new boss_gatewatcher_iron_handAI(pCreature); -} - -void AddSC_boss_gatewatcher_iron_hand() -{ - Script* pNewScript; - - pNewScript = new Script; - pNewScript->Name = "boss_gatewatcher_iron_hand"; - pNewScript->GetAI = &GetAI_boss_gatewatcher_iron_hand; - pNewScript->RegisterSelf(); -} diff --git a/scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp b/scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp index 70cb2a847..a75697a71 100644 --- a/scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp +++ b/scripts/outland/tempest_keep/the_mechanar/boss_nethermancer_sepethrea.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,7 +16,7 @@ /* ScriptData SDName: Boss_Nethermancer_Sepethrea -SD%Complete: 90 +SD%Complete: 95 SDComment: May need some small adjustments SDCategory: Tempest Keep, The Mechanar EndScriptData */ @@ -34,22 +34,16 @@ enum SAY_SLAY2 = -1554018, SAY_DEATH = -1554019, - SPELL_SUMMON_RAGIN_FLAMES = 35275, - SPELL_FROST_ATTACK = 35263, + SPELL_SUMMON_RAGING_FLAMES = 35275, + SPELL_SUMMON_RAGING_FLAMES_H = 39084, + SPELL_FROST_ATTACK = 45195, SPELL_ARCANE_BLAST = 35314, SPELL_DRAGONS_BREATH = 35250, - SPELL_KNOCKBACK = 37317, - SPELL_SOLARBURN = 35267, NPC_RAGING_FLAMES = 20481, - - // Summons spells - SPELL_INFERNO = 35268, - SPELL_INFERNO_H = 39346, - SPELL_FIRE_TAIL = 35278, }; -struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI +struct boss_nethermancer_sepethreaAI : public ScriptedAI { boss_nethermancer_sepethreaAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -64,30 +58,29 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI uint32 m_uiFrostAttackTimer; uint32 m_uiArcaneBlastTimer; uint32 m_uiDragonsBreathTimer; - uint32 m_uiKnockbackTimer; - uint32 m_uiSolarburnTimer; - void Reset() + void Reset() override { - m_uiFrostAttackTimer = urand(7000, 10000); - m_uiArcaneBlastTimer = urand(12000, 18000); - m_uiDragonsBreathTimer = urand(18000, 22000); - m_uiKnockbackTimer = urand(22000, 28000); - m_uiSolarburnTimer = 30000; + m_uiFrostAttackTimer = urand(8000, 17000); + m_uiArcaneBlastTimer = urand(14000, 25000); + m_uiDragonsBreathTimer = urand(20000, 26000); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); - DoCastSpellIfCan(m_creature, SPELL_SUMMON_RAGIN_FLAMES); + DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SUMMON_RAGING_FLAMES : SPELL_SUMMON_RAGING_FLAMES_H); + + if (m_pInstance) + m_pInstance->SetData(TYPE_SEPETHREA, IN_PROGRESS); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY1 : SAY_SLAY2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); @@ -95,7 +88,13 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI m_pInstance->SetData(TYPE_SEPETHREA, DONE); } - void JustSummoned(Creature* pSummoned) + void JustReachedHome() override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_SEPETHREA, FAIL); + } + + void JustSummoned(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_RAGING_FLAMES) { @@ -108,7 +107,7 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -118,7 +117,7 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI if (m_uiFrostAttackTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_ATTACK) == CAST_OK) - m_uiFrostAttackTimer = urand(7000, 10000); + m_uiFrostAttackTimer = urand(5000, 17000); } else m_uiFrostAttackTimer -= uiDiff; @@ -127,7 +126,7 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI if (m_uiArcaneBlastTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_ARCANE_BLAST) == CAST_OK) - m_uiArcaneBlastTimer = 15000; + m_uiArcaneBlastTimer = urand(15000, 30000); } else m_uiArcaneBlastTimer -= uiDiff; @@ -140,33 +139,12 @@ struct MANGOS_DLL_DECL boss_nethermancer_sepethreaAI : public ScriptedAI if (urand(0, 1)) DoScriptText(urand(0, 1) ? SAY_DRAGONS_BREATH_1 : SAY_DRAGONS_BREATH_2, m_creature); - m_uiDragonsBreathTimer = urand(12000, 22000); + m_uiDragonsBreathTimer = urand(20000, 35000); } } else m_uiDragonsBreathTimer -= uiDiff; - // Knockback - if (m_uiKnockbackTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_KNOCKBACK) == CAST_OK) - m_uiKnockbackTimer = urand(15000, 25000); - } - else - m_uiKnockbackTimer -= uiDiff; - - // Solarburn - if (m_uiSolarburnTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1)) - { - if (DoCastSpellIfCan(pTarget, SPELL_SOLARBURN) == CAST_OK) - m_uiSolarburnTimer = 30000; - } - } - else - m_uiSolarburnTimer -= uiDiff; - DoMeleeAttackIfReady(); } }; @@ -176,56 +154,6 @@ CreatureAI* GetAI_boss_nethermancer_sepethrea(Creature* pCreature) return new boss_nethermancer_sepethreaAI(pCreature); } -struct MANGOS_DLL_DECL mob_ragin_flamesAI : public ScriptedAI -{ - mob_ragin_flamesAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - ScriptedInstance* m_pInstance; - bool m_bIsRegularMode; - - uint32 inferno_Timer; - uint32 flame_timer; - - void Reset() - { - inferno_Timer = 10000; - flame_timer = 500; - } - - void UpdateAI(const uint32 diff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (inferno_Timer < diff) - { - DoCastSpellIfCan(m_creature->getVictim(), m_bIsRegularMode ? SPELL_INFERNO : SPELL_INFERNO_H); - - m_creature->TauntApply(m_creature->getVictim()); - - inferno_Timer = 10000; - }else inferno_Timer -= diff; - - if (flame_timer < diff) - { - DoCastSpellIfCan(m_creature,SPELL_FIRE_TAIL); - flame_timer = 500; - }else flame_timer -=diff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_mob_ragin_flames(Creature* pCreature) -{ - return new mob_ragin_flamesAI(pCreature); -} - void AddSC_boss_nethermancer_sepethrea() { Script* pNewScript; @@ -234,9 +162,4 @@ void AddSC_boss_nethermancer_sepethrea() pNewScript->Name = "boss_nethermancer_sepethrea"; pNewScript->GetAI = &GetAI_boss_nethermancer_sepethrea; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_ragin_flames"; - pNewScript->GetAI = &GetAI_mob_ragin_flames; - pNewScript->RegisterSelf(); } diff --git a/scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp b/scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp index c602a7b3c..dcfc99a7f 100644 --- a/scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp +++ b/scripts/outland/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +16,13 @@ /* ScriptData SDName: Boss Pathaleon the Calculator -SD%Complete: 40 -SDComment: Pathway event NYI; The Nether Wraith script is wrong - needs research and update +SD%Complete: 95 +SDComment: Timers may need update. SDCategory: Tempest Keep, The Mechanar EndScriptData */ #include "precompiled.h" +#include "mechanar.h" enum { @@ -40,7 +41,8 @@ enum SPELL_DOMINATION = 35280, SPELL_ARCANE_EXPLOSION_H = 15453, SPELL_FRENZY = 36992, - SPELL_DISGRUNTLED_ANGER = 35289, // research where to use this - possible to be used by Nether Wraits when boss is at 20% HP + SPELL_SUICIDE = 35301, // kill the Nether Wraiths + SPELL_DISGRUNTLED_ANGER = 35289, // empower a Nether Wraith SPELL_SUMMON_NETHER_WRAITH_1 = 35285, SPELL_SUMMON_NETHER_WRAITH_2 = 35286, @@ -54,85 +56,73 @@ enum static const uint32 aWraithSummonSpells[4] = {SPELL_SUMMON_NETHER_WRAITH_1, SPELL_SUMMON_NETHER_WRAITH_2, SPELL_SUMMON_NETHER_WRAITH_3, SPELL_SUMMON_NETHER_WRAITH_4}; -struct MANGOS_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI +struct boss_pathaleon_the_calculatorAI : public ScriptedAI { boss_pathaleon_the_calculatorAI(Creature* pCreature) : ScriptedAI(pCreature) { - // Add the summon spells to a vector for better handling - for (uint8 i = 0; i < 4; ++i) - m_vSummonSpells.push_back(aWraithSummonSpells[i]); - + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); Reset(); } + ScriptedInstance* m_pInstance; bool m_bIsRegularMode; uint32 m_uiSummonTimer; + uint32 m_uiAngerTimer; uint32 m_uiManaTapTimer; uint32 m_uiArcaneTorrentTimer; uint32 m_uiDominationTimer; uint32 m_uiArcaneExplosionTimer; bool m_bIsEnraged; - std::vector m_vSummonSpells; - - void Reset() + void Reset() override { - m_uiSummonTimer = 30000; - m_uiManaTapTimer = urand(12000, 20000); - m_uiArcaneTorrentTimer = urand(16000, 25000); + m_uiSummonTimer = urand(12000, 23000); + m_uiAngerTimer = urand(31000, 42000); + m_uiManaTapTimer = urand(2000, 9000); + m_uiArcaneTorrentTimer = urand(11000, 24000); m_uiDominationTimer = urand(25000, 40000); - m_uiArcaneExplosionTimer = urand(8000, 13000); + m_uiArcaneExplosionTimer = urand(18000, 45000); m_bIsEnraged = false; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* /*pVictim*/) override { DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); } - void JustDied(Unit* pKiller) + void JustDied(Unit* /*pKiller*/) override { DoScriptText(SAY_DEATH, m_creature); + + if (m_pInstance) + m_pInstance->SetData(TYPE_PATHALEON, DONE); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (m_creature->getVictim()) pSummoned->AI()->AttackStart(m_creature->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (m_uiSummonTimer < uiDiff) - { - // Choose 3 random spells out of 4 - std::random_shuffle(m_vSummonSpells.begin(), m_vSummonSpells.end()); - for (uint8 i = 0; i < 3; ++i) - DoCastSpellIfCan(m_creature, m_vSummonSpells[i], CAST_TRIGGERED); - - DoScriptText(SAY_SUMMON, m_creature); - m_uiSummonTimer = urand(30000, 45000); - } - else - m_uiSummonTimer -= uiDiff; - if (m_uiManaTapTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANA_TAP, SELECT_FLAG_POWER_MANA)) { if (DoCastSpellIfCan(pTarget, SPELL_MANA_TAP) == CAST_OK) - m_uiManaTapTimer = urand(14000, 22000); + m_uiManaTapTimer = urand(16000, 34000); } } else @@ -141,7 +131,7 @@ struct MANGOS_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI if (m_uiArcaneTorrentTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_TORRENT) == CAST_OK) - m_uiArcaneTorrentTimer = urand(12000, 18000); + m_uiArcaneTorrentTimer = urand(40000, 52000); } else m_uiArcaneTorrentTimer -= uiDiff; @@ -166,7 +156,7 @@ struct MANGOS_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI if (m_uiArcaneExplosionTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_ARCANE_EXPLOSION_H) == CAST_OK) - m_uiArcaneExplosionTimer = urand(10000, 14000); + m_uiArcaneExplosionTimer = urand(13000, 25000); } else m_uiArcaneExplosionTimer -= uiDiff; @@ -176,30 +166,53 @@ struct MANGOS_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI { if (DoCastSpellIfCan(m_creature, SPELL_FRENZY) == CAST_OK) { - // ToDo: despawn nether wraiths here + DoCastSpellIfCan(m_creature, SPELL_SUICIDE, CAST_TRIGGERED); DoScriptText(SAY_ENRAGE, m_creature); m_bIsEnraged = true; } } + // Summon and empower Nether Wraiths only when not enraged + else + { + if (m_uiSummonTimer < uiDiff) + { + uint8 uiMaxWraith = urand(3, 4); + for (uint8 i = 0; i < uiMaxWraith; ++i) + DoCastSpellIfCan(m_creature, aWraithSummonSpells[i], CAST_TRIGGERED); + + DoScriptText(SAY_SUMMON, m_creature); + m_uiSummonTimer = urand(45000, 50000); + } + else + m_uiSummonTimer -= uiDiff; + + if (m_uiAngerTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DISGRUNTLED_ANGER) == CAST_OK) + m_uiAngerTimer = urand(55000, 84000); + } + else + m_uiAngerTimer -= uiDiff; + } DoMeleeAttackIfReady(); } }; -struct MANGOS_DLL_DECL mob_nether_wraithAI : public ScriptedAI +struct mob_nether_wraithAI : public ScriptedAI { mob_nether_wraithAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint32 m_uiArcaneMissilesTimer; - uint32 m_uiDetonationTimer; + bool m_bHasDetonated; - void Reset() + void Reset() override { m_uiArcaneMissilesTimer = urand(1000, 4000); - m_uiDetonationTimer = 20000; + m_bHasDetonated = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -217,21 +230,17 @@ struct MANGOS_DLL_DECL mob_nether_wraithAI : public ScriptedAI } } else - m_uiArcaneMissilesTimer -=uiDiff; + m_uiArcaneMissilesTimer -= uiDiff; - if (m_uiDetonationTimer) + if (!m_bHasDetonated && m_creature->GetHealthPercent() < 10.0f) { - if (m_uiDetonationTimer <= uiDiff) + if (DoCastSpellIfCan(m_creature, SPELL_DETONATION, CAST_TRIGGERED) == CAST_OK) { - if (DoCastSpellIfCan(m_creature, SPELL_DETONATION) == CAST_OK) - { - // Not sure if this one needs to be despawned here. Needs further research - //m_creature->ForcedDespawn(2200); - m_uiDetonationTimer = 0; - } + // Selfkill after the detonation + m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false); + m_bHasDetonated = true; + return; } - else - m_uiDetonationTimer -= uiDiff; } DoMeleeAttackIfReady(); diff --git a/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp b/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp index 37ec25031..f0574a4ab 100644 --- a/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp +++ b/scripts/outland/tempest_keep/the_mechanar/instance_mechanar.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,39 +16,231 @@ /* ScriptData SDName: Instance_Mechanar -SD%Complete: 20 -SDComment: +SD%Complete: 70 +SDComment: Elevator needs core support SDCategory: Mechanar EndScriptData */ #include "precompiled.h" #include "mechanar.h" -instance_mechanar::instance_mechanar(Map* pMap) : ScriptedInstance(pMap) { Initialize(); } +instance_mechanar::instance_mechanar(Map* pMap) : ScriptedInstance(pMap), + m_uiBridgeEventTimer(0), + m_uiBridgeEventPhase(0) +{ + Initialize(); +} void instance_mechanar::Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); } +void instance_mechanar::OnPlayerEnter(Player* pPlayer) +{ + // Check encounter states + if (GetData(TYPE_SEPETHREA) != DONE || GetData(TYPE_PATHALEON) == DONE) + return; + + // Check if already summoned + if (GetSingleCreatureFromStorage(NPC_PATHALEON, true)) + return; + + pPlayer->SummonCreature(aBridgeEventLocs[6][0].m_uiSpawnEntry, aBridgeEventLocs[6][0].m_fX, aBridgeEventLocs[6][0].m_fY, aBridgeEventLocs[6][0].m_fZ, aBridgeEventLocs[6][0].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0); +} + +void instance_mechanar::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_PATHALEON: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + case NPC_ASTROMAGE: + case NPC_PHYSICIAN: + case NPC_CENTURION: + case NPC_ENGINEER: + case NPC_NETHERBINDER: + case NPC_FORGE_DESTROYER: + if (pCreature->IsTemporarySummon()) + m_sBridgeTrashGuidSet.insert(pCreature->GetObjectGuid()); + break; + } +} + +void instance_mechanar::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_MOARG_DOOR_1: + if (m_auiEncounter[TYPE_GYRO_KILL] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_MOARG_DOOR_2: + if (m_auiEncounter[TYPE_IRON_HAND] == DONE) + pGo->SetGoState(GO_STATE_ACTIVE); + break; + case GO_NETHERMANCER_DOOR: + break; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + void instance_mechanar::SetData(uint32 uiType, uint32 uiData) { - switch(uiType) + switch (uiType) { + case TYPE_GYRO_KILL: + if (uiData == DONE) + DoUseDoorOrButton(GO_MOARG_DOOR_1); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_IRON_HAND: + if (uiData == DONE) + DoUseDoorOrButton(GO_MOARG_DOOR_2); + m_auiEncounter[uiType] = uiData; + break; + case TYPE_CAPACITUS: + m_auiEncounter[uiType] = uiData; + break; case TYPE_SEPETHREA: - m_auiEncounter[0] = uiData; + m_auiEncounter[uiType] = uiData; + if (uiData == DONE) + m_uiBridgeEventTimer = 10000; + DoUseDoorOrButton(GO_NETHERMANCER_DOOR); + break; + case TYPE_PATHALEON: + m_auiEncounter[uiType] = uiData; break; } + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } } -uint32 instance_mechanar::GetData(uint32 uiType) +uint32 instance_mechanar::GetData(uint32 uiType) const { - if (uiType == TYPE_SEPETHREA) - return m_auiEncounter[0]; + if (uiType < MAX_ENCOUNTER) + return m_auiEncounter[uiType]; return 0; } +void instance_mechanar::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + { + if (m_auiEncounter[i] == IN_PROGRESS) + m_auiEncounter[i] = NOT_STARTED; + } + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_mechanar::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_GYRO_KILL: SetData(TYPE_GYRO_KILL, DONE); break; + case NPC_IRON_HAND: SetData(TYPE_IRON_HAND, DONE); break; + case NPC_LORD_CAPACITUS: SetData(TYPE_CAPACITUS, DONE); break; + + case NPC_ASTROMAGE: + case NPC_PHYSICIAN: + case NPC_CENTURION: + case NPC_ENGINEER: + case NPC_NETHERBINDER: + case NPC_FORGE_DESTROYER: + if (m_sBridgeTrashGuidSet.find(pCreature->GetObjectGuid()) != m_sBridgeTrashGuidSet.end()) + { + m_sBridgeTrashGuidSet.erase(pCreature->GetObjectGuid()); + + if (m_sBridgeTrashGuidSet.empty()) + { + // After the 3rd wave wait 10 seconds + if (m_uiBridgeEventPhase == 3) + m_uiBridgeEventTimer = 10000; + else + DoSpawnBridgeWave(); + } + } + break; + } +} + +void instance_mechanar::DoSpawnBridgeWave() +{ + if (Player* pPlayer = GetPlayerInMap(true, false)) + { + for (uint8 i = 0; i < MAX_BRIDGE_TRASH; ++i) + { + // Skip the blank entries + if (aBridgeEventLocs[m_uiBridgeEventPhase][i].m_uiSpawnEntry == 0) + break; + + if (Creature* pTemp = pPlayer->SummonCreature(aBridgeEventLocs[m_uiBridgeEventPhase][i].m_uiSpawnEntry, aBridgeEventLocs[m_uiBridgeEventPhase][i].m_fX, aBridgeEventLocs[m_uiBridgeEventPhase][i].m_fY, aBridgeEventLocs[m_uiBridgeEventPhase][i].m_fZ, aBridgeEventLocs[m_uiBridgeEventPhase][i].m_fO, TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pTemp->CastSpell(pTemp, SPELL_ETHEREAL_TELEPORT, false); + + switch (m_uiBridgeEventPhase) + { + case 1: // These waves should attack the player directly + case 2: + case 4: + case 5: + pTemp->AI()->AttackStart(pPlayer); + break; + case 6: // Pathaleon + DoScriptText(SAY_PATHALEON_INTRO, pTemp); + break; + } + } + } + } + ++m_uiBridgeEventPhase; +} + +void instance_mechanar::Update(uint32 uiDiff) +{ + if (m_uiBridgeEventTimer) + { + if (m_uiBridgeEventTimer <= uiDiff) + { + DoSpawnBridgeWave(); + m_uiBridgeEventTimer = 0; + } + else + m_uiBridgeEventTimer -= uiDiff; + } +} + InstanceData* GetInstanceData_instance_mechanar(Map* pMap) { return new instance_mechanar(pMap); diff --git a/scripts/outland/tempest_keep/the_mechanar/mechanar.h b/scripts/outland/tempest_keep/the_mechanar/mechanar.h index fe53e938b..c1d6e5279 100644 --- a/scripts/outland/tempest_keep/the_mechanar/mechanar.h +++ b/scripts/outland/tempest_keep/the_mechanar/mechanar.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -7,23 +7,117 @@ enum { - MAX_ENCOUNTER = 1, + MAX_ENCOUNTER = 5, + MAX_BRIDGE_LOCATIONS = 7, + MAX_BRIDGE_TRASH = 4, - TYPE_SEPETHREA = 1 + TYPE_GYRO_KILL = 0, + TYPE_IRON_HAND = 1, + TYPE_CAPACITUS = 2, + TYPE_SEPETHREA = 3, + TYPE_PATHALEON = 4, + + NPC_GYRO_KILL = 19218, + NPC_IRON_HAND = 19710, + NPC_LORD_CAPACITUS = 19219, + // NPC_SEPETHREA = 19221, + NPC_PATHALEON = 19220, + + // bridge event related + NPC_ASTROMAGE = 19168, + NPC_PHYSICIAN = 20990, + NPC_CENTURION = 19510, + NPC_ENGINEER = 20988, + NPC_NETHERBINDER = 20059, + NPC_FORGE_DESTROYER = 19735, + + GO_MOARG_DOOR_1 = 184632, + GO_MOARG_DOOR_2 = 184322, + // GO_FACTORY_ELEVATOR = 183788, + GO_NETHERMANCER_DOOR = 184449, + + SPELL_ETHEREAL_TELEPORT = 34427, + + SAY_PATHALEON_INTRO = -1554028, +}; + +struct SpawnLocation +{ + uint32 m_uiSpawnEntry; + float m_fX, m_fY, m_fZ, m_fO; +}; + +static const SpawnLocation aBridgeEventLocs[MAX_BRIDGE_LOCATIONS][4] = +{ + { + {NPC_ASTROMAGE, 243.9323f, -24.53621f, 26.3284f, 0}, + {NPC_ASTROMAGE, 240.5847f, -21.25438f, 26.3284f, 0}, + {NPC_PHYSICIAN, 238.4178f, -25.92982f, 26.3284f, 0}, + {NPC_CENTURION, 237.1122f, -19.14261f, 26.3284f, 0}, + }, + { + {NPC_FORGE_DESTROYER, 199.945f, -22.85885f, 24.95783f, 0}, + {0, 0, 0, 0, 0}, + }, + { + {NPC_ENGINEER, 179.8642f, -25.84609f, 24.8745f, 0}, + {NPC_ENGINEER, 181.9983f, -17.56084f, 24.8745f, 0}, + {NPC_PHYSICIAN, 183.4078f, -22.46612f, 24.8745f, 0}, + {0, 0, 0, 0, 0}, + }, + { + {NPC_ENGINEER, 141.0496f, 37.86048f, 24.87399f, 4.65f}, + {NPC_ASTROMAGE, 137.6626f, 34.89631f, 24.8742f, 4.65f}, + {NPC_PHYSICIAN, 135.3587f, 38.03816f, 24.87417f, 4.65f}, + {0, 0, 0, 0, 0}, + }, + { + {NPC_FORGE_DESTROYER, 137.8275f, 53.18128f, 24.95783f, 4.65f}, + {0, 0, 0, 0, 0}, + }, + { + {NPC_PHYSICIAN, 134.3062f, 109.1506f, 26.45663f, 4.65f}, + {NPC_ASTROMAGE, 135.3307f, 99.96439f, 26.45663f, 4.65f}, + {NPC_NETHERBINDER, 141.3976f, 102.7863f, 26.45663f, 4.65f}, + {NPC_ENGINEER, 140.8281f, 112.0363f, 26.45663f, 4.65f}, + }, + { + {NPC_PATHALEON, 139.5425f, 149.3192f, 25.65904f, 4.63f}, + {0, 0, 0, 0, 0}, + }, }; -class MANGOS_DLL_DECL instance_mechanar : public ScriptedInstance +class instance_mechanar : public ScriptedInstance { public: instance_mechanar(Map* pMap); - void Initialize(); + void Initialize() override; + + void OnPlayerEnter(Player* pPlayer) override; + void OnObjectCreate(GameObject* pGo) override; + void OnCreatureCreate(Creature* pCreature) override; + + void OnCreatureDeath(Creature* pCreature) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; - void SetData(uint32 uiType, uint32 uiData); - uint32 GetData(uint32 uiType); + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; private: + void DoSpawnBridgeWave(); + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + uint32 m_uiBridgeEventTimer; + uint8 m_uiBridgeEventPhase; + + GuidSet m_sBridgeTrashGuidSet; }; #endif diff --git a/scripts/outland/terokkar_forest.cpp b/scripts/outland/terokkar_forest.cpp index e15a1a3b5..2463772ec 100644 --- a/scripts/outland/terokkar_forest.cpp +++ b/scripts/outland/terokkar_forest.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,26 +17,24 @@ /* ScriptData SDName: Terokkar_Forest SD%Complete: 80 -SDComment: Quest support: 9889, 10009, 10873, 10896, 10446/10447, 10852, 10887, 10922, 11096, 11093, 10051, 10052, 10898. +SDComment: Quest support: 9889, 10009, 10051, 10052, 10446/10447, 10852, 10873, 10887, 10896, 10898, 10922, 10988, 11085, 11093, 11096. SDCategory: Terokkar Forest EndScriptData */ /* ContentData mob_unkor_the_ruthless -mob_infested_root_walker -mob_rotting_forest_rager mob_netherweb_victim npc_akuno -npc_floon npc_hungry_nether_ray npc_letoll npc_mana_bomb_exp_trigger go_mana_bomb -npc_slim go_veil_skith_cage npc_captive_child npc_isla_starmane npc_skywing +npc_cenarion_sparrowhawk +npc_skyguard_prisoner EndContentData */ #include "precompiled.h" @@ -51,35 +49,34 @@ enum { SAY_SUBMIT = -1000194, - FACTION_HOSTILE = 45, FACTION_FRIENDLY = 35, - QUEST_DONT_KILL_THE_FAT_ONE = 9889, SPELL_PULVERIZE = 2676, - // SPELL_QUID9889 = 32174, // TODO Make use of this quest-credit spell + SPELL_QUID9889 = 32174, }; -struct MANGOS_DLL_DECL mob_unkor_the_ruthlessAI : public ScriptedAI +struct mob_unkor_the_ruthlessAI : public ScriptedAI { mob_unkor_the_ruthlessAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } bool m_bCanDoQuest; uint32 m_uiUnfriendlyTimer; uint32 m_uiPulverizeTimer; + uint32 m_uiFriendlyTimer; - void Reset() + void Reset() override { - m_bCanDoQuest = false; + m_bCanDoQuest = false; m_uiUnfriendlyTimer = 0; - m_uiPulverizeTimer = 3000; + m_uiFriendlyTimer = 0; + m_uiPulverizeTimer = 3000; m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->setFaction(FACTION_HOSTILE); } void DoNice() { DoScriptText(SAY_SUBMIT, m_creature); - m_creature->setFaction(FACTION_FRIENDLY); + m_creature->SetFactionTemporary(FACTION_FRIENDLY, TEMPFACTION_RESTORE_REACH_HOME); m_creature->SetStandState(UNIT_STAND_STATE_SIT); m_creature->RemoveAllAuras(); m_creature->DeleteThreatList(); @@ -87,58 +84,40 @@ struct MANGOS_DLL_DECL mob_unkor_the_ruthlessAI : public ScriptedAI m_uiUnfriendlyTimer = 60000; } - void DamageTaken(Unit* pDealer, uint32 &uiDamage) + void UpdateAI(const uint32 uiDiff) override { - if ((m_creature->GetHealth() - uiDamage)*100 / m_creature->GetMaxHealth() >= 30) + // Reset npc on timer + if (m_uiUnfriendlyTimer) + { + if (m_uiUnfriendlyTimer <= uiDiff) + EnterEvadeMode(); + else + m_uiUnfriendlyTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; - if (Player* pPlayer = pDealer->GetCharmerOrOwnerPlayerOrPlayerItself()) + // Do quest kill credit at 30% + if (!m_bCanDoQuest && m_creature->GetHealthPercent() < 30.0f) { - if (Group* pGroup = pPlayer->GetGroup()) - { - for(GroupReference* itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* pGroupie = itr->getSource(); - if (pGroupie && - pGroupie->GetQuestStatus(QUEST_DONT_KILL_THE_FAT_ONE) == QUEST_STATUS_INCOMPLETE && - pGroupie->GetReqKillOrCastCurrentCount(QUEST_DONT_KILL_THE_FAT_ONE, 18260) == 10) - { - pGroupie->AreaExploredOrEventHappens(QUEST_DONT_KILL_THE_FAT_ONE); - if (!m_bCanDoQuest) - m_bCanDoQuest = true; - } - } - } - else if (pPlayer->GetQuestStatus(QUEST_DONT_KILL_THE_FAT_ONE) == QUEST_STATUS_INCOMPLETE && - pPlayer->GetReqKillOrCastCurrentCount(QUEST_DONT_KILL_THE_FAT_ONE, 18260) == 10) - { - pPlayer->AreaExploredOrEventHappens(QUEST_DONT_KILL_THE_FAT_ONE); - m_bCanDoQuest = true; - } + DoCastSpellIfCan(m_creature, SPELL_QUID9889, CAST_TRIGGERED); + m_uiFriendlyTimer = 1000; + m_bCanDoQuest = true; } - } - void UpdateAI(const uint32 uiDiff) - { - if (m_bCanDoQuest) + // Set faction right after the spell is casted, in order to avoid any issues + if (m_uiFriendlyTimer) { - if (!m_uiUnfriendlyTimer) + if (m_uiFriendlyTimer <= uiDiff) { - //DoCastSpellIfCan(m_creature,SPELL_QUID9889); //not using spell for now DoNice(); + m_uiFriendlyTimer = 0; } else - { - if (m_uiUnfriendlyTimer <= uiDiff) - EnterEvadeMode(); - else - m_uiUnfriendlyTimer -= uiDiff; - } + m_uiFriendlyTimer -= uiDiff; } - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - if (m_uiPulverizeTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_PULVERIZE); @@ -156,65 +135,6 @@ CreatureAI* GetAI_mob_unkor_the_ruthless(Creature* pCreature) return new mob_unkor_the_ruthlessAI(pCreature); } -/*###### -## mob_infested_root_walker -######*/ - -enum -{ - SPELL_SUMMON_WOOD_MITES = 39130, -}; - -struct MANGOS_DLL_DECL mob_infested_root_walkerAI : public ScriptedAI -{ - mob_infested_root_walkerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() { } - - void DamageTaken(Unit* pDealer, uint32 &uiDamage) - { - if (m_creature->GetHealth() <= uiDamage) - if (pDealer->IsControlledByPlayer()) - if (urand(0, 3)) - //Summon Wood Mites - DoCastSpellIfCan(m_creature, SPELL_SUMMON_WOOD_MITES, CAST_TRIGGERED); - } -}; - -CreatureAI* GetAI_mob_infested_root_walker(Creature* pCreature) -{ - return new mob_infested_root_walkerAI(pCreature); -} - -/*###### -## mob_rotting_forest_rager -######*/ - -enum -{ - SPELL_SUMMON_LOTS_OF_WOOD_MIGHTS = 39134, -}; - -struct MANGOS_DLL_DECL mob_rotting_forest_ragerAI : public ScriptedAI -{ - mob_rotting_forest_ragerAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - void Reset() { } - - void DamageTaken(Unit* pDealer, uint32 &uiDamage) - { - if (m_creature->GetHealth() <= uiDamage) - if (pDealer->IsControlledByPlayer()) - if (urand(0, 3)) - //Summon Lots of Wood Mights - DoCastSpellIfCan(m_creature, SPELL_SUMMON_LOTS_OF_WOOD_MIGHTS, CAST_TRIGGERED); - } -}; -CreatureAI* GetAI_mob_rotting_forest_rager(Creature* pCreature) -{ - return new mob_rotting_forest_ragerAI(pCreature); -} - /*###### ## mob_netherweb_victim ######*/ @@ -223,14 +143,15 @@ enum { NPC_FREED_WARRIOR = 22459, QUEST_TAKEN_IN_NIGHT = 10873 - //SPELL_FREE_WEBBED = 38950 + // SPELL_FREE_WEBBED = 38950 }; const uint32 netherwebVictims[6] = { 18470, 16805, 21242, 18452, 22482, 21285 }; -struct MANGOS_DLL_DECL mob_netherweb_victimAI : public ScriptedAI + +struct mob_netherweb_victimAI : public ScriptedAI { mob_netherweb_victimAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -238,10 +159,10 @@ struct MANGOS_DLL_DECL mob_netherweb_victimAI : public ScriptedAI Reset(); } - void Reset() { } - void MoveInLineOfSight(Unit* pWho) { } + void Reset() override { } + void MoveInLineOfSight(Unit* /*pWho*/) override { } - void JustDied(Unit* pKiller) + void JustDied(Unit* pKiller) override { if (Player* pPlayer = pKiller->GetCharmerOrOwnerPlayerOrPlayerItself()) { @@ -249,11 +170,11 @@ struct MANGOS_DLL_DECL mob_netherweb_victimAI : public ScriptedAI { if (!urand(0, 3)) { - m_creature->SummonCreature(NPC_FREED_WARRIOR, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(NPC_FREED_WARRIOR, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); pPlayer->KilledMonsterCredit(NPC_FREED_WARRIOR, m_creature->GetObjectGuid()); } else - m_creature->SummonCreature(netherwebVictims[urand(0, 5)], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + m_creature->SummonCreature(netherwebVictims[urand(0, 5)], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 60000); } } } @@ -282,35 +203,35 @@ enum NPC_CABAL_SKIRMISHER = 21661 }; -static float m_afAmbushB1[]= {-2895.525879f, 5336.431641f, -11.800f}; -static float m_afAmbushB2[]= {-2890.604980f, 5331.938965f, -11.282f}; +static float m_afAmbushB1[] = { -2895.525879f, 5336.431641f, -11.800f}; +static float m_afAmbushB2[] = { -2890.604980f, 5331.938965f, -11.282f}; -struct MANGOS_DLL_DECL npc_akunoAI : public npc_escortAI +struct npc_akunoAI : public npc_escortAI { npc_akunoAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } uint32 m_uiChainLightningTimer; - void Reset() + void Reset() override { m_uiChainLightningTimer = 1000; } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 5: DoScriptText(SAY_AKU_AMBUSH_A, m_creature); - m_creature->SummonCreature(NPC_CABAL_SKIRMISHER, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_CABAL_SKIRMISHER, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 14: DoScriptText(SAY_AKU_AMBUSH_B, m_creature); - if (Creature* pTemp = m_creature->SummonCreature(NPC_CABAL_SKIRMISHER, m_afAmbushB1[0], m_afAmbushB1[1], m_afAmbushB1[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000)) + if (Creature* pTemp = m_creature->SummonCreature(NPC_CABAL_SKIRMISHER, m_afAmbushB1[0], m_afAmbushB1[1], m_afAmbushB1[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000)) DoScriptText(SAY_AKU_AMBUSH_B_REPLY, pTemp); - m_creature->SummonCreature(NPC_CABAL_SKIRMISHER, m_afAmbushB2[0], m_afAmbushB2[1], m_afAmbushB2[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); + m_creature->SummonCreature(NPC_CABAL_SKIRMISHER, m_afAmbushB2[0], m_afAmbushB2[1], m_afAmbushB2[2], 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 25000); break; case 15: SetRun(); @@ -325,12 +246,12 @@ struct MANGOS_DLL_DECL npc_akunoAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -354,7 +275,7 @@ bool QuestAccept_npc_akuno(Player* pPlayer, Creature* pCreature, const Quest* pQ if (npc_akunoAI* pEscortAI = dynamic_cast(pCreature->AI())) { pCreature->SetStandState(UNIT_STAND_STATE_STAND); - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); DoScriptText(SAY_AKU_START, pCreature); pEscortAI->Start(false, pPlayer, pQuest); @@ -368,72 +289,6 @@ CreatureAI* GetAI_npc_akuno(Creature* pCreature) return new npc_akunoAI(pCreature); } -/*###### -## npc_floon -- TODO move to EventAI -######*/ - -enum -{ - SPELL_SILENCE = 6726, - SPELL_FROSTBOLT = 9672, - SPELL_FROST_NOVA = 11831, -}; - -struct MANGOS_DLL_DECL npc_floonAI : public ScriptedAI -{ - npc_floonAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_uiNormFaction = pCreature->getFaction(); - Reset(); - } - - uint32 m_uiNormFaction; - uint32 m_uiSilence_Timer; - uint32 m_uiFrostbolt_Timer; - uint32 m_uiFrostNova_Timer; - - void Reset() - { - m_uiSilence_Timer = 2000; - m_uiFrostbolt_Timer = 4000; - m_uiFrostNova_Timer = 9000; - - if (m_creature->getFaction() != m_uiNormFaction) - m_creature->setFaction(m_uiNormFaction); - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - if (m_uiSilence_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_SILENCE); - m_uiSilence_Timer = 30000; - }else m_uiSilence_Timer -= uiDiff; - - if (m_uiFrostNova_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature,SPELL_FROST_NOVA); - m_uiFrostNova_Timer = 20000; - }else m_uiFrostNova_Timer -= uiDiff; - - if (m_uiFrostbolt_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_FROSTBOLT); - m_uiFrostbolt_Timer = 5000; - }else m_uiFrostbolt_Timer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - -CreatureAI* GetAI_npc_floon(Creature* pCreature) -{ - return new npc_floonAI(pCreature); -} - /*###### ## npc_hungry_nether_ray ######*/ @@ -445,13 +300,13 @@ enum SPELL_FEED_CREDIT = 41427, // credit for quest 11093 }; -struct MANGOS_DLL_DECL npc_hungry_nether_rayAI : public ScriptedPetAI +struct npc_hungry_nether_rayAI : public ScriptedPetAI { npc_hungry_nether_rayAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } - void Reset() { } + void Reset() override { } - void OwnerKilledUnit(Unit* pVictim) + void OwnerKilledUnit(Unit* pVictim) override { if (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->GetEntry() == NPC_BLACK_WARP_CHASER) { @@ -506,8 +361,8 @@ enum MAX_RESEARCHER = 4 }; -//Some details still missing from here, and will also have issues if followers evade for any reason. -struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI +// Some details still missing from here, and will also have issues if followers evade for any reason. +struct npc_letollAI : public npc_escortAI { npc_letollAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -521,16 +376,16 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI uint32 m_uiEventTimer; uint32 m_uiEventCount; - void Reset() {} + void Reset() override {} - //will make them follow, but will only work until they enter combat with any unit + // will make them follow, but will only work until they enter combat with any unit void SetFormation() { uint32 uiCount = 0; - for(std::list::iterator itr = m_lResearchersList.begin(); itr != m_lResearchersList.end(); ++itr) + for (std::list::iterator itr = m_lResearchersList.begin(); itr != m_lResearchersList.end(); ++itr) { - float fAngle = uiCount < MAX_RESEARCHER ? M_PI/MAX_RESEARCHER - (uiCount*2*M_PI/MAX_RESEARCHER) : 0.0f; + float fAngle = uiCount < MAX_RESEARCHER ? M_PI / MAX_RESEARCHER - (uiCount * 2 * M_PI / MAX_RESEARCHER) : 0.0f; if ((*itr)->isAlive() && !(*itr)->isInCombat()) (*itr)->GetMotionMaster()->MoveFollow(m_creature, 2.5f, fAngle); @@ -545,7 +400,7 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI { uint8 uiNum = 1; - for(std::list::iterator itr = m_lResearchersList.begin(); itr != m_lResearchersList.end(); ++itr) + for (std::list::iterator itr = m_lResearchersList.begin(); itr != m_lResearchersList.end(); ++itr) { if (uiListNum && uiListNum != uiNum) { @@ -561,7 +416,7 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI return NULL; } - void JustStartedEscort() + void JustStartedEscort() override { m_uiEventTimer = 5000; m_uiEventCount = 0; @@ -574,9 +429,9 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI SetFormation(); } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 0: if (Player* pPlayer = GetPlayerForEscort()) @@ -598,13 +453,13 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI } } - void Aggro(Unit* pWho) + void Aggro(Unit* pWho) override { if (pWho->isInCombat() && pWho->GetTypeId() == TYPEID_UNIT && pWho->GetEntry() == NPC_BONE_SIFTER) DoScriptText(SAY_LE_HELP_HIM, m_creature); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { Player* pPlayer = GetPlayerForEscort(); @@ -614,7 +469,7 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI pSummoned->AI()->AttackStart(m_creature); } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { @@ -624,7 +479,7 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI { m_uiEventTimer = 7000; - switch(m_uiEventCount) + switch (m_uiEventCount) { case 0: DoScriptText(SAY_LE_ALMOST, m_creature); @@ -671,7 +526,7 @@ struct MANGOS_DLL_DECL npc_letollAI : public npc_escortAI break; case 12: DoScriptText(SAY_LE_IN_YOUR_FACE, m_creature); - m_creature->SummonCreature(NPC_BONE_SIFTER, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_BONE_SIFTER, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 13: DoScriptText(EMOTE_LE_PICK_UP, m_creature); @@ -711,7 +566,7 @@ bool QuestAccept_npc_letoll(Player* pPlayer, Creature* pCreature, const Quest* p if (npc_letollAI* pEscortAI = dynamic_cast(pCreature->AI())) { DoScriptText(SAY_LE_START, pCreature); - pCreature->setFaction(FACTION_ESCORT_N_NEUTRAL_PASSIVE); + pCreature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); pEscortAI->Start(false, pPlayer, pQuest, true); } @@ -739,7 +594,7 @@ enum NPC_MANA_BOMB_KILL_TRIGGER = 21039 }; -struct MANGOS_DLL_DECL npc_mana_bomb_exp_triggerAI : public ScriptedAI +struct npc_mana_bomb_exp_triggerAI : public ScriptedAI { npc_mana_bomb_exp_triggerAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -749,7 +604,7 @@ struct MANGOS_DLL_DECL npc_mana_bomb_exp_triggerAI : public ScriptedAI uint32 m_uiEventTimer; uint32 m_uiEventCounter; - void Reset() + void Reset() override { pManaBomb = NULL; m_bIsActivated = false; @@ -769,7 +624,7 @@ struct MANGOS_DLL_DECL npc_mana_bomb_exp_triggerAI : public ScriptedAI pManaBomb = pGo; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_bIsActivated) return; @@ -781,7 +636,7 @@ struct MANGOS_DLL_DECL npc_mana_bomb_exp_triggerAI : public ScriptedAI if (m_uiEventCounter < 10) m_creature->CastSpell(m_creature, SPELL_MANA_BOMB_LIGHTNING, false); - switch(m_uiEventCounter) + switch (m_uiEventCounter) { case 5: if (pManaBomb) @@ -840,36 +695,6 @@ bool GOUse_go_mana_bomb(Player* pPlayer, GameObject* pGo) } /*###### -## npc_slim -######*/ - -enum -{ - FACTION_CONSORTIUM = 933 -}; - -bool GossipHello_npc_slim(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isVendor() && pPlayer->GetReputationRank(FACTION_CONSORTIUM) >= REP_FRIENDLY) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(9896, pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_GOSSIP_MENU(9895, pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_slim(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - -/*##### ## go_veil_skith_cage & npc_captive_child #####*/ @@ -889,10 +714,10 @@ bool GOUse_go_veil_skith_cage(Player* pPlayer, GameObject* pGo) { std::list lChildrenList; GetCreatureListWithEntryInGrid(lChildrenList, pGo, NPC_CAPTIVE_CHILD, INTERACTION_DISTANCE); - for(std::list::const_iterator itr = lChildrenList.begin(); itr != lChildrenList.end(); ++itr) + for (std::list::const_iterator itr = lChildrenList.begin(); itr != lChildrenList.end(); ++itr) { pPlayer->KilledMonsterCredit(NPC_CAPTIVE_CHILD, (*itr)->GetObjectGuid()); - switch(urand(0,3)) + switch (urand(0, 3)) { case 0: DoScriptText(SAY_THANKS_1, *itr); break; case 1: DoScriptText(SAY_THANKS_2, *itr); break; @@ -907,13 +732,13 @@ bool GOUse_go_veil_skith_cage(Player* pPlayer, GameObject* pGo) return false; }; -struct MANGOS_DLL_DECL npc_captive_child : public ScriptedAI +struct npc_captive_child : public ScriptedAI { npc_captive_child(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } - void Reset() {} + void Reset() override {} - void MovementInform(uint32 uiMotionType, uint32 uiPointId) + void MovementInform(uint32 uiMotionType, uint32 /*uiPointId*/) override { if (uiMotionType == POINT_MOTION_TYPE) m_creature->ForcedDespawn(); // we only have one waypoint @@ -951,7 +776,7 @@ enum SPELL_TRAVELFORM = 32447 // guesswork }; -struct MANGOS_DLL_DECL npc_isla_starmaneAI : public npc_escortAI +struct npc_isla_starmaneAI : public npc_escortAI { npc_isla_starmaneAI(Creature* pCreature) : npc_escortAI(pCreature) { @@ -963,7 +788,7 @@ struct MANGOS_DLL_DECL npc_isla_starmaneAI : public npc_escortAI uint32 m_uiMoonfireTimer; uint32 m_uiWrathTimer; - void Reset() + void Reset() override { m_uiPeriodicTalkTimer = urand(20000, 40000); m_uiEntanglingRootsTimer = 100; @@ -974,15 +799,15 @@ struct MANGOS_DLL_DECL npc_isla_starmaneAI : public npc_escortAI m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); } - void JustStartedEscort() + void JustStartedEscort() override { m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); DoScriptText(SAY_ISLA_START, m_creature); - if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_CAGE, 2*INTERACTION_DISTANCE)) + if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_CAGE, 2 * INTERACTION_DISTANCE)) pCage->Use(m_creature); } - void WaypointStart(uint32 uiPointId) + void WaypointStart(uint32 uiPointId) override { switch (uiPointId) { @@ -991,9 +816,9 @@ struct MANGOS_DLL_DECL npc_isla_starmaneAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { - switch(uiPointId) + switch (uiPointId) { case 6: DoScriptText(SAY_ISLA_WAITING, m_creature); @@ -1010,7 +835,7 @@ struct MANGOS_DLL_DECL npc_isla_starmaneAI : public npc_escortAI } } - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { @@ -1065,7 +890,7 @@ bool QuestAccept_npc_isla_starmane(Player* pPlayer, Creature* pCreature, const Q { if (npc_isla_starmaneAI* pEscortAI = dynamic_cast(pCreature->AI())) { - pCreature->setFaction(pPlayer->GetTeam() == ALLIANCE ? FACTION_ESCORT_A_NEUTRAL_ACTIVE : FACTION_ESCORT_H_NEUTRAL_ACTIVE); + pCreature->SetFactionTemporary(pPlayer->GetTeam() == ALLIANCE ? FACTION_ESCORT_A_NEUTRAL_ACTIVE : FACTION_ESCORT_H_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); pEscortAI->Start(false, pPlayer, pQuest); } } @@ -1090,27 +915,38 @@ enum SAY_SKYWING_SUMMON = -1000801, SAY_SKYWING_END = -1000802, - //SPELL_TRANSFORM = ?????, // ToDo: research the transform spell id + SPELL_FEATHERY_CYCLONE_BURST = 39166, // triggered many times by server side spell - 39167 (channeled for 5 sec) + SPELL_RILAK_THE_REDEEMED = 39179, NPC_LUANGA_THE_IMPRISONER = 18533, QUEST_SKYWING = 10898 }; -static const float aLuangaSpawnCoords[3] = {-3507.203f, 4084.619f, 92.947f}; +static const float aLuangaSpawnCoords[3] = { -3507.203f, 4084.619f, 92.947f}; -struct MANGOS_DLL_DECL npc_skywingAI : public npc_escortAI +struct npc_skywingAI : public npc_escortAI { npc_skywingAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void Reset() {} + uint32 m_uiCycloneTimer; + uint8 m_uiCycloneCounter; + + void Reset() override + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + { + m_uiCycloneTimer = 0; + m_uiCycloneCounter = 0; + } + } - void WaypointReached(uint32 uiPointId) + void WaypointReached(uint32 uiPointId) override { switch (uiPointId) { case 6: - DoScriptText(SAY_SKYWING_TREE_DOWN ,m_creature); + DoScriptText(SAY_SKYWING_TREE_DOWN , m_creature); break; case 36: DoScriptText(SAY_SKYWING_TREE_UP, m_creature); @@ -1124,10 +960,11 @@ struct MANGOS_DLL_DECL npc_skywingAI : public npc_escortAI break; case 80: DoScriptText(SAY_SKYWING_SUMMON, m_creature); - m_creature->SummonCreature(NPC_LUANGA_THE_IMPRISONER, aLuangaSpawnCoords[0], aLuangaSpawnCoords[1], aLuangaSpawnCoords[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + m_creature->SummonCreature(NPC_LUANGA_THE_IMPRISONER, aLuangaSpawnCoords[0], aLuangaSpawnCoords[1], aLuangaSpawnCoords[2], 0, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 81: - // ToDo: implement transform spell here + // Start transformation + m_uiCycloneTimer = 100; break; case 82: DoScriptText(SAY_SKYWING_END, m_creature); @@ -1137,10 +974,38 @@ struct MANGOS_DLL_DECL npc_skywingAI : public npc_escortAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { pSummoned->AI()->AttackStart(m_creature); } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (m_uiCycloneTimer) + { + if (m_uiCycloneTimer <= uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FEATHERY_CYCLONE_BURST) == CAST_OK) + { + ++m_uiCycloneCounter; + + if (m_uiCycloneCounter == 30) + DoCastSpellIfCan(m_creature, SPELL_RILAK_THE_REDEEMED, CAST_TRIGGERED); + + // Only cast this spell 50 times + if (m_uiCycloneCounter == 50) + m_uiCycloneTimer = 0; + else + m_uiCycloneTimer = 100; + } + } + else + m_uiCycloneTimer -= uiDiff; + } + + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + } }; bool QuestAccept_npc_skywing(Player* pPlayer, Creature* pCreature, const Quest* pQuest) @@ -1163,6 +1028,210 @@ CreatureAI* GetAI_npc_skywing(Creature* pCreature) return new npc_skywingAI(pCreature); } +/*###### +## npc_cenarion_sparrowhawk +######*/ + +enum +{ + EMOTE_FOLLOW = -1000963, + EMOTE_SURVEY = -1000964, + EMOTE_LOCATE = -1000965, + + NPC_SKETTIS_RAVEN_STONE = 22986, + GO_RAVEN_STONE = 185541, +}; + +struct npc_cenarion_sparrowhawkAI : public ScriptedAI +{ + npc_cenarion_sparrowhawkAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiSurveyTimer; + bool m_bFirstTimer; + + ObjectGuid m_currentStone; + + void Reset() override + { + m_uiSurveyTimer = 3000; + m_bFirstTimer = true; + DoScriptText(EMOTE_FOLLOW, m_creature); + } + + void MovementInform(uint32 uiMoveType, uint32 uiPointId) override + { + if (uiMoveType != POINT_MOTION_TYPE || !uiPointId) + return; + + // despawn the trigger and spawn the nearby stone + if (Creature* pStoneTrigger = m_creature->GetMap()->GetCreature(m_currentStone)) + pStoneTrigger->ForcedDespawn(); + + if (GameObject* pStone = GetClosestGameObjectWithEntry(m_creature, GO_RAVEN_STONE, 5.0f)) + { + pStone->SetRespawnTime(pStone->GetRespawnDelay()); + pStone->Refresh(); + } + DoScriptText(EMOTE_LOCATE, m_creature); + + // check if we still have other stones in range + m_uiSurveyTimer = 5000; + } + + void DoFindNearbyStones() + { + float fX, fY, fZ; + if (Creature* pStoneTrigger = GetClosestCreatureWithEntry(m_creature, NPC_SKETTIS_RAVEN_STONE, 80.0f)) + { + m_currentStone = pStoneTrigger->GetObjectGuid(); + pStoneTrigger->GetContactPoint(m_creature, fX, fY, fZ); + + m_creature->SetWalk(false); + m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); + } + else + m_creature->ForcedDespawn(10000); + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiSurveyTimer) + { + if (m_uiSurveyTimer <= uiDiff) + { + if (m_bFirstTimer) + { + DoScriptText(EMOTE_SURVEY, m_creature); + m_bFirstTimer = false; + } + + DoFindNearbyStones(); + m_uiSurveyTimer = 0; + } + else + m_uiSurveyTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_cenarion_sparrowhawk(Creature* pCreature) +{ + return new npc_cenarion_sparrowhawkAI(pCreature); +} + +/*##### +## npc_skyguard_prisoner +#####*/ + +enum +{ + SAY_ESCORT_START = -1001006, + SAY_AMBUSH_END = -1001007, + SAY_ESCORT_COMPLETE = -1001008, + SAY_AMBUSH_1 = -1001009, + SAY_AMBUSH_2 = -1001010, + SAY_AMBUSH_3 = -1001011, + SAY_AMBUSH_4 = -1001012, + + NPC_WING_GUARD = 21644, + GO_PRISONER_CAGE = 185952, + + QUEST_ID_ESCAPE_SKETTIS = 11085, +}; + +struct npc_skyguard_prisonerAI : public npc_escortAI +{ + npc_skyguard_prisonerAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + void Reset() override { } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); + + // ToDo: add additional WP when DB will support it + if (m_creature->GetPositionZ() < 310.0f) + { + SetEscortPaused(true); + //SetCurrentWaypoint(WP_ID_SPAWN_1); + //SetEscortPaused(false); + script_error_log("NPC entry %u, location %f, %f, %f does not have waypoints implemented for current spawn location. Please contact customer support!", m_creature->GetEntry(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + } + else if (m_creature->GetPositionZ() < 330.0f) + { + SetEscortPaused(true); + //SetCurrentWaypoint(WP_ID_SPAWN_2); + //SetEscortPaused(false); + script_error_log("NPC entry %u, location %f, %f, %f does not have waypoints implemented for current spawn location. Please contact customer support!", m_creature->GetEntry(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); + } + // else just use standard WP + + // open cage + if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_PRISONER_CAGE, 10.0f)) + pCage->Use(m_creature); + } + } + + void JustSummoned(Creature* pSummoned) override + { + if (pSummoned->GetEntry() == NPC_WING_GUARD) + { + pSummoned->AI()->AttackStart(m_creature); + + switch (urand(0, 3)) + { + case 0: DoScriptText(SAY_AMBUSH_1, pSummoned); break; + case 1: DoScriptText(SAY_AMBUSH_2, pSummoned); break; + case 2: DoScriptText(SAY_AMBUSH_3, pSummoned); break; + case 3: DoScriptText(SAY_AMBUSH_4, pSummoned); break; + } + } + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 0: + DoScriptText(SAY_ESCORT_START, m_creature); + break; + case 13: + m_creature->SummonCreature(NPC_WING_GUARD, -4179.043f, 3081.007f, 328.28f, 4.51f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_WING_GUARD, -4181.610f, 3081.289f, 328.32f, 4.52f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 14: + DoScriptText(SAY_AMBUSH_END, m_creature); + break; + case 18: + DoScriptText(SAY_ESCORT_COMPLETE, m_creature); + SetRun(); + + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_ESCAPE_SKETTIS, m_creature); + break; + } + } +}; + +CreatureAI* GetAI_npc_skyguard_prisoner(Creature* pCreature) +{ + return new npc_skyguard_prisonerAI(pCreature); +} + +bool QuestAccept_npc_skyguard_prisoner(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_ESCAPE_SKETTIS) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + void AddSC_terokkar_forest() { Script* pNewScript; @@ -1172,16 +1241,6 @@ void AddSC_terokkar_forest() pNewScript->GetAI = &GetAI_mob_unkor_the_ruthless; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "mob_infested_root_walker"; - pNewScript->GetAI = &GetAI_mob_infested_root_walker; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_rotting_forest_rager"; - pNewScript->GetAI = &GetAI_mob_rotting_forest_rager; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "mob_netherweb_victim"; pNewScript->GetAI = &GetAI_mob_netherweb_victim; @@ -1193,11 +1252,6 @@ void AddSC_terokkar_forest() pNewScript->pQuestAcceptNPC = &QuestAccept_npc_akuno; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_floon"; - pNewScript->GetAI = &GetAI_npc_floon; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_hungry_nether_ray"; pNewScript->GetAI = &GetAI_npc_hungry_nether_ray; @@ -1219,12 +1273,6 @@ void AddSC_terokkar_forest() pNewScript->pGOUse = &GOUse_go_mana_bomb; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_slim"; - pNewScript->pGossipHello = &GossipHello_npc_slim; - pNewScript->pGossipSelect = &GossipSelect_npc_slim; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "go_veil_skith_cage"; pNewScript->pGOUse = &GOUse_go_veil_skith_cage; @@ -1246,4 +1294,15 @@ void AddSC_terokkar_forest() pNewScript->GetAI = &GetAI_npc_skywing; pNewScript->pQuestAcceptNPC = &QuestAccept_npc_skywing; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_cenarion_sparrowhawk"; + pNewScript->GetAI = &GetAI_npc_cenarion_sparrowhawk; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_skyguard_prisoner"; + pNewScript->GetAI = &GetAI_npc_skyguard_prisoner; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_skyguard_prisoner; + pNewScript->RegisterSelf(); } diff --git a/scripts/outland/zangarmarsh.cpp b/scripts/outland/zangarmarsh.cpp index 926134568..90347722d 100644 --- a/scripts/outland/zangarmarsh.cpp +++ b/scripts/outland/zangarmarsh.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,98 +17,20 @@ /* ScriptData SDName: Zangarmarsh SD%Complete: 100 -SDComment: Quest support: 9752, 9785, 10009. Mark Of ... buffs. +SDComment: Quest support: 9729, 9752, 9785, 10009. SDCategory: Zangarmarsh EndScriptData */ /* ContentData -npcs_ashyen_and_keleth npc_cooshcoosh npc_kayra_longmane event_stormcrow +npc_fhwoor EndContentData */ #include "precompiled.h" #include "escort_ai.h" -/*###### -## npcs_ashyen_and_keleth -######*/ - -#define SAY_REWARD_BLESS -1000207 - -#define GOSSIP_ITEM_BLESS_ASH "Grant me your mark, wise ancient." -#define GOSSIP_ITEM_BLESS_KEL "Grant me your mark, mighty ancient." - -//#define TEXT_BLESSINGS "" - -bool GossipHello_npcs_ashyen_and_keleth(Player* pPlayer, Creature* pCreature) -{ - if (pPlayer->GetReputationRank(942) > REP_NEUTRAL) - { - if (pCreature->GetEntry() == 17900) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BLESS_ASH, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - if (pCreature->GetEntry() == 17901) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_BLESS_KEL, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - } - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npcs_ashyen_and_keleth(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_INFO_DEF+1) - { - pCreature->setPowerType(POWER_MANA); - pCreature->SetMaxPower(POWER_MANA,200); //set a "fake" mana value, we can't depend on database doing it in this case - pCreature->SetPower(POWER_MANA,200); - - if (pCreature->GetEntry() == 17900) //check which creature we are dealing with - { - switch (pPlayer->GetReputationRank(942)) - { //mark of lore - case REP_FRIENDLY: - pCreature->CastSpell(pPlayer, 31808, true); - break; - case REP_HONORED: - pCreature->CastSpell(pPlayer, 31810, true); - break; - case REP_REVERED: - pCreature->CastSpell(pPlayer, 31811, true); - break; - case REP_EXALTED: - pCreature->CastSpell(pPlayer, 31815, true); - break; - } - } - - if (pCreature->GetEntry() == 17901) - { - switch (pPlayer->GetReputationRank(942)) //mark of war - { - case REP_FRIENDLY: - pCreature->CastSpell(pPlayer, 31807, true); - break; - case REP_HONORED: - pCreature->CastSpell(pPlayer, 31812, true); - break; - case REP_REVERED: - pCreature->CastSpell(pPlayer, 31813, true); - break; - case REP_EXALTED: - pCreature->CastSpell(pPlayer, 31814, true); - break; - } - } - - DoScriptText(SAY_REWARD_BLESS, pCreature, pPlayer); - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); - } - return true; -} - /*###### ## npc_cooshcoosh ######*/ @@ -118,7 +40,7 @@ enum SPELL_LIGHTNING_BOLT = 9532, }; -struct MANGOS_DLL_DECL npc_cooshcooshAI : public ScriptedAI +struct npc_cooshcooshAI : public ScriptedAI { npc_cooshcooshAI(Creature* pCreature) : ScriptedAI(pCreature) { @@ -129,7 +51,7 @@ struct MANGOS_DLL_DECL npc_cooshcooshAI : public ScriptedAI uint32 m_uiNormFaction; uint32 m_uiLightningBolt_Timer; - void Reset() + void Reset() override { m_uiLightningBolt_Timer = 2000; @@ -137,16 +59,17 @@ struct MANGOS_DLL_DECL npc_cooshcooshAI : public ScriptedAI m_creature->setFaction(m_uiNormFaction); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiLightningBolt_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(),SPELL_LIGHTNING_BOLT); + DoCastSpellIfCan(m_creature->getVictim(), SPELL_LIGHTNING_BOLT); m_uiLightningBolt_Timer = 5000; - }else m_uiLightningBolt_Timer -= uiDiff; + } + else m_uiLightningBolt_Timer -= uiDiff; DoMeleeAttackIfReady(); } @@ -173,23 +96,23 @@ enum NPC_SLAVEBINDER = 18042 }; -struct MANGOS_DLL_DECL npc_kayra_longmaneAI : public npc_escortAI +struct npc_kayra_longmaneAI : public npc_escortAI { npc_kayra_longmaneAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } - void WaypointReached(uint32 i) + void WaypointReached(uint32 i) override { Player* pPlayer = GetPlayerForEscort(); if (!pPlayer) return; - switch(i) + switch (i) { case 4: DoScriptText(SAY_AMBUSH1, m_creature, pPlayer); - DoSpawnCreature(NPC_SLAVEBINDER, -10.0f, -5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - DoSpawnCreature(NPC_SLAVEBINDER, -8.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + DoSpawnCreature(NPC_SLAVEBINDER, -10.0f, -5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + DoSpawnCreature(NPC_SLAVEBINDER, -8.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 5: DoScriptText(SAY_PROGRESS, m_creature, pPlayer); @@ -197,8 +120,8 @@ struct MANGOS_DLL_DECL npc_kayra_longmaneAI : public npc_escortAI break; case 16: DoScriptText(SAY_AMBUSH2, m_creature, pPlayer); - DoSpawnCreature(NPC_SLAVEBINDER, -10.0f, -5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - DoSpawnCreature(NPC_SLAVEBINDER, -8.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + DoSpawnCreature(NPC_SLAVEBINDER, -10.0f, -5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); + DoSpawnCreature(NPC_SLAVEBINDER, -8.0f, 5.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); break; case 17: DoScriptText(SAY_END, m_creature, pPlayer); @@ -209,7 +132,7 @@ struct MANGOS_DLL_DECL npc_kayra_longmaneAI : public npc_escortAI } } - void Reset() { } + void Reset() override { } }; bool QuestAccept_npc_kayra_longmane(Player* pPlayer, Creature* pCreature, const Quest* pQuest) @@ -239,7 +162,7 @@ enum EVENT_ID_STORMCROW = 11225, }; -bool ProcessEventId_event_taxi_stormcrow(uint32 uiEventId, Object* pSource, Object* pTarget, bool bIsStart) +bool ProcessEventId_event_taxi_stormcrow(uint32 uiEventId, Object* pSource, Object* /*pTarget*/, bool bIsStart) { if (uiEventId == EVENT_ID_STORMCROW && !bIsStart && pSource->GetTypeId() == TYPEID_PLAYER) { @@ -250,16 +173,164 @@ bool ProcessEventId_event_taxi_stormcrow(uint32 uiEventId, Object* pSource, Obje return false; } +/*##### +## npc_fhwoor +#####*/ + +enum +{ + SAY_ESCORT_START = -1000995, + SAY_PREPARE = -1000996, + SAY_CAMP_ENTER = -1000997, + SAY_AMBUSH = -1000998, + SAY_AMBUSH_CLEARED = -1000999, + SAY_ESCORT_COMPLETE = -1001000, + + SPELL_STOMP = 31277, + SPELL_THUNDERSHOCK = 31964, + + NPC_ENCHANTRESS = 18088, + NPC_SLAVEDRIVER = 18089, + NPC_SSSLITH = 18154, + + GO_ARK_OF_SSSLITH = 182082, + + QUEST_ID_FHWOOR_SMASH = 9729, +}; + +struct npc_fhwoorAI : public npc_escortAI +{ + npc_fhwoorAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } + + uint32 m_uiStompTimer; + uint32 m_uiShockTimer; + + bool m_bIsAmbush; + + void Reset() override + { + m_uiStompTimer = urand(3000, 7000); + m_uiShockTimer = urand(7000, 11000); + m_bIsAmbush = false; + } + + void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override + { + if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) + { + DoScriptText(SAY_ESCORT_START, m_creature, pInvoker); + m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); + Start(true, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue), true); + } + } + + void JustSummoned(Creature* pSummoned) override + { + // move summoned towards the creature + if (m_bIsAmbush) + { + float fX, fY, fZ; + m_creature->GetContactPoint(pSummoned, fX, fY, fZ); + pSummoned->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + + void SummonedCreatureJustDied(Creature* pSummoned) override + { + // resume escort + if (pSummoned->GetEntry() == NPC_SSSLITH) + SetEscortPaused(false); + } + + void WaypointReached(uint32 uiPointId) override + { + switch (uiPointId) + { + case 24: + DoScriptText(SAY_PREPARE, m_creature); + break; + case 25: + DoScriptText(SAY_CAMP_ENTER, m_creature); + SetRun(false); + break; + case 46: + // despawn the Ark + if (GameObject* pArk = GetClosestGameObjectWithEntry(m_creature, GO_ARK_OF_SSSLITH, 10.0f)) + pArk->SetLootState(GO_JUST_DEACTIVATED); + // spawn npcs + m_creature->SummonCreature(NPC_ENCHANTRESS, 526.12f, 8136.96f, 21.64f, 0.57f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_SLAVEDRIVER, 524.09f, 8138.67f, 21.49f, 0.58f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_SLAVEDRIVER, 526.93f, 8133.88f, 21.56f, 0.58f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + break; + case 70: + DoScriptText(SAY_AMBUSH, m_creature); + // spawn npcs + m_bIsAmbush = true; + m_creature->SummonCreature(NPC_SSSLITH, 162.91f, 8192.08f, 22.55f, 5.98f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_ENCHANTRESS, 162.34f, 8193.99f, 22.85f, 5.98f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + m_creature->SummonCreature(NPC_SLAVEDRIVER, 163.07f, 8187.04f, 22.71f, 0.10f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 60000); + SetEscortPaused(true); + break; + case 71: + DoScriptText(SAY_AMBUSH_CLEARED, m_creature); + SetRun(); + break; + case 92: + SetRun(false); + break; + case 93: + DoScriptText(SAY_ESCORT_COMPLETE, m_creature); + if (Player* pPlayer = GetPlayerForEscort()) + pPlayer->GroupEventHappens(QUEST_ID_FHWOOR_SMASH, m_creature); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) + return; + + if (m_uiStompTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_STOMP) == CAST_OK) + m_uiStompTimer = urand(9000, 15000); + } + else + m_uiStompTimer -= uiDiff; + + if (m_uiShockTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_THUNDERSHOCK) == CAST_OK) + m_uiShockTimer = urand(15000, 20000); + } + else + m_uiShockTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } +}; + +CreatureAI* GetAI_npc_fhwoor(Creature* pCreature) +{ + return new npc_fhwoorAI(pCreature); +} + +bool QuestAccept_npc_fhwoor(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +{ + if (pQuest->GetQuestId() == QUEST_ID_FHWOOR_SMASH) + { + pCreature->AI()->SendAIEvent(AI_EVENT_START_ESCORT, pPlayer, pCreature, pQuest->GetQuestId()); + return true; + } + + return false; +} + void AddSC_zangarmarsh() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npcs_ashyen_and_keleth"; - pNewScript->pGossipHello = &GossipHello_npcs_ashyen_and_keleth; - pNewScript->pGossipSelect = &GossipSelect_npcs_ashyen_and_keleth; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_cooshcoosh"; pNewScript->GetAI = &GetAI_npc_cooshcoosh; @@ -275,4 +346,10 @@ void AddSC_zangarmarsh() pNewScript->Name = "event_taxi_stormcrow"; pNewScript->pProcessEventId = &ProcessEventId_event_taxi_stormcrow; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "npc_fhwoor"; + pNewScript->GetAI = &GetAI_npc_fhwoor; + pNewScript->pQuestAcceptNPC = &QuestAccept_npc_fhwoor; + pNewScript->RegisterSelf(); } diff --git a/scripts/world/areatrigger_scripts.cpp b/scripts/world/areatrigger_scripts.cpp index f38aa8d55..b6d729266 100644 --- a/scripts/world/areatrigger_scripts.cpp +++ b/scripts/world/areatrigger_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Areatrigger_Scripts SD%Complete: 100 -SDComment: Quest support: 4291, 6681, 11686, 10589/10604, 12741, 12548, 13315/13351, 12575 +SDComment: Quest support: 4291, 6681, 7632, 10589/10604, 11686, 12548, 12575, 12741, 13315/13351, 24849/24851. SDCategory: Areatrigger EndScriptData */ @@ -31,9 +31,13 @@ at_warsong_farms at_stormwright_shelf 5108 at_childrens_week_spot 3546,3547,3548,3552,3549,3550 at_scent_larkorwi 1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740 +at_murkdeep 1966 +at_hot_on_the_trail 5710, 5711, 5712, 5714, 5715, 5716 +at_ancient_leaf 3587 EndContentData */ #include "precompiled.h" +#include "world_map_scripts.h" static uint32 TriggerOrphanSpell[6][3] = { @@ -50,7 +54,7 @@ bool AreaTrigger_at_childrens_week_spot(Player* pPlayer, AreaTriggerEntry const* for (uint8 i = 0; i < 6; ++i) { if (pAt->id == TriggerOrphanSpell[i][0] && - pPlayer->GetMiniPet() && pPlayer->GetMiniPet()->GetEntry() == TriggerOrphanSpell[i][1]) + pPlayer->GetMiniPet() && pPlayer->GetMiniPet()->GetEntry() == TriggerOrphanSpell[i][1]) { pPlayer->CastSpell(pPlayer, TriggerOrphanSpell[i][2], true); return true; @@ -78,7 +82,7 @@ enum bool AreaTrigger_at_aldurthar_gate(Player* pPlayer, AreaTriggerEntry const* pAt) { - switch(pAt->id) + switch (pAt->id) { case TRIGGER_SOUTH: pPlayer->KilledMonsterCredit(NPC_SOUTH_GATE); break; case TRIGGER_CENTRAL: pPlayer->KilledMonsterCredit(NPC_CENTRAL_GATE); break; @@ -97,7 +101,7 @@ enum GO_COILFANG_WATERFALL = 184212 }; -bool AreaTrigger_at_coilfang_waterfall(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_coilfang_waterfall(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (GameObject* pGo = GetClosestGameObjectWithEntry(pPlayer, GO_COILFANG_WATERFALL, 35.0f)) { @@ -120,7 +124,7 @@ enum QUEST_GAINING_ACCESS_H = 10604 }; -bool AreaTrigger_at_legion_teleporter(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_legion_teleporter(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (pPlayer->isAlive() && !pPlayer->isInCombat()) { @@ -150,7 +154,7 @@ enum NPC_RAVENHOLDT = 13936 }; -bool AreaTrigger_at_ravenholdt(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_ravenholdt(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (pPlayer->GetQuestStatus(QUEST_MANOR_RAVENHOLDT) == QUEST_STATUS_INCOMPLETE) pPlayer->KilledMonsterCredit(NPC_RAVENHOLDT); @@ -172,13 +176,13 @@ enum bool AreaTrigger_at_spearborn_encampment(Player* pPlayer, AreaTriggerEntry const* pAt) { if (pPlayer->GetQuestStatus(QUEST_MISTWHISPER_TREASURE) == QUEST_STATUS_INCOMPLETE && - pPlayer->GetReqKillOrCastCurrentCount(QUEST_MISTWHISPER_TREASURE, NPC_TARTEK) == 0) + pPlayer->GetReqKillOrCastCurrentCount(QUEST_MISTWHISPER_TREASURE, NPC_TARTEK) == 0) { // can only spawn one at a time, it's not a too good solution if (GetClosestCreatureWithEntry(pPlayer, NPC_TARTEK, 50.0f)) return false; - pPlayer->SummonCreature(NPC_TARTEK, pAt->x, pAt->y, pAt->z, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, MINUTE*IN_MILLISECONDS); + pPlayer->SummonCreature(NPC_TARTEK, pAt->x, pAt->y, pAt->z, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS); } return false; @@ -204,7 +208,7 @@ bool AreaTrigger_at_warsong_farms(Player* pPlayer, AreaTriggerEntry const* pAt) { if (!pPlayer->isDead() && pPlayer->GetQuestStatus(QUEST_THE_WARSONG_FARMS) == QUEST_STATUS_INCOMPLETE) { - switch(pAt->id) + switch (pAt->id) { case AT_SLAUGHTERHOUSE: pPlayer->KilledMonsterCredit(NPC_CREDIT_SLAUGHTERHOUSE); break; case AT_GRAINERY: pPlayer->KilledMonsterCredit(NPC_CREDIT_GRAINERY); break; @@ -232,7 +236,7 @@ bool AreaTrigger_at_waygate(Player* pPlayer, AreaTriggerEntry const* pAt) { if (!pPlayer->isDead() && pPlayer->GetQuestStatus(QUEST_THE_MARKERS_OVERLOOK) == QUEST_STATUS_COMPLETE && pPlayer->GetQuestStatus(QUEST_THE_MARKERS_PERCH) == QUEST_STATUS_COMPLETE) { - switch(pAt->id) + switch (pAt->id) { case AT_WAYGATE_SHOLOZAR: pPlayer->CastSpell(pPlayer, SPELL_SHOLOZAR_TO_UNGORO_TELEPORT, false); break; case AT_WAYGATE_UNGORO: pPlayer->CastSpell(pPlayer, SPELL_UNGORO_TO_SHOLOZAR_TELEPORT, false); break; @@ -252,7 +256,7 @@ enum SPELL_CREATE_TRUE_POWER_OF_THE_TEMPEST = 53067 }; -bool AreaTrigger_at_stormwright_shelf(Player* pPlayer, AreaTriggerEntry const* pAt) +bool AreaTrigger_at_stormwright_shelf(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) { if (!pPlayer->isDead() && pPlayer->GetQuestStatus(QUEST_STRENGTH_OF_THE_TEMPEST) == QUEST_STATUS_INCOMPLETE) pPlayer->CastSpell(pPlayer, SPELL_CREATE_TRUE_POWER_OF_THE_TEMPEST, false); @@ -275,7 +279,134 @@ bool AreaTrigger_at_scent_larkorwi(Player* pPlayer, AreaTriggerEntry const* pAt) if (pPlayer->isAlive() && !pPlayer->isGameMaster() && pPlayer->GetQuestStatus(QUEST_SCENT_OF_LARKORWI) == QUEST_STATUS_INCOMPLETE) { if (!GetClosestCreatureWithEntry(pPlayer, NPC_LARKORWI_MATE, 25.0f, false, false)) - pPlayer->SummonCreature(NPC_LARKORWI_MATE, pAt->x, pAt->y, pAt->z, 3.3f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2*MINUTE*IN_MILLISECONDS); + pPlayer->SummonCreature(NPC_LARKORWI_MATE, pAt->x, pAt->y, pAt->z, 3.3f, TEMPSUMMON_TIMED_OOC_DESPAWN, 2 * MINUTE * IN_MILLISECONDS); + } + + return false; +} + +/*###### +## at_murkdeep +######*/ + +bool AreaTrigger_at_murkdeep(Player* pPlayer, AreaTriggerEntry const* /*pAt*/) +{ + // Handle Murkdeep event start + // The area trigger summons 3 Greymist Coastrunners; The rest of the event is handled by world map scripts + if (pPlayer->isAlive() && !pPlayer->isGameMaster() && pPlayer->GetQuestStatus(QUEST_WANTED_MURKDEEP) == QUEST_STATUS_INCOMPLETE) + { + ScriptedMap* pScriptedMap = (ScriptedMap*)pPlayer->GetInstanceData(); + if (!pScriptedMap) + return false; + + // If Murkdeep is already spawned, skip the rest + if (pScriptedMap->GetSingleCreatureFromStorage(NPC_MURKDEEP, true)) + return true; + + // Check if there are already coastrunners (dead or alive) around the area + if (GetClosestCreatureWithEntry(pPlayer, NPC_GREYMIST_COASTRUNNNER, 60.0f, false, false)) + return true; + + float fX, fY, fZ; + for (uint8 i = 0; i < 3; ++i) + { + // Spawn locations are defined in World Maps Scripts.h + pPlayer->GetRandomPoint(aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][0], aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][1], aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][2], 5.0f, fX, fY, fZ); + + if (Creature* pTemp = pPlayer->SummonCreature(NPC_GREYMIST_COASTRUNNNER, fX, fY, fZ, aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pTemp->SetWalk(false); + pTemp->GetRandomPoint(aSpawnLocations[POS_IDX_MURKDEEP_MOVE][0], aSpawnLocations[POS_IDX_MURKDEEP_MOVE][1], aSpawnLocations[POS_IDX_MURKDEEP_MOVE][2], 5.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + } + + return false; +} + +/*###### +## at_hot_on_the_trail +######*/ + +struct HotOnTrailData +{ + uint32 uiAtEntry, uiQuestEntry, uiCreditEntry, uiSpellEntry; +}; + +static const HotOnTrailData aHotOnTrailValues[6] = +{ + {5710, 24849, 38340, 71713}, // Stormwind Bank + {5711, 24849, 38341, 71745}, // Stormwind Auction House + {5712, 24849, 38342, 71752}, // Stormwind Barber Shop + {5714, 24851, 38341, 71760}, // Orgrimmar Auction House + {5715, 24851, 38340, 71759}, // Orgrimmar Bank + {5716, 24851, 38342, 71758}, // Orgrimmar Barber Shop +}; + +bool AreaTrigger_at_hot_on_the_trail(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; + + for (uint8 i = 0; i < 6; ++i) + { + if (pAt->id == aHotOnTrailValues[i].uiAtEntry) + { + if (pPlayer->GetQuestStatus(aHotOnTrailValues[i].uiQuestEntry) == QUEST_STATUS_INCOMPLETE && + pPlayer->GetReqKillOrCastCurrentCount(aHotOnTrailValues[i].uiQuestEntry, aHotOnTrailValues[i].uiCreditEntry) == 0) + { + pPlayer->CastSpell(pPlayer, aHotOnTrailValues[i].uiSpellEntry, true); + return true; + } + } + } + + return false; +} + +/*###### +## at_ancient_leaf +######*/ + +enum +{ + QUEST_ANCIENT_LEAF = 7632, + + NPC_VARTRUS = 14524, + NPC_STOMA = 14525, + NPC_HASTAT = 14526, + + MAX_ANCIENTS = 3, +}; + +struct AncientSpawn +{ + uint32 uiEntry; + float fX, fY, fZ, fO; +}; + +static const AncientSpawn afSpawnLocations[MAX_ANCIENTS] = +{ + { NPC_VARTRUS, 6204.051758f, -1172.575684f, 370.079224f, 0.86052f }, // Vartus the Ancient + { NPC_STOMA, 6246.953613f, -1155.985718f, 366.182953f, 2.90269f }, // Stoma the Ancient + { NPC_HASTAT, 6193.449219f, -1137.834106f, 366.260529f, 5.77332f }, // Hastat the Ancient +}; + +bool AreaTrigger_at_ancient_leaf(Player* pPlayer, AreaTriggerEntry const* pAt) +{ + if (pPlayer->isGameMaster() || !pPlayer->isAlive()) + return false; + + // Handle Call Ancients event start - The area trigger summons 3 ancients + if (pPlayer->GetQuestStatus(QUEST_ANCIENT_LEAF) == QUEST_STATUS_COMPLETE) + { + // If ancients are already spawned, skip the rest + if (GetClosestCreatureWithEntry(pPlayer, NPC_VARTRUS, 50.0f) || GetClosestCreatureWithEntry(pPlayer, NPC_STOMA, 50.0f) || GetClosestCreatureWithEntry(pPlayer, NPC_HASTAT, 50.0f)) + return true; + + for (uint8 i = 0; i < MAX_ANCIENTS; ++i) + pPlayer->SummonCreature(afSpawnLocations[i].uiEntry, afSpawnLocations[i].fX, afSpawnLocations[i].fY, afSpawnLocations[i].fZ, afSpawnLocations[i].fO, TEMPSUMMON_TIMED_DESPAWN, 5 * MINUTE * IN_MILLISECONDS); } return false; @@ -334,4 +465,19 @@ void AddSC_areatrigger_scripts() pNewScript->Name = "at_scent_larkorwi"; pNewScript->pAreaTrigger = &AreaTrigger_at_scent_larkorwi; pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_murkdeep"; + pNewScript->pAreaTrigger = &AreaTrigger_at_murkdeep; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_hot_on_the_trail"; + pNewScript->pAreaTrigger = &AreaTrigger_at_hot_on_the_trail; + pNewScript->RegisterSelf(); + + pNewScript = new Script; + pNewScript->Name = "at_ancient_leaf"; + pNewScript->pAreaTrigger = &AreaTrigger_at_ancient_leaf; + pNewScript->RegisterSelf(); } diff --git a/scripts/world/bosses_emerald_dragons.cpp b/scripts/world/bosses_emerald_dragons.cpp index 84b4222b5..9345f9b3a 100644 --- a/scripts/world/bosses_emerald_dragons.cpp +++ b/scripts/world/bosses_emerald_dragons.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -27,9 +27,7 @@ boss_emeriss boss_lethon npc_spirit_shade boss_taerar -boss_shade_of_taerar -- TODO move to Acid boss_ysondre -mob_dementeddruids; -- TODO move to Acid EndContentData */ #include "precompiled.h" @@ -52,7 +50,7 @@ enum NPC_DREAM_FOG = 15224, }; -struct MANGOS_DLL_DECL boss_emerald_dragonAI : public ScriptedAI +struct boss_emerald_dragonAI : public ScriptedAI { boss_emerald_dragonAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } @@ -62,7 +60,7 @@ struct MANGOS_DLL_DECL boss_emerald_dragonAI : public ScriptedAI uint32 m_uiNoxiousBreathTimer; uint32 m_uiTailsweepTimer; - void Reset() + void Reset() override { m_uiEventCounter = 1; @@ -71,21 +69,21 @@ struct MANGOS_DLL_DECL boss_emerald_dragonAI : public ScriptedAI m_uiTailsweepTimer = 4000; } - void EnterCombat(Unit* pEnemy) + void EnterCombat(Unit* pEnemy) override { DoCastSpellIfCan(m_creature, SPELL_MARK_OF_NATURE_AURA, CAST_TRIGGERED); ScriptedAI::EnterCombat(pEnemy); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { // Mark killed players with Mark of Nature if (pVictim->GetTypeId() == TYPEID_PLAYER) pVictim->CastSpell(pVictim, SPELL_MARK_OF_NATURE_PLAYER, true, NULL, NULL, m_creature->GetObjectGuid()); } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) pSummoned->AI()->AttackStart(pTarget); @@ -98,9 +96,9 @@ struct MANGOS_DLL_DECL boss_emerald_dragonAI : public ScriptedAI virtual bool DoSpecialDragonAbility() = 0; // Return true to handle shared timers and MeleeAttack - virtual bool UpdateDragonAI(const uint32 uiDiff) { return true; } + virtual bool UpdateDragonAI(const uint32 /*uiDiff*/) { return true; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) @@ -157,25 +155,25 @@ enum SPELL_PUTRID_MUSHROOM = 24904, // Summons a mushroom on killing a player }; -struct MANGOS_DLL_DECL boss_emerissAI : public boss_emerald_dragonAI +struct boss_emerissAI : public boss_emerald_dragonAI { boss_emerissAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) { Reset(); } uint32 m_uiVolatileInfectionTimer; - void Reset() + void Reset() override { boss_emerald_dragonAI::Reset(); m_uiVolatileInfectionTimer = 12000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_EMERISS_AGGRO, m_creature); } - void KilledUnit(Unit* pVictim) + void KilledUnit(Unit* pVictim) override { // summon a mushroom on the spot the player dies if (pVictim->GetTypeId() == TYPEID_PLAYER) @@ -238,11 +236,11 @@ enum SPELL_SPIRIT_SHAPE_VISUAL = 24809, }; -struct MANGOS_DLL_DECL boss_lethonAI : public boss_emerald_dragonAI +struct boss_lethonAI : public boss_emerald_dragonAI { boss_lethonAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) {} - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_LETHON_AGGRO, m_creature); // Shadow bolt wirl is a periodic aura which triggers a set of shadowbolts every 2 secs; may need some core tunning @@ -262,7 +260,7 @@ struct MANGOS_DLL_DECL boss_lethonAI : public boss_emerald_dragonAI } // Need this code here, as SPELL_DRAW_SPIRIT has no Script- or Dummyeffect - void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) + void SpellHitTarget(Unit* pTarget, const SpellEntry* pSpell) override { // Summon a shade for each player hit if (pTarget->GetTypeId() == TYPEID_PLAYER && pSpell->Id == SPELL_DRAW_SPIRIT) @@ -275,7 +273,7 @@ struct MANGOS_DLL_DECL boss_lethonAI : public boss_emerald_dragonAI } } - void JustSummoned(Creature* pSummoned) + void JustSummoned(Creature* pSummoned) override { // Move the shade to lethon if (pSummoned->GetEntry() == NPC_SPIRIT_SHADE) @@ -285,18 +283,18 @@ struct MANGOS_DLL_DECL boss_lethonAI : public boss_emerald_dragonAI } }; -struct MANGOS_DLL_DECL npc_spirit_shadeAI : public ScriptedAI +struct npc_spirit_shadeAI : public ScriptedAI { npc_spirit_shadeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } bool m_bHasHealed; - void Reset() + void Reset() override { m_bHasHealed = false; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_bHasHealed && pWho->GetEntry() == NPC_LETHON && pWho->IsWithinDistInMap(m_creature, 3.0f)) { @@ -308,9 +306,9 @@ struct MANGOS_DLL_DECL npc_spirit_shadeAI : public ScriptedAI } } - void AttackStart(Unit* pWho) { } + void AttackStart(Unit* /*pWho*/) override { } - void UpdateAI(const uint32 uiDiff) { } + void UpdateAI(const uint32 /*uiDiff*/) override { } }; CreatureAI* GetAI_boss_lethon(Creature* pCreature) @@ -345,7 +343,7 @@ enum SPELL_POSIONBREATH = 20667 }; -struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI +struct boss_taerarAI : public boss_emerald_dragonAI { boss_taerarAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) { Reset(); } @@ -354,7 +352,7 @@ struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI uint32 m_uiShadesTimeoutTimer; uint8 m_uiShadesDead; - void Reset() + void Reset() override { boss_emerald_dragonAI::Reset(); @@ -368,7 +366,7 @@ struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_TAERAR_AGGRO, m_creature); } @@ -395,7 +393,7 @@ struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI return false; } - void SummonedCreatureJustDied(Creature* pSummoned) + void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_SHADE_OF_TAERAR) { @@ -422,7 +420,7 @@ struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI if (m_uiShadesTimeoutTimer) { if (m_uiShadesTimeoutTimer <= uiDiff) - DoUnbanishBoss(); + DoUnbanishBoss(); else m_uiShadesTimeoutTimer -= uiDiff; @@ -453,57 +451,11 @@ struct MANGOS_DLL_DECL boss_taerarAI : public boss_emerald_dragonAI } }; -// Shades of Taerar Script -struct MANGOS_DLL_DECL boss_shadeoftaerarAI : public ScriptedAI -{ - boss_shadeoftaerarAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiPoisonCloud_Timer; - uint32 m_uiPosionBreath_Timer; - - void Reset() - { - m_uiPoisonCloud_Timer = 8000; - m_uiPosionBreath_Timer = 12000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //PoisonCloud_Timer - if (m_uiPoisonCloud_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_POSIONCLOUD); - m_uiPoisonCloud_Timer = 30000; - } - else - m_uiPoisonCloud_Timer -= uiDiff; - - //PosionBreath_Timer - if (m_uiPosionBreath_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_POSIONBREATH); - m_uiPosionBreath_Timer = 12000; - } - else - m_uiPosionBreath_Timer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - CreatureAI* GetAI_boss_taerar(Creature* pCreature) { return new boss_taerarAI(pCreature); } -CreatureAI* GetAI_boss_shadeoftaerar(Creature* pCreature) -{ - return new boss_shadeoftaerarAI(pCreature); -} - /*###### ## boss_ysondre ######*/ @@ -516,25 +468,25 @@ enum SPELL_LIGHTNING_WAVE = 24819, SPELL_SUMMON_DRUIDS = 24795, - //druid spells + // druid spells SPELL_MOONFIRE = 21669 }; // Ysondre script -struct MANGOS_DLL_DECL boss_ysondreAI : public boss_emerald_dragonAI +struct boss_ysondreAI : public boss_emerald_dragonAI { boss_ysondreAI(Creature* pCreature) : boss_emerald_dragonAI(pCreature) { Reset(); } uint32 m_uiLightningWaveTimer; - void Reset() + void Reset() override { boss_emerald_dragonAI::Reset(); m_uiLightningWaveTimer = 12000; } - void Aggro(Unit* pWho) + void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_YSONDRE_AGGRO, m_creature); } @@ -544,7 +496,7 @@ struct MANGOS_DLL_DECL boss_ysondreAI : public boss_emerald_dragonAI { DoScriptText(SAY_SUMMON_DRUIDS, m_creature); - for(int i = 0; i < 10; ++i) + for (int i = 0; i < 10; ++i) DoCastSpellIfCan(m_creature, SPELL_SUMMON_DRUIDS, CAST_TRIGGERED); return true; @@ -566,46 +518,11 @@ struct MANGOS_DLL_DECL boss_ysondreAI : public boss_emerald_dragonAI } }; -// Summoned druid script -struct MANGOS_DLL_DECL mob_dementeddruidsAI : public ScriptedAI -{ - mob_dementeddruidsAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - - uint32 m_uiMoonFire_Timer; - - void Reset() - { - m_uiMoonFire_Timer = 3000; - } - - void UpdateAI(const uint32 uiDiff) - { - if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - return; - - //MoonFire_Timer - if (m_uiMoonFire_Timer < uiDiff) - { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_MOONFIRE); - m_uiMoonFire_Timer = 5000; - } - else - m_uiMoonFire_Timer -= uiDiff; - - DoMeleeAttackIfReady(); - } -}; - CreatureAI* GetAI_boss_ysondre(Creature* pCreature) { return new boss_ysondreAI(pCreature); } -CreatureAI* GetAI_mob_dementeddruids(Creature* pCreature) -{ - return new mob_dementeddruidsAI(pCreature); -} - void AddSC_bosses_emerald_dragons() { Script* pNewScript; @@ -630,18 +547,8 @@ void AddSC_bosses_emerald_dragons() pNewScript->GetAI = &GetAI_boss_taerar; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "boss_shade_of_taerar"; - pNewScript->GetAI = &GetAI_boss_shadeoftaerar; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "boss_ysondre"; pNewScript->GetAI = &GetAI_boss_ysondre; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "mob_dementeddruids"; - pNewScript->GetAI = &GetAI_mob_dementeddruids; - pNewScript->RegisterSelf(); } diff --git a/scripts/world/go_scripts.cpp b/scripts/world/go_scripts.cpp index a294a8e1a..5fb8706d9 100644 --- a/scripts/world/go_scripts.cpp +++ b/scripts/world/go_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,44 +17,24 @@ /* ScriptData SDName: GO_Scripts SD%Complete: 100 -SDComment: Quest support: 5088, 5097, 5098, 5381, 6481, 10990, 10991, 10992, 12557, 14092/14076. Barov_journal->Teaches spell 26089 +SDComment: Quest support: 5097, 5098, 12557, 14092/14076. Barov_journal->Teaches spell 26089 SDCategory: Game Objects EndScriptData */ /* ContentData -go_cat_figurine (the "trap" version of GO, two different exist) go_barov_journal go_ethereum_prison go_ethereum_stasis go_mysterious_snow_mound -go_resonite_cask -go_sacred_fire_of_life -go_shrine_of_the_birds go_tele_to_dalaran_crystal go_tele_to_violet_stand go_andorhal_tower go_scourge_enclosure go_lab_work_reagents -go_hand_of_iruxos_crystal EndContentData */ #include "precompiled.h" -/*###### -## go_cat_figurine -######*/ - -enum -{ - SPELL_SUMMON_GHOST_SABER = 5968, -}; - -bool GOUse_go_cat_figurine(Player* pPlayer, GameObject* pGo) -{ - pPlayer->CastSpell(pPlayer, SPELL_SUMMON_GHOST_SABER, true); - return false; -} - /*###### ## go_barov_journal ######*/ @@ -65,7 +45,7 @@ enum SPELL_LEARN_FELCLOTH_BAG = 26095 }; -bool GOUse_go_barov_journal(Player* pPlayer, GameObject* pGo) +bool GOUse_go_barov_journal(Player* pPlayer, GameObject* /*pGo*/) { if (pPlayer->HasSkill(SKILL_TAILORING) && pPlayer->GetBaseSkillValue(SKILL_TAILORING) >= 280 && !pPlayer->HasSpell(SPELL_TAILOR_FELCLOTH_BAG)) { @@ -97,17 +77,17 @@ enum const uint32 uiNpcPrisonEntry[] = { - 22810, 22811, 22812, 22813, 22814, 22815, //good guys - 20783, 20784, 20785, 20786, 20788, 20789, 20790 //bad guys + 22810, 22811, 22812, 22813, 22814, 22815, // good guys + 20783, 20784, 20785, 20786, 20788, 20789, 20790 // bad guys }; bool GOUse_go_ethereum_prison(Player* pPlayer, GameObject* pGo) { - uint8 uiRandom = urand(0, (sizeof(uiNpcPrisonEntry) / sizeof(uint32)) -1); + uint8 uiRandom = urand(0, countof(uiNpcPrisonEntry) - 1); if (Creature* pCreature = pPlayer->SummonCreature(uiNpcPrisonEntry[uiRandom], - pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), pGo->GetAngle(pPlayer), - TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), pGo->GetAngle(pPlayer), + TEMPSUMMON_TIMED_OOC_DESPAWN, 30000)) { if (!pCreature->IsHostileTo(pPlayer)) { @@ -115,7 +95,7 @@ bool GOUse_go_ethereum_prison(Player* pPlayer, GameObject* pGo) if (FactionTemplateEntry const* pFaction = pCreature->getFactionTemplateEntry()) { - switch(pFaction->faction) + switch (pFaction->faction) { case FACTION_LC: uiSpell = SPELL_REP_LC; break; case FACTION_SHAT: uiSpell = SPELL_REP_SHAT; break; @@ -126,9 +106,9 @@ bool GOUse_go_ethereum_prison(Player* pPlayer, GameObject* pGo) } if (uiSpell) - pCreature->CastSpell(pPlayer,uiSpell,false); + pCreature->CastSpell(pPlayer, uiSpell, false); else - error_log("SD2: go_ethereum_prison summoned creature (entry %u) but faction (%u) are not expected by script.",pCreature->GetEntry(),pCreature->getFaction()); + script_error_log("go_ethereum_prison summoned creature (entry %u) but faction (%u) are not expected by script.", pCreature->GetEntry(), pCreature->getFaction()); } } } @@ -147,35 +127,15 @@ const uint32 uiNpcStasisEntry[] = bool GOUse_go_ethereum_stasis(Player* pPlayer, GameObject* pGo) { - uint8 uiRandom = urand(0, (sizeof(uiNpcStasisEntry) / sizeof(uint32)) -1); + uint8 uiRandom = urand(0, countof(uiNpcStasisEntry) - 1); pPlayer->SummonCreature(uiNpcStasisEntry[uiRandom], - pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), pGo->GetAngle(pPlayer), - TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), pGo->GetAngle(pPlayer), + TEMPSUMMON_TIMED_OOC_DESPAWN, 30000); return false; } -/*###### -## go_gilded_brazier -######*/ - -enum -{ - NPC_STILLBLADE = 17716, -}; - -bool GOUse_go_gilded_brazier(Player* pPlayer, GameObject* pGO) -{ - if (pGO->GetGoType() == GAMEOBJECT_TYPE_GOOBER) - { - if (Creature* pCreature = pPlayer->SummonCreature(NPC_STILLBLADE, 8087.632f, -7542.740f, 151.568f, 0.122f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) - pCreature->AI()->AttackStart(pPlayer); - } - - return true; -} - /*###### ## go_jump_a_tron ######*/ @@ -207,7 +167,7 @@ enum bool GOUse_go_mysterious_snow_mound(Player* pPlayer, GameObject* pGo) { - if (urand(0,1)) + if (urand(0, 1)) { pPlayer->CastSpell(pPlayer, SPELL_SUMMON_DEEP_JORMUNGAR, true); } @@ -224,80 +184,6 @@ bool GOUse_go_mysterious_snow_mound(Player* pPlayer, GameObject* pGo) return true; } -/*###### -## go_resonite_cask -######*/ - -enum -{ - NPC_GOGGEROC = 11920 -}; - -bool GOUse_go_resonite_cask(Player* pPlayer, GameObject* pGO) -{ - if (pGO->GetGoType() == GAMEOBJECT_TYPE_GOOBER) - pGO->SummonCreature(NPC_GOGGEROC, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000); - - return false; -} - -/*###### -## go_sacred_fire_of_life -######*/ - -enum -{ - NPC_ARIKARA = 10882, -}; - -bool GOUse_go_sacred_fire_of_life(Player* pPlayer, GameObject* pGO) -{ - if (pGO->GetGoType() == GAMEOBJECT_TYPE_GOOBER) - pPlayer->SummonCreature(NPC_ARIKARA, -5008.338f, -2118.894f, 83.657f, 0.874f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - - return true; -} - -/*###### -## go_shrine_of_the_birds -######*/ - -enum -{ - NPC_HAWK_GUARD = 22992, - NPC_EAGLE_GUARD = 22993, - NPC_FALCON_GUARD = 22994, - GO_SHRINE_HAWK = 185551, - GO_SHRINE_EAGLE = 185547, - GO_SHRINE_FALCON = 185553 -}; - -bool GOUse_go_shrine_of_the_birds(Player* pPlayer, GameObject* pGo) -{ - uint32 uiBirdEntry = 0; - - float fX,fY,fZ; - pGo->GetClosePoint(fX, fY, fZ, pGo->GetObjectBoundingRadius(), INTERACTION_DISTANCE); - - switch(pGo->GetEntry()) - { - case GO_SHRINE_HAWK: - uiBirdEntry = NPC_HAWK_GUARD; - break; - case GO_SHRINE_EAGLE: - uiBirdEntry = NPC_EAGLE_GUARD; - break; - case GO_SHRINE_FALCON: - uiBirdEntry = NPC_FALCON_GUARD; - break; - } - - if (uiBirdEntry) - pPlayer->SummonCreature(uiBirdEntry, fX, fY, fZ, pGo->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - - return false; -} - /*###### ## go_tele_to_dalaran_crystal ######*/ @@ -308,12 +194,12 @@ enum QUEST_TELE_CRYSTAL_FLAG = 12845 }; -bool GOUse_go_tele_to_dalaran_crystal(Player* pPlayer, GameObject* pGo) +bool GOUse_go_tele_to_dalaran_crystal(Player* pPlayer, GameObject* /*pGo*/) { if (pPlayer->GetQuestRewardStatus(QUEST_TELE_CRYSTAL_FLAG)) return false; - //TODO: must send error message (what kind of message? On-screen?) + // TODO: must send error message (what kind of message? On-screen?) return true; } @@ -321,7 +207,7 @@ bool GOUse_go_tele_to_dalaran_crystal(Player* pPlayer, GameObject* pGo) ## go_tele_to_violet_stand ######*/ -bool GOUse_go_tele_to_violet_stand(Player* pPlayer, GameObject* pGo) +bool GOUse_go_tele_to_violet_stand(Player* pPlayer, GameObject* /*pGo*/) { if (pPlayer->GetQuestRewardStatus(QUEST_LEARN_LEAVE_RETURN) || pPlayer->GetQuestStatus(QUEST_LEARN_LEAVE_RETURN) == QUEST_STATUS_INCOMPLETE) return false; @@ -329,24 +215,6 @@ bool GOUse_go_tele_to_violet_stand(Player* pPlayer, GameObject* pGo) return true; } -enum -{ - NPC_ZELEMAR_THE_WRATHFULL = 17830, - SAY_AGGRO = -1000579 -}; - -float Position[4] = {-327.99f, 221.74f, -20.31f, 3.87f}; - -bool GOUse_go_blood_filled_orb(Player* pPlayer, GameObject* pGo) -{ - if (Creature* pZelemar = pGo->SummonCreature(NPC_ZELEMAR_THE_WRATHFULL, Position[0], Position[1], Position[2], Position[3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) - { - DoScriptText(SAY_AGGRO, pZelemar); - pZelemar->AI()->AttackStart(pPlayer); - } - return false; -} - /*###### ## go_andorhal_tower ######*/ @@ -370,7 +238,7 @@ bool GOUse_go_andorhal_tower(Player* pPlayer, GameObject* pGo) if (pPlayer->GetQuestStatus(QUEST_ALL_ALONG_THE_WATCHTOWERS_ALLIANCE) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_ALL_ALONG_THE_WATCHTOWERS_HORDE) == QUEST_STATUS_INCOMPLETE) { uint32 uiKillCredit = 0; - switch(pGo->GetEntry()) + switch (pGo->GetEntry()) { case GO_ANDORHAL_TOWER_1: uiKillCredit = NPC_ANDORHAL_TOWER_1; break; case GO_ANDORHAL_TOWER_2: uiKillCredit = NPC_ANDORHAL_TOWER_2; break; @@ -391,7 +259,6 @@ enum { SPELL_GYMER_LOCK_EXPLOSION = 55529, NPC_GYMER_LOCK_DUMMY = 29928 - }; bool GOUse_go_scourge_enclosure(Player* pPlayer, GameObject* pGo) @@ -400,9 +267,9 @@ bool GOUse_go_scourge_enclosure(Player* pPlayer, GameObject* pGo) GetCreatureListWithEntryInGrid(m_lResearchersList, pGo, NPC_GYMER_LOCK_DUMMY, 15.0f); if (!m_lResearchersList.empty()) { - for(std::list::iterator itr = m_lResearchersList.begin(); itr != m_lResearchersList.end(); ++itr) + for (std::list::iterator itr = m_lResearchersList.begin(); itr != m_lResearchersList.end(); ++itr) { - (*itr)->CastSpell((*itr),SPELL_GYMER_LOCK_EXPLOSION,true); + (*itr)->CastSpell((*itr), SPELL_GYMER_LOCK_EXPLOSION, true); } } pPlayer->KilledMonsterCredit(NPC_GYMER_LOCK_DUMMY); @@ -448,39 +315,10 @@ bool GOUse_go_lab_work_reagents(Player* pPlayer, GameObject* pGo) return false; } -/*###### -## go_hand_of_iruxos_crystal -######*/ - -/* TODO - * Actually this script is extremely vague, but as long as there is no valid information - * hidden in some dark places, this will be the best we can do here :( - * Do not consider this a well proven script. - */ - -enum -{ - // QUEST_HAND_OF_IRUXOS = 5381, - NPC_IRUXOS = 11876, -}; - -bool GOUse_go_hand_of_iruxos_crystal(Player* pPlayer, GameObject* pGo) -{ - if (Creature* pIruxos = pGo->SummonCreature(NPC_IRUXOS, 0.0f, 0.0f, 0.0f, pPlayer->GetOrientation() + M_PI_F, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000)) - pIruxos->AI()->AttackStart(pPlayer); - - return false; -} - void AddSC_go_scripts() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "go_cat_figurine"; - pNewScript->pGOUse = &GOUse_go_cat_figurine; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "go_barov_journal"; pNewScript->pGOUse = &GOUse_go_barov_journal; @@ -496,11 +334,6 @@ void AddSC_go_scripts() pNewScript->pGOUse = &GOUse_go_ethereum_stasis; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "go_gilded_brazier"; - pNewScript->pGOUse = &GOUse_go_gilded_brazier; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "go_jump_a_tron"; pNewScript->pGOUse = &GOUse_go_jump_a_tron; @@ -511,21 +344,6 @@ void AddSC_go_scripts() pNewScript->pGOUse = &GOUse_go_mysterious_snow_mound; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "go_resonite_cask"; - pNewScript->pGOUse = &GOUse_go_resonite_cask; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_sacred_fire_of_life"; - pNewScript->pGOUse = &GOUse_go_sacred_fire_of_life; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_shrine_of_the_birds"; - pNewScript->pGOUse = &GOUse_go_shrine_of_the_birds; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "go_tele_to_dalaran_crystal"; pNewScript->pGOUse = &GOUse_go_tele_to_dalaran_crystal; @@ -536,11 +354,6 @@ void AddSC_go_scripts() pNewScript->pGOUse = &GOUse_go_tele_to_violet_stand; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "go_blood_filled_orb"; - pNewScript->pGOUse = &GOUse_go_blood_filled_orb; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "go_andorhal_tower"; pNewScript->pGOUse = &GOUse_go_andorhal_tower; @@ -555,9 +368,4 @@ void AddSC_go_scripts() pNewScript->Name = "go_lab_work_reagents"; pNewScript->pGOUse = &GOUse_go_lab_work_reagents; pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "go_hand_of_iruxos_crystal"; - pNewScript->pGOUse = &GOUse_go_hand_of_iruxos_crystal; - pNewScript->RegisterSelf(); } diff --git a/scripts/world/guards.cpp b/scripts/world/guards.cpp index fa0fceec8..c0557234a 100644 --- a/scripts/world/guards.cpp +++ b/scripts/world/guards.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* ScriptData SDName: Guards SD%Complete: 100 -SDComment: CombatAI should be organized better for future. +SDComment: CombatAI should be organized better for future. Quest support 13188 / 13189. SDCategory: Guards EndScriptData */ @@ -116,7 +116,7 @@ CreatureAI* GetAI_guard_shattrath(Creature* pCreature) * guard_shattrath_aldor *******************************************************/ -struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI +struct guard_shattrath_aldorAI : public guardAI { guard_shattrath_aldorAI(Creature* pCreature) : guardAI(pCreature) { Reset(); } @@ -125,7 +125,7 @@ struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI ObjectGuid m_playerGuid; bool m_bCanTeleport; - void Reset() + void Reset() override { m_uiBanish_Timer = 5000; m_uiExile_Timer = 8500; @@ -133,7 +133,7 @@ struct MANGOS_DLL_DECL guard_shattrath_aldorAI : public guardAI m_bCanTeleport = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -183,7 +183,7 @@ CreatureAI* GetAI_guard_shattrath_aldor(Creature* pCreature) * guard_shattrath_scryer *******************************************************/ -struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI +struct guard_shattrath_scryerAI : public guardAI { guard_shattrath_scryerAI(Creature* pCreature) : guardAI(pCreature) { Reset(); } @@ -192,7 +192,7 @@ struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI ObjectGuid m_playerGuid; bool m_bCanTeleport; - void Reset() + void Reset() override { m_uiBanish_Timer = 5000; m_uiExile_Timer = 8500; @@ -200,7 +200,7 @@ struct MANGOS_DLL_DECL guard_shattrath_scryerAI : public guardAI m_bCanTeleport = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -271,6 +271,69 @@ CreatureAI* GetAI_guard_undercity(Creature* pCreature) return new guardAI(pCreature); } +/******************************************************* + * quests 13188 / 13189 + *******************************************************/ + +enum +{ + SPELL_RETURN_ORGRIMMAR = 58552, + SPELL_RETURN_STORMWIND = 58533, + + SPELL_TOSS_APPLE = 58509, + SPELL_TOSS_BANANA = 58513, + SPELL_SPIT = 58520, + + EMOTE_APPLE = -1609081, + EMOTE_BANANA = -1609082, + EMOTE_SPIT = -1609083, + SAY_RANDOM_1 = -1609084, + SAY_RANDOM_2 = -1609085, + SAY_RANDOM_3 = -1609086, + SAY_RANDOM_4 = -1609087, + SAY_RANDOM_5 = -1609088, + SAY_RANDOM_6 = -1609287, + SAY_RANDOM_7 = -1609288, + SAY_RANDOM_8 = -1609289, +}; + +bool EffectDummyCreature_npc_city_guard(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // check spell ids; creature ids are defined in script target + if ((uiSpellId == SPELL_RETURN_ORGRIMMAR || uiSpellId == SPELL_RETURN_STORMWIND) && uiEffIndex == EFFECT_INDEX_0) + { + // random action + switch (urand(0, 10)) + { + case 0: + pCreatureTarget->CastSpell(pCaster, SPELL_TOSS_APPLE, true); + DoScriptText(EMOTE_APPLE, pCreatureTarget, pCaster); + break; + case 1: + pCreatureTarget->CastSpell(pCaster, SPELL_TOSS_BANANA, true); + DoScriptText(EMOTE_BANANA, pCreatureTarget, pCaster); + break; + case 2: + pCreatureTarget->CastSpell(pCaster, SPELL_SPIT, true); + DoScriptText(EMOTE_SPIT, pCreatureTarget, pCaster); + break; + case 3: DoScriptText(SAY_RANDOM_1, pCreatureTarget, pCaster); break; + case 4: DoScriptText(SAY_RANDOM_2, pCreatureTarget, pCaster); break; + case 5: DoScriptText(SAY_RANDOM_3, pCreatureTarget, pCaster); break; + case 6: DoScriptText(SAY_RANDOM_4, pCreatureTarget, pCaster); break; + case 7: DoScriptText(SAY_RANDOM_5, pCreatureTarget, pCaster); break; + case 8: DoScriptText(SAY_RANDOM_6, pCreatureTarget, pCaster); break; + case 9: DoScriptText(SAY_RANDOM_7, pCreatureTarget, pCaster); break; + case 10: DoScriptText(SAY_RANDOM_8, pCreatureTarget, pCaster); break; + } + + // return true as we don't need further script handling in DB + return true; + } + + return false; +} + void AddSC_guards() { Script* pNewScript; @@ -333,6 +396,7 @@ void AddSC_guards() pNewScript = new Script; pNewScript->Name = "guard_orgrimmar"; pNewScript->GetAI = &GetAI_guard_orgrimmar; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_city_guard; pNewScript->RegisterSelf(); pNewScript = new Script; @@ -358,6 +422,7 @@ void AddSC_guards() pNewScript = new Script; pNewScript->Name = "guard_stormwind"; pNewScript->GetAI = &GetAI_guard_stormwind; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_city_guard; pNewScript->RegisterSelf(); pNewScript = new Script; diff --git a/scripts/world/item_scripts.cpp b/scripts/world/item_scripts.cpp index 5371c6be1..026004add 100644 --- a/scripts/world/item_scripts.cpp +++ b/scripts/world/item_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,7 +39,7 @@ enum SPELL_ARCANE_CHARGES = 45072 }; -bool ItemUse_item_arcane_charges(Player* pPlayer, Item* pItem, const SpellCastTargets &pTargets) +bool ItemUse_item_arcane_charges(Player* pPlayer, Item* pItem, const SpellCastTargets& /*pTargets*/) { if (pPlayer->IsTaxiFlying()) return false; @@ -56,7 +56,7 @@ bool ItemUse_item_arcane_charges(Player* pPlayer, Item* pItem, const SpellCastTa # item_flying_machine #####*/ -bool ItemUse_item_flying_machine(Player* pPlayer, Item* pItem, const SpellCastTargets &pTargets) +bool ItemUse_item_flying_machine(Player* pPlayer, Item* pItem, const SpellCastTargets& /*pTargets*/) { uint32 itemId = pItem->GetEntry(); @@ -68,7 +68,7 @@ bool ItemUse_item_flying_machine(Player* pPlayer, Item* pItem, const SpellCastTa if (pPlayer->GetBaseSkillValue(SKILL_RIDING) == 300) return false; - debug_log("SD2: Player attempt to use item %u, but did not meet riding requirement",itemId); + debug_log("SD2: Player attempt to use item %u, but did not meet riding requirement", itemId); pPlayer->SendEquipError(EQUIP_ERR_CANT_EQUIP_SKILL, pItem, NULL); return true; } @@ -83,7 +83,7 @@ enum SPELL_GORDREKS_OINTMENT = 32578 }; -bool ItemUse_item_gor_dreks_ointment(Player* pPlayer, Item* pItem, const SpellCastTargets &pTargets) +bool ItemUse_item_gor_dreks_ointment(Player* pPlayer, Item* pItem, const SpellCastTargets& pTargets) { if (pTargets.getUnitTarget() && pTargets.getUnitTarget()->GetTypeId() == TYPEID_UNIT && pTargets.getUnitTarget()->HasAura(SPELL_GORDREKS_OINTMENT)) { @@ -109,7 +109,7 @@ enum ZONE_ID_HOWLING = 495 }; -bool ItemUse_item_petrov_cluster_bombs(Player* pPlayer, Item* pItem, const SpellCastTargets &pTargets) +bool ItemUse_item_petrov_cluster_bombs(Player* pPlayer, Item* pItem, const SpellCastTargets& /*pTargets*/) { if (pPlayer->GetZoneId() != ZONE_ID_HOWLING) return false; diff --git a/scripts/world/mob_generic_creature.cpp b/scripts/world/mob_generic_creature.cpp index 025616de2..dbfa94d7e 100644 --- a/scripts/world/mob_generic_creature.cpp +++ b/scripts/world/mob_generic_creature.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,58 +25,61 @@ EndScriptData */ #define GENERIC_CREATURE_COOLDOWN 5000 -struct MANGOS_DLL_DECL generic_creatureAI : public ScriptedAI +struct generic_creatureAI : public ScriptedAI { generic_creatureAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - uint32 GlobalCooldown; //This variable acts like the global cooldown that players have (1.5 seconds) - uint32 BuffTimer; //This variable keeps track of buffs + uint32 GlobalCooldown; // This variable acts like the global cooldown that players have (1.5 seconds) + uint32 BuffTimer; // This variable keeps track of buffs bool IsSelfRooted; - void Reset() + void Reset() override { GlobalCooldown = 0; - BuffTimer = 0; //Rebuff as soon as we can + BuffTimer = 0; // Rebuff as soon as we can IsSelfRooted = false; } - void Aggro(Unit *who) + void Aggro(Unit* who) override { - if (!m_creature->CanReachWithMeleeAttack(who)) - { - IsSelfRooted = true; - } + if (!m_creature->CanReachWithMeleeAttack(who)) + { + IsSelfRooted = true; + } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 diff) override { - //Always decrease our global cooldown first + // Always decrease our global cooldown first if (GlobalCooldown > diff) GlobalCooldown -= diff; else GlobalCooldown = 0; - //Buff timer (only buff when we are alive and not in combat + // Buff timer (only buff when we are alive and not in combat if (!m_creature->isInCombat() && m_creature->isAlive()) + { if (BuffTimer < diff) { - //Find a spell that targets friendly and applies an aura (these are generally buffs) - SpellEntry const *info = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA); + // Find a spell that targets friendly and applies an aura (these are generally buffs) + SpellEntry const* info = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA); if (info && !GlobalCooldown) { - //Cast the buff spell + // Cast the buff spell DoCastSpell(m_creature, info); - //Set our global cooldown + // Set our global cooldown GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - //Set our timer to 10 minutes before rebuff + // Set our timer to 10 minutes before rebuff BuffTimer = 600000; - }//Try agian in 30 seconds + }// Try agian in 30 seconds else BuffTimer = 30000; - }else BuffTimer -= diff; + } + else BuffTimer -= diff; + } - //Return since we have no target + // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; @@ -84,31 +87,31 @@ struct MANGOS_DLL_DECL generic_creatureAI : public ScriptedAI if (m_creature->IsNonMeleeSpellCasted(false)) return; - //If we are within range melee the target + // If we are within range melee the target if (m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) { - //Make sure our attack is ready + // Make sure our attack is ready if (m_creature->isAttackReady()) { bool Healing = false; - SpellEntry const *info = NULL; + SpellEntry const* info = NULL; - //Select a healing spell if less than 30% hp + // Select a healing spell if less than 30% hp if (m_creature->GetHealthPercent() < 30.0f) info = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); - //No healing spell available, select a hostile spell + // No healing spell available, select a hostile spell if (info) Healing = true; else info = SelectSpell(m_creature->getVictim(), -1, -1, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE); - //50% chance if elite or higher, 20% chance if not, to replace our white hit with a spell - if (info && (rand() % (m_creature->GetCreatureInfo()->rank > 1 ? 2 : 5) == 0) && !GlobalCooldown) + // 50% chance if elite or higher, 20% chance if not, to replace our white hit with a spell + if (info && (rand() % (m_creature->GetCreatureInfo()->Rank > 1 ? 2 : 5) == 0) && !GlobalCooldown) { - //Cast the spell + // Cast the spell if (Healing)DoCastSpell(m_creature, info); else DoCastSpell(m_creature->getVictim(), info); - //Set our global cooldown + // Set our global cooldown GlobalCooldown = GENERIC_CREATURE_COOLDOWN; } else m_creature->AttackerStateUpdate(m_creature->getVictim()); @@ -119,36 +122,35 @@ struct MANGOS_DLL_DECL generic_creatureAI : public ScriptedAI else { bool Healing = false; - SpellEntry const *info = NULL; + SpellEntry const* info = NULL; - //Select a healing spell if less than 30% hp ONLY 33% of the time + // Select a healing spell if less than 30% hp ONLY 33% of the time if (m_creature->GetHealthPercent() < 30.0f && !urand(0, 2)) info = SelectSpell(m_creature, -1, -1, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING); - //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) + // No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) if (info) Healing = true; else info = SelectSpell(m_creature->getVictim(), -1, -1, SELECT_TARGET_ANY_ENEMY, 0, 0, ATTACK_DISTANCE, 0, SELECT_EFFECT_DONTCARE); - //Found a spell, check if we arn't on cooldown + // Found a spell, check if we arn't on cooldown if (info && !GlobalCooldown) { - //If we are currently moving stop us and set the movement generator + // If we are currently moving stop us and set the movement generator if (!IsSelfRooted) { IsSelfRooted = true; } - //Cast spell - if (Healing) DoCastSpell(m_creature,info); - else DoCastSpell(m_creature->getVictim(),info); + // Cast spell + if (Healing) DoCastSpell(m_creature, info); + else DoCastSpell(m_creature->getVictim(), info); - //Set our global cooldown + // Set our global cooldown GlobalCooldown = GENERIC_CREATURE_COOLDOWN; - - }//If no spells available and we arn't moving run to target + }// If no spells available and we arn't moving run to target else if (IsSelfRooted) { - //Cancel our current spell and then allow movement agian + // Cancel our current spell and then allow movement agian m_creature->InterruptNonMeleeSpells(false); IsSelfRooted = false; } diff --git a/scripts/world/npc_professions.cpp b/scripts/world/npc_professions.cpp index 7f8409ee0..239c6492a 100644 --- a/scripts/world/npc_professions.cpp +++ b/scripts/world/npc_professions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -59,15 +59,6 @@ there is no difference here (except that default text is chosen with `gameobject # gossip item and box texts ###*/ -#define GOSSIP_LEARN_POTION "Please teach me how to become a Master of Potions, Lauranna" -#define GOSSIP_UNLEARN_POTION "I wish to unlearn Potion Mastery" -#define GOSSIP_LEARN_TRANSMUTE "Please teach me how to become a Master of Transmutations, Zarevhi" -#define GOSSIP_UNLEARN_TRANSMUTE "I wish to unlearn Transmutation Mastery" -#define GOSSIP_LEARN_ELIXIR "Please teach me how to become a Master of Elixirs, Lorokeem" -#define GOSSIP_UNLEARN_ELIXIR "I wish to unlearn Elixir Mastery" - -#define BOX_UNLEARN_ALCHEMY_SPEC "Do you really want to unlearn your alchemy specialty and lose all associated recipes? \n Cost: " - #define GOSSIP_WEAPON_LEARN "Please teach me how to become a Weaponsmith" #define GOSSIP_WEAPON_UNLEARN "I wish to unlearn the art of Weaponsmithing" #define GOSSIP_ARMOR_LEARN "Please teach me how to become a Armorsmith" @@ -94,15 +85,6 @@ there is no difference here (except that default text is chosen with `gameobject #define BOX_UNLEARN_LEATHER_SPEC "Do you really want to unlearn your leatherworking specialty and lose all associated recipes? \n Cost: " -#define GOSSIP_LEARN_SPELLFIRE "Please teach me how to become a Spellcloth tailor" -#define GOSSIP_UNLEARN_SPELLFIRE "I wish to unlearn Spellfire Tailoring" -#define GOSSIP_LEARN_MOONCLOTH "Please teach me how to become a Mooncloth tailor" -#define GOSSIP_UNLEARN_MOONCLOTH "I wish to unlearn Mooncloth Tailoring" -#define GOSSIP_LEARN_SHADOWEAVE "Please teach me how to become a Shadoweave tailor" -#define GOSSIP_UNLEARN_SHADOWEAVE "I wish to unlearn Shadoweave Tailoring" - -#define BOX_UNLEARN_TAILOR_SPEC "Do you really want to unlearn your tailoring specialty and lose all associated recipes? \n Cost: " - #define GOSSIP_LEARN_GOBLIN "I am absolutely certain that i want to learn Goblin engineering" #define GOSSIP_LEARN_GNOMISH "I am absolutely certain that i want to learn Gnomish engineering" @@ -155,45 +137,11 @@ there is no difference here (except that default text is chosen with `gameobject #define S_LEARN_GOBLIN 20221 #define S_LEARN_GNOMISH 20220 -#define S_SPELLFIRE 26797 -#define S_MOONCLOTH 26798 -#define S_SHADOWEAVE 26801 - -#define S_LEARN_SPELLFIRE 26796 -#define S_LEARN_MOONCLOTH 26799 -#define S_LEARN_SHADOWEAVE 26800 - -#define S_UNLEARN_SPELLFIRE 41299 -#define S_UNLEARN_MOONCLOTH 41558 -#define S_UNLEARN_SHADOWEAVE 41559 - -#define S_TRANSMUTE 28672 -#define S_ELIXIR 28677 -#define S_POTION 28675 - -#define S_LEARN_TRANSMUTE 28674 -#define S_LEARN_ELIXIR 28678 -#define S_LEARN_POTION 28676 - -#define S_UNLEARN_TRANSMUTE 41565 -#define S_UNLEARN_ELIXIR 41564 -#define S_UNLEARN_POTION 41563 - /*### # formulas to calculate unlearning cost ###*/ -int32 GetLearningCost(Player* pPlayer) //tailor, alchemy -{ - return 200000; -} - -int32 GetUnlearnCostHigh(Player* pPlayer) //tailor, alchemy -{ - return 1500000; -} - -int32 GetUnlearnCostMedium(Player* pPlayer) //blacksmith, leatherwork +int32 GetUnlearnCostMedium(Player* pPlayer) // blacksmith, leatherwork { uint32 level = pPlayer->getLevel(); @@ -205,7 +153,7 @@ int32 GetUnlearnCostMedium(Player* pPlayer) //blacksmith, leathe return 1000000; } -int32 GetUnlearnCostLow(Player* pPlayer) //blacksmith +int32 GetUnlearnCostLow(Player* pPlayer) // blacksmith { if (pPlayer->getLevel() < 66) return 50000; @@ -224,23 +172,23 @@ bool EquippedOk(Player* pPlayer, uint32 spellId) if (!spell) return false; - for(int i=0; i<3; ++i) + for (int i = 0; i < 3; ++i) { uint32 reqSpell = spell->EffectTriggerSpell[i]; if (!reqSpell) continue; Item* pItem; - for(int j = EQUIPMENT_SLOT_START; j < EQUIPMENT_SLOT_END; ++j) + for (int j = EQUIPMENT_SLOT_START; j < EQUIPMENT_SLOT_END; ++j) { pItem = pPlayer->GetItemByPos(INVENTORY_SLOT_BAG_0, j); if (pItem) if (pItem->GetProto()->RequiredSpell == reqSpell) - { - //pPlayer has item equipped that require specialty. Not allow to unlearn, player has to unequip first - debug_log("SD2: player attempt to unlearn spell %u, but item %u is equipped.",reqSpell,pItem->GetProto()->ItemId); - return false; - } + { + // pPlayer has item equipped that require specialty. Not allow to unlearn, player has to unequip first + debug_log("SD2: player attempt to unlearn spell %u, but item %u is equipped.", reqSpell, pItem->GetProto()->ItemId); + return false; + } } } return true; @@ -251,281 +199,94 @@ void ProfessionUnlearnSpells(Player* pPlayer, uint32 type) switch (type) { case 36436: // S_UNLEARN_WEAPON - pPlayer->removeSpell(36125); // Light Earthforged Blade - pPlayer->removeSpell(36128); // Light Emberforged Hammer - pPlayer->removeSpell(36126); // Light Skyforged Axe + pPlayer->removeSpell(36125); // Light Earthforged Blade + pPlayer->removeSpell(36128); // Light Emberforged Hammer + pPlayer->removeSpell(36126); // Light Skyforged Axe break; case 36435: // S_UNLEARN_ARMOR - pPlayer->removeSpell(36122); // Earthforged Leggings - pPlayer->removeSpell(36129); // Heavy Earthforged Breastplate - pPlayer->removeSpell(36130); // Stormforged Hauberk - pPlayer->removeSpell(34533); // Breastplate of Kings - pPlayer->removeSpell(34529); // Nether Chain Shirt - pPlayer->removeSpell(34534); // Bulwark of Kings - pPlayer->removeSpell(36257); // Bulwark of the Ancient Kings - pPlayer->removeSpell(36256); // Embrace of the Twisting Nether - pPlayer->removeSpell(34530); // Twisting Nether Chain Shirt - pPlayer->removeSpell(36124); // Windforged Leggings + pPlayer->removeSpell(36122); // Earthforged Leggings + pPlayer->removeSpell(36129); // Heavy Earthforged Breastplate + pPlayer->removeSpell(36130); // Stormforged Hauberk + pPlayer->removeSpell(34533); // Breastplate of Kings + pPlayer->removeSpell(34529); // Nether Chain Shirt + pPlayer->removeSpell(34534); // Bulwark of Kings + pPlayer->removeSpell(36257); // Bulwark of the Ancient Kings + pPlayer->removeSpell(36256); // Embrace of the Twisting Nether + pPlayer->removeSpell(34530); // Twisting Nether Chain Shirt + pPlayer->removeSpell(36124); // Windforged Leggings break; case 36441: // S_UNLEARN_HAMMER - pPlayer->removeSpell(36262); // Dragonstrike - pPlayer->removeSpell(34546); // Dragonmaw - pPlayer->removeSpell(34545); // Drakefist Hammer - pPlayer->removeSpell(36136); // Lavaforged Warhammer - pPlayer->removeSpell(34547); // Thunder - pPlayer->removeSpell(34567); // Deep Thunder - pPlayer->removeSpell(36263); // Stormherald - pPlayer->removeSpell(36137); // Great Earthforged Hammer + pPlayer->removeSpell(36262); // Dragonstrike + pPlayer->removeSpell(34546); // Dragonmaw + pPlayer->removeSpell(34545); // Drakefist Hammer + pPlayer->removeSpell(36136); // Lavaforged Warhammer + pPlayer->removeSpell(34547); // Thunder + pPlayer->removeSpell(34567); // Deep Thunder + pPlayer->removeSpell(36263); // Stormherald + pPlayer->removeSpell(36137); // Great Earthforged Hammer break; case 36439: // S_UNLEARN_AXE - pPlayer->removeSpell(36260); // Wicked Edge of the Planes - pPlayer->removeSpell(34562); // Black Planar Edge - pPlayer->removeSpell(34541); // The Planar Edge - pPlayer->removeSpell(36134); // Stormforged Axe - pPlayer->removeSpell(36135); // Skyforged Great Axe - pPlayer->removeSpell(36261); // Bloodmoon - pPlayer->removeSpell(34543); // Lunar Crescent - pPlayer->removeSpell(34544); // Mooncleaver + pPlayer->removeSpell(36260); // Wicked Edge of the Planes + pPlayer->removeSpell(34562); // Black Planar Edge + pPlayer->removeSpell(34541); // The Planar Edge + pPlayer->removeSpell(36134); // Stormforged Axe + pPlayer->removeSpell(36135); // Skyforged Great Axe + pPlayer->removeSpell(36261); // Bloodmoon + pPlayer->removeSpell(34543); // Lunar Crescent + pPlayer->removeSpell(34544); // Mooncleaver break; case 36438: // S_UNLEARN_SWORD - pPlayer->removeSpell(36258); // Blazefury - pPlayer->removeSpell(34537); // Blazeguard - pPlayer->removeSpell(34535); // Fireguard - pPlayer->removeSpell(36131); // Windforged Rapier - pPlayer->removeSpell(36133); // Stoneforged Claymore - pPlayer->removeSpell(34538); // Lionheart Blade - pPlayer->removeSpell(34540); // Lionheart Champion - pPlayer->removeSpell(36259); // Lionheart Executioner + pPlayer->removeSpell(36258); // Blazefury + pPlayer->removeSpell(34537); // Blazeguard + pPlayer->removeSpell(34535); // Fireguard + pPlayer->removeSpell(36131); // Windforged Rapier + pPlayer->removeSpell(36133); // Stoneforged Claymore + pPlayer->removeSpell(34538); // Lionheart Blade + pPlayer->removeSpell(34540); // Lionheart Champion + pPlayer->removeSpell(36259); // Lionheart Executioner break; case 36434: // S_UNLEARN_DRAGON - pPlayer->removeSpell(36076); // Dragonstrike Leggings - pPlayer->removeSpell(36079); // Golden Dragonstrike Breastplate - pPlayer->removeSpell(35576); // Ebon Netherscale Belt - pPlayer->removeSpell(35577); // Ebon Netherscale Bracers - pPlayer->removeSpell(35575); // Ebon Netherscale Breastplate - pPlayer->removeSpell(35582); // Netherstrike Belt - pPlayer->removeSpell(35584); // Netherstrike Bracers - pPlayer->removeSpell(35580); // Netherstrike Breastplate + pPlayer->removeSpell(36076); // Dragonstrike Leggings + pPlayer->removeSpell(36079); // Golden Dragonstrike Breastplate + pPlayer->removeSpell(35576); // Ebon Netherscale Belt + pPlayer->removeSpell(35577); // Ebon Netherscale Bracers + pPlayer->removeSpell(35575); // Ebon Netherscale Breastplate + pPlayer->removeSpell(35582); // Netherstrike Belt + pPlayer->removeSpell(35584); // Netherstrike Bracers + pPlayer->removeSpell(35580); // Netherstrike Breastplate break; case 36328: // S_UNLEARN_ELEMENTAL - pPlayer->removeSpell(36074); // Blackstorm Leggings - pPlayer->removeSpell(36077); // Primalstorm Breastplate - pPlayer->removeSpell(35590); // Primalstrike Belt - pPlayer->removeSpell(35591); // Primalstrike Bracers - pPlayer->removeSpell(35589); // Primalstrike Vest + pPlayer->removeSpell(36074); // Blackstorm Leggings + pPlayer->removeSpell(36077); // Primalstorm Breastplate + pPlayer->removeSpell(35590); // Primalstrike Belt + pPlayer->removeSpell(35591); // Primalstrike Bracers + pPlayer->removeSpell(35589); // Primalstrike Vest break; case 36433: // S_UNLEARN_TRIBAL - pPlayer->removeSpell(35585); // Windhawk Hauberk - pPlayer->removeSpell(35587); // Windhawk Belt - pPlayer->removeSpell(35588); // Windhawk Bracers - pPlayer->removeSpell(36075); // Wildfeather Leggings - pPlayer->removeSpell(36078); // Living Crystal Breastplate + pPlayer->removeSpell(35585); // Windhawk Hauberk + pPlayer->removeSpell(35587); // Windhawk Belt + pPlayer->removeSpell(35588); // Windhawk Bracers + pPlayer->removeSpell(36075); // Wildfeather Leggings + pPlayer->removeSpell(36078); // Living Crystal Breastplate break; case 41299: // S_UNLEARN_SPELLFIRE - pPlayer->removeSpell(26752); // Spellfire Belt - pPlayer->removeSpell(26753); // Spellfire Gloves - pPlayer->removeSpell(26754); // Spellfire Robe + pPlayer->removeSpell(26752); // Spellfire Belt + pPlayer->removeSpell(26753); // Spellfire Gloves + pPlayer->removeSpell(26754); // Spellfire Robe break; case 41558: // S_UNLEARN_MOONCLOTH - pPlayer->removeSpell(26760); // Primal Mooncloth Belt - pPlayer->removeSpell(26761); // Primal Mooncloth Shoulders - pPlayer->removeSpell(26762); // Primal Mooncloth Robe + pPlayer->removeSpell(26760); // Primal Mooncloth Belt + pPlayer->removeSpell(26761); // Primal Mooncloth Shoulders + pPlayer->removeSpell(26762); // Primal Mooncloth Robe break; case 41559: // S_UNLEARN_SHADOWEAVE - pPlayer->removeSpell(26756); // Frozen Shadoweave Shoulders - pPlayer->removeSpell(26757); // Frozen Shadoweave Boots - pPlayer->removeSpell(26758); // Frozen Shadoweave Robe - break; - } -} - -/*### -# start menues alchemy -###*/ - -bool HasAlchemySpell(Player* pPlayer) -{ - if (pPlayer->HasSpell(S_TRANSMUTE) || pPlayer->HasSpell(S_ELIXIR) || pPlayer->HasSpell(S_POTION)) - return true; - return false; -} - -bool GossipHello_npc_prof_alchemy(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if (pCreature->isTrainer()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - uint32 eCreature = pCreature->GetEntry(); - - if (pPlayer->HasSkill(SKILL_ALCHEMY) && pPlayer->GetBaseSkillValue(SKILL_ALCHEMY)>=350 && pPlayer->getLevel() > 67) - { - if (pPlayer->GetQuestRewardStatus(10899) || pPlayer->GetQuestRewardStatus(10902) || pPlayer->GetQuestRewardStatus(10897)) - { - switch (eCreature) - { - case 22427: //Zarevhi - if (!HasAlchemySpell(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_TRANSMUTE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 1); - if (pPlayer->HasSpell(S_TRANSMUTE)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_TRANSMUTE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); - break; - case 19052: //Lorokeem - if (!HasAlchemySpell(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_ELIXIR, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 2); - if (pPlayer->HasSpell(S_ELIXIR)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_ELIXIR, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 5); - break; - case 17909: //Lauranna Thar'well - if (!HasAlchemySpell(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_POTION, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 3); - if (pPlayer->HasSpell(S_POTION)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_POTION, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 6); - break; - } - } - } - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -void SendActionMenu_npc_prof_alchemy(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetObjectGuid()); - break; - //Learn Alchemy - case GOSSIP_ACTION_INFO_DEF + 1: - if (!pPlayer->HasSpell(S_TRANSMUTE) && pPlayer->GetMoney() >= uint32(GetLearningCost(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_LEARN_TRANSMUTE, true); - pPlayer->ModifyMoney(-GetLearningCost(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - if (!pPlayer->HasSpell(S_ELIXIR) && pPlayer->GetMoney() >= uint32(GetLearningCost(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_LEARN_ELIXIR, true); - pPlayer->ModifyMoney(-GetLearningCost(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - if (!pPlayer->HasSpell(S_POTION) && pPlayer->GetMoney() >= uint32(GetLearningCost(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_LEARN_POTION, true); - pPlayer->ModifyMoney(-GetLearningCost(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - //Unlearn Alchemy - case GOSSIP_ACTION_INFO_DEF + 4: - if (pPlayer->GetMoney() >= uint32(GetUnlearnCostHigh(pPlayer))) - { - pCreature->CastSpell(pPlayer, S_UNLEARN_TRANSMUTE, true); - pPlayer->ModifyMoney(-GetUnlearnCostHigh(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - if (pPlayer->GetMoney() >= uint32(GetUnlearnCostHigh(pPlayer))) - { - pCreature->CastSpell(pPlayer, S_UNLEARN_ELIXIR, true); - pPlayer->ModifyMoney(-GetUnlearnCostHigh(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - if (pPlayer->GetMoney() >= uint32(GetUnlearnCostHigh(pPlayer))) - { - pCreature->CastSpell(pPlayer, S_UNLEARN_POTION, true); - pPlayer->ModifyMoney(-GetUnlearnCostHigh(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); + pPlayer->removeSpell(26756); // Frozen Shadoweave Shoulders + pPlayer->removeSpell(26757); // Frozen Shadoweave Boots + pPlayer->removeSpell(26758); // Frozen Shadoweave Robe break; } } -void SendConfirmLearn_npc_prof_alchemy(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - if (uiAction) - { - uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) - { - case 22427: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_TRANSMUTE, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 19052: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_ELIXIR, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 17909: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_POTION, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - } - } -} - -void SendConfirmUnlearn_npc_prof_alchemy(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - if (uiAction) - { - uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) - { - case 22427: //Zarevhi - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_TRANSMUTE, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_ALCHEMY_SPEC, GetUnlearnCostHigh(pPlayer),false); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 19052: //Lorokeem - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_ELIXIR, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_ALCHEMY_SPEC, GetUnlearnCostHigh(pPlayer),false); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 17909: //Lauranna Thar'well - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_POTION, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_ALCHEMY_SPEC, GetUnlearnCostHigh(pPlayer),false); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - } - } -} - -bool GossipSelect_npc_prof_alchemy(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiSender) - { - case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_alchemy(pPlayer, pCreature, uiAction); break; - case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_alchemy(pPlayer, pCreature, uiAction); break; - case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_alchemy(pPlayer, pCreature, uiAction); break; - case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_alchemy(pPlayer, pCreature, uiAction); break; - } - return true; -} - /*### # start menues blacksmith ###*/ @@ -547,48 +308,48 @@ bool GossipHello_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); uint32 eCreature = pCreature->GetEntry(); - //WEAPONSMITH & ARMORSMITH - if (pPlayer->GetBaseSkillValue(SKILL_BLACKSMITHING)>=225) + // WEAPONSMITH & ARMORSMITH + if (pPlayer->GetBaseSkillValue(SKILL_BLACKSMITHING) >= 225) { switch (eCreature) { - case 11145: //Myolor Sunderfury - case 11176: //Krathok Moltenfist + case 11145: // Myolor Sunderfury + case 11176: // Krathok Moltenfist if (!pPlayer->HasSpell(S_ARMOR) && !pPlayer->HasSpell(S_WEAPON) && pPlayer->GetReputationRank(REP_ARMOR) == REP_FRIENDLY) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARMOR_LEARN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); if (!pPlayer->HasSpell(S_WEAPON) && !pPlayer->HasSpell(S_ARMOR) && pPlayer->GetReputationRank(REP_WEAPON) == REP_FRIENDLY) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_WEAPON_LEARN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); break; - case 11146: //Ironus Coldsteel - case 11178: //Borgosh Corebender + case 11146: // Ironus Coldsteel + case 11178: // Borgosh Corebender if (pPlayer->HasSpell(S_WEAPON)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_WEAPON_UNLEARN, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 3); break; - case 5164: //Grumnus Steelshaper - case 11177: //Okothos Ironrager + case 5164: // Grumnus Steelshaper + case 11177: // Okothos Ironrager if (pPlayer->HasSpell(S_ARMOR)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ARMOR_UNLEARN, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); break; } } - //WEAPONSMITH SPEC - if (pPlayer->HasSpell(S_WEAPON) && pPlayer->getLevel() > 49 && pPlayer->GetBaseSkillValue(SKILL_BLACKSMITHING)>=250) + // WEAPONSMITH SPEC + if (pPlayer->HasSpell(S_WEAPON) && pPlayer->getLevel() > 49 && pPlayer->GetBaseSkillValue(SKILL_BLACKSMITHING) >= 250) { switch (eCreature) { - case 11191: //Lilith the Lithe + case 11191: // Lilith the Lithe if (!HasWeaponSub(pPlayer)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_HAMMER, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 5); if (pPlayer->HasSpell(S_HAMMER)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 8); break; - case 11192: //Kilram + case 11192: // Kilram if (!HasWeaponSub(pPlayer)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_AXE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 6); if (pPlayer->HasSpell(S_AXE)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 9); break; - case 11193: //Seril Scourgebane + case 11193: // Seril Scourgebane if (!HasWeaponSub(pPlayer)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_SWORD, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 7); if (pPlayer->HasSpell(S_SWORD)) @@ -603,7 +364,7 @@ bool GossipHello_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature) void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_TRADE: pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); @@ -611,12 +372,12 @@ void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, ui case GOSSIP_ACTION_TRAIN: pPlayer->SEND_TRAINERLIST(pCreature->GetObjectGuid()); break; - //Learn Armor/Weapon + // Learn Armor/Weapon case GOSSIP_ACTION_INFO_DEF + 1: if (!pPlayer->HasSpell(S_ARMOR)) { pPlayer->CastSpell(pPlayer, S_LEARN_ARMOR, true); - //pCreature->CastSpell(pPlayer, S_REP_ARMOR, true); + // pCreature->CastSpell(pPlayer, S_REP_ARMOR, true); } pPlayer->CLOSE_GOSSIP_MENU(); break; @@ -624,18 +385,18 @@ void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, ui if (!pPlayer->HasSpell(S_WEAPON)) { pPlayer->CastSpell(pPlayer, S_LEARN_WEAPON, true); - //pCreature->CastSpell(pPlayer, S_REP_WEAPON, true); + // pCreature->CastSpell(pPlayer, S_REP_WEAPON, true); } pPlayer->CLOSE_GOSSIP_MENU(); break; - //Unlearn Armor/Weapon + // Unlearn Armor/Weapon case GOSSIP_ACTION_INFO_DEF + 3: if (HasWeaponSub(pPlayer)) { - //unknown textID (TALK_MUST_UNLEARN_WEAPON) + // unknown textID (TALK_MUST_UNLEARN_WEAPON) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); } - else if (EquippedOk(pPlayer,S_UNLEARN_WEAPON)) + else if (EquippedOk(pPlayer, S_UNLEARN_WEAPON)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostLow(pPlayer))) { @@ -644,17 +405,18 @@ void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, ui pPlayer->ModifyMoney(-GetUnlearnCostLow(pPlayer)); pCreature->CastSpell(pPlayer, S_REP_ARMOR, true); pPlayer->CLOSE_GOSSIP_MENU(); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); } else { - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); } break; case GOSSIP_ACTION_INFO_DEF + 4: - if (EquippedOk(pPlayer,S_UNLEARN_ARMOR)) + if (EquippedOk(pPlayer, S_UNLEARN_ARMOR)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostLow(pPlayer))) { @@ -662,13 +424,15 @@ void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, ui ProfessionUnlearnSpells(pPlayer, S_UNLEARN_ARMOR); pPlayer->ModifyMoney(-GetUnlearnCostLow(pPlayer)); pCreature->CastSpell(pPlayer, S_REP_WEAPON, true); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; - //Learn Hammer/Axe/Sword + // Learn Hammer/Axe/Sword case GOSSIP_ACTION_INFO_DEF + 5: pPlayer->CastSpell(pPlayer, S_LEARN_HAMMER, true); pPlayer->CLOSE_GOSSIP_MENU(); @@ -681,47 +445,53 @@ void SendActionMenu_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, ui pPlayer->CastSpell(pPlayer, S_LEARN_SWORD, true); pPlayer->CLOSE_GOSSIP_MENU(); break; - //Unlearn Hammer/Axe/Sword + // Unlearn Hammer/Axe/Sword case GOSSIP_ACTION_INFO_DEF + 8: - if (EquippedOk(pPlayer,S_UNLEARN_HAMMER)) + if (EquippedOk(pPlayer, S_UNLEARN_HAMMER)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostMedium(pPlayer))) { pPlayer->CastSpell(pPlayer, S_UNLEARN_HAMMER, true); ProfessionUnlearnSpells(pPlayer, S_UNLEARN_HAMMER); pPlayer->ModifyMoney(-GetUnlearnCostMedium(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; case GOSSIP_ACTION_INFO_DEF + 9: - if (EquippedOk(pPlayer,S_UNLEARN_AXE)) + if (EquippedOk(pPlayer, S_UNLEARN_AXE)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostMedium(pPlayer))) { pPlayer->CastSpell(pPlayer, S_UNLEARN_AXE, true); ProfessionUnlearnSpells(pPlayer, S_UNLEARN_AXE); pPlayer->ModifyMoney(-GetUnlearnCostMedium(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; case GOSSIP_ACTION_INFO_DEF + 10: - if (EquippedOk(pPlayer,S_UNLEARN_SWORD)) + if (EquippedOk(pPlayer, S_UNLEARN_SWORD)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostMedium(pPlayer))) { pPlayer->CastSpell(pPlayer, S_UNLEARN_SWORD, true); ProfessionUnlearnSpells(pPlayer, S_UNLEARN_SWORD); pPlayer->ModifyMoney(-GetUnlearnCostMedium(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; } @@ -732,21 +502,21 @@ void SendConfirmLearn_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, if (uiAction) { uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) + switch (eCreature) { case 11191: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_HAMMER, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID (TALK_HAMMER_LEARN) + // unknown textID (TALK_HAMMER_LEARN) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; case 11192: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_AXE, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID (TALK_AXE_LEARN) + // unknown textID (TALK_AXE_LEARN) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; case 11193: pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_SWORD, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID (TALK_SWORD_LEARN) + // unknown textID (TALK_SWORD_LEARN) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; } @@ -758,30 +528,30 @@ void SendConfirmUnlearn_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature if (uiAction) { uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) + switch (eCreature) { - case 11146: //Ironus Coldsteel - case 11178: //Borgosh Corebender - case 5164: //Grumnus Steelshaper - case 11177: //Okothos Ironrager - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_SMITH_SPEC, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_ARMORORWEAPON, GetUnlearnCostLow(pPlayer),false); - //unknown textID (TALK_UNLEARN_AXEORWEAPON) + case 11146: // Ironus Coldsteel + case 11178: // Borgosh Corebender + case 5164: // Grumnus Steelshaper + case 11177: // Okothos Ironrager + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_SMITH_SPEC, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_ARMORORWEAPON, GetUnlearnCostLow(pPlayer), false); + // unknown textID (TALK_UNLEARN_AXEORWEAPON) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; case 11191: - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_WEAPON_SPEC, GetUnlearnCostMedium(pPlayer),false); - //unknown textID (TALK_HAMMER_UNLEARN) + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_HAMMER, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_WEAPON_SPEC, GetUnlearnCostMedium(pPlayer), false); + // unknown textID (TALK_HAMMER_UNLEARN) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; case 11192: - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_WEAPON_SPEC, GetUnlearnCostMedium(pPlayer),false); - //unknown textID (TALK_AXE_UNLEARN) + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_AXE, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_WEAPON_SPEC, GetUnlearnCostMedium(pPlayer), false); + // unknown textID (TALK_AXE_UNLEARN) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; case 11193: - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_SWORD, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_WEAPON_SPEC, GetUnlearnCostMedium(pPlayer),false); - //unknown textID (TALK_SWORD_UNLEARN) + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_SWORD, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_WEAPON_SPEC, GetUnlearnCostMedium(pPlayer), false); + // unknown textID (TALK_SWORD_UNLEARN) pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; } @@ -790,7 +560,7 @@ void SendConfirmUnlearn_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature bool GossipSelect_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) { - switch(uiSender) + switch (uiSender) { case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_blacksmith(pPlayer, pCreature, uiAction); break; case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_blacksmith(pPlayer, pCreature, uiAction); break; @@ -802,10 +572,10 @@ bool GossipSelect_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, uint /*bool QuestComplete_npc_prof_blacksmith(Player* pPlayer, Creature* pCreature, const Quest* pQuest) { - if ((pQuest->GetQuestId() == 5283) || (pQuest->GetQuestId() == 5301)) //armorsmith + if ((pQuest->GetQuestId() == 5283) || (pQuest->GetQuestId() == 5301)) // armorsmith pCreature->CastSpell(pPlayer, 17451, true); - if ((pQuest->GetQuestId() == 5284) || (pQuest->GetQuestId() == 5302)) //weaponsmith + if ((pQuest->GetQuestId() == 5284) || (pQuest->GetQuestId() == 5302)) // weaponsmith pCreature->CastSpell(pPlayer, 17452, true); return true; @@ -826,22 +596,22 @@ bool GossipHello_npc_prof_leather(Player* pPlayer, Creature* pCreature) uint32 eCreature = pCreature->GetEntry(); - if (pPlayer->HasSkill(SKILL_LEATHERWORKING) && pPlayer->GetBaseSkillValue(SKILL_LEATHERWORKING)>=250 && pPlayer->getLevel() > 49) + if (pPlayer->HasSkill(SKILL_LEATHERWORKING) && pPlayer->GetBaseSkillValue(SKILL_LEATHERWORKING) >= 250 && pPlayer->getLevel() > 49) { switch (eCreature) { - case 7866: //Peter Galen - case 7867: //Thorkaf Dragoneye + case 7866: // Peter Galen + case 7867: // Thorkaf Dragoneye if (pPlayer->HasSpell(S_DRAGON)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 1); break; - case 7868: //Sarah Tanner - case 7869: //Brumn Winterhoof + case 7868: // Sarah Tanner + case 7869: // Brumn Winterhoof if (pPlayer->HasSpell(S_ELEMENTAL)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 2); break; - case 7870: //Caryssia Moonhunter - case 7871: //Se'Jib + case 7870: // Caryssia Moonhunter + case 7871: // Se'Jib if (pPlayer->HasSpell(S_TRIBAL)) pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 3); break; @@ -854,7 +624,7 @@ bool GossipHello_npc_prof_leather(Player* pPlayer, Creature* pCreature) void SendActionMenu_npc_prof_leather(Player* pPlayer, Creature* pCreature, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_TRADE: pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); @@ -862,47 +632,53 @@ void SendActionMenu_npc_prof_leather(Player* pPlayer, Creature* pCreature, uint3 case GOSSIP_ACTION_TRAIN: pPlayer->SEND_TRAINERLIST(pCreature->GetObjectGuid()); break; - //Unlearn Leather + // Unlearn Leather case GOSSIP_ACTION_INFO_DEF + 1: - if (EquippedOk(pPlayer,S_UNLEARN_DRAGON)) + if (EquippedOk(pPlayer, S_UNLEARN_DRAGON)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostMedium(pPlayer))) { pPlayer->CastSpell(pPlayer, S_UNLEARN_DRAGON, true); ProfessionUnlearnSpells(pPlayer, S_UNLEARN_DRAGON); pPlayer->ModifyMoney(-GetUnlearnCostMedium(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; case GOSSIP_ACTION_INFO_DEF + 2: - if (EquippedOk(pPlayer,S_UNLEARN_ELEMENTAL)) + if (EquippedOk(pPlayer, S_UNLEARN_ELEMENTAL)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostMedium(pPlayer))) { pPlayer->CastSpell(pPlayer, S_UNLEARN_ELEMENTAL, true); ProfessionUnlearnSpells(pPlayer, S_UNLEARN_ELEMENTAL); pPlayer->ModifyMoney(-GetUnlearnCostMedium(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; case GOSSIP_ACTION_INFO_DEF + 3: - if (EquippedOk(pPlayer,S_UNLEARN_TRIBAL)) + if (EquippedOk(pPlayer, S_UNLEARN_TRIBAL)) { if (pPlayer->GetMoney() >= uint32(GetUnlearnCostMedium(pPlayer))) { pPlayer->CastSpell(pPlayer, S_UNLEARN_TRIBAL, true); ProfessionUnlearnSpells(pPlayer, S_UNLEARN_TRIBAL); pPlayer->ModifyMoney(-GetUnlearnCostMedium(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); + } + else + pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); + } + else + pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, NULL, NULL); pPlayer->CLOSE_GOSSIP_MENU(); break; } @@ -913,24 +689,24 @@ void SendConfirmUnlearn_npc_prof_leather(Player* pPlayer, Creature* pCreature, u if (uiAction) { uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) + switch (eCreature) { - case 7866: //Peter Galen - case 7867: //Thorkaf Dragoneye - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_LEATHER_SPEC, GetUnlearnCostMedium(pPlayer),false); - //unknown textID () + case 7866: // Peter Galen + case 7867: // Thorkaf Dragoneye + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_DRAGON, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_LEATHER_SPEC, GetUnlearnCostMedium(pPlayer), false); + // unknown textID () pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; - case 7868: //Sarah Tanner - case 7869: //Brumn Winterhoof - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_LEATHER_SPEC, GetUnlearnCostMedium(pPlayer),false); - //unknown textID () + case 7868: // Sarah Tanner + case 7869: // Brumn Winterhoof + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_ELEMENTAL, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_LEATHER_SPEC, GetUnlearnCostMedium(pPlayer), false); + // unknown textID () pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; - case 7870: //Caryssia Moonhunter - case 7871: //Se'Jib - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_LEATHER_SPEC, GetUnlearnCostMedium(pPlayer),false); - //unknown textID () + case 7870: // Caryssia Moonhunter + case 7871: // Se'Jib + pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_TRIBAL, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_LEATHER_SPEC, GetUnlearnCostMedium(pPlayer), false); + // unknown textID () pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); break; } @@ -939,7 +715,7 @@ void SendConfirmUnlearn_npc_prof_leather(Player* pPlayer, Creature* pCreature, u bool GossipSelect_npc_prof_leather(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) { - switch(uiSender) + switch (uiSender) { case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_leather(pPlayer, pCreature, uiAction); break; case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_leather(pPlayer, pCreature, uiAction); break; @@ -948,208 +724,6 @@ bool GossipSelect_npc_prof_leather(Player* pPlayer, Creature* pCreature, uint32 return true; } -/*### -# start menues tailoring -###*/ - -bool HasTailorSpell(Player* pPlayer) -{ - if (pPlayer->HasSpell(S_MOONCLOTH) || pPlayer->HasSpell(S_SHADOWEAVE) || pPlayer->HasSpell(S_SPELLFIRE)) - return true; - return false; -} - -bool GossipHello_npc_prof_tailor(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - if (pCreature->isTrainer()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, GOSSIP_TEXT_TRAIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRAIN); - - uint32 eCreature = pCreature->GetEntry(); - //TAILORING SPEC - if (pPlayer->HasSkill(SKILL_TAILORING) && pPlayer->GetBaseSkillValue(SKILL_TAILORING)>=350 && pPlayer->getLevel() > 59) - { - if (pPlayer->GetQuestRewardStatus(10831) || pPlayer->GetQuestRewardStatus(10832) || pPlayer->GetQuestRewardStatus(10833)) - { - switch (eCreature) - { - case 22213: //Gidge Spellweaver - if (!HasTailorSpell(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_SPELLFIRE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 1); - if (pPlayer->HasSpell(S_SPELLFIRE)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_SPELLFIRE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 4); - break; - case 22208: //Nasmara Moonsong - if (!HasTailorSpell(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_MOONCLOTH, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 2); - if (pPlayer->HasSpell(S_MOONCLOTH)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_MOONCLOTH, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 5); - break; - case 22212: //Andrion Darkspinner - if (!HasTailorSpell(pPlayer)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_SHADOWEAVE, GOSSIP_SENDER_LEARN, GOSSIP_ACTION_INFO_DEF + 3); - if (pPlayer->HasSpell(S_SHADOWEAVE)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_UNLEARN_SHADOWEAVE, GOSSIP_SENDER_UNLEARN, GOSSIP_ACTION_INFO_DEF + 6); - break; - } - } - } - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - return true; -} - -void SendActionMenu_npc_prof_tailor(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_TRAIN: - pPlayer->SEND_TRAINERLIST(pCreature->GetObjectGuid()); - break; - //Learn Tailor - case GOSSIP_ACTION_INFO_DEF + 1: - if (!pPlayer->HasSpell(S_SPELLFIRE) && pPlayer->GetMoney() >= uint32(GetLearningCost(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_LEARN_SPELLFIRE, true); - pPlayer->ModifyMoney(-GetLearningCost(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 2: - if (!pPlayer->HasSpell(S_MOONCLOTH) && pPlayer->GetMoney() >= uint32(GetLearningCost(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_LEARN_MOONCLOTH, true); - pPlayer->ModifyMoney(-GetLearningCost(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 3: - if (!pPlayer->HasSpell(S_SHADOWEAVE) && pPlayer->GetMoney() >= uint32(GetLearningCost(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_LEARN_SHADOWEAVE, true); - pPlayer->ModifyMoney(-GetLearningCost(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - //Unlearn Tailor - case GOSSIP_ACTION_INFO_DEF + 4: - if (EquippedOk(pPlayer,S_UNLEARN_SPELLFIRE)) - { - if (pPlayer->GetMoney() >= uint32(GetUnlearnCostHigh(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_UNLEARN_SPELLFIRE, true); - ProfessionUnlearnSpells(pPlayer, S_UNLEARN_SPELLFIRE); - pPlayer->ModifyMoney(-GetUnlearnCostHigh(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 5: - if (EquippedOk(pPlayer,S_UNLEARN_MOONCLOTH)) - { - if (pPlayer->GetMoney() >= uint32(GetUnlearnCostHigh(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_UNLEARN_MOONCLOTH, true); - ProfessionUnlearnSpells(pPlayer, S_UNLEARN_MOONCLOTH); - pPlayer->ModifyMoney(-GetUnlearnCostHigh(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - case GOSSIP_ACTION_INFO_DEF + 6: - if (EquippedOk(pPlayer,S_UNLEARN_SHADOWEAVE)) - { - if (pPlayer->GetMoney() >= uint32(GetUnlearnCostHigh(pPlayer))) - { - pPlayer->CastSpell(pPlayer, S_UNLEARN_SHADOWEAVE, true); - ProfessionUnlearnSpells(pPlayer, S_UNLEARN_SHADOWEAVE); - pPlayer->ModifyMoney(-GetUnlearnCostHigh(pPlayer)); - } else - pPlayer->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, 0, 0); - } else - pPlayer->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW,NULL,NULL); - pPlayer->CLOSE_GOSSIP_MENU(); - break; - } -} - -void SendConfirmLearn_npc_prof_tailor(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - if (uiAction) - { - uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) - { - case 22213: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_SPELLFIRE, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 22208: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_MOONCLOTH, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 22212: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LEARN_SHADOWEAVE, GOSSIP_SENDER_CHECK, uiAction); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - } - } -} - -void SendConfirmUnlearn_npc_prof_tailor(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - if (uiAction) - { - uint32 eCreature = pCreature->GetEntry(); - switch(eCreature) - { - case 22213: //Gidge Spellweaver - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_SPELLFIRE, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_TAILOR_SPEC, GetUnlearnCostHigh(pPlayer),false); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 22208: //Nasmara Moonsong - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_MOONCLOTH, GOSSIP_SENDER_CHECK, uiAction, BOX_UNLEARN_TAILOR_SPEC, GetUnlearnCostHigh(pPlayer),false); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - case 22212: //Andrion Darkspinner - pPlayer->ADD_GOSSIP_ITEM_EXTENDED(0, GOSSIP_UNLEARN_SHADOWEAVE, GOSSIP_SENDER_CHECK, uiAction,BOX_UNLEARN_TAILOR_SPEC, GetUnlearnCostHigh(pPlayer),false); - //unknown textID () - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - break; - } - } -} - -bool GossipSelect_npc_prof_tailor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiSender) - { - case GOSSIP_SENDER_MAIN: SendActionMenu_npc_prof_tailor(pPlayer, pCreature, uiAction); break; - case GOSSIP_SENDER_LEARN: SendConfirmLearn_npc_prof_tailor(pPlayer, pCreature, uiAction); break; - case GOSSIP_SENDER_UNLEARN: SendConfirmUnlearn_npc_prof_tailor(pPlayer, pCreature, uiAction); break; - case GOSSIP_SENDER_CHECK: SendActionMenu_npc_prof_tailor(pPlayer, pCreature, uiAction); break; - } - return true; -} - /*### # start menues for GO (engineering and leatherworking) ###*/ @@ -1171,12 +745,6 @@ void AddSC_npc_professions() { Script* pNewScript; - pNewScript = new Script; - pNewScript->Name = "npc_prof_alchemy"; - pNewScript->pGossipHello = &GossipHello_npc_prof_alchemy; - pNewScript->pGossipSelect = &GossipSelect_npc_prof_alchemy; - pNewScript->RegisterSelf(); - pNewScript = new Script; pNewScript->Name = "npc_prof_blacksmith"; pNewScript->pGossipHello = &GossipHello_npc_prof_blacksmith; @@ -1189,15 +757,9 @@ void AddSC_npc_professions() pNewScript->pGossipSelect = &GossipSelect_npc_prof_leather; pNewScript->RegisterSelf(); - pNewScript = new Script; - pNewScript->Name = "npc_prof_tailor"; - pNewScript->pGossipHello = &GossipHello_npc_prof_tailor; - pNewScript->pGossipSelect = &GossipSelect_npc_prof_tailor; - pNewScript->RegisterSelf(); - /*pNewScript = new Script; pNewScript->Name = "go_soothsaying_for_dummies"; pNewScript->pGOUse = &GOUse_go_soothsaying_for_dummies; - //pNewScript->pGossipSelect = &GossipSelect_go_soothsaying_for_dummies; + // pNewScript->pGossipSelect = &GossipSelect_go_soothsaying_for_dummies; pNewScript->RegisterSelf();*/ } diff --git a/scripts/world/npcs_special.cpp b/scripts/world/npcs_special.cpp index 6b799a5bd..2bf7580d2 100644 --- a/scripts/world/npcs_special.cpp +++ b/scripts/world/npcs_special.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,10 +37,8 @@ npc_garments_of_quests 80% NPC's related to all Garments of-quests 5621, 56 npc_injured_patient 100% patients for triage-quests (6622 and 6624) npc_doctor 100% Gustaf Vanhowzen and Gregory Victor, quest 6622 and 6624 (Triage) npc_innkeeper 25% ScriptName not assigned. Innkeepers in general. -npc_mount_vendor 100% Regular mount vendors all over the world. Display gossip if player doesn't meet the requirements to buy -npc_sayge 100% Darkmoon event fortune teller, buff player based on answers given -npc_tabard_vendor 50% allow recovering quest related tabards, achievement related ones need core support npc_spring_rabbit 1% Used for pet "Spring Rabbit" of Noblegarden +npc_redemption_target 100% Used for the paladin quests: 1779,1781,9600,9685 EndContentData */ /*######## @@ -71,45 +69,43 @@ const float RANGE_GUARDS_MARK = 50.0f; SpawnAssociation m_aSpawnAssociations[] = { - {2614, 15241, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Alliance) - {2615, 15242, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Horde) - {21974, 21976, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Area 52) - {21993, 15242, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Horde - Bat Rider) - {21996, 15241, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Alliance - Gryphon) - {21997, 21976, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Goblin - Area 52 - Zeppelin) - {21999, 15241, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Alliance) - {22001, 15242, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Horde) - {22002, 15242, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Ground (Horde) - {22003, 15241, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Ground (Alliance) - {22063, 21976, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Goblin - Area 52) - {22065, 22064, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Ethereal - Stormspire) - {22066, 22067, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Scryer - Dragonhawk) - {22068, 22064, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Ethereal - Stormspire) - {22069, 22064, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Stormspire) - {22070, 22067, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Scryer) - {22071, 22067, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Scryer) - {22078, 22077, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Aldor) - {22079, 22077, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Aldor - Gryphon) - {22080, 22077, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Aldor) - {22086, 22085, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Sporeggar) - {22087, 22085, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Sporeggar - Spore Bat) - {22088, 22085, SPAWNTYPE_TRIPWIRE_ROOFTOP}, //Air Force Trip Wire - Rooftop (Sporeggar) - {22090, 22089, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Toshley's Station - Flying Machine) - {22124, 22122, SPAWNTYPE_ALARMBOT}, //Air Force Alarm Bot (Cenarion) - {22125, 22122, SPAWNTYPE_ALARMBOT}, //Air Force Guard Post (Cenarion - Stormcrow) - {22126, 22122, SPAWNTYPE_ALARMBOT} //Air Force Trip Wire - Rooftop (Cenarion Expedition) + {2614, 15241, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Alliance) + {2615, 15242, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Horde) + {21974, 21976, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Area 52) + {21993, 15242, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Horde - Bat Rider) + {21996, 15241, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Alliance - Gryphon) + {21997, 21976, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Goblin - Area 52 - Zeppelin) + {21999, 15241, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Alliance) + {22001, 15242, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Horde) + {22002, 15242, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Ground (Horde) + {22003, 15241, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Ground (Alliance) + {22063, 21976, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Goblin - Area 52) + {22065, 22064, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Ethereal - Stormspire) + {22066, 22067, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Scryer - Dragonhawk) + {22068, 22064, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Ethereal - Stormspire) + {22069, 22064, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Stormspire) + {22070, 22067, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Scryer) + {22071, 22067, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Scryer) + {22078, 22077, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Aldor) + {22079, 22077, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Aldor - Gryphon) + {22080, 22077, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Aldor) + {22086, 22085, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Sporeggar) + {22087, 22085, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Sporeggar - Spore Bat) + {22088, 22085, SPAWNTYPE_TRIPWIRE_ROOFTOP}, // Air Force Trip Wire - Rooftop (Sporeggar) + {22090, 22089, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Toshley's Station - Flying Machine) + {22124, 22122, SPAWNTYPE_ALARMBOT}, // Air Force Alarm Bot (Cenarion) + {22125, 22122, SPAWNTYPE_ALARMBOT}, // Air Force Guard Post (Cenarion - Stormcrow) + {22126, 22122, SPAWNTYPE_ALARMBOT} // Air Force Trip Wire - Rooftop (Cenarion Expedition) }; -struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI +struct npc_air_force_botsAI : public ScriptedAI { npc_air_force_botsAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pSpawnAssoc = NULL; // find the correct spawnhandling - static uint32 uiEntryCount = sizeof(m_aSpawnAssociations)/sizeof(SpawnAssociation); - - for (uint8 i=0; iGetEntry()) { @@ -136,11 +132,11 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI SpawnAssociation* m_pSpawnAssoc; ObjectGuid m_spawnedGuid; - void Reset() { } + void Reset() override { } Creature* SummonGuard() { - Creature* pSummoned = m_creature->SummonCreature(m_pSpawnAssoc->m_uiSpawnedCreatureEntry, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000); + Creature* pSummoned = m_creature->SummonCreature(m_pSpawnAssoc->m_uiSpawnedCreatureEntry, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 300000); if (pSummoned) m_spawnedGuid = pSummoned->GetObjectGuid(); @@ -163,7 +159,7 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI return NULL; } - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (!m_pSpawnAssoc) return; @@ -182,7 +178,7 @@ struct MANGOS_DLL_DECL npc_air_force_botsAI : public ScriptedAI if (!pLastSpawnedGuard) m_spawnedGuid.Clear(); - switch(m_pSpawnAssoc->m_SpawnType) + switch (m_pSpawnAssoc->m_SpawnType) { case SPAWNTYPE_ALARMBOT: { @@ -263,13 +259,13 @@ enum FACTION_CHICKEN = 31 }; -struct MANGOS_DLL_DECL npc_chicken_cluckAI : public ScriptedAI +struct npc_chicken_cluckAI : public ScriptedAI { npc_chicken_cluckAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} uint32 m_uiResetFlagTimer; - void Reset() + void Reset() override { m_uiResetFlagTimer = 120000; @@ -277,7 +273,7 @@ struct MANGOS_DLL_DECL npc_chicken_cluckAI : public ScriptedAI m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } - void ReceiveEmote(Player* pPlayer, uint32 uiEmote) + void ReceiveEmote(Player* pPlayer, uint32 uiEmote) override { if (uiEmote == TEXTEMOTE_CHICKEN) { @@ -311,7 +307,7 @@ struct MANGOS_DLL_DECL npc_chicken_cluckAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { // Reset flags after a certain time has passed so that the next player has to start the 'event' again if (m_creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) @@ -332,7 +328,7 @@ CreatureAI* GetAI_npc_chicken_cluck(Creature* pCreature) return new npc_chicken_cluckAI(pCreature); } -bool QuestAccept_npc_chicken_cluck(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool QuestAccept_npc_chicken_cluck(Player* /*pPlayer*/, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_CLUCK) { @@ -343,7 +339,7 @@ bool QuestAccept_npc_chicken_cluck(Player* pPlayer, Creature* pCreature, const Q return true; } -bool QuestRewarded_npc_chicken_cluck(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool QuestRewarded_npc_chicken_cluck(Player* /*pPlayer*/, Creature* pCreature, const Quest* pQuest) { if (pQuest->GetQuestId() == QUEST_CLUCK) { @@ -363,13 +359,13 @@ enum SPELL_FIERY_SEDUCTION = 47057 }; -struct MANGOS_DLL_DECL npc_dancing_flamesAI : public ScriptedAI +struct npc_dancing_flamesAI : public ScriptedAI { npc_dancing_flamesAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() {} + void Reset() override {} - void ReceiveEmote(Player* pPlayer, uint32 uiEmote) + void ReceiveEmote(Player* pPlayer, uint32 uiEmote) override { m_creature->SetFacingToObject(pPlayer); @@ -382,7 +378,7 @@ struct MANGOS_DLL_DECL npc_dancing_flamesAI : public ScriptedAI pPlayer->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); } - switch(uiEmote) + switch (uiEmote) { case TEXTEMOTE_DANCE: DoCastSpellIfCan(pPlayer, SPELL_FIERY_SEDUCTION); break;// dance -> cast SPELL_FIERY_SEDUCTION case TEXTEMOTE_WAVE: m_creature->HandleEmote(EMOTE_ONESHOT_WAVE); break;// wave -> wave @@ -422,33 +418,33 @@ struct Location float x, y, z, o; }; -static Location AllianceCoords[]= +static Location AllianceCoords[] = { - {-3757.38f, -4533.05f, 14.16f, 3.62f}, // Top-far-right bunk as seen from entrance - {-3754.36f, -4539.13f, 14.16f, 5.13f}, // Top-far-left bunk - {-3749.54f, -4540.25f, 14.28f, 3.34f}, // Far-right bunk - {-3742.10f, -4536.85f, 14.28f, 3.64f}, // Right bunk near entrance - {-3755.89f, -4529.07f, 14.05f, 0.57f}, // Far-left bunk - {-3749.51f, -4527.08f, 14.07f, 5.26f}, // Mid-left bunk - {-3746.37f, -4525.35f, 14.16f, 5.22f}, // Left bunk near entrance + { -3757.38f, -4533.05f, 14.16f, 3.62f}, // Top-far-right bunk as seen from entrance + { -3754.36f, -4539.13f, 14.16f, 5.13f}, // Top-far-left bunk + { -3749.54f, -4540.25f, 14.28f, 3.34f}, // Far-right bunk + { -3742.10f, -4536.85f, 14.28f, 3.64f}, // Right bunk near entrance + { -3755.89f, -4529.07f, 14.05f, 0.57f}, // Far-left bunk + { -3749.51f, -4527.08f, 14.07f, 5.26f}, // Mid-left bunk + { -3746.37f, -4525.35f, 14.16f, 5.22f}, // Left bunk near entrance }; -//alliance run to where +// alliance run to where #define A_RUNTOX -3742.96f #define A_RUNTOY -4531.52f #define A_RUNTOZ 11.91f -static Location HordeCoords[]= +static Location HordeCoords[] = { - {-1013.75f, -3492.59f, 62.62f, 4.34f}, // Left, Behind - {-1017.72f, -3490.92f, 62.62f, 4.34f}, // Right, Behind - {-1015.77f, -3497.15f, 62.82f, 4.34f}, // Left, Mid - {-1019.51f, -3495.49f, 62.82f, 4.34f}, // Right, Mid - {-1017.25f, -3500.85f, 62.98f, 4.34f}, // Left, front - {-1020.95f, -3499.21f, 62.98f, 4.34f} // Right, Front + { -1013.75f, -3492.59f, 62.62f, 4.34f}, // Left, Behind + { -1017.72f, -3490.92f, 62.62f, 4.34f}, // Right, Behind + { -1015.77f, -3497.15f, 62.82f, 4.34f}, // Left, Mid + { -1019.51f, -3495.49f, 62.82f, 4.34f}, // Right, Mid + { -1017.25f, -3500.85f, 62.98f, 4.34f}, // Left, front + { -1020.95f, -3499.21f, 62.98f, 4.34f} // Right, Front }; -//horde run to where +// horde run to where #define H_RUNTOX -1016.44f #define H_RUNTOY -3508.48f #define H_RUNTOZ 62.96f @@ -462,130 +458,125 @@ const uint32 AllianceSoldierId[3] = const uint32 HordeSoldierId[3] = { - 12923, //12923 Injured Soldier - 12924, //12924 Badly injured Soldier - 12925 //12925 Critically injured Soldier + 12923, // 12923 Injured Soldier + 12924, // 12924 Badly injured Soldier + 12925 // 12925 Critically injured Soldier }; /*###### ## npc_doctor (handles both Gustaf Vanhowzen and Gregory Victor) ######*/ -struct MANGOS_DLL_DECL npc_doctorAI : public ScriptedAI +struct npc_doctorAI : public ScriptedAI { npc_doctorAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} ObjectGuid m_playerGuid; - uint32 SummonPatient_Timer; - uint32 SummonPatientCount; - uint32 PatientDiedCount; - uint32 PatientSavedCount; + uint32 m_uiSummonPatientTimer; + uint32 m_uiSummonPatientCount; + uint32 m_uiPatientDiedCount; + uint32 m_uiPatientSavedCount; - bool Event; + bool m_bIsEventInProgress; - GUIDList Patients; - std::vector Coordinates; + GuidList m_lPatientGuids; + std::vector m_vPatientSummonCoordinates; - void Reset() + void Reset() override { m_playerGuid.Clear(); - SummonPatient_Timer = 10000; - SummonPatientCount = 0; - PatientDiedCount = 0; - PatientSavedCount = 0; + m_uiSummonPatientTimer = 10000; + m_uiSummonPatientCount = 0; + m_uiPatientDiedCount = 0; + m_uiPatientSavedCount = 0; - Patients.clear(); - Coordinates.clear(); + m_lPatientGuids.clear(); + m_vPatientSummonCoordinates.clear(); - Event = false; + m_bIsEventInProgress = false; m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } void BeginEvent(Player* pPlayer); - void PatientDied(Location* Point); - void PatientSaved(Creature* soldier, Player* pPlayer, Location* Point); - void UpdateAI(const uint32 diff); + void PatientDied(Location* pPoint); + void PatientSaved(Creature* pSoldier, Player* pPlayer, Location* pPoint); + void UpdateAI(const uint32 uiDiff) override; }; /*##### ## npc_injured_patient (handles all the patients, no matter Horde or Alliance) #####*/ -struct MANGOS_DLL_DECL npc_injured_patientAI : public ScriptedAI +struct npc_injured_patientAI : public ScriptedAI { npc_injured_patientAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} ObjectGuid m_doctorGuid; - Location* Coord; + Location* m_pCoord; - void Reset() + void Reset() override { m_doctorGuid.Clear(); - Coord = NULL; + m_pCoord = NULL; - //no select + // no select m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //no regen health + // no regen health m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //to make them lay with face down + // to make them lay with face down m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - uint32 mobId = m_creature->GetEntry(); - - switch (mobId) - { //lower max health + switch (m_creature->GetEntry()) + { + // lower max health case 12923: - case 12938: //Injured Soldier + case 12938: // Injured Soldier m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.75)); break; case 12924: - case 12936: //Badly injured Soldier + case 12936: // Badly injured Soldier m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.50)); break; case 12925: - case 12937: //Critically injured Soldier + case 12937: // Critically injured Soldier m_creature->SetHealth(uint32(m_creature->GetMaxHealth()*.25)); break; } } - void SpellHit(Unit *caster, const SpellEntry *spell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { - if (caster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && spell->Id == 20804) + if (pCaster->GetTypeId() == TYPEID_PLAYER && m_creature->isAlive() && pSpell->Id == 20804) { - if ((((Player*)caster)->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (((Player*)caster)->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) + Player* pPlayer = static_cast(pCaster); + if (pPlayer->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE) { - if (m_doctorGuid) + if (Creature* pDoctor = m_creature->GetMap()->GetCreature(m_doctorGuid)) { - if (Creature* pDoctor = m_creature->GetMap()->GetCreature(m_doctorGuid)) - { - if (npc_doctorAI* pDocAI = dynamic_cast(pDoctor->AI())) - pDocAI->PatientSaved(m_creature, (Player*)caster, Coord); - } + if (npc_doctorAI* pDocAI = dynamic_cast(pDoctor->AI())) + pDocAI->PatientSaved(m_creature, pPlayer, m_pCoord); } } - //make not selectable + // make not selectable m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - //regen health + // regen health m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - //stand up + // stand up m_creature->SetStandState(UNIT_STAND_STATE_STAND); - switch(urand(0, 2)) + switch (urand(0, 2)) { - case 0: DoScriptText(SAY_DOC1,m_creature); break; - case 1: DoScriptText(SAY_DOC2,m_creature); break; - case 2: DoScriptText(SAY_DOC3,m_creature); break; + case 0: DoScriptText(SAY_DOC1, m_creature); break; + case 1: DoScriptText(SAY_DOC2, m_creature); break; + case 2: DoScriptText(SAY_DOC3, m_creature); break; } m_creature->SetWalk(false); - uint32 mobId = m_creature->GetEntry(); - - switch (mobId) + switch (m_creature->GetEntry()) { case 12923: case 12924: @@ -601,10 +592,10 @@ struct MANGOS_DLL_DECL npc_injured_patientAI : public ScriptedAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 uiDiff) override { - //lower HP on every world tick makes it a useful counter, not officlone though - uint32 uiHPLose = uint32(0.05f * diff); + // lower HP on every world tick makes it a useful counter, not officlone though + uint32 uiHPLose = uint32(0.05f * uiDiff); if (m_creature->isAlive() && m_creature->GetHealth() > 1 + uiHPLose) { m_creature->SetHealth(m_creature->GetHealth() - uiHPLose); @@ -617,13 +608,10 @@ struct MANGOS_DLL_DECL npc_injured_patientAI : public ScriptedAI m_creature->SetDeathState(JUST_DIED); m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); - if (m_doctorGuid) + if (Creature* pDoctor = m_creature->GetMap()->GetCreature(m_doctorGuid)) { - if (Creature* pDoctor = m_creature->GetMap()->GetCreature(m_doctorGuid)) - { - if (npc_doctorAI* pDocAI = dynamic_cast(pDoctor->AI())) - pDocAI->PatientDied(Coord); - } + if (npc_doctorAI* pDocAI = dynamic_cast(pDoctor->AI())) + pDocAI->PatientDied(m_pCoord); } } } @@ -642,36 +630,36 @@ void npc_doctorAI::BeginEvent(Player* pPlayer) { m_playerGuid = pPlayer->GetObjectGuid(); - SummonPatient_Timer = 10000; - SummonPatientCount = 0; - PatientDiedCount = 0; - PatientSavedCount = 0; + m_uiSummonPatientTimer = 10000; + m_uiSummonPatientCount = 0; + m_uiPatientDiedCount = 0; + m_uiPatientSavedCount = 0; - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case DOCTOR_ALLIANCE: - for(uint8 i = 0; i < ALLIANCE_COORDS; ++i) - Coordinates.push_back(&AllianceCoords[i]); + for (uint8 i = 0; i < ALLIANCE_COORDS; ++i) + m_vPatientSummonCoordinates.push_back(&AllianceCoords[i]); break; case DOCTOR_HORDE: - for(uint8 i = 0; i < HORDE_COORDS; ++i) - Coordinates.push_back(&HordeCoords[i]); + for (uint8 i = 0; i < HORDE_COORDS; ++i) + m_vPatientSummonCoordinates.push_back(&HordeCoords[i]); break; } - Event = true; + m_bIsEventInProgress = true; m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } -void npc_doctorAI::PatientDied(Location* Point) +void npc_doctorAI::PatientDied(Location* pPoint) { Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid); - if (pPlayer && ((pPlayer->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE) || (pPlayer->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE))) + if (pPlayer && (pPlayer->GetQuestStatus(6624) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(6622) == QUEST_STATUS_INCOMPLETE)) { - ++PatientDiedCount; + ++m_uiPatientDiedCount; - if (PatientDiedCount > 5 && Event) + if (m_uiPatientDiedCount > 5 && m_bIsEventInProgress) { if (pPlayer->GetQuestStatus(QUEST_TRIAGE_A) == QUEST_STATUS_INCOMPLETE) pPlayer->FailQuest(QUEST_TRIAGE_A); @@ -682,24 +670,24 @@ void npc_doctorAI::PatientDied(Location* Point) return; } - Coordinates.push_back(Point); + m_vPatientSummonCoordinates.push_back(pPoint); } else // If no player or player abandon quest in progress Reset(); } -void npc_doctorAI::PatientSaved(Creature* soldier, Player* pPlayer, Location* Point) +void npc_doctorAI::PatientSaved(Creature* /*soldier*/, Player* pPlayer, Location* pPoint) { if (pPlayer && m_playerGuid == pPlayer->GetObjectGuid()) { - if ((pPlayer->GetQuestStatus(QUEST_TRIAGE_A) == QUEST_STATUS_INCOMPLETE) || (pPlayer->GetQuestStatus(QUEST_TRIAGE_H) == QUEST_STATUS_INCOMPLETE)) + if (pPlayer->GetQuestStatus(QUEST_TRIAGE_A) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_TRIAGE_H) == QUEST_STATUS_INCOMPLETE) { - ++PatientSavedCount; + ++m_uiPatientSavedCount; - if (PatientSavedCount == 15) + if (m_uiPatientSavedCount == 15) { - for(GUIDList::const_iterator itr = Patients.begin(); itr != Patients.end(); ++itr) + for (GuidList::const_iterator itr = m_lPatientGuids.begin(); itr != m_lPatientGuids.end(); ++itr) { if (Creature* Patient = m_creature->GetMap()->GetCreature(*itr)) Patient->SetDeathState(JUST_DIED); @@ -714,67 +702,54 @@ void npc_doctorAI::PatientSaved(Creature* soldier, Player* pPlayer, Location* Po return; } - Coordinates.push_back(Point); + m_vPatientSummonCoordinates.push_back(pPoint); } } } -void npc_doctorAI::UpdateAI(const uint32 diff) +void npc_doctorAI::UpdateAI(const uint32 uiDiff) { - if (Event && SummonPatientCount >= 20) + if (m_bIsEventInProgress && m_uiSummonPatientCount >= 20) { Reset(); return; } - if (Event) + if (m_bIsEventInProgress && !m_vPatientSummonCoordinates.empty()) { - if (SummonPatient_Timer < diff) + if (m_uiSummonPatientTimer < uiDiff) { - Creature* Patient = NULL; - Location* Point = NULL; - - if (Coordinates.empty()) - return; - - std::vector::iterator itr = Coordinates.begin()+rand()%Coordinates.size(); + std::vector::iterator itr = m_vPatientSummonCoordinates.begin() + urand(0, m_vPatientSummonCoordinates.size() - 1); uint32 patientEntry = 0; - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case DOCTOR_ALLIANCE: patientEntry = AllianceSoldierId[urand(0, 2)]; break; - case DOCTOR_HORDE: patientEntry = HordeSoldierId[urand(0, 2)]; break; + case DOCTOR_HORDE: patientEntry = HordeSoldierId[urand(0, 2)]; break; default: - error_log("SD2: Invalid entry for Triage doctor. Please check your database"); + script_error_log("Invalid entry for Triage doctor. Please check your database"); return; } - Point = *itr; - - Patient = m_creature->SummonCreature(patientEntry, Point->x, Point->y, Point->z, Point->o, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); - - if (Patient) + if (Creature* Patient = m_creature->SummonCreature(patientEntry, (*itr)->x, (*itr)->y, (*itr)->z, (*itr)->o, TEMPSUMMON_TIMED_OOC_DESPAWN, 5000)) { - //303, this flag appear to be required for client side item->spell to work (TARGET_SINGLE_FRIEND) + // 303, this flag appear to be required for client side item->spell to work (TARGET_SINGLE_FRIEND) Patient->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); - Patients.push_back(Patient->GetObjectGuid()); + m_lPatientGuids.push_back(Patient->GetObjectGuid()); - npc_injured_patientAI* pPatientAI = dynamic_cast(Patient->AI()); - - if (pPatientAI) + if (npc_injured_patientAI* pPatientAI = dynamic_cast(Patient->AI())) { pPatientAI->m_doctorGuid = m_creature->GetObjectGuid(); - - if (Point) - pPatientAI->Coord = Point; + pPatientAI->m_pCoord = *itr; + m_vPatientSummonCoordinates.erase(itr); } - - Coordinates.erase(itr); } - SummonPatient_Timer = 10000; - ++SummonPatientCount; - }else SummonPatient_Timer -= diff; + m_uiSummonPatientTimer = 10000; + ++m_uiSummonPatientCount; + } + else + m_uiSummonPatientTimer -= uiDiff; } } @@ -828,7 +803,7 @@ enum SAY_SHAYA_GOODBYE = -1000263, }; -struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI +struct npc_garments_of_questsAI : public npc_escortAI { npc_garments_of_questsAI(Creature* pCreature) : npc_escortAI(pCreature) { Reset(); } @@ -839,7 +814,7 @@ struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI uint32 m_uiRunAwayTimer; - void Reset() + void Reset() override { m_playerGuid.Clear(); @@ -850,10 +825,10 @@ struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI m_creature->SetStandState(UNIT_STAND_STATE_KNEEL); // expect database to have RegenHealth=0 - m_creature->SetHealth(int(m_creature->GetMaxHealth()*0.7)); + m_creature->SetHealth(int(m_creature->GetMaxHealth() * 0.7)); } - void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) override { if (pSpell->Id == SPELL_LESSER_HEAL_R2 || pSpell->Id == SPELL_FORTITUDE_R1) { @@ -867,7 +842,7 @@ struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI if (pCaster->GetTypeId() == TYPEID_PLAYER) { - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case ENTRY_SHAYA: if (((Player*)pCaster)->GetQuestStatus(QUEST_MOON) == QUEST_STATUS_INCOMPLETE) @@ -963,9 +938,9 @@ struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI } } - void WaypointReached(uint32 uiPointId) {} + void WaypointReached(uint32 /*uiPointId*/) override {} - void UpdateEscortAI(const uint32 uiDiff) + void UpdateEscortAI(const uint32 uiDiff) override { if (m_bCanRun && !m_creature->isInCombat()) { @@ -973,7 +948,7 @@ struct MANGOS_DLL_DECL npc_garments_of_questsAI : public npc_escortAI { if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) { - switch(m_creature->GetEntry()) + switch (m_creature->GetEntry()) { case ENTRY_SHAYA: DoScriptText(SAY_SHAYA_GOODBYE, m_creature, pPlayer); break; case ENTRY_ROBERTS: DoScriptText(SAY_ROBERTS_GOODBYE, m_creature, pPlayer); break; @@ -1011,23 +986,23 @@ CreatureAI* GetAI_npc_garments_of_quests(Creature* pCreature) #define SPELL_DEATHTOUCH 5 -struct MANGOS_DLL_DECL npc_guardianAI : public ScriptedAI +struct npc_guardianAI : public ScriptedAI { npc_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) {Reset();} - void Reset() + void Reset() override { m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void UpdateAI(const uint32 diff) + void UpdateAI(const uint32 /*diff*/) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_creature->isAttackReady()) { - m_creature->CastSpell(m_creature->getVictim(),SPELL_DEATHTOUCH, true); + m_creature->CastSpell(m_creature->getVictim(), SPELL_DEATHTOUCH, true); m_creature->resetAttackTimer(); } } @@ -1050,8 +1025,8 @@ enum { TEXT_ID_WHAT_TO_DO = 1853, - SPELL_TRICK_OR_TREAT = 24751, // create item or random buff - SPELL_TRICK_OR_TREATED = 24755, // buff player get when tricked or treated + SPELL_TRICK_OR_TREAT = 24751, // create item or random buff + SPELL_TRICK_OR_TREATED = 24755, // buff player get when tricked or treated }; #define GOSSIP_ITEM_TRICK_OR_TREAT "Trick or Treat!" @@ -1062,13 +1037,13 @@ bool GossipHello_npc_innkeeper(Player* pPlayer, Creature* pCreature) pPlayer->PrepareGossipMenu(pCreature, pPlayer->GetDefaultGossipMenuForSource(pCreature)); if (IsHolidayActive(HOLIDAY_HALLOWS_END) && !pPlayer->HasAura(SPELL_TRICK_OR_TREATED, EFFECT_INDEX_0)) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TRICK_OR_TREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_TRICK_OR_TREAT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); // Should only apply to innkeeper close to start areas. if (AreaTableEntry const* pAreaEntry = GetAreaEntryByAreaID(pCreature->GetAreaId())) { if (pAreaEntry->flags & AREA_FLAG_LOWLEVEL) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WHAT_TO_DO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_WHAT_TO_DO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); } pPlayer->TalkedToCreature(pCreature->GetEntry(), pCreature->GetObjectGuid()); @@ -1076,9 +1051,9 @@ bool GossipHello_npc_innkeeper(Player* pPlayer, Creature* pCreature) return true; } -bool GossipSelect_npc_innkeeper(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool GossipSelect_npc_innkeeper(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) { - switch(uiAction) + switch (uiAction) { case GOSSIP_ACTION_INFO_DEF+1: pPlayer->SEND_GOSSIP_MENU(TEXT_ID_WHAT_TO_DO, pCreature->GetObjectGuid()); @@ -1099,387 +1074,6 @@ bool GossipSelect_npc_innkeeper(Player* pPlayer, Creature* pCreature, uint32 uiS return true; } -/*###### -## npc_mount_vendor -######*/ - -bool GossipHello_npc_mount_vendor(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - bool canBuy; - canBuy = false; - uint32 vendor = pCreature->GetEntry(); - uint8 race = pPlayer->getRace(); - - switch (vendor) - { - case 384: //Katie Hunter - case 1460: //Unger Statforth - case 2357: //Merideth Carlson - case 4885: //Gregor MacVince - if (pPlayer->GetReputationRank(72) != REP_EXALTED && race != RACE_HUMAN) - pPlayer->SEND_GOSSIP_MENU(5855, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 1261: //Veron Amberstill - if (pPlayer->GetReputationRank(47) != REP_EXALTED && race != RACE_DWARF) - pPlayer->SEND_GOSSIP_MENU(5856, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 3362: //Ogunaro Wolfrunner - if (pPlayer->GetReputationRank(76) != REP_EXALTED && race != RACE_ORC) - pPlayer->SEND_GOSSIP_MENU(5841, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 3685: //Harb Clawhoof - if (pPlayer->GetReputationRank(81) != REP_EXALTED && race != RACE_TAUREN) - pPlayer->SEND_GOSSIP_MENU(5843, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 4730: //Lelanai - if (pPlayer->GetReputationRank(69) != REP_EXALTED && race != RACE_NIGHTELF) - pPlayer->SEND_GOSSIP_MENU(5844, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 4731: //Zachariah Post - if (pPlayer->GetReputationRank(68) != REP_EXALTED && race != RACE_UNDEAD) - pPlayer->SEND_GOSSIP_MENU(5840, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 7952: //Zjolnir - if (pPlayer->GetReputationRank(530) != REP_EXALTED && race != RACE_TROLL) - pPlayer->SEND_GOSSIP_MENU(5842, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 7955: //Milli Featherwhistle - if (pPlayer->GetReputationRank(54) != REP_EXALTED && race != RACE_GNOME) - pPlayer->SEND_GOSSIP_MENU(5857, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 16264: //Winaestra - if (pPlayer->GetReputationRank(911) != REP_EXALTED && race != RACE_BLOODELF) - pPlayer->SEND_GOSSIP_MENU(10305, pCreature->GetObjectGuid()); - else canBuy = true; - break; - case 17584: //Torallius the Pack Handler - if (pPlayer->GetReputationRank(930) != REP_EXALTED && race != RACE_DRAENEI) - pPlayer->SEND_GOSSIP_MENU(10239, pCreature->GetObjectGuid()); - else canBuy = true; - break; - } - - if (canBuy) - { - if (pCreature->isVendor()) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - } - return true; -} - -bool GossipSelect_npc_mount_vendor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - if (uiAction == GOSSIP_ACTION_TRADE) - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - -/*###### -## npc_sayge -######*/ - -#define SPELL_DMG 23768 //dmg -#define SPELL_RES 23769 //res -#define SPELL_ARM 23767 //arm -#define SPELL_SPI 23738 //spi -#define SPELL_INT 23766 //int -#define SPELL_STM 23737 //stm -#define SPELL_STR 23735 //str -#define SPELL_AGI 23736 //agi -#define SPELL_FORTUNE 23765 //faire fortune - -bool GossipHello_npc_sayge(Player* pPlayer, Creature* pCreature) -{ - if (pCreature->isQuestGiver()) - pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); - - if (pPlayer->HasSpellCooldown(SPELL_INT) || - pPlayer->HasSpellCooldown(SPELL_ARM) || - pPlayer->HasSpellCooldown(SPELL_DMG) || - pPlayer->HasSpellCooldown(SPELL_RES) || - pPlayer->HasSpellCooldown(SPELL_STR) || - pPlayer->HasSpellCooldown(SPELL_AGI) || - pPlayer->HasSpellCooldown(SPELL_STM) || - pPlayer->HasSpellCooldown(SPELL_SPI)) - pPlayer->SEND_GOSSIP_MENU(7393, pCreature->GetObjectGuid()); - else - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Yes", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - pPlayer->SEND_GOSSIP_MENU(7339, pCreature->GetObjectGuid()); - } - - return true; -} - -void SendAction_npc_sayge(Player* pPlayer, Creature* pCreature, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Slay the Man", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Turn him over to liege", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Confiscate the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Let him go and have the corn", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - pPlayer->SEND_GOSSIP_MENU(7340, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Execute your friend painfully", GOSSIP_SENDER_MAIN+1, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Execute your friend painlessly", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Let your friend go", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(7341, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Confront the diplomat", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Show not so quiet defiance", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Remain quiet", GOSSIP_SENDER_MAIN+2, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(7361, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Speak against your brother openly", GOSSIP_SENDER_MAIN+6, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Help your brother in", GOSSIP_SENDER_MAIN+7, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Keep your brother out without letting him know", GOSSIP_SENDER_MAIN+8, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(7362, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Take credit, keep gold", GOSSIP_SENDER_MAIN+5, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Take credit, share the gold", GOSSIP_SENDER_MAIN+4, GOSSIP_ACTION_INFO_DEF); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Let the knight take credit", GOSSIP_SENDER_MAIN+3, GOSSIP_ACTION_INFO_DEF); - pPlayer->SEND_GOSSIP_MENU(7363, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF: - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Thanks", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->SEND_GOSSIP_MENU(7364, pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pCreature->CastSpell(pPlayer, SPELL_FORTUNE, false); - pPlayer->SEND_GOSSIP_MENU(7365, pCreature->GetObjectGuid()); - break; - } -} - -bool GossipSelect_npc_sayge(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiSender) - { - case GOSSIP_SENDER_MAIN: - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+1: - pCreature->CastSpell(pPlayer, SPELL_DMG, false); - pPlayer->AddSpellCooldown(SPELL_DMG,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+2: - pCreature->CastSpell(pPlayer, SPELL_RES, false); - pPlayer->AddSpellCooldown(SPELL_RES,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+3: - pCreature->CastSpell(pPlayer, SPELL_ARM, false); - pPlayer->AddSpellCooldown(SPELL_ARM,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+4: - pCreature->CastSpell(pPlayer, SPELL_SPI, false); - pPlayer->AddSpellCooldown(SPELL_SPI,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+5: - pCreature->CastSpell(pPlayer, SPELL_INT, false); - pPlayer->AddSpellCooldown(SPELL_INT,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+6: - pCreature->CastSpell(pPlayer, SPELL_STM, false); - pPlayer->AddSpellCooldown(SPELL_STM,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+7: - pCreature->CastSpell(pPlayer, SPELL_STR, false); - pPlayer->AddSpellCooldown(SPELL_STR,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - case GOSSIP_SENDER_MAIN+8: - pCreature->CastSpell(pPlayer, SPELL_AGI, false); - pPlayer->AddSpellCooldown(SPELL_AGI,0,time(NULL) + 7200); - SendAction_npc_sayge(pPlayer, pCreature, uiAction); - break; - } - return true; -} - -/*###### -## npc_tabard_vendor -######*/ - -enum -{ - QUEST_TRUE_MASTERS_OF_LIGHT = 9737, - QUEST_THE_UNWRITTEN_PROPHECY = 9762, - QUEST_INTO_THE_BREACH = 10259, - QUEST_BATTLE_OF_THE_CRIMSON_WATCH = 10781, - QUEST_SHARDS_OF_AHUNE = 11972, - - ACHIEVEMENT_EXPLORE_NORTHREND = 45, - ACHIEVEMENT_TWENTYFIVE_TABARDS = 1021, - ACHIEVEMENT_THE_LOREMASTER_A = 1681, - ACHIEVEMENT_THE_LOREMASTER_H = 1682, - - ITEM_TABARD_OF_THE_HAND = 24344, - ITEM_TABARD_OF_THE_BLOOD_KNIGHT = 25549, - ITEM_TABARD_OF_THE_PROTECTOR = 28788, - ITEM_OFFERING_OF_THE_SHATAR = 31408, - ITEM_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI = 31404, - ITEM_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI = 31405, - ITEM_TABARD_OF_THE_SUMMER_SKIES = 35279, - ITEM_TABARD_OF_THE_SUMMER_FLAMES = 35280, - ITEM_TABARD_OF_THE_ACHIEVER = 40643, - ITEM_LOREMASTERS_COLORS = 43300, - ITEM_TABARD_OF_THE_EXPLORER = 43348, - - SPELL_TABARD_OF_THE_BLOOD_KNIGHT = 54974, - SPELL_TABARD_OF_THE_HAND = 54976, - SPELL_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI = 54977, - SPELL_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI = 54982, - SPELL_TABARD_OF_THE_ACHIEVER = 55006, - SPELL_TABARD_OF_THE_PROTECTOR = 55008, - SPELL_LOREMASTERS_COLORS = 58194, - SPELL_TABARD_OF_THE_EXPLORER = 58224, - SPELL_TABARD_OF_SUMMER_SKIES = 62768, - SPELL_TABARD_OF_SUMMER_FLAMES = 62769 -}; - -#define GOSSIP_LOST_TABARD_OF_BLOOD_KNIGHT "I've lost my Tabard of Blood Knight." -#define GOSSIP_LOST_TABARD_OF_THE_HAND "I've lost my Tabard of the Hand." -#define GOSSIP_LOST_TABARD_OF_THE_PROTECTOR "I've lost my Tabard of the Protector." -#define GOSSIP_LOST_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI "I've lost my Green Trophy Tabard of the Illidari." -#define GOSSIP_LOST_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI "I've lost my Purple Trophy Tabard of the Illidari." -#define GOSSIP_LOST_TABARD_OF_SUMMER_SKIES "I've lost my Tabard of Summer Skies." -#define GOSSIP_LOST_TABARD_OF_SUMMER_FLAMES "I've lost my Tabard of Summer Flames." -#define GOSSIP_LOST_LOREMASTERS_COLORS "I've lost my Loremaster's Colors." -#define GOSSIP_LOST_TABARD_OF_THE_EXPLORER "I've lost my Tabard of the Explorer." -#define GOSSIP_LOST_TABARD_OF_THE_ACHIEVER "I've lost my Tabard of the Achiever." - -bool GossipHello_npc_tabard_vendor(Player* pPlayer, Creature* pCreature) -{ - bool m_bLostBloodKnight = false; - bool m_bLostHand = false; - bool m_bLostProtector = false; - bool m_bLostIllidari = false; - bool m_bLostSummer = false; - - //Tabard of the Blood Knight - if (pPlayer->GetQuestRewardStatus(QUEST_TRUE_MASTERS_OF_LIGHT) && !pPlayer->HasItemCount(ITEM_TABARD_OF_THE_BLOOD_KNIGHT, 1, true)) - m_bLostBloodKnight = true; - - //Tabard of the Hand - if (pPlayer->GetQuestRewardStatus(QUEST_THE_UNWRITTEN_PROPHECY) && !pPlayer->HasItemCount(ITEM_TABARD_OF_THE_HAND, 1, true)) - m_bLostHand = true; - - //Tabard of the Protector - if (pPlayer->GetQuestRewardStatus(QUEST_INTO_THE_BREACH) && !pPlayer->HasItemCount(ITEM_TABARD_OF_THE_PROTECTOR, 1, true)) - m_bLostProtector = true; - - //Green Trophy Tabard of the Illidari - //Purple Trophy Tabard of the Illidari - if (pPlayer->GetQuestRewardStatus(QUEST_BATTLE_OF_THE_CRIMSON_WATCH) && - (!pPlayer->HasItemCount(ITEM_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI, 1, true) && - !pPlayer->HasItemCount(ITEM_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, 1, true) && - !pPlayer->HasItemCount(ITEM_OFFERING_OF_THE_SHATAR, 1, true))) - m_bLostIllidari = true; - - //Tabard of Summer Skies - //Tabard of Summer Flames - if (pPlayer->GetQuestRewardStatus(QUEST_SHARDS_OF_AHUNE) && - !pPlayer->HasItemCount(ITEM_TABARD_OF_THE_SUMMER_SKIES, 1, true) && - !pPlayer->HasItemCount(ITEM_TABARD_OF_THE_SUMMER_FLAMES, 1, true)) - m_bLostSummer = true; - - if (m_bLostBloodKnight || m_bLostHand || m_bLostProtector || m_bLostIllidari || m_bLostSummer) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - - if (m_bLostBloodKnight) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_BLOOD_KNIGHT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +1); - - if (m_bLostHand) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_THE_HAND, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF +2); - - if (m_bLostProtector) - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_THE_PROTECTOR, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3); - - if (m_bLostIllidari) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+4); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+5); - } - - if (m_bLostSummer) - { - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_SUMMER_SKIES, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+6); - pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_LOST_TABARD_OF_SUMMER_FLAMES, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+7); - } - - pPlayer->SEND_GOSSIP_MENU(pPlayer->GetGossipTextId(pCreature), pCreature->GetObjectGuid()); - } - else - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - - return true; -} - -bool GossipSelect_npc_tabard_vendor(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) -{ - switch(uiAction) - { - case GOSSIP_ACTION_TRADE: - pPlayer->SEND_VENDORLIST(pCreature->GetObjectGuid()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_TABARD_OF_THE_BLOOD_KNIGHT, false); - break; - case GOSSIP_ACTION_INFO_DEF+2: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_TABARD_OF_THE_HAND, false); - break; - case GOSSIP_ACTION_INFO_DEF+3: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_TABARD_OF_THE_PROTECTOR, false); - break; - case GOSSIP_ACTION_INFO_DEF+4: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_GREEN_TROPHY_TABARD_OF_THE_ILLIDARI, false); - break; - case GOSSIP_ACTION_INFO_DEF+5: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_PURPLE_TROPHY_TABARD_OF_THE_ILLIDARI, false); - break; - case GOSSIP_ACTION_INFO_DEF+6: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_TABARD_OF_SUMMER_SKIES, false); - break; - case GOSSIP_ACTION_INFO_DEF+7: - pPlayer->CLOSE_GOSSIP_MENU(); - pPlayer->CastSpell(pPlayer, SPELL_TABARD_OF_SUMMER_FLAMES, false); - break; - } - return true; -} - /*###### ## npc_spring_rabbit ## ATTENTION: This is actually a "fun" script, entirely done without proper source! @@ -1498,7 +1092,7 @@ enum static const float DIST_START_EVENT = 15.0f; // Guesswork -struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI +struct npc_spring_rabbitAI : public ScriptedPetAI { npc_spring_rabbitAI(Creature* pCreature) : ScriptedPetAI(pCreature) { Reset(); } @@ -1507,7 +1101,7 @@ struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI uint32 m_uiStepTimer; float m_fMoveAngle; - void Reset() + void Reset() override { m_uiStep = 0; m_uiStepTimer = 0; @@ -1526,7 +1120,7 @@ struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI float m_fMoveAngle = m_creature->GetAngle(pPartner); float fDist = m_creature->GetDistance(pPartner); float fX, fY, fZ; - m_creature->GetNearPoint(m_creature, fX, fY, fZ, m_creature->GetObjectBoundingRadius(), fDist * 0.5f - m_creature->GetObjectBoundingRadius(), m_fMoveAngle); + m_creature->GetNearPoint(m_creature, fX, fY, fZ, m_creature->GetObjectBoundingRadius(), fDist * 0.5f, m_fMoveAngle); m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); @@ -1545,7 +1139,7 @@ struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI } // Event Starts when two rabbits see each other - void MoveInLineOfSight(Unit* pWho) + void MoveInLineOfSight(Unit* pWho) override { if (m_creature->getVictim()) return; @@ -1578,7 +1172,7 @@ struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI return false; } - void MovementInform(uint32 uiMovementType, uint32 uiData) + void MovementInform(uint32 uiMovementType, uint32 uiData) override { if (uiMovementType != POINT_MOTION_TYPE || uiData != 1) return; @@ -1598,12 +1192,12 @@ struct MANGOS_DLL_DECL npc_spring_rabbitAI : public ScriptedPetAI m_creature->SetFacingTo(m_fMoveAngle + M_PI_F * 0.5f); } - //m_creature->GetMotionMaster()->MoveRandom(); // does not move around current position, hence not usefull right now + // m_creature->GetMotionMaster()->MoveRandom(); // does not move around current position, hence not usefull right now m_creature->GetMotionMaster()->MoveIdle(); } // Overwrite ScriptedPetAI::UpdateAI, to prevent re-following while the event is active! - void UpdateAI(const uint32 uiDiff) + void UpdateAI(const uint32 uiDiff) override { if (!m_partnerGuid || !m_uiStepTimer) { @@ -1660,6 +1254,109 @@ CreatureAI* GetAI_npc_spring_rabbit(Creature* pCreature) return new npc_spring_rabbitAI(pCreature); } +/*###### +## npc_redemption_target +######*/ + +enum +{ + SAY_HEAL = -1000187, + + SPELL_SYMBOL_OF_LIFE = 8593, + SPELL_SHIMMERING_VESSEL = 31225, + SPELL_REVIVE_SELF = 32343, + + NPC_FURBOLG_SHAMAN = 17542, // draenei side + NPC_BLOOD_KNIGHT = 17768, // blood elf side +}; + +struct npc_redemption_targetAI : public ScriptedAI +{ + npc_redemption_targetAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset(); } + + uint32 m_uiEvadeTimer; + uint32 m_uiHealTimer; + + ObjectGuid m_playerGuid; + + void Reset() override + { + m_uiEvadeTimer = 0; + m_uiHealTimer = 0; + + m_creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + m_creature->SetStandState(UNIT_STAND_STATE_DEAD); + } + + void DoReviveSelf(ObjectGuid m_guid) + { + // Wait until he resets again + if (m_uiEvadeTimer) + return; + + DoCastSpellIfCan(m_creature, SPELL_REVIVE_SELF); + m_creature->SetDeathState(JUST_ALIVED); + m_playerGuid = m_guid; + m_uiHealTimer = 2000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiHealTimer) + { + if (m_uiHealTimer <= uiDiff) + { + if (Player* pPlayer = m_creature->GetMap()->GetPlayer(m_playerGuid)) + { + DoScriptText(SAY_HEAL, m_creature, pPlayer); + + // Quests 9600 and 9685 requires kill credit + if (m_creature->GetEntry() == NPC_FURBOLG_SHAMAN || m_creature->GetEntry() == NPC_BLOOD_KNIGHT) + pPlayer->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); + } + + m_creature->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + m_uiHealTimer = 0; + m_uiEvadeTimer = 2 * MINUTE * IN_MILLISECONDS; + } + else + m_uiHealTimer -= uiDiff; + } + + if (m_uiEvadeTimer) + { + if (m_uiEvadeTimer <= uiDiff) + { + EnterEvadeMode(); + m_uiEvadeTimer = 0; + } + else + m_uiEvadeTimer -= uiDiff; + } + } +}; + +CreatureAI* GetAI_npc_redemption_target(Creature* pCreature) +{ + return new npc_redemption_targetAI(pCreature); +} + +bool EffectDummyCreature_npc_redemption_target(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) +{ + // always check spellid and effectindex + if ((uiSpellId == SPELL_SYMBOL_OF_LIFE || uiSpellId == SPELL_SHIMMERING_VESSEL) && uiEffIndex == EFFECT_INDEX_0) + { + if (npc_redemption_targetAI* pTargetAI = dynamic_cast(pCreatureTarget->AI())) + pTargetAI->DoReviveSelf(pCaster->GetObjectGuid()); + + // always return true when we are handling this spell and effect + return true; + } + + return false; +} + void AddSC_npcs_special() { Script* pNewScript; @@ -1706,28 +1403,16 @@ void AddSC_npcs_special() pNewScript->Name = "npc_innkeeper"; pNewScript->pGossipHello = &GossipHello_npc_innkeeper; pNewScript->pGossipSelect = &GossipSelect_npc_innkeeper; - pNewScript->RegisterSelf(false); // script and error report disabled, but script can be used for custom needs, adding ScriptName - - pNewScript = new Script; - pNewScript->Name = "npc_mount_vendor"; - pNewScript->pGossipHello = &GossipHello_npc_mount_vendor; - pNewScript->pGossipSelect = &GossipSelect_npc_mount_vendor; - pNewScript->RegisterSelf(); - - pNewScript = new Script; - pNewScript->Name = "npc_sayge"; - pNewScript->pGossipHello = &GossipHello_npc_sayge; - pNewScript->pGossipSelect = &GossipSelect_npc_sayge; - pNewScript->RegisterSelf(); + pNewScript->RegisterSelf(false); // script and error report disabled, but script can be used for custom needs, adding ScriptName pNewScript = new Script; - pNewScript->Name = "npc_tabard_vendor"; - pNewScript->pGossipHello = &GossipHello_npc_tabard_vendor; - pNewScript->pGossipSelect = &GossipSelect_npc_tabard_vendor; + pNewScript->Name = "npc_spring_rabbit"; + pNewScript->GetAI = &GetAI_npc_spring_rabbit; pNewScript->RegisterSelf(); pNewScript = new Script; - pNewScript->Name = "npc_spring_rabbit"; - pNewScript->GetAI = &GetAI_npc_spring_rabbit; + pNewScript->Name = "npc_redemption_target"; + pNewScript->GetAI = &GetAI_npc_redemption_target; + pNewScript->pEffectDummyNPC = &EffectDummyCreature_npc_redemption_target; pNewScript->RegisterSelf(); } diff --git a/scripts/world/spell_scripts.cpp b/scripts/world/spell_scripts.cpp index 5be62beec..53198fd0b 100644 --- a/scripts/world/spell_scripts.cpp +++ b/scripts/world/spell_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,25 +22,28 @@ SDCategory: Spell EndScriptData */ /* ContentData -spell 34665 -spell 19512 spell 8913 +spell 19512 spell 21014 +spell 21050 spell 29528 spell 29866 -spell 46770 +spell 34665 +spell 37136 +spell 39246 +spell 43340 +spell 44935 +spell 45109 +spell 45111 spell 46023 +spell 46770 spell 47575 spell 50706 -spell 45109 -spell 45111 -spell 39246 -spell 52090 spell 51331 spell 51332 spell 51366 -spell 43340 -spell 48218 +spell 52090 +spell 56099 EndContentData */ #include "precompiled.h" @@ -57,7 +60,7 @@ enum GO_RED_SNAPPER = 181616, NPC_ANGRY_MURLOC = 17102, ITEM_RED_SNAPPER = 23614, - //SPELL_SUMMON_TEST = 49214 // ! Just wrong spell name? It summon correct creature (17102)but does not appear to be used. + // SPELL_SUMMON_TEST = 49214 // ! Just wrong spell name? It summon correct creature (17102)but does not appear to be used. // quest 11472 SPELL_ANUNIAQS_NET = 21014, @@ -66,9 +69,9 @@ enum ITEM_TASTY_REEF_FISH = 34127, }; -bool EffectDummyGameObj_spell_dummy_go(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, GameObject* pGOTarget) +bool EffectDummyGameObj_spell_dummy_go(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, GameObject* pGOTarget, ObjectGuid /*originalCasterGuid*/) { - switch(uiSpellId) + switch (uiSpellId) { case SPELL_ANUNIAQS_NET: { @@ -84,7 +87,7 @@ bool EffectDummyGameObj_spell_dummy_go(Unit* pCaster, uint32 uiSpellId, SpellEff } else { - if (Creature* pShark = pCaster->SummonCreature(NPC_REEF_SHARK, pGOTarget->GetPositionX(), pGOTarget->GetPositionY(), pGOTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + if (Creature* pShark = pCaster->SummonCreature(NPC_REEF_SHARK, pGOTarget->GetPositionX(), pGOTarget->GetPositionY(), pGOTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000)) pShark->AI()->AttackStart(pCaster); } @@ -102,7 +105,7 @@ bool EffectDummyGameObj_spell_dummy_go(Unit* pCaster, uint32 uiSpellId, SpellEff if (urand(0, 2)) { - if (Creature* pMurloc = pCaster->SummonCreature(NPC_ANGRY_MURLOC, pCaster->GetPositionX(), pCaster->GetPositionY()+20.0f, pCaster->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000)) + if (Creature* pMurloc = pCaster->SummonCreature(NPC_ANGRY_MURLOC, pCaster->GetPositionX(), pCaster->GetPositionY() + 20.0f, pCaster->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 10000)) pMurloc->AI()->AttackStart(pCaster); } else @@ -145,6 +148,7 @@ enum // quest 6124/6129 SPELL_APPLY_SALVE = 19512, + SPELL_SICKLY_AURA = 19502, NPC_SICKLY_DEER = 12298, NPC_SICKLY_GAZELLE = 12296, @@ -317,20 +321,39 @@ enum SAY_FREE_2 = -1000782, SAY_FREE_3 = -1000783, - // quest 12213, 12220, item 37173 - SPELL_SAMPLING_ENERGY = 48218, - // npcs that are only interactable while dead SPELL_SHROUD_OF_DEATH = 10848, SPELL_SPIRIT_PARTICLES = 17327, NPC_FRANCLORN_FORGEWRIGHT = 8888, NPC_GAERIYAN = 9299, NPC_GANJO = 26924, + + // quest 11521 + SPELL_EXPOSE_RAZORTHORN_ROOT = 44935, + SPELL_SUMMON_RAZORTHORN_ROOT = 44941, + NPC_RAZORTHORN_RAVAGER = 24922, + GO_RAZORTHORN_DIRT_MOUND = 187073, + + // for quest 10584 + SPELL_PROTOVOLTAIC_MAGNETO_COLLECTOR = 37136, + NPC_ENCASED_ELECTROMENTAL = 21731, + + // quest 6661 + SPELL_MELODIOUS_RAPTURE = 21050, + SPELL_MELODIOUS_RAPTURE_VISUAL = 21051, + NPC_DEEPRUN_RAT = 13016, + NPC_ENTHRALLED_DEEPRUN_RAT = 13017, + + // quest 12981 + SPELL_THROW_ICE = 56099, + SPELL_FROZEN_IRON_SCRAP = 56101, + NPC_SMOLDERING_SCRAP_BUNNY = 30169, + GO_SMOLDERING_SCRAP = 192124, }; bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) { - switch(pAura->GetId()) + switch (pAura->GetId()) { case SPELL_BLESSING_OF_PEACE: { @@ -344,7 +367,7 @@ bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) if (bApply) { - switch(urand(0, 4)) + switch (urand(0, 4)) { case 0: DoScriptText(SAY_BLESS_1, pCreature); break; case 1: DoScriptText(SAY_BLESS_2, pCreature); break; @@ -391,7 +414,7 @@ bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) if (pCreature->getStandState() == UNIT_STAND_STATE_KNEEL) pCreature->SetStandState(UNIT_STAND_STATE_STAND); - pCreature->ForcedDespawn(60*IN_MILLISECONDS); + pCreature->ForcedDespawn(60 * IN_MILLISECONDS); } return true; @@ -485,18 +508,28 @@ bool EffectAuraDummy_spell_aura_dummy_npc(const Aura* pAura, bool bApply) if (bApply) pCreature->m_AuraFlags |= UNIT_AURAFLAG_ALIVE_INVISIBLE; else - pCreature->m_AuraFlags |= ~UNIT_AURAFLAG_ALIVE_INVISIBLE; + pCreature->m_AuraFlags &= ~UNIT_AURAFLAG_ALIVE_INVISIBLE; return false; } + case SPELL_PROTOVOLTAIC_MAGNETO_COLLECTOR: + { + if (pAura->GetEffIndex() != EFFECT_INDEX_0) + return true; + + Unit* pTarget = pAura->GetTarget(); + if (bApply && pTarget->GetTypeId() == TYPEID_UNIT) + ((Creature*)pTarget)->UpdateEntry(NPC_ENCASED_ELECTROMENTAL); + return true; + } } return false; } -bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget) +bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellEffectIndex uiEffIndex, Creature* pCreatureTarget, ObjectGuid /*originalCasterGuid*/) { - switch(uiSpellId) + switch (uiSpellId) { case SPELL_ADMINISTER_ANTIDOTE: { @@ -519,11 +552,15 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE if (pCaster->GetTypeId() != TYPEID_PLAYER) return true; - if (pCreatureTarget->GetEntry() == NPC_SICKLY_DEER && ((Player*)pCaster)->GetTeam() == ALLIANCE) - pCreatureTarget->UpdateEntry(NPC_CURED_DEER); + if (pCreatureTarget->GetEntry() != NPC_SICKLY_DEER && pCreatureTarget->GetEntry() != NPC_SICKLY_GAZELLE) + return true; - if (pCreatureTarget->GetEntry() == NPC_SICKLY_GAZELLE && ((Player*)pCaster)->GetTeam() == HORDE) - pCreatureTarget->UpdateEntry(NPC_CURED_GAZELLE); + // Update entry, remove aura, set the kill credit and despawn + uint32 uiUpdateEntry = pCreatureTarget->GetEntry() == NPC_SICKLY_DEER ? NPC_CURED_DEER : NPC_CURED_GAZELLE; + pCreatureTarget->RemoveAurasDueToSpell(SPELL_SICKLY_AURA); + pCreatureTarget->UpdateEntry(uiUpdateEntry); + ((Player*)pCaster)->KilledMonsterCredit(uiUpdateEntry); + pCreatureTarget->ForcedDespawn(20000); return true; } @@ -554,11 +591,11 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE if (pCreatureTarget->getStandState() == UNIT_STAND_STATE_STAND) return true; - switch(urand(1,2)) + switch (urand(1, 2)) { case 1: { - switch(urand(1,3)) + switch (urand(1, 3)) { case 1: DoScriptText(SAY_RAND_ATTACK1, pCreatureTarget); break; case 2: DoScriptText(SAY_RAND_ATTACK2, pCreatureTarget); break; @@ -571,7 +608,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE } case 2: { - switch(urand(1,3)) + switch (urand(1, 3)) { case 1: DoScriptText(SAY_RAND_WORK1, pCreatureTarget); break; case 2: DoScriptText(SAY_RAND_WORK2, pCreatureTarget); break; @@ -596,8 +633,9 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE return true; pCreatureTarget->UpdateEntry(NPC_OWLKIN_INOC); + ((Player*)pCaster)->KilledMonsterCredit(NPC_OWLKIN_INOC); - //set despawn timer, since we want to remove creature after a short time + // set despawn timer, since we want to remove creature after a short time pCreatureTarget->ForcedDespawn(15000); return true; @@ -675,7 +713,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { uint32 uiNewEntry = 0; - switch(pCreatureTarget->GetEntry()) + switch (pCreatureTarget->GetEntry()) { case NPC_REANIMATED_FROSTWYRM: uiNewEntry = NPC_WEAK_REANIMATED_FROSTWYRM; break; case NPC_TURGID: uiNewEntry = NPC_WEAK_TURGID; break; @@ -746,7 +784,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { uint32 newSpellId = 0; - switch(pCreatureTarget->GetEntry()) + switch (pCreatureTarget->GetEntry()) { case NPC_COLLECT_A_TRON: newSpellId = SPELL_SUMMON_COLLECT_A_TRON; break; case NPC_DEFENDO_TANK: newSpellId = SPELL_SUMMON_DEFENDO_TANK; break; @@ -784,7 +822,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { if (uiEffIndex == EFFECT_INDEX_2) { - switch(urand(0,2)) + switch (urand(0, 2)) { case 0: { @@ -793,18 +831,18 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE } case 1: { - for (int i = 0; i<2; ++i) + for (int i = 0; i < 2; ++i) { - if (Creature* pSandGnome = pCaster->SummonCreature(NPC_SAND_GNOME, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + if (Creature* pSandGnome = pCaster->SummonCreature(NPC_SAND_GNOME, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000)) pSandGnome->AI()->AttackStart(pCaster); } break; } case 2: { - for (int i = 0; i<2; ++i) + for (int i = 0; i < 2; ++i) { - if (Creature* pMatureBoneSifter = pCaster->SummonCreature(NPC_MATURE_BONE_SIFTER, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000)) + if (Creature* pMatureBoneSifter = pCaster->SummonCreature(NPC_MATURE_BONE_SIFTER, pCreatureTarget->GetPositionX(), pCreatureTarget->GetPositionY(), pCreatureTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OOC_DESPAWN, 30000)) pMatureBoneSifter->AI()->AttackStart(pCaster); } break; @@ -831,7 +869,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { if (uiEffIndex == EFFECT_INDEX_0) { - bool isMale = urand(0,1); + bool isMale = urand(0, 1); Player* pPlayer = pCreatureTarget->GetLootRecipient(); if (isMale) @@ -839,7 +877,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE else DoScriptText(SAY_ITS_FEMALE, pCreatureTarget, pPlayer); - switch(pCreatureTarget->GetEntry()) + switch (pCreatureTarget->GetEntry()) { case NPC_FROST_LEOPARD: { @@ -876,7 +914,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { if (uiEffIndex == EFFECT_INDEX_0) { - for(int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { if (irand(i, 2)) // 2-3 summons pCreatureTarget->SummonCreature(NPC_MINION_OF_GUROK, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 5000); @@ -904,7 +942,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE pCreatureTarget->CastSpell(pCreatureTarget, SPELL_APPLE_FALLS_TO_GROUND, false); - if (Creature* pLuckyWilhelm = GetClosestCreatureWithEntry(pCreatureTarget, NPC_LUCKY_WILHELM, 2*INTERACTION_DISTANCE)) + if (Creature* pLuckyWilhelm = GetClosestCreatureWithEntry(pCreatureTarget, NPC_LUCKY_WILHELM, 2 * INTERACTION_DISTANCE)) DoScriptText(SAY_LUCKY_HIT_APPLE, pLuckyWilhelm); } return true; @@ -920,7 +958,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE case 3: DoScriptText(SAY_LUCKY_HIT_3, pCreatureTarget); break; } - if (Creature* pDrostan = GetClosestCreatureWithEntry(pCreatureTarget, NPC_DROSTAN, 4*INTERACTION_DISTANCE)) + if (Creature* pDrostan = GetClosestCreatureWithEntry(pCreatureTarget, NPC_DROSTAN, 4 * INTERACTION_DISTANCE)) DoScriptText(urand(0, 1) ? SAY_DROSTAN_GOT_LUCKY_1 : SAY_DROSTAN_GOT_LUCKY_2, pDrostan); } return true; @@ -929,7 +967,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE { if (uiEffIndex == EFFECT_INDEX_0) { - if (Creature* pDrostan = GetClosestCreatureWithEntry(pCreatureTarget, NPC_DROSTAN, 5*INTERACTION_DISTANCE)) + if (Creature* pDrostan = GetClosestCreatureWithEntry(pCreatureTarget, NPC_DROSTAN, 5 * INTERACTION_DISTANCE)) DoScriptText(urand(0, 1) ? SAY_DROSTAN_HIT_BIRD_1 : SAY_DROSTAN_HIT_BIRD_2, pDrostan); pCreatureTarget->DealDamage(pCreatureTarget, pCreatureTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); @@ -943,7 +981,7 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE if (pCreatureTarget->GetEntry() != NPC_CHILL_NYMPH || pCaster->GetTypeId() != TYPEID_PLAYER) return true; - switch(urand(0, 2)) + switch (urand(0, 2)) { case 0: DoScriptText(SAY_FREE_1, pCreatureTarget); break; case 1: DoScriptText(SAY_FREE_2, pCreatureTarget); break; @@ -955,18 +993,59 @@ bool EffectDummyCreature_spell_dummy_npc(Unit* pCaster, uint32 uiSpellId, SpellE pCreatureTarget->DeleteThreatList(); pCreatureTarget->AttackStop(true); pCreatureTarget->GetMotionMaster()->MoveFleeing(pCaster, 7); - pCreatureTarget->ForcedDespawn(7*IN_MILLISECONDS); + pCreatureTarget->ForcedDespawn(7 * IN_MILLISECONDS); } return true; } - case SPELL_SAMPLING_ENERGY: + case SPELL_EXPOSE_RAZORTHORN_ROOT: { if (uiEffIndex == EFFECT_INDEX_0) { - if (pCaster->GetTypeId() != TYPEID_PLAYER) + if (pCreatureTarget->GetEntry() != NPC_RAZORTHORN_RAVAGER) + return true; + + if (GameObject* pMound = GetClosestGameObjectWithEntry(pCreatureTarget, GO_RAZORTHORN_DIRT_MOUND, 20.0f)) + { + if (pMound->GetRespawnTime() != 0) + return true; + + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_SUMMON_RAZORTHORN_ROOT, true); + pMound->SetLootState(GO_JUST_DEACTIVATED); + } + } + return true; + } + case SPELL_MELODIOUS_RAPTURE: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + if (pCaster->GetTypeId() != TYPEID_PLAYER && pCreatureTarget->GetEntry() != NPC_DEEPRUN_RAT) return true; - ((Player*)pCaster)->KilledMonsterCredit(pCreatureTarget->GetEntry()); + pCreatureTarget->UpdateEntry(NPC_ENTHRALLED_DEEPRUN_RAT); + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_MELODIOUS_RAPTURE_VISUAL, false); + pCreatureTarget->GetMotionMaster()->MoveFollow(pCaster, frand(0.5f, 3.0f), frand(M_PI_F * 0.8f, M_PI_F * 1.2f)); + + ((Player*)pCaster)->KilledMonsterCredit(NPC_ENTHRALLED_DEEPRUN_RAT); + } + return true; + } + case SPELL_THROW_ICE: + { + if (uiEffIndex == EFFECT_INDEX_0) + { + if (pCreatureTarget->GetEntry() != NPC_SMOLDERING_SCRAP_BUNNY) + return true; + + if (GameObject* pScrap = GetClosestGameObjectWithEntry(pCreatureTarget, GO_SMOLDERING_SCRAP, 5.0f)) + { + if (pScrap->GetRespawnTime() != 0) + return true; + + pCreatureTarget->CastSpell(pCreatureTarget, SPELL_FROZEN_IRON_SCRAP, true); + pScrap->SetLootState(GO_JUST_DEACTIVATED); + pCreatureTarget->ForcedDespawn(1000); + } } return true; } diff --git a/scripts/world/world_map_scripts.cpp b/scripts/world/world_map_scripts.cpp index c1a4e5939..52ccf9ed3 100644 --- a/scripts/world/world_map_scripts.cpp +++ b/scripts/world/world_map_scripts.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,21 +16,35 @@ /* ScriptData SDName: world_map_scripts -SD%Complete: 0 -SDComment: Quest support: 11538 +SD%Complete: 100 +SDComment: Quest support: 4740, 11538 SDCategory: World Map Scripts EndScriptData */ #include "precompiled.h" +#include "world_map_scripts.h" /* ********************************************************* * EASTERN KINGDOMS */ -struct MANGOS_DLL_DECL world_map_eastern_kingdoms : public ScriptedMap +struct world_map_eastern_kingdoms : public ScriptedMap { world_map_eastern_kingdoms(Map* pMap) : ScriptedMap(pMap) {} - void SetData(uint32 uiType, uint32 uiData) {} + void OnCreatureCreate(Creature* pCreature) + { + switch (pCreature->GetEntry()) + { + case NPC_JONATHAN: + case NPC_WRYNN: + case NPC_BOLVAR: + case NPC_PRESTOR: + case NPC_WINDSOR: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + } + } + + void SetData(uint32 /*uiType*/, uint32 /*uiData*/) {} }; InstanceData* GetInstanceData_world_map_eastern_kingdoms(Map* pMap) @@ -41,11 +55,81 @@ InstanceData* GetInstanceData_world_map_eastern_kingdoms(Map* pMap) /* ********************************************************* * KALIMDOR */ -struct MANGOS_DLL_DECL world_map_kalimdor : public ScriptedMap +struct world_map_kalimdor : public ScriptedMap { - world_map_kalimdor(Map* pMap) : ScriptedMap(pMap) {} + world_map_kalimdor(Map* pMap) : ScriptedMap(pMap) { Initialize(); } + + uint8 m_uiMurkdeepAdds_KilledAddCount; + + void Initialize() + { + m_uiMurkdeepAdds_KilledAddCount = 0; + } + + void OnCreatureCreate(Creature* pCreature) + { + if (pCreature->GetEntry() == NPC_MURKDEEP) + m_mNpcEntryGuidStore[NPC_MURKDEEP] = pCreature->GetObjectGuid(); + } + + void OnCreatureDeath(Creature* pCreature) + { + switch (pCreature->GetEntry()) + { + case NPC_GREYMIST_COASTRUNNNER: + if (pCreature->IsTemporarySummon()) // Only count the ones summoned for Murkdeep quest + { + ++m_uiMurkdeepAdds_KilledAddCount; - void SetData(uint32 uiType, uint32 uiData) {} + // If all 3 coastrunners are killed, summon 2 warriors + if (m_uiMurkdeepAdds_KilledAddCount == 3) + { + float fX, fY, fZ; + for (uint8 i = 0; i < 2; ++i) + { + pCreature->GetRandomPoint(aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][0], aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][1], aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][2], 5.0f, fX, fY, fZ); + + if (Creature* pTemp = pCreature->SummonCreature(NPC_GREYMIST_WARRIOR, fX, fY, fZ, aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pTemp->SetWalk(false); + pTemp->GetRandomPoint(aSpawnLocations[POS_IDX_MURKDEEP_MOVE][0], aSpawnLocations[POS_IDX_MURKDEEP_MOVE][1], aSpawnLocations[POS_IDX_MURKDEEP_MOVE][2], 5.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + + m_uiMurkdeepAdds_KilledAddCount = 0; + } + } + break; + case NPC_GREYMIST_WARRIOR: + if (pCreature->IsTemporarySummon()) // Only count the ones summoned for Murkdeep quest + { + ++m_uiMurkdeepAdds_KilledAddCount; + + // After the 2 warriors are killed, Murkdeep spawns, along with a hunter + if (m_uiMurkdeepAdds_KilledAddCount == 2) + { + float fX, fY, fZ; + for (uint8 i = 0; i < 2; ++i) + { + pCreature->GetRandomPoint(aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][0], aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][1], aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][2], 5.0f, fX, fY, fZ); + + if (Creature* pTemp = pCreature->SummonCreature(!i ? NPC_MURKDEEP : NPC_GREYMIST_HUNTER, fX, fY, fZ, aSpawnLocations[POS_IDX_MURKDEEP_SPAWN][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + pTemp->SetWalk(false); + pTemp->GetRandomPoint(aSpawnLocations[POS_IDX_MURKDEEP_MOVE][0], aSpawnLocations[POS_IDX_MURKDEEP_MOVE][1], aSpawnLocations[POS_IDX_MURKDEEP_MOVE][2], 5.0f, fX, fY, fZ); + pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); + } + } + + m_uiMurkdeepAdds_KilledAddCount = 0; + } + } + break; + } + } + + void SetData(uint32 /*uiType*/, uint32 /*uiData*/) {} }; InstanceData* GetInstanceData_world_map_kalimdor(Map* pMap) @@ -56,20 +140,7 @@ InstanceData* GetInstanceData_world_map_kalimdor(Map* pMap) /* ********************************************************* * OUTLAND */ - -enum -{ - NPC_EMISSARY_OF_HATE = 25003, - NPC_IRESPEAKER = 24999, - NPC_UNLEASHED_HELLION = 25002, -}; - -static const float aSpawnLocations[1][4] = -{ - {12583.019531f, -6916.194336f, 4.601806f, 6.182446f} // Emissary of Hate, guesswork -}; - -struct MANGOS_DLL_DECL world_map_outland : public ScriptedMap +struct world_map_outland : public ScriptedMap { world_map_outland(Map* pMap) : ScriptedMap(pMap) { Initialize(); } @@ -97,7 +168,7 @@ struct MANGOS_DLL_DECL world_map_outland : public ScriptedMap ++m_uiEmissaryOfHate_KilledAddCount; if (m_uiEmissaryOfHate_KilledAddCount == 6) { - pCreature->SummonCreature(NPC_EMISSARY_OF_HATE, aSpawnLocations[0][0], aSpawnLocations[0][1], aSpawnLocations[0][2], aSpawnLocations[0][3], TEMPSUMMON_DEAD_DESPAWN, 0); + pCreature->SummonCreature(NPC_EMISSARY_OF_HATE, aSpawnLocations[POS_IDX_EMISSARY_SPAWN][0], aSpawnLocations[POS_IDX_EMISSARY_SPAWN][1], aSpawnLocations[POS_IDX_EMISSARY_SPAWN][2], aSpawnLocations[POS_IDX_EMISSARY_SPAWN][3], TEMPSUMMON_DEAD_DESPAWN, 0); m_uiEmissaryOfHate_KilledAddCount = 0; } } @@ -105,7 +176,7 @@ struct MANGOS_DLL_DECL world_map_outland : public ScriptedMap } } - void SetData(uint32 uiType, uint32 uiData) {} + void SetData(uint32 /*uiType*/, uint32 /*uiData*/) {} }; InstanceData* GetInstanceData_world_map_outland(Map* pMap) @@ -116,11 +187,11 @@ InstanceData* GetInstanceData_world_map_outland(Map* pMap) /* ********************************************************* * NORTHREND */ -struct MANGOS_DLL_DECL world_map_northrend : public ScriptedMap +struct world_map_northrend : public ScriptedMap { world_map_northrend(Map* pMap) : ScriptedMap(pMap) {} - void SetData(uint32 uiType, uint32 uiData) {} + void SetData(uint32 /*uiType*/, uint32 /*uiData*/) {} }; InstanceData* GetInstanceData_world_map_northrend(Map* pMap) diff --git a/scripts/world/world_map_scripts.h b/scripts/world/world_map_scripts.h new file mode 100644 index 000000000..0fe83cc82 --- /dev/null +++ b/scripts/world/world_map_scripts.h @@ -0,0 +1,45 @@ +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information + * This program is free software licensed under GPL version 2 + * Please see the included DOCS/LICENSE.TXT for more information */ + +#ifndef DEF_WORLD_MAP_SCRIPTS_H +#define DEF_WORLD_MAP_SCRIPTS_H + +enum +{ + // Quest 4740 + NPC_GREYMIST_COASTRUNNNER = 2202, + NPC_GREYMIST_WARRIOR = 2205, + NPC_GREYMIST_HUNTER = 2206, + NPC_MURKDEEP = 10323, + QUEST_WANTED_MURKDEEP = 4740, + + // Quest 6403 + NPC_JONATHAN = 466, + NPC_WRYNN = 1747, + NPC_BOLVAR = 1748, + NPC_PRESTOR = 1749, + NPC_WINDSOR = 12580, + + // Quest 11538 + NPC_EMISSARY_OF_HATE = 25003, + NPC_IRESPEAKER = 24999, + NPC_UNLEASHED_HELLION = 25002, +}; + +enum SpawnIndexes +{ + POS_IDX_EMISSARY_SPAWN = 0, + POS_IDX_MURKDEEP_SPAWN = 1, + POS_IDX_MURKDEEP_MOVE = 2, + POS_IDX_MAX = 3 +}; + +static const float aSpawnLocations[POS_IDX_MAX][4] = +{ + {12583.019f, -6916.194f, 4.601f, 6.18f}, // Emissary of Hate, guesswork + {4981.031f, 597.955f, -1.361f, 4.82f}, // Murkdeep spawn, guesswork + {4988.970f, 547.002f, 5.379f, 0.0f}, // Murkdeep move, guesswork +}; + +#endif diff --git a/sd2_revision_nr.h b/sd2_revision_nr.h index 60e9317aa..1cf4b9139 100644 --- a/sd2_revision_nr.h +++ b/sd2_revision_nr.h @@ -1,4 +1,4 @@ #ifndef __SD2_REVISION_NR_H__ #define __SD2_REVISION_NR_H__ - #define SD2_REVISION_NR "2529" + #define SD2_REVISION_NR "3154" #endif // __SD2_REVISION_NR_H__ diff --git a/sql/mangos_scriptname_full.sql b/sql/mangos_scriptname_full.sql index a863fb37e..4fbce35d2 100644 --- a/sql/mangos_scriptname_full.sql +++ b/sql/mangos_scriptname_full.sql @@ -69,6 +69,31 @@ INSERT INTO scripted_areatrigger VALUES (1738,'at_scent_larkorwi'), (1739,'at_scent_larkorwi'), (1740,'at_scent_larkorwi'); +DELETE FROM scripted_areatrigger WHERE entry IN (5604,5709,5732); +INSERT INTO scripted_areatrigger VALUES +(5604,'at_icecrown_citadel'), +(5709,'at_icecrown_citadel'), +(5732,'at_icecrown_citadel'); +DELETE FROM scripted_areatrigger WHERE entry in (4288,4485); +INSERT INTO scripted_areatrigger VALUES +(4288,'at_dark_portal'), +(4485,'at_dark_portal'); +DELETE FROM scripted_areatrigger WHERE entry=1966; +INSERT INTO scripted_areatrigger VALUES (1966,'at_murkdeep'); +DELETE FROM scripted_areatrigger WHERE entry IN (4047,4052); +INSERT INTO scripted_areatrigger VALUES +(4047,'at_temple_ahnqiraj'), +(4052,'at_temple_ahnqiraj'); +DELETE FROM scripted_areatrigger WHERE entry IN (5710,5711,5712,5714,5715,5716); +INSERT INTO scripted_areatrigger VALUES +(5710, 'at_hot_on_the_trail'), +(5711, 'at_hot_on_the_trail'), +(5712, 'at_hot_on_the_trail'), +(5714, 'at_hot_on_the_trail'), +(5715, 'at_hot_on_the_trail'), +(5716, 'at_hot_on_the_trail'); +DELETE FROM scripted_areatrigger WHERE entry=3587; +INSERT INTO scripted_areatrigger VALUES (3587,'at_ancient_leaf'); /* BATTLEGROUNDS */ @@ -78,39 +103,29 @@ UPDATE creature_template SET ScriptName='npc_spirit_guide' WHERE entry IN (13116 UPDATE creature_template SET ScriptName='boss_ysondre' WHERE entry=14887; UPDATE creature_template SET ScriptName='boss_emeriss' WHERE entry=14889; UPDATE creature_template SET ScriptName='boss_taerar' WHERE entry=14890; -UPDATE creature_template SET ScriptName='boss_shade_of_taerar' WHERE entry=15302; -UPDATE creature_template SET ScriptName='boss_kruul' WHERE entry=18338; UPDATE creature_template SET ScriptName='boss_azuregos' WHERE entry=6109; -UPDATE creature_template SET ScriptName='mob_dementeddruids' WHERE entry=15260; UPDATE creature_template SET ScriptName='boss_lethon' WHERE entry=14888; UPDATE creature_template SET ScriptName='npc_spirit_shade' WHERE entry=15261; /* GO */ -UPDATE gameobject_template SET ScriptName='go_cat_figurine' WHERE entry=13873; UPDATE gameobject_template SET ScriptName='go_barov_journal' WHERE entry=180794; UPDATE gameobject_template SET ScriptName='go_ethereum_prison' WHERE entry BETWEEN 184418 AND 184431; UPDATE gameobject_template SET ScriptName='go_ethereum_stasis' WHERE entry BETWEEN 185465 AND 185467; UPDATE gameobject_template SET ScriptName='go_ethereum_stasis' WHERE entry=184595; UPDATE gameobject_template SET ScriptName='go_ethereum_stasis' WHERE entry BETWEEN 185461 AND 185464; -UPDATE gameobject_template SET ScriptName='go_gilded_brazier' WHERE entry=181956; UPDATE gameobject_template SET ScriptName='go_jump_a_tron' WHERE entry=183146; UPDATE gameobject_template SET ScriptName='go_mysterious_snow_mound' WHERE entry=195308; -UPDATE gameobject_template SET ScriptName='go_resonite_cask' WHERE entry=178145; -UPDATE gameobject_template SET ScriptName='go_sacred_fire_of_life' WHERE entry=175944; -UPDATE gameobject_template SET ScriptName='go_shrine_of_the_birds' WHERE entry IN (185547,185553,185551); UPDATE gameobject_template SET ScriptName='go_tele_to_dalaran_crystal' WHERE entry=191230; UPDATE gameobject_template SET ScriptName='go_tele_to_violet_stand' WHERE entry=191229; -UPDATE gameobject_template SET ScriptName='go_blood_filled_orb' WHERE entry=182024; UPDATE gameobject_template SET ScriptName='go_andorhal_tower' WHERE entry IN (176094,176095,176096,176097); UPDATE gameobject_template SET ScriptName='go_scourge_enclosure' WHERE entry=191548; UPDATE gameobject_template SET ScriptName='go_veil_skith_cage' WHERE entry IN (185202,185203,185204,185205); UPDATE gameobject_template SET ScriptName='go_lab_work_reagents' WHERE entry IN (190462, 190473, 190478, 190459); -UPDATE gameobject_template SET ScriptName='go_hand_of_iruxos_crystal' WHERE entry=176581; /* GUARD */ UPDATE creature_template SET ScriptName='guard_azuremyst' WHERE entry=18038; -UPDATE creature_template SET ScriptName='guard_orgrimmar' WHERE entry=3296; -UPDATE creature_template SET ScriptName='guard_stormwind' WHERE entry IN (68,1976); +UPDATE creature_template SET ScriptName='guard_orgrimmar' WHERE entry IN (3296,14304); +UPDATE creature_template SET ScriptName='guard_stormwind' WHERE entry IN (68,1756,1976); UPDATE creature_template SET ScriptName='guard_contested' WHERE entry IN (9460,4624,3502,11190,15184); UPDATE creature_template SET ScriptName='guard_elwynnforest' WHERE entry=1423; UPDATE creature_template SET ScriptName='guard_eversong' WHERE entry=16221; @@ -134,7 +149,6 @@ UPDATE creature_template SET ScriptName='guard_shattrath_scryer' WHERE entry=185 UPDATE item_template SET ScriptName='item_arcane_charges' WHERE entry=34475; UPDATE item_template SET ScriptName='item_flying_machine' WHERE entry IN (34060,34061); UPDATE item_template SET ScriptName='item_gor_dreks_ointment' WHERE entry=30175; -UPDATE item_template SET ScriptName='item_tainted_core' WHERE entry=31088; UPDATE item_template SET ScriptName='item_petrov_cluster_bombs' WHERE entry=33098; /* NPC (usually creatures to be found in more than one specific zone) */ @@ -143,40 +157,37 @@ UPDATE creature_template SET ScriptName='npc_chicken_cluck' WHERE entry=620; UPDATE creature_template SET ScriptName='npc_dancing_flames' WHERE entry=25305; UPDATE creature_template SET ScriptName='npc_garments_of_quests' WHERE entry IN (12429,12423,12427,12430,12428); UPDATE creature_template SET ScriptName='npc_guardian' WHERE entry=5764; -UPDATE creature_template SET ScriptName='npc_mount_vendor' WHERE entry IN (384,1261,1460,2357,3362,3685,4730,4731,4885,7952,7955,16264,17584); UPDATE creature_template SET ScriptName='npc_doctor' WHERE entry IN (12939,12920); UPDATE creature_template SET ScriptName='npc_injured_patient' WHERE entry IN (12936,12937,12938,12923,12924,12925); -UPDATE creature_template SET ScriptName='npc_prof_alchemy' WHERE entry IN (17909,19052,22427); UPDATE creature_template SET ScriptName='npc_prof_blacksmith' WHERE entry IN (5164,11145,11146,11176,11177,11178,11191,11192,11193); UPDATE creature_template SET ScriptName='npc_prof_leather' WHERE entry IN (7866,7867,7868,7869,7870,7871); -UPDATE creature_template SET ScriptName='npc_prof_tailor' WHERE entry IN (22208,22212,22213); -UPDATE creature_template SET ScriptName='npc_sayge' WHERE entry=14822; -UPDATE creature_template SET ScriptName='npc_tabard_vendor' WHERE entry=28776; -- disabled, but can be used for custom -- UPDATE creature_template SET ScriptName='' WHERE npcflag!=npcflag|65536 AND ScriptName='npc_innkeeper'; -- UPDATE creature_template SET ScriptName='npc_innkeeper' WHERE npcflag=npcflag|65536; UPDATE creature_template SET ScriptName='npc_spring_rabbit' WHERE entry=32791; +UPDATE creature_template SET ScriptName='npc_redemption_target' WHERE entry IN (6172,6177,17542,17768); /* SPELL */ UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN ( -- eastern kingdoms -1200,8888, +1200,8888,13016, -- kalimdor 9299,12296,12298, -- outland -16880,16518,16847,17157,17326,17654,18879,22105,24918,25084,25085, +16880,16518,16847,17157,17326,17654,18879,21729,22105,24918,24922,25084,25085, -- northrend -23678,25752,25753,25758,25792,25793,26268,26270,26421,26616,26643,26841,26924,27122,27263,27264,27265,27808,28053,28054,28068,28093,28465,28600,29319,29327,29329,29330,29338,30146,32149); +23678,25752,25753,25758,25792,25793,26268,26270,26421,26616,26643,26841,26924,27122,27808,28053,28054,28068,28093,28465,28600,29319,29327,29329,29330,29338,30146,30169,32149); UPDATE gameobject_template SET ScriptName='spell_dummy_go' WHERE entry IN (181616,186949); /* WORLD MAP SCRIPTS */ -DELETE FROM world_template WHERE map IN (0, 1, 530, 571); +DELETE FROM world_template WHERE map IN (0, 1, 530, 571, 609); INSERT INTO world_template VALUES (0, 'world_map_eastern_kingdoms'), (1, 'world_map_kalimdor'), (530, 'world_map_outland'), -(571, 'world_map_northrend'); +(571, 'world_map_northrend'), +(609, 'world_map_ebon_hold'); /* */ /* ZONE */ @@ -184,12 +195,11 @@ INSERT INTO world_template VALUES /* ALTERAC MOUNTAINS */ - /* ALTERAC VALLEY */ - /* ARATHI HIGHLANDS */ UPDATE creature_template SET ScriptName='npc_professor_phizzlethorpe' WHERE entry=2768; +UPDATE creature_template SET ScriptName='npc_kinelory' WHERE entry=2713; /* ASHENVALE */ UPDATE creature_template SET ScriptName='npc_muglash' WHERE entry=12717; @@ -205,22 +215,20 @@ UPDATE creature_template SET ScriptName='npc_feero_ironhand' WHERE entry=4484; /* MANA TOMBS */ UPDATE creature_template SET ScriptName='boss_pandemonius' WHERE entry=18341; UPDATE creature_template SET ScriptName='boss_nexusprince_shaffar' WHERE entry=18344; -UPDATE creature_template SET ScriptName='mob_ethereal_beacon' WHERE entry=18431; /* AUCHENAI CRYPTS */ UPDATE creature_template SET ScriptName='boss_exarch_maladaar' WHERE entry=18373; -UPDATE creature_template SET ScriptName='mob_avatar_of_martyred' WHERE entry=18478; UPDATE creature_template SET ScriptName='mob_stolen_soul' WHERE entry=18441; UPDATE creature_template SET ScriptName='boss_shirrak' WHERE entry=18371; /* SETHEKK HALLS */ UPDATE instance_template SET ScriptName='instance_sethekk_halls' WHERE map=556; -UPDATE creature_template SET ScriptName='mob_syth_fire' WHERE entry=19203; -UPDATE creature_template SET ScriptName='mob_syth_arcane' WHERE entry=19205; -UPDATE creature_template SET ScriptName='mob_syth_frost' WHERE entry=19204; -UPDATE creature_template SET ScriptName='mob_syth_shadow' WHERE entry=19206; UPDATE creature_template SET ScriptName='boss_talon_king_ikiss' WHERE entry=18473; UPDATE creature_template SET ScriptName='boss_darkweaver_syth' WHERE entry=18472; +UPDATE creature_template SET ScriptName='boss_anzu' WHERE entry=23035; +DELETE FROM scripted_event_id WHERE id=14797; +INSERT INTO scripted_event_id VALUES +(14797,'event_spell_summon_raven_god'); /* SHADOW LABYRINTH */ UPDATE instance_template SET ScriptName='instance_shadow_labyrinth' WHERE map=555; @@ -235,7 +243,10 @@ UPDATE creature_template SET ScriptName='npc_void_traveler' WHERE entry=19226; /* */ /* AHN'KAHET */ +UPDATE creature_template SET ScriptName='boss_amanitar' WHERE entry=30258; +UPDATE creature_template SET ScriptName='npc_amanitar_mushroom' WHERE entry IN (30391,30435); UPDATE creature_template SET ScriptName='boss_jedoga' WHERE entry=29310; +UPDATE creature_template SET ScriptName='npc_twilight_volunteer' WHERE entry=30385; UPDATE creature_template SET ScriptName='boss_nadox' WHERE entry=29309; UPDATE creature_template SET ScriptName='mob_ahnkahar_egg' WHERE entry IN (30172,30173); UPDATE creature_template SET ScriptName='boss_taldaram' WHERE entry=29308; @@ -245,6 +256,7 @@ UPDATE instance_template SET ScriptName='instance_ahnkahet' WHERE map=619; /* AZJOL-NERUB */ UPDATE creature_template SET ScriptName='boss_anubarak' WHERE entry=29120; +UPDATE creature_template SET ScriptName='npc_impale_target' WHERE entry=29184; UPDATE creature_template SET ScriptName='boss_hadronox' WHERE entry=28921; UPDATE creature_template SET ScriptName='boss_krikthir' WHERE entry=28684; UPDATE instance_template SET ScriptName='instance_azjol-nerub' WHERE map=601; @@ -264,11 +276,9 @@ UPDATE creature_template SET ScriptName='npc_magwin' WHERE entry=17312; /* BADLANDS */ - /* BARRENS */ UPDATE creature_template SET ScriptName='npc_beaten_corpse' WHERE entry=10668; UPDATE creature_template SET ScriptName='npc_gilthares' WHERE entry=3465; -UPDATE creature_template SET ScriptName='npc_sputtervalve' WHERE entry=3442; UPDATE creature_template SET ScriptName='npc_taskmaster_fizzule' WHERE entry=7233; UPDATE creature_template SET ScriptName='npc_twiggy_flathead' WHERE entry=6248; DELETE FROM scripted_areatrigger WHERE entry=522; @@ -297,26 +307,21 @@ UPDATE creature_template SET ScriptName='boss_illidan_stormrage' WHERE entry=229 UPDATE creature_template SET ScriptName='boss_high_nethermancer_zerevor' WHERE entry=22950; -- Mage at Illidari Council UPDATE creature_template SET ScriptName='boss_gathios_the_shatterer' WHERE entry=22949; -- Paladin at Illidari Council UPDATE creature_template SET ScriptName='boss_maiev_shadowsong' WHERE entry=23197; -- Maiev Shadowsong -UPDATE gameobject_template SET ScriptName='gameobject_cage_trap' WHERE entry=185916; -- Cage Trap GO in Illidan Encounter -UPDATE creature_template SET ScriptName='mob_blaze' WHERE entry=23259; -- Blaze mob in Illidan Phase 2 UPDATE creature_template SET ScriptName='mob_flame_of_azzinoth' WHERE entry=22997; -- Flame of Azzinoth (Illidan Phase 2) UPDATE creature_template SET ScriptName='mob_blade_of_azzinoth' WHERE entry=22996; -- Blade of Azzinoth (Illidan Phase 2) -UPDATE creature_template SET ScriptName='mob_demon_fire' WHERE entry=23069; -- Demon Fire in Illidan Phase 2 -UPDATE creature_template SET ScriptName='mob_flame_crash' WHERE entry=23336; -- Flame Crash in Illidan Normal Form UPDATE creature_template SET ScriptName='mob_cage_trap_trigger' WHERE entry=23304; -- Cage Trap mob in Illidan Phase 3/4 Normal UPDATE creature_template SET ScriptName='mob_shadow_demon' WHERE entry=23375; -- Shadow Demon in Illidan Demon Form UPDATE creature_template SET ScriptName='npc_volcano' WHERE entry=23085; -- Supremus Volcano UPDATE creature_template SET ScriptName='molten_flame' WHERE entry=23095; -- Molten Flame in SUpremus UPDATE creature_template SET ScriptName='mob_ashtongue_channeler' WHERE entry=23421; -- Ashtongue CHanneler in Shade of AKama UPDATE creature_template SET ScriptName='mob_ashtongue_sorcerer' WHERE entry=23215; -- Ashtongue Sorcerer in Shade of Akama -UPDATE creature_template SET ScriptName='npc_enslaved_soul' WHERE entry=23469; -- Enslaved Soul in Reliquary Event -UPDATE creature_template SET ScriptName='mob_doom_blossom' WHERE entry=23123; -- Doom Blossoms in Teron Gorefiend's encounter UPDATE creature_template SET ScriptName='npc_spirit_of_olum' WHERE entry=23411; --- UPDATE creature_template SET ScriptName='mob_shadowy_construct' WHERE entry=23111; -- Shadowy Construct in Teron Gorefiend's encounter. Commented until Mind Control is implemented. +UPDATE creature_template SET ScriptName='npc_enslaved_soul' WHERE entry=23469; /* BLACKFATHOM DEPTHS */ UPDATE instance_template SET ScriptName='instance_blackfathom_deeps' WHERE map=48; UPDATE gameobject_template SET ScriptName='go_fire_of_akumai' WHERE entry IN (21118,21119,21120,21121); +UPDATE gameobject_template SET ScriptName='go_fathom_stone' WHERE entry=177964; /* BLACKROCK DEPTHS */ DELETE FROM scripted_areatrigger WHERE entry=1526; @@ -325,46 +330,34 @@ UPDATE instance_template SET ScriptName='instance_blackrock_depths' WHERE map =2 UPDATE creature_template SET ScriptName='boss_emperor_dagran_thaurissan' WHERE entry=9019; UPDATE creature_template SET ScriptName='boss_moira_bronzebeard' WHERE entry=8929; UPDATE creature_template SET ScriptName='boss_ambassador_flamelash' WHERE entry=9156; -UPDATE creature_template SET ScriptName='boss_anubshiah' WHERE entry=9031; UPDATE creature_template SET ScriptName='boss_doomrel' WHERE entry=9039; -UPDATE creature_template SET ScriptName='boss_gloomrel' WHERE entry=9037; UPDATE creature_template SET ScriptName='boss_general_angerforge' WHERE entry=9033; -UPDATE creature_template SET ScriptName='boss_gorosh_the_dervish' WHERE entry=9027; -UPDATE creature_template SET ScriptName='boss_grizzle' WHERE entry=9028; UPDATE creature_template SET ScriptName='boss_high_interrogator_gerstahn' WHERE entry=9018; -UPDATE creature_template SET ScriptName='boss_magmus' WHERE entry=9938; -UPDATE creature_template SET ScriptName='mob_phalanx' WHERE entry=9502; +UPDATE creature_template SET ScriptName='boss_coren_direbrew' WHERE entry=23872; UPDATE creature_template SET ScriptName='npc_grimstone' WHERE entry=10096; UPDATE creature_template SET ScriptName='npc_theldren_trigger' WHERE entry=16079; -UPDATE creature_template SET ScriptName='npc_lokhtos_darkbargainer' WHERE entry=12944; UPDATE creature_template SET ScriptName='npc_kharan_mighthammer' WHERE entry=9021; UPDATE creature_template SET ScriptName='npc_rocknot' WHERE entry=9503; +UPDATE creature_template SET ScriptName='npc_marshal_windsor' WHERE entry=9023; +UPDATE creature_template SET ScriptName='npc_dughal_stormwing' WHERE entry=9022; +UPDATE creature_template SET ScriptName='npc_tobias_seecher' WHERE entry=9679; UPDATE gameobject_template SET ScriptName='go_shadowforge_brazier' WHERE entry IN (174744, 174745); UPDATE gameobject_template SET ScriptName='go_relic_coffer_door' WHERE entry IN (174554, 174555, 174556, 174557, 174558, 174559, 174560, 174561, 174562, 174563, 174564, 174566); /* BLACKROCK SPIRE */ UPDATE instance_template SET ScriptName='instance_blackrock_spire' WHERE map=229; -/* BLACKROCK SPIRE Lower bosses */ -UPDATE creature_template SET ScriptName='boss_highlord_omokk' WHERE entry=9196; -UPDATE creature_template SET ScriptName='boss_shadow_hunter_voshgajin' WHERE entry=9236; -UPDATE creature_template SET ScriptName='boss_warmaster_voone' WHERE entry=9237; -UPDATE creature_template SET ScriptName='boss_mother_smolderweb' WHERE entry=10596; -UPDATE creature_template SET ScriptName='quartermaster_zigris' WHERE entry=9736; -UPDATE creature_template SET ScriptName='boss_halycon' WHERE entry=10220; UPDATE creature_template SET ScriptName='boss_overlord_wyrmthalak' WHERE entry=9568; -/* BLACKROCK SPIRE Upper bosses */ -UPDATE creature_template SET ScriptName='boss_the_beast' WHERE entry=10430; -UPDATE creature_template SET ScriptName='boss_drakkisath' WHERE entry=10363; UPDATE creature_template SET ScriptName='boss_gyth' WHERE entry=10339; -UPDATE creature_template SET ScriptName='boss_rend_blackhand' WHERE entry=10429; UPDATE creature_template SET ScriptName='boss_pyroguard_emberseer' WHERE entry=9816; DELETE FROM scripted_event_id WHERE id=4884; INSERT INTO scripted_event_id VALUES (4884,'event_spell_altar_emberseer'); +UPDATE gameobject_template SET ScriptName='go_father_flame' WHERE entry=175245; /* BLACKWING LAIR */ UPDATE instance_template SET ScriptName='instance_blackwing_lair' WHERE map=469; UPDATE creature_template SET ScriptName='boss_razorgore' WHERE entry=12435; +UPDATE gameobject_template SET ScriptName='go_black_dragon_egg' WHERE entry=177807; UPDATE creature_template SET ScriptName='boss_vaelastrasz' WHERE entry=13020; UPDATE creature_template SET ScriptName='boss_broodlord' WHERE entry=12017; UPDATE creature_template SET ScriptName='boss_firemaw' WHERE entry=11983; @@ -375,9 +368,11 @@ UPDATE creature_template SET ScriptName='boss_victor_nefarius' WHERE entry=10162 UPDATE creature_template SET ScriptName='boss_nefarian' WHERE entry=11583; /* BLADE'S EDGE MOUNTAINS */ -UPDATE creature_template SET ScriptName='mobs_bladespire_ogre' WHERE entry IN (19998,20334,21296,21975); UPDATE creature_template SET ScriptName='mobs_nether_drake' WHERE entry IN (20021,21817,21820,21821,21823); UPDATE creature_template SET ScriptName='npc_daranelle' WHERE entry=21469; +UPDATE creature_template SET ScriptName='npc_bloodmaul_stout_trigger' WHERE entry=21241; +UPDATE creature_template SET ScriptName='npc_simon_game_bunny' WHERE entry=22923; +UPDATE creature_template SET ScriptName='npc_light_orb_collector' WHERE entry IN (21926,22333); /* BLASTED LANDS */ UPDATE creature_template SET ScriptName='npc_fallen_hero_of_horde' WHERE entry=7572; @@ -388,12 +383,17 @@ UPDATE creature_template SET ScriptName='mob_webbed_creature' WHERE entry=17680; /* BOREAN TUNDRA */ UPDATE creature_template SET ScriptName='npc_nesingwary_trapper' WHERE entry=25835; UPDATE creature_template SET ScriptName='npc_oil_stained_wolf' WHERE entry=25791; -UPDATE gameobject_template SET ScriptName='go_caribou_trap' WHERE entry IN (187982,187995,187996,187997,187998,187999,188000,188001,188002,188003,188004,188005,188006,188007,188008); UPDATE creature_template SET ScriptName='npc_sinkhole_kill_credit' WHERE entry IN (26248,26249); UPDATE creature_template SET ScriptName='npc_lurgglbr' WHERE entry=25208; +UPDATE creature_template SET ScriptName='npc_beryl_sorcerer' WHERE entry=25316; +UPDATE creature_template SET ScriptName='npc_captured_beryl_sorcerer' WHERE entry=25474; +UPDATE creature_template SET ScriptName='npc_nexus_drake_hatchling' WHERE entry=26127; +UPDATE creature_template SET ScriptName='npc_scourged_flamespitter' WHERE entry=25582; +UPDATE creature_template SET ScriptName='npc_bonker_togglevolt' WHERE entry=25589; /* BURNING STEPPES */ UPDATE creature_template SET ScriptName='npc_ragged_john' WHERE entry=9563; +UPDATE creature_template SET ScriptName='npc_grark_lorkrub' WHERE entry=9520; /* */ /* CAVERNS OF TIME */ @@ -405,32 +405,33 @@ UPDATE creature_template SET ScriptName='npc_tyrande_whisperwind' WHERE entry=17 UPDATE creature_template SET ScriptName='npc_thrall' WHERE entry=17852; UPDATE creature_template SET ScriptName='npc_jaina_proudmoore' WHERE entry=17772; UPDATE creature_template SET ScriptName='boss_archimonde' WHERE entry=17968; -UPDATE creature_template SET ScriptName='mob_doomfire' WHERE entry=18095; -UPDATE creature_template SET ScriptName='mob_doomfire_targetting' WHERE entry=18104; -UPDATE creature_template SET ScriptName='mob_ancient_wisp' WHERE entry=17946; +UPDATE creature_template SET ScriptName='npc_doomfire_spirit' WHERE entry=18104; /* OLD HILLSBRAD */ UPDATE instance_template SET ScriptName='instance_old_hillsbrad' WHERE map=560; -UPDATE creature_template SET ScriptName='boss_lieutenant_drake' WHERE entry=17848; -UPDATE creature_template SET ScriptName='boss_epoch_hunter' WHERE entry=18096; -UPDATE creature_template SET ScriptName='boss_captain_skarloc' WHERE entry=17862; -UPDATE gameobject_template SET ScriptName='go_barrel_old_hillsbrad' WHERE entry=182589; -UPDATE creature_template SET ScriptName='npc_brazen' WHERE entry=18725; UPDATE creature_template SET ScriptName='npc_erozion' WHERE entry=18723; UPDATE creature_template SET ScriptName='npc_taretha' WHERE entry=18887; UPDATE creature_template SET ScriptName='npc_thrall_old_hillsbrad' WHERE entry=17876; +DELETE FROM scripted_event_id WHERE id=11111; +INSERT INTO scripted_event_id VALUES +(11111,'event_go_barrel_old_hillsbrad'); /* THE CULLING OF STRATHOLME */ UPDATE instance_template SET ScriptName='instance_culling_of_stratholme' WHERE map=595; UPDATE creature_template SET ScriptName='npc_chromie' WHERE entry IN (26527, 27915); -UPDATE creature_template SET ScriptName='spell_dummy_npc_crates_bunny' WHERE entry=30996; +UPDATE creature_template SET ScriptName='spell_dummy_npc_crates_bunny' WHERE entry=27827; +UPDATE creature_template SET ScriptName='npc_spell_dummy_crusader_strike' WHERE entry IN (28167,28169); +UPDATE creature_template SET ScriptName='npc_arthas' WHERE entry=26499; +DELETE FROM scripted_areatrigger WHERE entry=5291; +INSERT INTO scripted_areatrigger VALUES +(5291,'at_culling_of_stratholme'); /* THE DARK PORTAL */ UPDATE creature_template SET ScriptName='boss_chrono_lord_deja' WHERE entry=17879; UPDATE creature_template SET ScriptName='boss_aeonus' WHERE entry=17881; UPDATE creature_template SET ScriptName='boss_temporus' WHERE entry=17880; UPDATE instance_template SET ScriptName='instance_dark_portal' WHERE map=269; -UPDATE creature_template SET ScriptName='npc_medivh_bm' WHERE entry=15608; +UPDATE creature_template SET ScriptName='npc_medivh_black_morass' WHERE entry=15608; UPDATE creature_template SET ScriptName='npc_time_rift' WHERE entry=17838; /* */ @@ -438,6 +439,9 @@ UPDATE creature_template SET ScriptName='npc_time_rift' WHERE entry=17838; /* */ /* THE SLAVE PENS */ +UPDATE creature_template SET ScriptName='boss_ahune' WHERE entry=25740; +UPDATE creature_template SET ScriptName='npc_frozen_core' WHERE entry=25865; +UPDATE creature_template SET ScriptName='npc_ice_spear_bunny' WHERE entry=25985; /* THE UNDERBOG */ UPDATE creature_template SET ScriptName='mob_underbog_mushroom' WHERE entry=17990; @@ -449,7 +453,6 @@ UPDATE creature_template SET ScriptName='boss_hydromancer_thespia' WHERE entry=1 UPDATE creature_template SET ScriptName='boss_mekgineer_steamrigger' WHERE entry=17796; UPDATE creature_template SET ScriptName='boss_warlord_kalithresh' WHERE entry=17798; UPDATE gameobject_template SET ScriptName='go_main_chambers_access_panel' WHERE entry IN (184125,184126); -UPDATE creature_template SET ScriptName='mob_coilfang_waterelemental' WHERE entry=17917; UPDATE creature_template SET ScriptName='mob_naga_distiller' WHERE entry=17954; UPDATE creature_template SET ScriptName='mob_steamrigger_mechanic' WHERE entry=17951; @@ -458,7 +461,6 @@ UPDATE instance_template SET ScriptName='instance_serpent_shrine' WHERE map=548; UPDATE creature_template SET ScriptName='boss_hydross_the_unstable' WHERE entry=21216; /* Leotheras the Blind event */ UPDATE creature_template SET ScriptName='boss_leotheras_the_blind' WHERE entry=21215; -UPDATE creature_template SET ScriptName='boss_leotheras_the_blind_demonform' WHERE entry=21875; /* Fathom-lord Karathress event */ UPDATE creature_template SET ScriptName='boss_fathomlord_karathress' WHERE entry=21214; UPDATE creature_template SET ScriptName='boss_fathomguard_sharkkis' WHERE entry=21966; @@ -470,9 +472,7 @@ UPDATE creature_template SET ScriptName='mob_water_globule' WHERE entry=21913; /* Lady Vashj event */ UPDATE creature_template SET ScriptName='boss_lady_vashj' WHERE entry=21212; UPDATE creature_template SET ScriptName='mob_enchanted_elemental' WHERE entry=21958; -UPDATE creature_template SET ScriptName='mob_tainted_elemental' WHERE entry=22009; -UPDATE creature_template SET ScriptName='mob_toxic_sporebat' WHERE entry=22140; -UPDATE creature_template SET ScriptName='mob_shield_generator_channel' WHERE entry=19870; +UPDATE gameobject_template SET ScriptName='go_shield_generator' WHERE entry IN (185051,185052,185053,185054); /* The Lurker Below event */ UPDATE gameobject_template SET ScriptName='go_strange_pool' WHERE entry=184956; UPDATE creature_template SET ScriptName='boss_the_lurker_below' WHERE entry=21217; @@ -484,6 +484,20 @@ UPDATE creature_template SET ScriptName='boss_the_lurker_below' WHERE entry=2121 /* */ /* TRAIL OF THE CHAMPION */ +UPDATE instance_template SET ScriptName='instance_trial_of_the_champion' WHERE map=650; +UPDATE creature_template SET ScriptName='npc_toc_herald' WHERE entry IN (35004, 35005); +UPDATE creature_template SET ScriptName='boss_champion_warrior' WHERE entry IN (34705,35572); +UPDATE creature_template SET ScriptName='boss_champion_mage' WHERE entry IN (34702,35569); +UPDATE creature_template SET ScriptName='boss_champion_shaman' WHERE entry IN (34701,35571); +UPDATE creature_template SET ScriptName='boss_champion_hunter' WHERE entry IN (34657,35570); +UPDATE creature_template SET ScriptName='boss_champion_rogue' WHERE entry IN (34703,35617); +UPDATE creature_template SET ScriptName='npc_champion_mount' WHERE entry IN (35644,36559,35637,35633,35768,34658,35636,35638,35635,35640,35641,35634); +UPDATE creature_template SET ScriptName='npc_trial_grand_champion' WHERE entry IN (35328,35331,35330,35332,35329,35314,35326,35325,35323,35327); +UPDATE creature_template SET ScriptName='boss_eadric' WHERE entry=35119; +UPDATE creature_template SET ScriptName='boss_paletress' WHERE entry=34928; +UPDATE creature_template SET ScriptName='boss_black_knight' WHERE entry=35451; +UPDATE creature_template SET ScriptName='npc_black_knight_gryphon' WHERE entry=35491; +UPDATE creature_template SET ScriptName='npc_black_knight_ghoul' WHERE entry IN (35545,35564,35590); /* TRIAL OF THE CRUSADER */ UPDATE instance_template SET ScriptName='instance_trial_of_the_crusader' WHERE map=649; @@ -497,6 +511,25 @@ UPDATE creature_template SET ScriptName='boss_jaraxxus' WHERE entry=34780; UPDATE creature_template SET ScriptName='boss_anubarak_trial' WHERE entry=34564; UPDATE creature_template SET ScriptName='boss_fjola' WHERE entry=34497; UPDATE creature_template SET ScriptName='boss_eydis' WHERE entry=34496; +UPDATE creature_template SET ScriptName='npc_concentrated_bullet' WHERE entry IN (34628,34630); +UPDATE creature_template SET ScriptName='npc_valkyr_stalker' WHERE entry IN (34704,34720); +UPDATE creature_template SET ScriptName='npc_anubarak_spike' WHERE entry=34660; +UPDATE creature_template SET ScriptName='npc_frost_sphere' WHERE entry=34606; +UPDATE creature_template SET ScriptName='npc_nerubian_borrow' WHERE entry=34862; +UPDATE creature_template SET ScriptName='boss_crusader_death_knight' WHERE entry IN (34461,34458); +UPDATE creature_template SET ScriptName='boss_crusader_druid_balance' WHERE entry IN (34460,34451); +UPDATE creature_template SET ScriptName='boss_crusader_druid_resto' WHERE entry IN (34469,34459); +UPDATE creature_template SET ScriptName='boss_crusader_hunter' WHERE entry IN (34467,34448); +UPDATE creature_template SET ScriptName='boss_crusader_mage' WHERE entry IN (34468,34449); +UPDATE creature_template SET ScriptName='boss_crusader_paladin_holy' WHERE entry IN (34465,34445); +UPDATE creature_template SET ScriptName='boss_crusader_paladin_retri' WHERE entry IN (34471,34456); +UPDATE creature_template SET ScriptName='boss_crusader_priest_disc' WHERE entry IN (34466,34447); +UPDATE creature_template SET ScriptName='boss_crusader_priest_shadow' WHERE entry IN (34473,34441); +UPDATE creature_template SET ScriptName='boss_crusader_rogue' WHERE entry IN (34472,34454); +UPDATE creature_template SET ScriptName='boss_crusader_shaman_enha' WHERE entry IN (34463,34455); +UPDATE creature_template SET ScriptName='boss_crusader_shaman_resto' WHERE entry IN (34470,34444); +UPDATE creature_template SET ScriptName='boss_crusader_warlock' WHERE entry IN (34474,34450); +UPDATE creature_template SET ScriptName='boss_crusader_warrior' WHERE entry IN (34475,34453); /* DALARAN */ UPDATE creature_template SET ScriptName='npc_dalaran_guardian_mage' WHERE entry IN (29255, 29254); @@ -506,10 +539,11 @@ UPDATE creature_template SET ScriptName='npc_kerlonian' WHERE entry=11218; UPDATE creature_template SET ScriptName='npc_prospector_remtravel' WHERE entry=2917; UPDATE creature_template SET ScriptName='npc_threshwackonator' WHERE entry=6669; UPDATE creature_template SET ScriptName='npc_volcor' WHERE entry=3692; +UPDATE creature_template SET ScriptName='npc_therylune' WHERE entry=3584; +UPDATE creature_template SET ScriptName='npc_rabid_bear' WHERE entry=2164; /* DARNASSUS */ - /* DEADMINES */ UPDATE creature_template SET ScriptName='boss_mr_smite' WHERE entry=646; UPDATE instance_template SET ScriptName='instance_deadmines' WHERE map=36; @@ -517,7 +551,6 @@ UPDATE gameobject_template SET ScriptName='go_defias_cannon' WHERE entry=16398; /* DEADWIND PASS */ - /* DESOLACE */ UPDATE creature_template SET ScriptName='npc_aged_dying_ancient_kodo' WHERE entry IN (4700, 4701, 4702, 11627); UPDATE creature_template SET ScriptName='npc_dalinda_malem' WHERE entry=5644; @@ -527,10 +560,8 @@ UPDATE creature_template SET ScriptName='npc_melizza_brimbuzzle' WHERE entry=122 UPDATE instance_template SET ScriptName='instance_dire_maul' WHERE map=429; /* DRAGONBLIGHT */ -UPDATE creature_template SET ScriptName='npc_afrasastrasz' WHERE entry=27575; UPDATE creature_template SET ScriptName='npc_destructive_ward' WHERE entry=27430; -UPDATE creature_template SET ScriptName='npc_tariolstrasz' WHERE entry=26443; -UPDATE creature_template SET ScriptName='npc_torastrasza' WHERE entry=26949; +UPDATE creature_template SET ScriptName='npc_crystalline_ice_giant' WHERE entry=26809; /* DRAK'THARON KEEP */ UPDATE creature_template SET ScriptName='boss_novos' WHERE entry=26631; @@ -540,30 +571,26 @@ UPDATE creature_template SET ScriptName='boss_trollgore' WHERE entry=26630; UPDATE instance_template SET ScriptName='instance_draktharon_keep' WHERE map=600; /* DUN MOROGH */ -UPDATE creature_template SET ScriptName='npc_narm_faulk' WHERE entry=6177; - /* DUROTAR */ UPDATE creature_template SET ScriptName='npc_lazy_peon' WHERE entry=10556; - /* DUSKWOOD */ - /* DUSTWALLOW MARSH */ UPDATE creature_template SET ScriptName='mobs_risen_husk_spirit' WHERE entry IN (23554,23555); UPDATE creature_template SET ScriptName='npc_ogron' WHERE entry=4983; UPDATE creature_template SET ScriptName='npc_morokk' WHERE entry=4500; UPDATE creature_template SET ScriptName='npc_restless_apparition' WHERE entry=23861; UPDATE creature_template SET ScriptName='npc_private_hendel' WHERE entry=4966; +UPDATE creature_template SET ScriptName='npc_stinky_ignatz' WHERE entry=4880; +UPDATE creature_template SET ScriptName='boss_tethyr' WHERE entry=23899; DELETE FROM scripted_areatrigger WHERE entry=4752; INSERT INTO scripted_areatrigger VALUES (4752,'at_nats_landing'); /* EASTERN PLAGUELANDS */ -UPDATE creature_template SET ScriptName='mobs_ghoul_flayer' WHERE entry IN (8530,8531,8532); -UPDATE creature_template SET ScriptName='npc_darrowshire_spirit' WHERE entry=11064; -UPDATE creature_template SET ScriptName='npc_tirion_fordring' WHERE entry=1855; +UPDATE creature_template SET ScriptName='npc_eris_havenfire' WHERE entry=14494; /* EBON HOLD */ UPDATE creature_template SET ScriptName='npc_death_knight_initiate' WHERE entry=28406; @@ -571,10 +598,15 @@ UPDATE creature_template SET ScriptName='npc_unworthy_initiate_anchor' WHERE ent UPDATE creature_template SET ScriptName='npc_unworthy_initiate' WHERE entry IN (29519,29520,29565,29566,29567); UPDATE gameobject_template SET ScriptName='go_acherus_soul_prison' WHERE entry IN (191577,191580,191581,191582,191583,191584,191585,191586,191587,191588,191589,191590); UPDATE creature_template SET ScriptName='npc_a_special_surprise' WHERE entry IN (29032,29061,29065,29067,29068,29070,29074,29072,29073,29071); -UPDATE creature_template SET ScriptName='npc_koltira_deathweaver' WHERE entry=28912; +UPDATE creature_template SET ScriptName='npc_eye_of_acherus' WHERE entry=28511; +UPDATE creature_template SET ScriptName='npc_scarlet_ghoul' WHERE entry=28845; +UPDATE creature_template SET ScriptName='npc_highlord_darion_mograine' WHERE entry=29173; +UPDATE creature_template SET ScriptName='npc_fellow_death_knight' WHERE entry IN (29199, 29204, 29200); +UPDATE creature_template SET ScriptName='npc_lich_king_light_dawn' WHERE entry=29183; +UPDATE creature_template SET ScriptName='npc_acherus_deathcharger' WHERE entry=28782; +UPDATE creature_template SET ScriptName='npc_scarlet_courier' WHERE entry=29076; /* ELWYNN FOREST */ -UPDATE creature_template SET ScriptName='npc_henze_faulk' WHERE entry=6172; /* EVERSONG WOODS */ UPDATE creature_template SET ScriptName='npc_kelerun_bloodmourn' WHERE entry=17807; @@ -589,14 +621,14 @@ INSERT INTO scripted_event_id VALUES (8328, 'npc_kroshius'); UPDATE creature_template SET ScriptName='npc_kitten' WHERE entry=9937; UPDATE creature_template SET ScriptName='npc_corrupt_saber' WHERE entry=10042; -UPDATE creature_template SET ScriptName='npcs_riverbreeze_and_silversky' WHERE entry IN (9528,9529); UPDATE creature_template SET ScriptName='npc_niby_the_almighty' WHERE entry=14469; UPDATE creature_template SET ScriptName='npc_kroshius' WHERE entry=14467; +UPDATE creature_template SET ScriptName='npc_captured_arkonarin' WHERE entry=11016; +UPDATE creature_template SET ScriptName='npc_arei' WHERE entry=9598; /* FERALAS */ -UPDATE creature_template SET ScriptName='npc_gregan_brewspewer' WHERE entry=7775; UPDATE creature_template SET ScriptName='npc_oox22fe' WHERE entry=7807; -UPDATE creature_template SET ScriptName='npc_screecher_spirit' WHERE entry=8612; +UPDATE creature_template SET ScriptName='npc_shay_leafrunner' WHERE entry=7774; /* GHOSTLANDS */ UPDATE creature_template SET ScriptName='npc_ranger_lilatha' WHERE entry=16295; @@ -605,10 +637,13 @@ UPDATE creature_template SET ScriptName='npc_ranger_lilatha' WHERE entry=16295; UPDATE creature_template SET ScriptName='boss_thermaplugg' WHERE entry=7800; UPDATE gameobject_template SET ScriptName='go_gnomeface_button' WHERE entry BETWEEN 142214 AND 142219; UPDATE creature_template SET ScriptName='npc_blastmaster_emi_shortfuse' WHERE entry=7998; +UPDATE creature_template SET ScriptName='npc_kernobee' WHERE entry=7850; UPDATE instance_template SET ScriptName='instance_gnomeregan' WHERE map=90; /* GRIZZLY HILLS */ UPDATE creature_template SET ScriptName='npc_depleted_war_golem' WHERE entry=27017; +UPDATE creature_template SET ScriptName='npc_harrison_jones' WHERE entry=26814; +UPDATE creature_template SET ScriptName='npc_emily' WHERE entry=26588; /* GRUUL'S LAIR */ UPDATE instance_template SET ScriptName='instance_gruuls_lair' WHERE map =565; @@ -621,12 +656,13 @@ UPDATE creature_template SET ScriptName='boss_olm_the_summoner' WHERE entry=1883 UPDATE creature_template SET ScriptName='boss_krosh_firehand' WHERE entry=18832; /* GUNDRAK */ -UPDATE creature_template SET ScriptName='boss_colossus' WHERE entry=29307; +UPDATE creature_template SET ScriptName='boss_drakkari_colossus' WHERE entry=29307; +UPDATE creature_template SET ScriptName='boss_drakkari_elemental' WHERE entry=29573; +UPDATE creature_template SET ScriptName='npc_living_mojo' WHERE entry=29830; UPDATE creature_template SET ScriptName='boss_eck' WHERE entry=29932; UPDATE creature_template SET ScriptName='boss_galdarah' WHERE entry=29306; UPDATE creature_template SET ScriptName='boss_moorabi' WHERE entry=29305; UPDATE creature_template SET ScriptName='boss_sladran' WHERE entry=29304; -UPDATE creature_template SET ScriptName='mob_sladran_summon_target' WHERE entry=29682; UPDATE gameobject_template SET ScriptName='go_gundrak_altar' WHERE entry IN (192518, 192519, 192520); UPDATE instance_template SET ScriptName='instance_gundrak' WHERE map=604; @@ -668,36 +704,75 @@ UPDATE gameobject_template SET ScriptName='go_manticron_cube' WHERE entry=181713 UPDATE creature_template SET ScriptName='boss_magtheridon' WHERE entry=17257; UPDATE creature_template SET ScriptName='mob_abyssal' WHERE entry=17454; UPDATE creature_template SET ScriptName='mob_hellfire_channeler' WHERE entry=17256; +UPDATE creature_template SET ScriptName='npc_target_trigger' WHERE entry=17474; /* HELLFIRE PENINSULA */ UPDATE creature_template SET ScriptName='boss_doomlord_kazzak' WHERE entry=18728; UPDATE creature_template SET ScriptName='npc_aeranas' WHERE entry=17085; UPDATE creature_template SET ScriptName='npc_ancestral_wolf' WHERE entry=17077; UPDATE creature_template SET ScriptName='npc_demoniac_scryer' WHERE entry=22258; -UPDATE creature_template SET ScriptName='npc_tracy_proudwell' WHERE entry=18266; UPDATE creature_template SET ScriptName='npc_wounded_blood_elf' WHERE entry=16993; +UPDATE creature_template SET ScriptName='npc_fel_guard_hound' WHERE entry=21847; +UPDATE creature_template SET ScriptName='npc_anchorite_barada' WHERE entry=22431; +UPDATE creature_template SET ScriptName='npc_colonel_jules' WHERE entry=22432; +UPDATE creature_template SET ScriptName='npc_magister_aledis' WHERE entry=20159; /* HILLSBRAD FOOTHILLS */ - /* HINTERLANDS */ UPDATE creature_template SET ScriptName='npc_00x09hl' WHERE entry=7806; UPDATE creature_template SET ScriptName='npc_rinji' WHERE entry=7780; /* HOWLING FJORD */ -DELETE FROM scripted_areatrigger WHERE entry=4778; -INSERT INTO scripted_areatrigger VALUES (4778,'at_ancient_male_vrykul'); +DELETE FROM scripted_areatrigger WHERE entry IN (4778,4779); +INSERT INTO scripted_areatrigger VALUES +(4778,'at_ancient_male_vrykul'), +(4779,'at_nifflevar'); UPDATE creature_template SET ScriptName='npc_ancient_male_vrykul' WHERE entry=24314; UPDATE creature_template SET ScriptName='npc_daegarn' WHERE entry=24151; -UPDATE creature_template SET ScriptName='npc_deathstalker_razael' WHERE entry=23998; -UPDATE creature_template SET ScriptName='npc_dark_ranger_lyana' WHERE entry=23778; -UPDATE creature_template SET ScriptName='npc_greer_orehammer' WHERE entry=23859; UPDATE creature_template SET ScriptName='npc_silvermoon_harry' WHERE entry=24539; +UPDATE creature_template SET ScriptName='npc_lich_king_village' WHERE entry=24248; +UPDATE creature_template SET ScriptName='npc_king_ymiron' WHERE entry=24321; +UPDATE creature_template SET ScriptName='npc_firecrackers_bunny' WHERE entry=24230; +UPDATE creature_template SET ScriptName='npc_apothecary_hanes' WHERE entry=23784; +UPDATE creature_template SET ScriptName='npc_scalawag_frog' WHERE entry=26503; /* */ /* ICECROWN CITADEL */ /* */ +/* ICECROWN CITADEL */ +UPDATE instance_template SET ScriptName='instance_icecrown_citadel' WHERE map=631; +UPDATE creature_template SET ScriptName='boss_lord_marrowgar' WHERE entry=36612; +UPDATE creature_template SET ScriptName='npc_bone_spike' WHERE entry IN (36619,38711,38712); +UPDATE creature_template SET ScriptName='npc_coldflame' WHERE entry=36672; +UPDATE creature_template SET ScriptName='boss_lady_deathwhisper' WHERE entry=36855; +UPDATE creature_template SET ScriptName='boss_deathbringer_saurfang' WHERE entry=37813; +UPDATE creature_template SET ScriptName='npc_queen_lanathel_intro' WHERE entry=38004; +UPDATE creature_template SET ScriptName='npc_blood_orb_control' WHERE entry=38008; +UPDATE creature_template SET ScriptName='npc_ball_of_flame' WHERE entry IN (38332,38451); +UPDATE creature_template SET ScriptName='npc_kinetic_bomb' WHERE entry=38454; +UPDATE creature_template SET ScriptName='npc_dark_nucleus' WHERE entry=38369; +UPDATE creature_template SET ScriptName='boss_taldaram_icc' WHERE entry=37973; +UPDATE creature_template SET ScriptName='boss_keleseth_icc' WHERE entry=37972; +UPDATE creature_template SET ScriptName='boss_valanar_icc' WHERE entry=37970; +UPDATE creature_template SET ScriptName='boss_blood_queen_lanathel' WHERE entry=37955; +UPDATE creature_template SET ScriptName='boss_sindragosa' WHERE entry=36853; +UPDATE creature_template SET ScriptName='npc_rimefang_icc' WHERE entry=37533; +UPDATE creature_template SET ScriptName='npc_spinestalker_icc' WHERE entry=37534; +UPDATE creature_template SET ScriptName='mob_frost_bomb' WHERE entry=37186; +UPDATE creature_template SET ScriptName='boss_festergut' WHERE entry=36626; +UPDATE creature_template SET ScriptName='boss_rotface' WHERE entry=36627; +UPDATE creature_template SET ScriptName='mob_little_ooze' WHERE entry=36897; +UPDATE creature_template SET ScriptName='mob_big_ooze' WHERE entry=36899; +UPDATE creature_template SET ScriptName='boss_valithria_dreamwalker' WHERE entry=36789; +UPDATE creature_template SET ScriptName='boss_professor_putricide' WHERE entry=36678; +UPDATE creature_template SET ScriptName='boss_the_lich_king_icc' WHERE entry=36597; +DELETE FROM scripted_event_id WHERE id IN (23426,23438); +INSERT INTO scripted_event_id VALUES +(23426,'event_gameobject_citadel_valve'), +(23438,'event_gameobject_citadel_valve'); + /* FORGE OF SOULS */ UPDATE creature_template SET ScriptName='boss_bronjahm' WHERE entry=36497; UPDATE creature_template SET ScriptName='npc_corrupted_soul_fragment' WHERE entry=36535; @@ -705,16 +780,31 @@ UPDATE creature_template SET ScriptName='boss_devourer_of_souls' WHERE entry=365 UPDATE instance_template SET ScriptName='instance_forge_of_souls' WHERE map=632; /* HALLS OF REFLECTION */ +UPDATE instance_template SET ScriptName='instance_halls_of_reflection' WHERE map=668; /* PIT OF SARON */ UPDATE instance_template SET ScriptName='instance_pit_of_saron' WHERE map=658; UPDATE creature_template SET ScriptName='boss_forgemaster_garfrost' WHERE entry=36494; +UPDATE creature_template SET ScriptName='boss_krick' WHERE entry=36477; +UPDATE creature_template SET ScriptName='boss_ick' WHERE entry=36476; +UPDATE creature_template SET ScriptName='npc_exploding_orb' WHERE entry=36610; +UPDATE creature_template SET ScriptName='npc_ymirjar_deathbringer' WHERE entry=36892; +UPDATE creature_template SET ScriptName='npc_collapsing_icicle' WHERE entry=36847; +UPDATE creature_template SET ScriptName='boss_tyrannus' WHERE entry=36658; +UPDATE creature_template SET ScriptName='boss_rimefang_pos' WHERE entry=36661; +DELETE FROM scripted_areatrigger WHERE entry IN (5578,5581); +INSERT INTO scripted_areatrigger VALUES +(5578,'at_pit_of_saron'), +(5581,'at_pit_of_saron'); /* ICECROWN */ -UPDATE creature_template SET ScriptName='npc_dame_evniki_kapsalis' WHERE entry=34885; +UPDATE creature_template SET ScriptName='npc_squad_leader' WHERE entry IN (31737,31833); +UPDATE creature_template SET ScriptName='npc_infantry' WHERE entry IN (31701,31832); +UPDATE creature_template SET ScriptName='npc_father_kamaros' WHERE entry IN (31279,32800); +UPDATE creature_template SET ScriptName='npc_saronite_mine_slave' WHERE entry=31397; +UPDATE creature_template SET ScriptName='npc_grand_admiral_westwind' WHERE entry=29621; /* IRONFORGE */ -UPDATE creature_template SET ScriptName='npc_royal_historian_archesonus' WHERE entry=8879; /* ISLE OF QUEL'DANAS */ UPDATE creature_template SET ScriptName='npc_converted_sentry' WHERE entry=24981; @@ -722,7 +812,7 @@ UPDATE creature_template SET ScriptName='npc_converted_sentry' WHERE entry=24981 /* KARAZHAN */ UPDATE instance_template SET ScriptName='instance_karazhan' WHERE map=532; UPDATE creature_template SET ScriptName='boss_midnight' WHERE entry=16151; -UPDATE creature_template SET ScriptName='boss_attumen' WHERE entry=15550; +UPDATE creature_template SET ScriptName='boss_attumen' WHERE entry IN (15550,16152); UPDATE creature_template SET ScriptName='boss_moroes' WHERE entry=15687; UPDATE creature_template SET ScriptName='boss_maiden_of_virtue' WHERE entry=16457; UPDATE creature_template SET ScriptName='boss_curator' WHERE entry=15691; @@ -731,29 +821,41 @@ UPDATE creature_template SET ScriptName='boss_romulo' WHERE entry=17533; UPDATE creature_template SET ScriptName='boss_dorothee' WHERE entry=17535; UPDATE creature_template SET ScriptName='boss_strawman' WHERE entry=17543; UPDATE creature_template SET ScriptName='boss_tinhead' WHERE entry=17547; -UPDATE creature_template SET ScriptName='mob_tito' WHERE entry=17548; UPDATE creature_template SET ScriptName='boss_roar' WHERE entry=17546; UPDATE creature_template SET ScriptName='boss_crone' WHERE entry=18168; UPDATE creature_template SET ScriptName='boss_terestian_illhoof' WHERE entry=15688; UPDATE creature_template SET ScriptName='boss_shade_of_aran' WHERE entry=16524; UPDATE creature_template SET ScriptName='boss_netherspite' WHERE entry=15689; UPDATE creature_template SET ScriptName='boss_malchezaar' WHERE entry=15690; --- UPDATE creature_template SET ScriptName='boss_nightbane' WHERE entry=17225; -UPDATE creature_template SET ScriptName='boss_baroness_dorothea_millstipe' WHERE entry=19875; -UPDATE creature_template SET ScriptName='boss_baron_rafe_dreuger' WHERE entry=19874; -UPDATE creature_template SET ScriptName='boss_lady_catriona_von_indi' WHERE entry=19872; -UPDATE creature_template SET ScriptName='boss_lady_keira_berrybuck' WHERE entry=17007; -UPDATE creature_template SET ScriptName='boss_lord_robin_daris' WHERE entry=19876; -UPDATE creature_template SET ScriptName='boss_lord_crispin_ference' WHERE entry=19873; +UPDATE creature_template SET ScriptName='boss_nightbane' WHERE entry=17225; UPDATE creature_template SET ScriptName='boss_bigbadwolf' WHERE entry=17521; -UPDATE creature_template SET ScriptName='mob_aran_elemental' WHERE entry=17167; UPDATE creature_template SET ScriptName='mob_demon_chain' WHERE entry=17248; UPDATE creature_template SET ScriptName='npc_fiendish_portal' WHERE entry=17265; -UPDATE creature_template SET ScriptName='mob_cyclone' WHERE entry=18412; -UPDATE creature_template SET ScriptName='netherspite_infernal' WHERE entry=17646; +UPDATE creature_template SET ScriptName='npc_shade_of_aran_blizzard' WHERE entry=17161; +UPDATE creature_template SET ScriptName='npc_netherspite_portal' WHERE entry IN (17367,17368,17369); +UPDATE creature_template SET ScriptName='npc_infernal_target' WHERE entry=17644; UPDATE creature_template SET ScriptName='npc_berthold' WHERE entry=16153; UPDATE creature_template SET ScriptName='npc_barnes' WHERE entry=16812; UPDATE creature_template SET ScriptName='npc_grandmother' WHERE entry=17603; +UPDATE creature_template SET ScriptName='npc_image_of_medivh' WHERE entry=17651; +UPDATE creature_template SET ScriptName='npc_image_arcanagos' WHERE entry=17652; +UPDATE creature_template SET ScriptName='npc_echo_of_medivh' WHERE entry=16816; +UPDATE creature_template SET ScriptName='npc_king_llane' WHERE entry=21684; +UPDATE creature_template SET ScriptName='npc_warchief_blackhand' WHERE entry=21752; +UPDATE creature_template SET ScriptName='npc_human_conjurer' WHERE entry=21683; +UPDATE creature_template SET ScriptName='npc_orc_warlock' WHERE entry=21750; +UPDATE creature_template SET ScriptName='npc_human_footman' WHERE entry=17211; +UPDATE creature_template SET ScriptName='npc_orc_grunt' WHERE entry=17469; +UPDATE creature_template SET ScriptName='npc_water_elemental' WHERE entry=21160; +UPDATE creature_template SET ScriptName='npc_summoned_daemon' WHERE entry=21726; +UPDATE creature_template SET ScriptName='npc_human_charger' WHERE entry=21664; +UPDATE creature_template SET ScriptName='npc_orc_wolf' WHERE entry=21748; +UPDATE creature_template SET ScriptName='npc_human_cleric' WHERE entry=21682; +UPDATE creature_template SET ScriptName='npc_orc_necrolyte' WHERE entry=21747; +DELETE FROM scripted_event_id WHERE id IN (10591,10951); +INSERT INTO scripted_event_id VALUES +(10591,'event_spell_summon_nightbane'), +(10951,'event_spell_medivh_journal'); /* LOCH MODAN */ UPDATE creature_template SET ScriptName='npc_mountaineer_pebblebitty' WHERE entry=3836; @@ -766,26 +868,25 @@ UPDATE creature_template SET ScriptName='mob_fel_crystal' WHERE entry=24722; UPDATE creature_template SET ScriptName='boss_vexallus' WHERE entry=24744; UPDATE creature_template SET ScriptName='mob_pure_energy' WHERE entry=24745; UPDATE creature_template SET ScriptName='boss_priestess_delrissa' WHERE entry=24560; -UPDATE creature_template SET ScriptName='boss_kagani_nightstrike' WHERE entry=24557; -UPDATE creature_template SET ScriptName='boss_ellris_duskhallow' WHERE entry=24558; -UPDATE creature_template SET ScriptName='boss_eramas_brightblaze' WHERE entry=24554; -UPDATE creature_template SET ScriptName='boss_yazzai' WHERE entry=24561; -UPDATE creature_template SET ScriptName='boss_warlord_salaris' WHERE entry=24559; -UPDATE creature_template SET ScriptName='boss_garaxxas' WHERE entry=24555; --- UPDATE creature_template SET ScriptName='mob_sliver' WHERE entry=24552; -UPDATE creature_template SET ScriptName='boss_apoko' WHERE entry=24553; -UPDATE creature_template SET ScriptName='boss_zelfan' WHERE entry=24556; +UPDATE creature_template SET ScriptName='npc_kagani_nightstrike' WHERE entry=24557; +UPDATE creature_template SET ScriptName='npc_ellris_duskhallow' WHERE entry=24558; +UPDATE creature_template SET ScriptName='npc_eramas_brightblaze' WHERE entry=24554; +UPDATE creature_template SET ScriptName='npc_yazzai' WHERE entry=24561; +UPDATE creature_template SET ScriptName='npc_warlord_salaris' WHERE entry=24559; +UPDATE creature_template SET ScriptName='npc_garaxxas' WHERE entry=24555; +UPDATE creature_template SET ScriptName='npc_apoko' WHERE entry=24553; +UPDATE creature_template SET ScriptName='npc_zelfan' WHERE entry=24556; UPDATE creature_template SET ScriptName='boss_felblood_kaelthas' WHERE entry=24664; UPDATE creature_template SET ScriptName='mob_arcane_sphere' WHERE entry=24708; UPDATE creature_template SET ScriptName='mob_felkael_phoenix' WHERE entry=24674; UPDATE creature_template SET ScriptName='mob_felkael_phoenix_egg' WHERE entry=24675; -UPDATE creature_template SET ScriptName='npc_kalecgos' WHERE entry IN (24844, 24848); +UPDATE creature_template SET ScriptName='npc_kalecgos' WHERE entry=24844; +DELETE FROM scripted_event_id WHERE id=16547; +INSERT INTO scripted_event_id VALUES +(16547,'event_go_scrying_orb'); /* MARAUDON */ -UPDATE creature_template SET ScriptName='boss_princess_theradras' WHERE entry=12201; UPDATE creature_template SET ScriptName='boss_noxxion' WHERE entry=13282; -UPDATE creature_template SET ScriptName='boss_landslide' WHERE entry=12203; -UPDATE creature_template SET ScriptName='celebras_the_cursed' WHERE entry=12225; /* MOLTEN CORE */ UPDATE instance_template SET ScriptName='instance_molten_core' WHERE map=409; @@ -804,23 +905,18 @@ UPDATE creature_template SET ScriptName='mob_core_rager' WHERE entry=11672; UPDATE creature_template SET ScriptName='mob_flamewaker_priest' WHERE entry=11662; /* MOONGLADE */ -UPDATE creature_template SET ScriptName='npc_bunthen_plainswind' WHERE entry=11798; UPDATE creature_template SET ScriptName='npc_clintar_dw_spirit' WHERE entry=22916; -UPDATE creature_template SET ScriptName='npc_great_bear_spirit' WHERE entry=11956; -UPDATE creature_template SET ScriptName='npc_silva_filnaveth' WHERE entry=11800; UPDATE creature_template SET ScriptName='npc_keeper_remulos' WHERE entry=11832; UPDATE creature_template SET ScriptName='boss_eranikus' WHERE entry=15491; /* MULGORE */ UPDATE creature_template SET ScriptName='npc_kyle_the_frenzied' WHERE entry=23616; -UPDATE creature_template SET ScriptName='npc_skorn_whitecloud' WHERE entry=3052; /* NAGRAND */ UPDATE creature_template SET ScriptName='mob_lump' WHERE entry=18351; -UPDATE creature_template SET ScriptName='npc_altruis_the_sufferer' WHERE entry=18417; -UPDATE creature_template SET ScriptName='npc_greatmother_geyah' WHERE entry=18141; -UPDATE creature_template SET ScriptName='npc_maghar_captive' WHERE entry=18210; +UPDATE creature_template SET ScriptName='npc_nagrand_captive' WHERE entry IN (18209,18210); UPDATE creature_template SET ScriptName='npc_creditmarker_visit_with_ancestors' WHERE entry IN (18840,18841,18842,18843); +UPDATE creature_template SET ScriptName='npc_rethhedron' WHERE entry=22357; /* NAXXRAMAS */ UPDATE instance_template SET ScriptName='instance_naxxramas' WHERE map=533; @@ -846,6 +942,7 @@ UPDATE creature_template SET ScriptName='boss_stalagg' WHERE entry=15929; UPDATE creature_template SET ScriptName='boss_feugen' WHERE entry=15930; UPDATE creature_template SET ScriptName='npc_tesla_coil' WHERE entry=16218; UPDATE creature_template SET ScriptName='boss_sapphiron' WHERE entry=15989; +UPDATE gameobject_template SET ScriptName='go_sapphiron_birth' WHERE entry=181356; UPDATE creature_template SET ScriptName='boss_kelthuzad' WHERE entry=15990; /* NETHERSTORM */ @@ -854,22 +951,33 @@ INSERT INTO scripted_areatrigger VALUES (4497,'at_commander_dawnforge'); UPDATE gameobject_template SET ScriptName='go_manaforge_control_console' WHERE entry IN (183770,183956,184311,184312); UPDATE creature_template SET ScriptName='npc_manaforge_control_console' WHERE entry IN (20209,20417,20418,20440); UPDATE creature_template SET ScriptName='npc_commander_dawnforge' WHERE entry=19831; -UPDATE creature_template SET ScriptName='npc_protectorate_nether_drake' WHERE entry=20903; UPDATE creature_template SET ScriptName='npc_bessy' WHERE entry=20415; UPDATE creature_template SET ScriptName='npc_maxx_a_million' WHERE entry=19589; UPDATE creature_template SET ScriptName='npc_zeppit' WHERE entry=22484; +UPDATE creature_template SET ScriptName='npc_protectorate_demolitionist' WHERE entry=20802; +UPDATE creature_template SET ScriptName='npc_captured_vanguard' WHERE entry=20763; +UPDATE creature_template SET ScriptName='npc_drijya' WHERE entry=20281; +UPDATE creature_template SET ScriptName='npc_dimensius' WHERE entry=19554; /* */ /* THE NEXUS */ /* */ /* EYE OF ETERNITY */ +UPDATE instance_template SET ScriptName='instance_eye_of_eternity' WHERE map=616; +UPDATE creature_template SET ScriptName='boss_malygos' WHERE entry=28859; +UPDATE creature_template SET ScriptName='npc_power_spark' WHERE entry=30084; +UPDATE creature_template SET ScriptName='npc_wyrmrest_skytalon' WHERE entry=30161; +DELETE FROM scripted_event_id WHERE id=20711; +INSERT INTO scripted_event_id VALUES +(20711,'event_go_focusing_iris'); /* NEXUS */ UPDATE creature_template SET ScriptName='boss_anomalus' WHERE entry=26763; UPDATE creature_template SET ScriptName='mob_chaotic_rift' WHERE entry=26918; UPDATE creature_template SET ScriptName='boss_keristrasza' WHERE entry=26723; UPDATE creature_template SET ScriptName='boss_ormorok' WHERE entry=26794; +UPDATE creature_template SET ScriptName='npc_crystal_spike_trigger' WHERE entry IN (27101, 27079); UPDATE creature_template SET ScriptName='boss_telestra' WHERE entry=26731; UPDATE gameobject_template SET ScriptName='go_containment_sphere' WHERE entry IN (188526, 188527, 188528); UPDATE instance_template SET ScriptName='instance_nexus' WHERE map=576; @@ -878,6 +986,18 @@ UPDATE instance_template SET ScriptName='instance_nexus' WHERE map=576; UPDATE instance_template SET ScriptName='instance_oculus' WHERE map=578; UPDATE creature_template SET ScriptName='boss_eregos' WHERE entry=27656; UPDATE creature_template SET ScriptName='boss_urom' WHERE entry=27655; +UPDATE creature_template SET ScriptName='boss_varos' WHERE entry=27447; +UPDATE creature_template SET ScriptName='npc_azure_ring_captain' WHERE entry=28236; +UPDATE creature_template SET ScriptName='npc_arcane_beam' WHERE entry=28239; +UPDATE creature_template SET ScriptName='npc_centrifuge_core' WHERE entry=28183; +UPDATE creature_template SET ScriptName='npc_planar_anomaly' WHERE entry=30879; +UPDATE creature_template SET ScriptName='npc_oculus_drake' WHERE entry IN (27756, 27692, 27755); +DELETE FROM scripted_event_id WHERE id IN (10665,12229,18454,18455); +INSERT INTO scripted_event_id VALUES +(10665,'event_spell_call_captain'), +(12229,'event_spell_call_captain'), +(18454,'event_spell_call_captain'), +(18455,'event_spell_call_captain'); /* OBSIDIAN SANCTUM */ UPDATE instance_template SET ScriptName='instance_obsidian_sanctum' WHERE map=615; @@ -885,10 +1005,10 @@ UPDATE creature_template SET ScriptName='boss_sartharion' WHERE entry=28860; UPDATE creature_template SET ScriptName='mob_vesperon' WHERE entry=30449; UPDATE creature_template SET ScriptName='mob_shadron' WHERE entry=30451; UPDATE creature_template SET ScriptName='mob_tenebron' WHERE entry=30452; -UPDATE creature_template SET ScriptName='mob_twilight_eggs' WHERE entry=30882; -UPDATE creature_template SET ScriptName='mob_twilight_whelp' WHERE entry IN (30890, 31214); -UPDATE creature_template SET ScriptName='mob_acolyte_of_shadron' WHERE entry=31218; -UPDATE creature_template SET ScriptName='mob_acolyte_of_vesperon' WHERE entry=31219; +UPDATE creature_template SET ScriptName='mob_twilight_eggs' WHERE entry IN (30882,31204); +UPDATE creature_template SET ScriptName='npc_tenebron_egg_controller' WHERE entry=31138; +UPDATE creature_template SET ScriptName='npc_flame_tsunami' WHERE entry=30616; +UPDATE creature_template SET ScriptName='npc_fire_cyclone' WHERE entry=30648; /* ONYXIA'S LAIR */ UPDATE instance_template SET ScriptName='instance_onyxias_lair' WHERE map=249; @@ -900,18 +1020,29 @@ UPDATE creature_template SET ScriptName='npc_thrall_warchief' WHERE entry=4949; /* RAGEFIRE CHASM */ - /* RAZORFEN DOWNS */ -UPDATE creature_template SET ScriptName='boss_amnennar_the_coldbringer' WHERE entry=7358; +UPDATE instance_template SET ScriptName='instance_razorfen_downs' WHERE map=129; UPDATE creature_template SET ScriptName='npc_belnistrasz' WHERE entry=8516; +DELETE FROM scripted_event_id WHERE id=3130; +INSERT INTO scripted_event_id VALUES (3130, 'event_go_tutenkash_gong'); /* RAZORFEN KRAUL */ UPDATE instance_template SET ScriptName='instance_razorfen_kraul' WHERE map=47; UPDATE creature_template SET ScriptName='npc_willix_the_importer' WHERE entry=4508; +UPDATE creature_template SET ScriptName='npc_snufflenose_gopher' WHERE entry=4781; /* REDRIDGE MOUNTAINS */ UPDATE creature_template SET ScriptName='npc_corporal_keeshan' WHERE entry=349; +/* RUBY SANCTUM */ +UPDATE instance_template SET ScriptName='instance_ruby_sanctum' WHERE map=724; +UPDATE creature_template SET ScriptName='boss_baltharus' WHERE entry=39751; +UPDATE creature_template SET ScriptName='boss_saviana' WHERE entry=39747; +UPDATE creature_template SET ScriptName='boss_zarithrian' WHERE entry=39746; +UPDATE creature_template SET ScriptName='npc_baltharus_clone' WHERE entry=39899; +UPDATE creature_template SET ScriptName='boss_halion_real' WHERE entry=39863; +UPDATE creature_template SET ScriptName='boss_halion_twilight' WHERE entry=40142; + /* RUINS OF AHN'QIRAJ */ UPDATE instance_template SET ScriptName='instance_ruins_of_ahnqiraj' WHERE map=509; UPDATE creature_template SET ScriptName='mob_anubisath_guardian' WHERE entry=15355; @@ -923,30 +1054,23 @@ UPDATE gameobject_template SET ScriptName='go_ossirian_crystal' WHERE entry=1806 UPDATE creature_template SET ScriptName='npc_hive_zara_larva' WHERE entry=15555; UPDATE creature_template SET ScriptName='boss_buru' WHERE entry=15370; UPDATE creature_template SET ScriptName='npc_buru_egg' WHERE entry=15514; +UPDATE creature_template SET ScriptName='npc_general_andorov' WHERE entry=15471; +UPDATE creature_template SET ScriptName='npc_kaldorei_elite' WHERE entry=15473; /* SCARLET MONASTERY */ UPDATE instance_template SET ScriptName='instance_scarlet_monastery' WHERE map=189; UPDATE creature_template SET ScriptName='boss_arcanist_doan' WHERE entry=6487; -UPDATE creature_template SET ScriptName='boss_azshir_the_sleepless' WHERE entry=6490; -UPDATE creature_template SET ScriptName='boss_bloodmage_thalnos' WHERE entry=4543; UPDATE creature_template SET ScriptName='boss_herod' WHERE entry=3975; -UPDATE creature_template SET ScriptName='boss_high_inquisitor_fairbanks' WHERE entry=4542; UPDATE creature_template SET ScriptName='boss_high_inquisitor_whitemane' WHERE entry=3977; -UPDATE creature_template SET ScriptName='boss_houndmaster_loksey' WHERE entry=3974; -UPDATE creature_template SET ScriptName='boss_interrogator_vishas' WHERE entry=3983; UPDATE creature_template SET ScriptName='boss_scarlet_commander_mograine' WHERE entry=3976; -UPDATE creature_template SET ScriptName='boss_scorn' WHERE entry=14693; UPDATE creature_template SET ScriptName='mob_scarlet_trainee' WHERE entry=6575; UPDATE creature_template SET ScriptName='boss_headless_horseman' WHERE entry=23682; +UPDATE creature_template SET ScriptName='boss_head_of_horseman' WHERE entry=23775; /* SCHOLOMANCE */ UPDATE instance_template SET ScriptName='instance_scholomance' WHERE map=289; UPDATE creature_template SET ScriptName='boss_darkmaster_gandling' WHERE entry=1853; -UPDATE creature_template SET ScriptName='boss_death_knight_darkreaver' WHERE entry=14516; -UPDATE creature_template SET ScriptName='boss_vectus' WHERE entry=10432; UPDATE creature_template SET ScriptName='boss_jandice_barov' WHERE entry=10503; -UPDATE creature_template SET ScriptName='boss_kormok' WHERE entry=16118; -UPDATE creature_template SET ScriptName='mob_illusionofjandicebarov' WHERE entry=11439; DELETE FROM scripted_event_id WHERE id IN (5618, 5619, 5620, 5621, 5622, 5623); INSERT INTO scripted_event_id VALUES (5618,'event_spell_gandling_shadow_portal'), @@ -957,6 +1081,7 @@ INSERT INTO scripted_event_id VALUES (5623,'event_spell_gandling_shadow_portal'); /* SEARING GORGE */ +UPDATE creature_template SET ScriptName='npc_dorius_stonetender' WHERE entry=8284; /* SHADOWFANG KEEP */ UPDATE instance_template SET ScriptName='instance_shadowfang_keep' WHERE map=33; @@ -970,11 +1095,9 @@ UPDATE creature_template SET ScriptName='npc_valentine_boss_manager' WHERE entry /* SHADOWMOON VALLEY */ UPDATE creature_template SET ScriptName='boss_doomwalker' WHERE entry=17711; -UPDATE creature_template SET ScriptName='npc_drake_dealer_hurlunk' WHERE entry=23489; UPDATE creature_template SET ScriptName='npc_dragonmaw_peon' WHERE entry=22252; UPDATE creature_template SET ScriptName='mob_mature_netherwing_drake' WHERE entry=21648; UPDATE creature_template SET ScriptName='mob_enslaved_netherwing_drake' WHERE entry=21722; -UPDATE creature_template SET ScriptName='npc_karynaku' WHERE entry=22112; UPDATE creature_template SET ScriptName='npc_wilda' WHERE entry=21027; UPDATE creature_template SET ScriptName='mob_torloth' WHERE entry=22076; UPDATE creature_template SET ScriptName='npc_totem_of_spirits' WHERE entry=21071; @@ -987,26 +1110,28 @@ INSERT INTO scripted_event_id VALUES UPDATE creature_template SET ScriptName='npc_lord_illidan_stormrage' WHERE entry=22083; UPDATE gameobject_template SET ScriptName='go_crystal_prison' WHERE entry=185126; UPDATE creature_template SET ScriptName='npc_spawned_oronok_tornheart' WHERE entry=21685; +UPDATE creature_template SET ScriptName='npc_domesticated_felboar' WHERE entry=21195; +UPDATE creature_template SET ScriptName='npc_shadowmoon_tuber_node' WHERE entry=21347; +UPDATE creature_template SET ScriptName='npc_veneratus_spawn_node' WHERE entry=21334; /* SHATTRATH */ UPDATE creature_template SET ScriptName='npc_dirty_larry' WHERE entry=19720; UPDATE creature_template SET ScriptName='npc_khadgars_servant' WHERE entry=19685; UPDATE creature_template SET ScriptName='npc_salsalabim' WHERE entry=18584; -UPDATE creature_template SET ScriptName='npc_shattrathflaskvendors' WHERE entry IN (23483,23484); /* SHOLAZAR BASIN */ UPDATE creature_template SET ScriptName='npc_helice' WHERE entry=28787; UPDATE creature_template SET ScriptName='npc_injured_rainspeaker' WHERE entry=28217; UPDATE creature_template SET ScriptName='npc_mosswalker_victim' WHERE entry=28113; +UPDATE creature_template SET ScriptName='npc_tipsy_mcmanus' WHERE entry=28566; +UPDATE creature_template SET ScriptName='npc_wants_fruit_credit' WHERE entry IN (28535,28536,28537); +UPDATE gameobject_template SET ScriptName='go_quest_still_at_it_credit' WHERE entry IN (190635,190636); /* SILITHUS */ -UPDATE creature_template SET ScriptName='npc_highlord_demitrian' WHERE entry=14347; -UPDATE creature_template SET ScriptName='npcs_rutgar_and_frankal' WHERE entry IN (15170,15171); UPDATE creature_template SET ScriptName='npc_anachronos_the_ancient' WHERE entry=15381; UPDATE gameobject_template SET ScriptName='go_crystalline_tear' WHERE entry=180633; /* SILVERMOON */ -UPDATE creature_template SET ScriptName='npc_blood_knight_stillblade' WHERE entry=17768; /* SILVERPINE FOREST */ UPDATE creature_template SET ScriptName='npc_deathstalker_erland' WHERE entry=1978; @@ -1015,15 +1140,19 @@ UPDATE creature_template SET ScriptName='npc_deathstalker_faerleia' WHERE entry= /* STOCKADES */ /* STONETALON MOUNTAINS */ -UPDATE creature_template SET ScriptName='npc_braug_dimspirit' WHERE entry=4489; UPDATE creature_template SET ScriptName='npc_kaya' WHERE entry=11856; /* STORM PEAKS */ +UPDATE creature_template SET ScriptName='npc_floating_spirit' WHERE entry IN (30141,30143,30145); +UPDATE creature_template SET ScriptName='npc_restless_frostborn' WHERE entry IN (29974,30135,30144); +UPDATE creature_template SET ScriptName='npc_injured_miner' WHERE entry=29434; /* STORMWIND CITY */ UPDATE creature_template SET ScriptName='npc_bartleby' WHERE entry=6090; UPDATE creature_template SET ScriptName='npc_dashel_stonefist' WHERE entry=4961; UPDATE creature_template SET ScriptName='npc_lady_katrana_prestor' WHERE entry=1749; +UPDATE creature_template SET ScriptName='npc_squire_rowe' WHERE entry=17804; +UPDATE creature_template SET ScriptName='npc_reginald_windsor' WHERE entry =12580; /* STRANGLETHORN VALE */ UPDATE creature_template SET ScriptName='mob_yenniku' WHERE entry=2530; @@ -1031,19 +1160,12 @@ UPDATE creature_template SET ScriptName='mob_yenniku' WHERE entry=2530; /* STRATHOLME */ UPDATE instance_template SET ScriptName='instance_stratholme' WHERE map=329; UPDATE creature_template SET ScriptName='boss_dathrohan_balnazzar' WHERE entry=10812; -UPDATE creature_template SET ScriptName='boss_magistrate_barthilas' WHERE entry=10435; UPDATE creature_template SET ScriptName='boss_maleki_the_pallid' WHERE entry=10438; -UPDATE creature_template SET ScriptName='boss_nerubenkan' WHERE entry=10437; UPDATE creature_template SET ScriptName='boss_cannon_master_willey' WHERE entry=10997; UPDATE creature_template SET ScriptName='boss_baroness_anastari' WHERE entry=10436; -UPDATE creature_template SET ScriptName='boss_ramstein_the_gorger' WHERE entry=10439; -UPDATE creature_template SET ScriptName='boss_timmy_the_cruel' WHERE entry=10808; UPDATE creature_template SET ScriptName='boss_silver_hand_bosses' WHERE entry IN (17910,17911,17912,17913,17914); -UPDATE creature_template SET ScriptName='boss_postmaster_malown' WHERE entry=11143; -UPDATE creature_template SET ScriptName='boss_baron_rivendare' WHERE entry=10440; UPDATE creature_template SET ScriptName='mobs_spectral_ghostly_citizen' WHERE entry IN (10384,10385); UPDATE creature_template SET ScriptName='mob_restless_soul' WHERE entry=11122; -UPDATE creature_template SET ScriptName='mob_freed_soul' WHERE entry=11136; UPDATE gameobject_template SET ScriptName='go_gauntlet_gate' WHERE entry=175357; UPDATE gameobject_template SET ScriptName='go_service_gate' WHERE entry=175368; UPDATE gameobject_template SET ScriptName='go_stratholme_postbox' WHERE entry IN (176346,176349,176350,176351,176352,176353); @@ -1081,11 +1203,15 @@ UPDATE creature_template SET ScriptName='npc_shadow_image' WHERE entry=25214; UPDATE creature_template SET ScriptName='boss_muru' WHERE entry=25741; UPDATE creature_template SET ScriptName='boss_entropius' WHERE entry=25840; UPDATE creature_template SET ScriptName='npc_portal_target' WHERE entry=25770; -UPDATE creature_template SET ScriptName='npc_void_sentinel_summoner' WHERE entry=25782; UPDATE creature_template SET ScriptName='boss_kiljaeden' WHERE entry=25315; UPDATE creature_template SET ScriptName='npc_kiljaeden_controller' WHERE entry=25608; UPDATE creature_template SET ScriptName='spell_dummy_npc_brutallus_cloud' WHERE entry=25703; UPDATE creature_template SET ScriptName='boss_felmyst' WHERE entry=25038; +UPDATE creature_template SET ScriptName='npc_shield_orb' WHERE entry=25502; +UPDATE creature_template SET ScriptName='npc_power_blue_flight' WHERE entry=25653; +UPDATE creature_template SET ScriptName='npc_demonic_vapor' WHERE entry=25265; +UPDATE creature_template SET ScriptName='npc_darkness' WHERE entry=25879; +UPDATE creature_template SET ScriptName='npc_singularity' WHERE entry=25855; /* SWAMP OF SORROWS */ UPDATE creature_template SET ScriptName='npc_galen_goodward' WHERE entry=5391; @@ -1093,7 +1219,6 @@ UPDATE creature_template SET ScriptName='npc_galen_goodward' WHERE entry=5391; /* TANARIS */ UPDATE creature_template SET ScriptName='mob_aquementas' WHERE entry=9453; UPDATE creature_template SET ScriptName='npc_custodian_of_time' WHERE entry=20129; -UPDATE creature_template SET ScriptName='npc_marin_noggenfogger' WHERE entry=7564; UPDATE creature_template SET ScriptName='npc_oox17tn' WHERE entry=7784; UPDATE creature_template SET ScriptName='npc_stone_watcher_of_norgannon' WHERE entry=7918; UPDATE creature_template SET ScriptName='npc_tooga' WHERE entry=5955; @@ -1106,9 +1231,7 @@ UPDATE creature_template SET ScriptName='npc_mist' WHERE entry=3568; /* */ /* THE MECHANAR */ -UPDATE creature_template SET ScriptName='boss_gatewatcher_iron_hand' WHERE entry=19710; UPDATE creature_template SET ScriptName='boss_nethermancer_sepethrea' WHERE entry=19221; -UPDATE creature_template SET ScriptName='mob_ragin_flames' WHERE entry=20481; UPDATE creature_template SET ScriptName='boss_pathaleon_the_calculator' WHERE entry=19220; UPDATE creature_template SET ScriptName='mob_nether_wraith' WHERE entry=21062; UPDATE instance_template SET ScriptName='instance_mechanar' WHERE map=554; @@ -1121,16 +1244,14 @@ UPDATE creature_template SET ScriptName='mob_warp_splinter_treant' WHERE entry=1 /* THE ARCATRAZ */ UPDATE instance_template SET ScriptName='instance_arcatraz' WHERE map=552; -UPDATE creature_template SET ScriptName='mob_zerekethvoidzone' WHERE entry=21101; UPDATE creature_template SET ScriptName='boss_harbinger_skyriss' WHERE entry=20912; -UPDATE creature_template SET ScriptName='boss_harbinger_skyriss_illusion' WHERE entry IN (21466,21467); +UPDATE creature_template SET ScriptName='boss_dalliah' WHERE entry=20885; +UPDATE creature_template SET ScriptName='boss_soccothrates' WHERE entry=20886; UPDATE creature_template SET ScriptName='npc_warden_mellichar' WHERE entry=20904; UPDATE creature_template SET ScriptName='npc_millhouse_manastorm' WHERE entry=20977; /* THE EYE */ UPDATE instance_template SET ScriptName='instance_the_eye' WHERE map=550; -/* The Eye Trash Mobs */ -UPDATE creature_template SET ScriptName='mob_crystalcore_devastator' WHERE entry=20040; /* Al'ar event */ UPDATE creature_template SET ScriptName='boss_alar' WHERE entry=19514; /* Void Reaver event */ @@ -1156,36 +1277,35 @@ UPDATE creature_template SET ScriptName='boss_yauj' WHERE entry=15543; UPDATE creature_template SET ScriptName='boss_kri' WHERE entry=15511; UPDATE creature_template SET ScriptName='boss_sartura' WHERE entry=15516; UPDATE creature_template SET ScriptName='boss_fankriss' WHERE entry=15510; --- UPDATE creature_template SET ScriptName='boss_viscidus' WHERE entry=15299; --- UPDATE creature_template SET ScriptName='boss_glob_of_viscidus' WHERE entry=15667; +UPDATE creature_template SET ScriptName='boss_viscidus' WHERE entry=15299; +UPDATE creature_template SET ScriptName='npc_glob_of_viscidus' WHERE entry=15667; UPDATE creature_template SET ScriptName='boss_huhuran' WHERE entry=15509; UPDATE creature_template SET ScriptName='boss_veklor' WHERE entry=15276; UPDATE creature_template SET ScriptName='boss_veknilash' WHERE entry=15275; UPDATE creature_template SET ScriptName='boss_ouro' WHERE entry=15517; +UPDATE creature_template SET ScriptName='npc_ouro_spawner' WHERE entry=15957; UPDATE creature_template SET ScriptName='boss_eye_of_cthun' WHERE entry=15589; UPDATE creature_template SET ScriptName='mob_sartura_royal_guard' WHERE entry=15984; -UPDATE creature_template SET ScriptName='mob_claw_tentacle' WHERE entry=15725; -UPDATE creature_template SET ScriptName='mob_eye_tentacle' WHERE entry=15726; UPDATE creature_template SET ScriptName='mob_giant_claw_tentacle' WHERE entry=15728; -UPDATE creature_template SET ScriptName='mob_giant_eye_tentacle' WHERE entry=15334; -UPDATE creature_template SET ScriptName='mob_giant_flesh_tentacle' WHERE entry=15802; UPDATE creature_template SET ScriptName='mob_anubisath_sentinel' WHERE entry=15264; +DELETE FROM scripted_areatrigger WHERE entry IN (4033,4034); +INSERT INTO scripted_areatrigger VALUES +(4033,'at_stomach_cthun'), +(4034,'at_stomach_cthun'); /* TEROKKAR FOREST */ -UPDATE creature_template SET ScriptName='mob_infested_root_walker' WHERE entry=22095; UPDATE creature_template SET ScriptName='mob_netherweb_victim' WHERE entry=22355; -UPDATE creature_template SET ScriptName='mob_rotting_forest_rager' WHERE entry=22307; UPDATE creature_template SET ScriptName='mob_unkor_the_ruthless' WHERE entry=18262; UPDATE creature_template SET ScriptName='npc_akuno' WHERE entry=22377; -UPDATE creature_template SET ScriptName='npc_floon' WHERE entry=18588; UPDATE creature_template SET ScriptName='npc_hungry_nether_ray' WHERE entry=23439; UPDATE creature_template SET ScriptName='npc_letoll' WHERE entry=22458; UPDATE creature_template SET ScriptName='npc_mana_bomb_exp_trigger' WHERE entry=20767; UPDATE gameobject_template SET ScriptName='go_mana_bomb' WHERE entry=184725; -UPDATE creature_template SET ScriptName='npc_slim' WHERE entry=19679; UPDATE creature_template SET ScriptName='npc_captive_child' WHERE entry=22314; UPDATE creature_template SET ScriptName='npc_isla_starmane' WHERE entry=18760; UPDATE creature_template SET ScriptName="npc_skywing" WHERE entry=22424; +UPDATE creature_template SET ScriptName="npc_cenarion_sparrowhawk" WHERE entry=22972; +UPDATE creature_template SET ScriptName="npc_skyguard_prisoner" WHERE entry=23383; /* THOUSAND NEEDLES */ UPDATE creature_template SET ScriptName='npc_kanati' WHERE entry=10638; @@ -1194,7 +1314,6 @@ UPDATE creature_template SET ScriptName='npc_paoka_swiftmountain' WHERE entry=10 UPDATE creature_template SET ScriptName='npc_lakota_windsong' WHERE entry=10646; /* THUNDER BLUFF */ -UPDATE creature_template SET ScriptName='npc_cairne_bloodhoof' WHERE entry=3057; /* TIRISFAL GLADES */ UPDATE gameobject_template SET ScriptName='go_mausoleum_trigger' WHERE entry=104593; @@ -1230,18 +1349,102 @@ UPDATE instance_template SET ScriptName='instance_halls_of_stone' WHERE map=599; UPDATE creature_template SET ScriptName='boss_maiden_of_grief' WHERE entry=27975; UPDATE creature_template SET ScriptName='boss_sjonnir' WHERE entry=27978; UPDATE creature_template SET ScriptName='npc_brann_hos' WHERE entry=28070; +UPDATE creature_template SET ScriptName='npc_dark_matter' WHERE entry=28235; +UPDATE creature_template SET ScriptName='npc_searing_gaze' WHERE entry=28265; /* ULDUAR */ UPDATE instance_template SET ScriptName='instance_ulduar' WHERE map=603; +UPDATE gameobject_template SET ScriptName='go_ulduar_teleporter' WHERE entry=194569; UPDATE creature_template SET ScriptName='boss_general_vezax' WHERE entry=33271; +UPDATE creature_template SET ScriptName='npc_saronite_vapor' WHERE entry=33488; UPDATE creature_template SET ScriptName='boss_auriaya' WHERE entry=33515; UPDATE creature_template SET ScriptName='boss_feral_defender' WHERE entry=34035; UPDATE creature_template SET ScriptName='boss_brundir' WHERE entry=32857; UPDATE creature_template SET ScriptName='boss_molgeim' WHERE entry=32927; UPDATE creature_template SET ScriptName='boss_steelbreaker' WHERE entry=32867; -DELETE FROM scripted_event_id WHERE id=9735; +UPDATE creature_template SET ScriptName='boss_ignis' WHERE entry=33118; +UPDATE creature_template SET ScriptName='npc_iron_construct' WHERE entry=33121; +UPDATE creature_template SET ScriptName='npc_scorch' WHERE entry=33221; +UPDATE creature_template SET ScriptName='boss_xt_002' WHERE entry=33293; +UPDATE creature_template SET ScriptName='boss_heart_deconstructor' WHERE entry=33329; +UPDATE creature_template SET ScriptName='npc_scrapbot' WHERE entry=33343; +UPDATE creature_template SET ScriptName='npc_xt_toy_pile' WHERE entry=33337; +UPDATE creature_template SET ScriptName='boss_razorscale' WHERE entry=33186; +UPDATE creature_template SET ScriptName='npc_expedition_commander' WHERE entry=33210; +UPDATE creature_template SET ScriptName='npc_razorscale_spawner' WHERE entry=33245; +UPDATE creature_template SET ScriptName='npc_harpoon_fire_state' WHERE entry=33282; +UPDATE creature_template SET ScriptName='npc_keeper_norgannon' WHERE entry=33686; +UPDATE creature_template SET ScriptName='npc_brann_ulduar' WHERE entry=33579; +UPDATE creature_template SET ScriptName='boss_flame_leviathan' WHERE entry=33113; +UPDATE creature_template SET ScriptName='npc_hodir_fury_reticle' WHERE entry=33108; +UPDATE creature_template SET ScriptName='npc_hodir_fury' WHERE entry=33212; +UPDATE creature_template SET ScriptName='npc_freya_ward' WHERE entry=33367; +UPDATE creature_template SET ScriptName='npc_mimiron_inferno' WHERE entry=33370; +UPDATE creature_template SET ScriptName='boss_kologarn' WHERE entry=32930; +UPDATE creature_template SET ScriptName='npc_focused_eyebeam' WHERE entry IN (33802,33632); +UPDATE creature_template SET ScriptName='npc_rubble_stalker' WHERE entry=33809; +UPDATE creature_template SET ScriptName='npc_storm_tempered_keeper' WHERE entry IN (33699,33722); +UPDATE creature_template SET ScriptName='npc_charged_sphere' WHERE entry=33715; +UPDATE creature_template SET ScriptName='boss_algalon' WHERE entry=32871; +UPDATE creature_template SET ScriptName='npc_living_constellation' WHERE entry=33052; +UPDATE creature_template SET ScriptName='npc_worm_hole' WHERE entry=34099; +UPDATE creature_template SET ScriptName='npc_black_hole' WHERE entry=32953; +UPDATE creature_template SET ScriptName='npc_collapsing_star' WHERE entry=32955; +UPDATE gameobject_template SET ScriptName='go_celestial_access' WHERE entry IN (194628,194752); +UPDATE creature_template SET ScriptName='boss_hodir' WHERE entry=32845; +UPDATE creature_template SET ScriptName='npc_flash_freeze' WHERE entry IN (32926,32938); +UPDATE creature_template SET ScriptName='npc_icicle_target' WHERE entry=33174; +UPDATE creature_template SET ScriptName='boss_thorim' WHERE entry=32865; +UPDATE creature_template SET ScriptName='boss_sif' WHERE entry=33196; +UPDATE creature_template SET ScriptName='npc_thunder_orb' WHERE entry=33378; +UPDATE creature_template SET ScriptName='npc_runic_colossus' WHERE entry=32872; +UPDATE creature_template SET ScriptName='boss_freya' WHERE entry=32906; +UPDATE creature_template SET ScriptName='npc_eonars_gift' WHERE entry=33228; +UPDATE creature_template SET ScriptName='npc_nature_bomb' WHERE entry=34129; +UPDATE creature_template SET ScriptName='npc_iron_roots' WHERE entry IN (33088,33168); +UPDATE creature_template SET ScriptName='npc_healthy_spore' WHERE entry=33215; +UPDATE creature_template SET ScriptName='npc_water_spirit' WHERE entry=33202; +UPDATE creature_template SET ScriptName='npc_snaplasher' WHERE entry=32916; +UPDATE creature_template SET ScriptName='npc_storm_lasher' WHERE entry=32919; +UPDATE creature_template SET ScriptName='boss_mimiron' WHERE entry=33350; +UPDATE creature_template SET ScriptName='boss_leviathan_mk2' WHERE entry=33432; +UPDATE creature_template SET ScriptName='boss_vx001' WHERE entry=33651; +UPDATE creature_template SET ScriptName='boss_aerial_unit' WHERE entry=33670; +UPDATE creature_template SET ScriptName='npc_proximity_mine' WHERE entry=34362; +UPDATE creature_template SET ScriptName='npc_bot_trigger' WHERE entry=33856; +UPDATE creature_template SET ScriptName='npc_rocket_strike' WHERE entry=34047; +UPDATE creature_template SET ScriptName='npc_frost_bomb' WHERE entry=34149; +UPDATE creature_template SET ScriptName='npc_mimiron_flames' WHERE entry IN (34363,34121); +UPDATE creature_template SET ScriptName='boss_leviathan_mk2_turret' WHERE entry=34071; +UPDATE creature_template SET ScriptName='npc_computer' WHERE entry=34143; +UPDATE gameobject_template SET ScriptName='go_big_red_button' WHERE entry=194739; +UPDATE creature_template SET ScriptName='npc_ulduar_keeper' WHERE entry IN (33241,33242,33244,33213); +UPDATE creature_template SET ScriptName='boss_sara' WHERE entry=33134; +UPDATE creature_template SET ScriptName='boss_yogg_saron' WHERE entry=33288; +UPDATE creature_template SET ScriptName='npc_ominous_cloud' WHERE entry=33292; +UPDATE creature_template SET ScriptName='npc_death_ray' WHERE entry=33881; +UPDATE creature_template SET ScriptName='npc_voice_yogg_saron' WHERE entry=33280; +UPDATE creature_template SET ScriptName='npc_brain_yogg_saron' WHERE entry=33890; +UPDATE creature_template SET ScriptName='npc_guardian_of_yogg' WHERE entry=33136; +UPDATE creature_template SET ScriptName='npc_immortal_guardian' WHERE entry=33988; +UPDATE creature_template SET ScriptName='npc_constrictor_tentacle' WHERE entry=33983; +UPDATE creature_template SET ScriptName='npc_descent_madness' WHERE entry=34072; +UPDATE creature_template SET ScriptName='npc_laughing_skull' WHERE entry=33990; +UPDATE creature_template SET ScriptName='npc_keeper_mimiron' WHERE entry=33412; +UPDATE creature_template SET ScriptName='npc_keeper_thorim' WHERE entry=33413; +DELETE FROM scripted_event_id WHERE id IN (9735,20907,20964,21030,21031,21032,21033,21045,21605,21606,21620); INSERT INTO scripted_event_id VALUES -(9735,'event_spell_saronite_barrier'); +(9735, 'event_spell_saronite_barrier'), -- Vezax saronite barrier event +(20907,'event_boss_hodir'), -- Hodir shatter chest event +(20964,'event_spell_harpoon_shot'), -- Razorscale harpoon event +(21030,'event_go_ulduar_tower'), -- Tower of Life destroyed event +(21031,'event_go_ulduar_tower'), -- Tower of Storms destroyed event +(21032,'event_go_ulduar_tower'), -- Tower of Frost destroyed event +(21033,'event_go_ulduar_tower'), -- Tower of Flame destroyed event +(21045,'event_boss_hodir'), -- Hodir attack start event +(21605,'event_ulduar'), -- Flame Leviathan shutdown event +(21606,'event_ulduar'), -- XT-002 Scrap repair event +(21620,'event_ulduar'); -- Ignis construct shatter event /* UN'GORO CRATER */ UPDATE creature_template SET ScriptName='npc_ame01' WHERE entry=9623; @@ -1249,7 +1452,6 @@ UPDATE creature_template SET ScriptName='npc_ringo' WHERE entry=9999; /* UNDERCITY */ UPDATE creature_template SET ScriptName='npc_lady_sylvanas_windrunner' WHERE entry=10181; -UPDATE creature_template SET ScriptName='npc_highborne_lamenter' WHERE entry=21628; /* */ /* UTGARDE KEEP */ @@ -1267,34 +1469,45 @@ UPDATE creature_template SET ScriptName='mob_vrykul_skeleton' WHERE entry=23970; /* UTGARDE PINNACLE */ UPDATE creature_template SET ScriptName='boss_gortok' WHERE entry=26687; -DELETE FROM scripted_areatrigger WHERE entry=4991; -INSERT INTO scripted_areatrigger VALUES (4991,'at_skadi'); +UPDATE creature_template SET ScriptName='npc_gortok_subboss' WHERE entry IN (26683,26684,26685,26686); UPDATE creature_template SET ScriptName='boss_skadi' WHERE entry=26693; +UPDATE creature_template SET ScriptName='npc_grauf' WHERE entry=26893; +UPDATE creature_template SET ScriptName='npc_flame_breath_trigger' WHERE entry=28351; UPDATE creature_template SET ScriptName='boss_svala' WHERE entry=29281; -DELETE FROM scripted_areatrigger WHERE entry=5140; -INSERT INTO scripted_areatrigger VALUES (5140,'at_svala_intro'); UPDATE creature_template SET ScriptName='boss_ymiron' WHERE entry=26861; UPDATE instance_template SET ScriptName='instance_pinnacle' WHERE map=575; +DELETE FROM scripted_areatrigger WHERE entry IN (4991,5140); +INSERT INTO scripted_areatrigger VALUES +(4991,'at_skadi'), +(5140,'at_svala_intro'); +DELETE FROM scripted_event_id WHERE id IN (17728,20651); +INSERT INTO scripted_event_id VALUES +(17728,'event_spell_gortok_event'), +(20651,'event_achiev_kings_bane'); /* VAULT OF ARCHAVON */ - /* VIOLET HOLD */ UPDATE instance_template SET ScriptName='instance_violet_hold' WHERE map=608; UPDATE gameobject_template SET ScriptName='go_activation_crystal' WHERE entry=193611; UPDATE creature_template SET ScriptName='npc_door_seal' WHERE entry=30896; UPDATE creature_template SET ScriptName='npc_sinclari' WHERE entry=30658; +UPDATE creature_template SET ScriptName='npc_prison_event_controller' WHERE entry=30883; UPDATE creature_template SET ScriptName='npc_teleportation_portal' WHERE entry IN (31011,30679,32174); UPDATE creature_template SET ScriptName='boss_ichoron' WHERE entry IN (29313,32234); UPDATE creature_template SET ScriptName='boss_erekem' WHERE entry IN (29315,32226); +UPDATE creature_template SET ScriptName='npc_erekem_guard' WHERE entry IN (29395,32228); /* WAILING CAVERNS */ UPDATE instance_template SET ScriptName='instance_wailing_caverns' WHERE map=43; UPDATE creature_template SET ScriptName='npc_disciple_of_naralex' WHERE entry=3678; /* WESTERN PLAGUELANDS */ -UPDATE creature_template SET ScriptName='npc_myranda_the_hag' WHERE entry=11872; UPDATE creature_template SET ScriptName='npc_the_scourge_cauldron' WHERE entry=11152; +UPDATE creature_template SET ScriptName='npc_anchorite_truuen' WHERE entry=17238; +UPDATE creature_template SET ScriptName='npc_taelan_fordring' WHERE entry=1842; +UPDATE creature_template SET ScriptName='npc_isillien' WHERE entry=1840; +UPDATE creature_template SET ScriptName='npc_tirion_fordring' WHERE entry=12126; /* WESTFALL */ UPDATE creature_template SET ScriptName='npc_daphne_stilwell' WHERE entry=6182; @@ -1305,16 +1518,15 @@ UPDATE creature_template SET ScriptName='npc_tapoke_slim_jahn' WHERE entry=4962; UPDATE creature_template SET ScriptName='npc_mikhail' WHERE entry=4963; /* WINTERSPRING */ -UPDATE creature_template SET ScriptName='npc_lorax' WHERE entry=10918; UPDATE creature_template SET ScriptName='npc_ranshalla' WHERE entry=10300; UPDATE gameobject_template SET ScriptName='go_elune_fire' WHERE entry IN (177417, 177404); /* ZANGARMARSH */ DELETE FROM scripted_event_id WHERE id=11225; INSERT INTO scripted_event_id VALUES (11225,'event_taxi_stormcrow'); -UPDATE creature_template SET ScriptName='npcs_ashyen_and_keleth' WHERE entry IN (17900,17901); UPDATE creature_template SET ScriptName='npc_cooshcoosh' WHERE entry=18586; UPDATE creature_template SET ScriptName='npc_kayra_longmane' WHERE entry=17969; +UPDATE creature_template SET ScriptName='npc_fhwoor' WHERE entry=17877; /* ZUL'AMAN */ UPDATE instance_template SET ScriptName='instance_zulaman' WHERE map=568; @@ -1326,33 +1538,29 @@ UPDATE creature_template SET ScriptName='boss_halazzi' WHERE entry=23577; UPDATE creature_template SET ScriptName='boss_spirit_lynx' WHERE entry=24143; UPDATE creature_template SET ScriptName='boss_janalai' WHERE entry=23578; UPDATE creature_template SET ScriptName='boss_malacrass' WHERE entry=24239; -UPDATE creature_template SET ScriptName='mob_alyson_antille' WHERE entry=24240; -UPDATE creature_template SET ScriptName='mob_thurg' WHERE entry=24241; -UPDATE creature_template SET ScriptName='mob_slither' WHERE entry=24242; -UPDATE creature_template SET ScriptName='mob_lord_raadan' WHERE entry=24243; -UPDATE creature_template SET ScriptName='mob_gazakroth' WHERE entry=24244; -UPDATE creature_template SET ScriptName='mob_fenstalker' WHERE entry=24245; -UPDATE creature_template SET ScriptName='mob_darkheart' WHERE entry=24246; -UPDATE creature_template SET ScriptName='mob_koragg' WHERE entry=24247; UPDATE creature_template SET ScriptName='boss_nalorakk' WHERE entry=23576; UPDATE creature_template SET ScriptName='boss_zuljin' WHERE entry=23863; +UPDATE creature_template SET ScriptName='npc_feather_vortex' WHERE entry=24136; +UPDATE creature_template SET ScriptName='npc_dragonhawk_egg' WHERE entry=23817; UPDATE creature_template SET ScriptName='npc_janalai_firebomb' WHERE entry=23920; UPDATE creature_template SET ScriptName='npc_amanishi_hatcher' WHERE entry IN (23818,24504); -UPDATE creature_template SET ScriptName='npc_hatchling' WHERE entry=23598; UPDATE creature_template SET ScriptName='npc_forest_frog' WHERE entry=24396; /* ZUL'DRAK */ UPDATE creature_template SET ScriptName='npc_gurgthock' WHERE entry=30007; +UPDATE creature_template SET ScriptName='npc_ghoul_feeding_bunny' WHERE entry=28591; +UPDATE creature_template SET ScriptName='npc_decaying_ghoul' WHERE entry=28565; /* ZUL'FARRAK */ UPDATE instance_template SET ScriptName='instance_zulfarrak' WHERE map=209; -DELETE FROM scripted_event_id WHERE id=2488; -INSERT INTO scripted_event_id VALUES (2488,'event_go_zulfarrak_gong'); +DELETE FROM scripted_event_id WHERE id IN (2488,2609); +INSERT INTO scripted_event_id VALUES +(2488,'event_go_zulfarrak_gong'), +(2609,'event_spell_unlocking'); DELETE FROM scripted_areatrigger WHERE entry=1447; INSERT INTO scripted_areatrigger VALUES (1447,'at_zulfarrak'); -UPDATE creature_template SET ScriptName='npc_sergeant_bly' WHERE entry=7604; -UPDATE creature_template SET ScriptName='npc_weegli_blastfuse' WHERE entry=7607; +UPDATE creature_template SET ScriptName='boss_zumrah' WHERE entry=7271; /* ZUL'GURUB */ UPDATE instance_template SET ScriptName='instance_zulgurub' WHERE map=309; @@ -1361,21 +1569,16 @@ UPDATE creature_template SET ScriptName='boss_venoxis' WHERE entry=14507; UPDATE creature_template SET ScriptName='boss_marli' WHERE entry=14510; UPDATE creature_template SET ScriptName='boss_mandokir' WHERE entry=11382; UPDATE creature_template SET ScriptName='mob_ohgan' WHERE entry=14988; -UPDATE creature_template SET ScriptName='boss_gahzranka' WHERE entry=15114; UPDATE creature_template SET ScriptName='boss_jindo' WHERE entry=11380; UPDATE creature_template SET ScriptName='boss_hakkar' WHERE entry=14834; UPDATE creature_template SET ScriptName='boss_thekal' WHERE entry=14509; UPDATE creature_template SET ScriptName='boss_arlokk' WHERE entry=14515; UPDATE gameobject_template SET ScriptName='go_gong_of_bethekk' WHERE entry=180526; -UPDATE creature_template SET ScriptName='boss_grilek' WHERE entry=15082; UPDATE creature_template SET ScriptName='boss_hazzarah' WHERE entry=15083; UPDATE creature_template SET ScriptName='boss_renataki' WHERE entry=15084; -UPDATE creature_template SET ScriptName='boss_wushoolay' WHERE entry=15085; UPDATE creature_template SET ScriptName='mob_zealot_lorkhan' WHERE entry=11347; UPDATE creature_template SET ScriptName='mob_zealot_zath' WHERE entry=11348; UPDATE creature_template SET ScriptName='mob_healing_ward' WHERE entry=14987; -UPDATE creature_template SET ScriptName='mob_spawn_of_marli' WHERE entry=15041; -UPDATE creature_template SET ScriptName='mob_batrider' WHERE entry=14965; -UPDATE creature_template SET ScriptName='mob_shade_of_jindo' WHERE entry=14986; +UPDATE creature_template SET ScriptName='npc_gurubashi_bat_rider' WHERE entry=14750; /* EOF */ diff --git a/sql/scriptdev2_script_full.sql b/sql/scriptdev2_script_full.sql index cccf31c91..faa752f43 100644 --- a/sql/scriptdev2_script_full.sql +++ b/sql/scriptdev2_script_full.sql @@ -3,7 +3,7 @@ -- DELETE FROM sd2_db_version; -INSERT INTO sd2_db_version (version) VALUES ('ScriptDev2 (for MaNGOS 11962+) '); +INSERT INTO sd2_db_version (version) VALUES ('ScriptDev2 (for CMaNGOS 12839+) '); -- -- Below contains data for table `script_texts` mainly used in C++ parts. @@ -107,7 +107,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000153,'Contemptible wretch!',11338,1,0,0,'kazzak SAY_KILL2'), (-1000154,'The universe will be remade.',11339,1,0,0,'kazzak SAY_KILL3'), (-1000155,'The Legion... will never... fall.',11340,1,0,0,'kazzak SAY_DEATH'), -(-1000156,'REUSE ME',0,0,0,0,'REUSE ME'), + +(-1000156,'Bloodmaul Brew? Me favorite!',0,0,0,0,'bladespire ogre SAY_BREW_1'), + (-1000157,'Invaders, you dangle upon the precipice of oblivion! The Burning Legion comes and with it comes your end.',0,1,0,0,'kazzak SAY_RAND1'), (-1000158,'Impudent whelps, you only delay the inevitable. Where one has fallen, ten shall rise. Such is the will of Kazzak...',0,1,0,0,'kazzak SAY_RAND2'), @@ -146,7 +148,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000185,'%s puts the shell to his ear.',0,2,7,0,'engineer_spark EMOTE_SHELL'), (-1000186,'Now I cut you!',0,1,7,0,'engineer_spark SAY_ATTACK'), -(-1000187,'Thank you, dear $C, you just saved my life.',0,0,7,0,'faulk SAY_HEAL'), +(-1000187,'Thank you, dear $C, you just saved my life.',0,0,0,0,'npc_redemption_target SAY_HEAL'), (-1000188,'Deployment sucessful. Trespassers will be neutralized.',0,0,0,0,'converted_sentry SAY_CONVERTED_1'), (-1000189,'Objective acquired. Initiating security routines.',0,0,0,0,'converted_sentry SAY_CONVERTED_2'), @@ -155,14 +157,14 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000191,'You taste good with maybe a little salt and pepper.',0,0,0,0,' SAY_LUMP_1'), (-1000192,'OK, OK! Lump give up!',0,0,0,0,' SAY_LUMP_DEFEAT'), -(-1000193,'Thank you, dear $C, you just saved my life.',0,0,1,0,'stillblade SAY_HEAL'), +(-1000193,'%s looks down at the discarded necklace. In her sadness, the lady incants a glamour, which beckons forth Highborne spirits. The chamber resonates with their ancient song about the Sin\'dorei...',10896,2,1,0,'lady_sylvanas EMOTE_LAMENT_START'), (-1000194,'I give up! Please don\'t kill me!',0,0,0,0,'unkor SAY_SUBMIT'), -(-1000195,'REUSE ME',0,0,0,0,'REUSE ME'), +(-1000195,'Thank you again, $N. I\'ll make my way to the road now. When you can, find Terenthis and let him know we escaped.',0,0,0,1,'volcor SAY_ESCAPE'), (-1000196,'Belore...',0,0,1,0,'lady_sylvanas SAY_LAMENT_END'), -(-1000197,'%s kneels down and pick up the amulet.',0,2,1,0,'lady_sylvanas EMOTE_LAMENT_END'), +(-1000197,'%s kneels down and pick up the amulet.',0,2,1,16,'lady_sylvanas EMOTE_LAMENT_END'), (-1000198,'Taste blade, mongrel!',0,0,0,0,'SAY_GUARD_SIL_AGGRO1'), (-1000199,'Please tell me that you didn\'t just do what I think you just did. Please tell me that I\'m not going to have to hurt you...',0,0,0,0,'SAY_GUARD_SIL_AGGRO2'), @@ -176,9 +178,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000205,'%s looks at you unexpectadly.',0,2,0,0,'cluck EMOTE_H_HELLO'), (-1000206,'%s starts pecking at the feed.',0,2,0,0,'cluck EMOTE_CLUCK_TEXT2'), -(-1000207,'You have my blessing',0,0,0,0,'ashyen_and_keleth SAY_REWARD_BLESS'), - -(-1000208,'REUSE ME',0,0,0,0,'REUSE ME'), +(-1000207,'Mmm. Me thirsty!',0,0,0,0,'bladespire ogre SAY_BREW_2'), +(-1000208,'Ohh, look! Bloodmaul Brew! Mmmm...',0,0,0,0,'bladespire ogre SAY_BREW_3'), (-1000209,'Very well. Let\'s see what you have to show me, $N.',0,0,1,0,'anvilward SAY_ANVIL1'), (-1000210,'What manner of trick is this, $R? If you seek to ambush me, I warn you I will not go down quietly!',0,0,1,0,'anvilward SAY_ANVIL2'), @@ -387,8 +388,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000386,'Now we must find the exit.',0,0,0,0,'wilda SAY_WIL_FIND_EXIT'), (-1000387,'Lady Vashj must answer for these atrocities. She must be brought to justice!',0,0,0,0,'wilda SAY_WIL_PROGRESS4'), (-1000388,'The tumultuous nature of the great waterways of Azeroth and Draenor are a direct result of tormented water spirits.',0,0,0,0,'wilda SAY_WIL_PROGRESS5'), -(-1000389,'It shouldn\'t be much further, $n. The exit is just up ahead.',0,0,0,0,'wilda SAY_WIL_JUST_AHEAD'), -(-1000390,'Thank you, $n. Please return to my brethren at the Altar of Damnation, near the Hand of Gul\'dan, and tell them that Wilda is safe. May the Earthmother watch over you...',0,0,0,0,'wilda SAY_WIL_END'), +(-1000389,'It shouldn\'t be much further, $n. The exit is just up ahead.',0,0,0,1,'wilda SAY_WIL_JUST_AHEAD'), +(-1000390,'Thank you, $n. Please return to my brethren at the Altar of Damnation, near the Hand of Gul\'dan, and tell them that Wilda is safe. May the Earthmother watch over you...',0,0,0,3,'wilda SAY_WIL_END'), (-1000391,'I\'m Thirsty.',0,0,0,0,'tooga SAY_TOOG_THIRST'), (-1000392,'Torta must be so worried.',0,0,0,0,'tooga SAY_TOOG_WORRIED'), @@ -606,7 +607,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000577,'This is far enough. I can make it on my own from here.',0,0,0,0,'Lurgglbr - SAY_END_1'), (-1000578,'Thank you for helping me $r. Please tell the king I am back.',0,0,0,0,'Lurgglbr - SAY_END_2'), -(-1000579,'Insolent fool! You thought to steal Zelemar\'s blood? You shall pay with your own!',0,1,0,0,'Zelemar the Wrathful - Aggro'), +(-1000579,'There! Destroy him! The Cipher must be recovered!',0,0,0,25,'spirit hunter - SAY_VENERATUS_SPAWN'), (-1000580,'Sleep now, young one ...',0,0,0,0,'Raelorasz SAY_SLEEP'), (-1000581,'A wonderful specimen.',0,0,0,0,'Raeloarsz SAY_SPECIMEN'), @@ -875,7 +876,424 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1000811,'Farewell, mortals... The earthmender knows what fire feels...',0,0,0,0, 'Spirit of Earth SAY_EARTH_EPILOGUE_6'), (-1000812,'We leave, Torlok. I have only one request...',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_7'), (-1000813,'The Torn-heart men give their weapons to Earthmender Torlok.',0,2,0,0,'Torlok EMOTE_GIVE_WEAPONS'), -(-1000814,'Give these to the heroes that made this possible.',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_8'); +(-1000814,'Give these to the heroes that made this possible.',0,0,0,1,'Oronok SAY_ORONOK_EPILOGUE_8'), + +(-1000815,'Be healed!',0,1,0,0,'Eris Havenfire SAY_PHASE_HEAL'), +(-1000816,'We are saved! The peasants have escaped the Scourge!',0,1,0,0,'Eris Havenfire SAY_EVENT_END'), +(-1000817,'I have failed once more...',0,1,0,0,'Eris Havenfire SAY_EVENT_FAIL_1'), +(-1000818,'I now return to whence I came, only to find myself here once more to relive the same epic tragedy.',0,0,0,0,'Eris Havenfire SAY_EVENT_FAIL_2'), +(-1000819,'The Scourge are upon us! Run! Run for your lives!',0,1,0,0,'Peasant SAY_PEASANT_APPEAR_1'), +(-1000820,'Please help us! The Prince has gone mad!',0,1,0,0,'Peasant SAY_PEASANT_APPEAR_2'), +(-1000821,'Seek sanctuary in Hearthglen! It is our only hope!',0,1,0,0,'Peasant SAY_PEASANT_APPEAR_3'), + +(-1000822,'The signal has been sent. He should be arriving shortly.',0,0,0,1,'squire rowe SAY_SIGNAL_SENT'), +(-1000823,'Yawww!',0,0,0,35,'reginald windsor SAY_DISMOUNT'), +(-1000824,'I knew you would come, $N. It is good to see you again, friend.',0,0,0,1,'reginald windsor SAY_WELCOME'), + +(-1000825,'On guard, friend. The lady dragon will not give in without a fight.',0,0,0,1,'reginald windsor SAY_QUEST_ACCEPT'), +(-1000826,'As was fated a lifetime ago in Karazhan, monster - I come - and with me I bring justice.',0,6,0,22,'reginald windsor SAY_GET_READY'), +(-1000827,'Seize him! Seize the worthless criminal and his allies!',0,6,0,0,'prestor SAY_GONNA_DIE'), +(-1000828,'Reginald, you know that I cannot let you pass.',0,0,0,1,'jonathan SAY_DIALOG_1'), +(-1000829,'You must do what you think is right, Marcus. We served together under Turalyon. He made us both the men that we are today. Did he err with me? Do you truly believe my intent is to cause harm to our alliance? Would I shame our heroes?',0,0,0,1,'reginald windsor SAY_DIALOG_2'), +(-1000830,'Holding me here is not the right decision, Marcus.',0,0,0,1,'reginald windsor SAY_DIALOG_3'), +(-1000831,'%s appears lost in contemplation.',0,2,0,0,'jonathan EMOTE_CONTEMPLATION'), +(-1000832,'I am ashamed, old friend. I know not what I do anymore. It is not you that would dare bring shame to the heroes of legend - it is I. It is I and the rest of these corrupt politicians. They fill our lives with empty promises, unending lies.',0,0,0,1,'jonathan SAY_DIALOG_4'), +(-1000833,'We shame our ancestors. We shame those lost to us... forgive me, Reginald.',0,0,0,1,'jonathan SAY_DIALOG_5'), +(-1000834,'Dear friend, you honor them with your vigilant watch. You are steadfast in your allegiance. I do not doubt for a moment that you would not give as great a sacrifice for your people as any of the heroes you stand under.',0,0,0,1,'reginald windsor SAY_DIALOG_6'), +(-1000835,'Now, it is time to bring her reign to an end, Marcus. Stand down, friend.',0,0,0,1,'reginald windsor SAY_DIALOG_7'), +(-1000836,'Stand down! Can you not see that heroes walk among us?',0,0,0,5,'jonathan SAY_DIALOG_8'), +(-1000837,'Move aside! Let them pass!',0,0,0,5,'jonathan SAY_DIALOG_9'), +(-1000838,'Reginald Windsor is not to be harmed! He shall pass through untouched!',0,1,0,22,'jonathan SAY_DIALOG_10'), +(-1000839,'Go, Reginald. May the light guide your hand.',0,0,0,1,'jonathan SAY_DIALOG_11'), +(-1000840,'Thank you, old friend. You have done the right thing.',0,0,0,1,'reginald windsor SAY_DIALOG_12'), +(-1000841,'Follow me, friends. To Stormwind Keep!',0,0,0,0,'reginald windsor SAY_DIALOG_13'), +(-1000842,'Light be with you, sir.',0,0,0,66,'guard SAY_1'), +(-1000843,'We are but dirt beneath your feet, sir.',0,0,0,66,'guard SAY_2'), +(-1000844,'...nerves of thorium.',0,0,0,66,'guard SAY_3'), +(-1000845,'Make way!',0,0,0,66,'guard SAY_4'), +(-1000846,'A living legend...',0,0,0,66,'guard SAY_5'), +(-1000847,'A moment I shall remember for always.',0,0,0,66,'guard SAY_6'), +(-1000848,'You are an inspiration to us all, sir.',0,0,0,66,'guard SAY_7'), +(-1000849,'Be brave, friends. The reptile will thrash wildly. It is an act of desperation. When you are ready, give me the word.',0,0,0,25,'reginald windsor SAY_BEFORE_KEEP'), +(-1000850,'Onward!',0,0,0,5,'reginald windsor SAY_GO_TO_KEEP'), +(-1000851,'Majesty, run while you still can. She is not what you think her to be...',0,0,0,1,'reginald windsor SAY_IN_KEEP_1'), +(-1000852,'To the safe hall, your majesty.',0,0,0,1,'bolvar SAY_IN_KEEP_2'), +(-1000853,'The masquerade is over, Lady Prestor. Or should I call you by your true name... Onyxia...',0,0,0,25,'reginald windsor SAY_IN_KEEP_3'), +(-1000854,'%s laughs.',0,2,0,11,'prestor EMOTE_IN_KEEP_LAUGH'), +(-1000855,'You will be incarcerated and tried for treason, Windsor. I shall watch with glee as they hand down a guilty verdict and sentence you to death by hanging...',0,0,0,1,'prestor SAY_IN_KEEP_4'), +(-1000856,'And as your limp body dangles from the rafters, I shall take pleasure in knowing that a mad man has been put to death. After all, what proof do you have? Did you expect to come in here and point your fingers at royalty and leave unscathed?',0,0,0,6,'prestor SAY_IN_KEEP_5'), +(-1000857,'You will not escape your fate, Onyxia. It has been prophesied - a vision resonating from the great halls of Karazhan. It ends now...',0,0,0,1,'reginald windsor SAY_IN_KEEP_6'), +(-1000858,'%s reaches into his pack and pulls out the encoded tablets...',0,2,0,0,'reginald windsor EMOTE_IN_KEEP_REACH'), +(-1000859,'The Dark Irons thought these tablets to be encoded. This is not any form of coding, it is the tongue of ancient dragon.',0,0,0,1,'reginald windsor SAY_IN_KEEP_7'), +(-1000860,'Listen, dragon. Let the truth resonate throughout these halls.',0,0,0,1,'reginald windsor SAY_IN_KEEP_8'), +(-1000861,'%s reads from the tablets. Unknown, unheard sounds flow through your consciousness',0,2,0,0,'reginald windsor EMOTE_IN_KEEP_READ'), +(-1000862,'%s gasps.',0,2,0,0,'bolvar EMOTE_IN_KEEP_GASP'), +(-1000863,'Curious... Windsor, in this vision, did you survive? I only ask because one thing that I can and will assure is your death. Here and now.',0,0,0,1,'onyxia SAY_IN_KEEP_9'), +(-1000864,'Dragon filth! Guards! Guards! Seize this monster!',0,1,0,22,'bolvar SAY_IN_KEEP_1'), +(-1000865,'Yesss... Guards, come to your lord\'s aid!',0,0,0,1,'onyxia SAY_IN_KEEP_10'), +(-1000866,'DO NOT LET HER ESCAPE!',0,0,0,1,'reginald windsor SAY_IN_KEEP_11'), +(-1000867,'Was this fabled, Windsor? If it was death that you came for then the prophecy has been fulfilled. May your consciousness rot in the Twisting Nether. Finish the rest of these meddlesome insects, children. Bolvar, you have been a pleasureable puppet.',0,0,0,0,'onyxia SAY_IN_KEEP_12'), +(-1000868,'You have failed him, mortalsss... Farewell!',0,1,0,0,'onyxia SAY_IN_KEEP_12'), +(-1000869,'Reginald... I... I am sorry.',0,0,0,0,'bolvar SAY_IN_KEEP_13'), +(-1000870,'Bol... Bolvar... the medallion... use...',0,0,0,0,'reginald windsor SAY_IN_KEEP_14'), +(-1000871,'%s dies.',0,2,0,0,'reginald windsor EMOTE_IN_KEEP_DIE'), +(-1000872,'%s hisses',0,2,0,0,'reginald windsor EMOTE_GUARD_TRANSFORM'), + +(-1000873,'I know the way, insect. There is no need to prod me as if I were cattle.',0,0,0,1,'grark SAY_START'), +(-1000874,'Surely you do not think that you will get away with this incursion. They will come for me and you shall pay for your insolence.',0,0,0,1,'grark SAY_PAY'), +(-1000875,'RUN THEM THROUGH BROTHERS!',0,0,0,5,'grark SAY_FIRST_AMBUSH_START'), +(-1000876,'I doubt you will be so lucky the next time you encounter my brethren.',0,0,0,1,'grark SAY_FIRST_AMBUSH_END'), +(-1000877,'They come for you, fool!',0,0,0,5,'grark SAY_SEC_AMBUSH_START'), +(-1000878,'What do you think you accomplish from this, fool? Even now, the Blackrock armies make preparations to destroy your world.',0,0,0,1,'grark SAY_SEC_AMBUSH_END'), +(-1000879,'On darkest wing they fly. Prepare to meet your end!',0,0,0,5,'grark SAY_THIRD_AMBUSH_START'), +(-1000880,'The worst is yet to come!',0,0,0,1,'grark SAY_THIRD_AMBUSH_END'), +(-1000881,'%s laughs.',0,2,0,11,'grark EMOTE_LAUGH'), +(-1000882,'Time to make your final stand, Insect.',0,0,0,0,'grark SAY_LAST_STAND'), +(-1000883,'Kneel, Grark',0,0,0,1,'lexlort SAY_LEXLORT_1'), +(-1000884,'Grark Lorkrub, you have been charged and found guilty of treason against Horde. How you plead is unimportant. High Executioner Nuzrak, step forward.',0,0,0,1,'lexlort SAY_LEXLORT_2'), +(-1000885,'%s raises his massive axe over Grark.',0,2,0,27,'nuzark EMOTE_RAISE_AXE'), +(-1000886,'%s raises his hand and then lowers it.',0,2,0,0,'lexlort EMOTE_LOWER_HAND'), +(-1000887,'End him...',0,0,0,0,'lexlort SAY_LEXLORT_3'), +(-1000888,'You, soldier, report back to Kargath at once!',0,0,0,1,'lexlort SAY_LEXLORT_4'), +(-1000889,'%s submits.',0,2,0,0,'grark EMOTE_SUBMIT'), +(-1000890,'You have come to play? Then let us play!',0,0,0,0,'grark SAY_AGGRO'), + +(-1000891,'Let\'s do this... Just keep me covered and I\'ll deliver the package.',0,0,0,0,'demolitionist SAY_INTRO'), +(-1000892,'I\'m under attack! I repeat, I am under attack!',0,0,0,0,'demolitionist SAY_ATTACK_1'), +(-1000893,'I need to find a new line of work.',0,0,0,0,'demolitionist SAY_ATTACK_2'), +(-1000894,'By the second sun of K\'aresh, look at this place! I can only imagine what Salhadaar is planning. Come on, let\'s keep going.',0,0,0,1,'demolitionist SAY_STAGING_GROUNDS'), +(-1000895,'With this much void waste and run off, a toxic void horror can\'t be too far behind.',0,0,0,0,'demolitionist SAY_TOXIC_HORROR'), +(-1000896,'Look there, fleshling! Salhadaar\'s conduits! He\'s keeping well fed...',0,0,0,1,'demolitionist SAY_SALHADAAR'), +(-1000897,'Alright, keep me protected while I plant this disruptor. This shouldn\'t take very long...',0,0,0,0,'demolitionist SAY_DISRUPTOR'), +(-1000898,'Protect the conduit! Stop the intruders!',0,0,0,0,'nexus stalkers SAY_PROTECT'), +(-1000899,'Done! Back up! Back up!',0,0,0,0,'demolitionist SAY_FINISH_1'), +(-1000900,'Looks like my work here is done. Report to the holo-image of Ameer over at the transporter.',0,0,0,1,'demolitionist SAY_FINISH_2'), + +(-1000901,'Thanks, friend. Will you help me get out of here?',0,0,0,1,'vanguard SAY_VANGUARD_INTRO'), +(-1000902,'We\'re not too far from the Protectorate Watch Post, $N. This way!',0,0,0,1,'vanguard SAY_VANGUARD_START'), +(-1000903,'Commander! This fleshling rescued me!',0,0,0,0,'vanguard SAY_VANGUARD_FINISH'), +(-1000904,'%s salutes $N.',0,2,0,0,'vanguard EMOTE_VANGUARD_FINISH'), + +(-1000905,'Ok, let\'s go!!',0,0,0,1,'therylune SAY_THERYLUNE_START'), +(-1000906,'I can make it the rest of the way. $N. THANKS!',0,0,0,1,'therylune SAY_THERYLUNE_START'), + +(-1000907,'%s sniffs at the air. A tuber is near!',0,2,0,0,'domesticated felboar EMOTE_SNIFF_AIR'), +(-1000908,'%s starts to dig.',0,2,0,0,'domesticated felboar EMOTE_START_DIG'), +(-1000909,'%s squeals with glee at its discovery.',0,2,0,0,'domesticated felboar EMOTE_SQUEAL'), + +(-1000910,'Shall we begin, my friend?',0,0,0,0,'anchorite truuen SAY_BEGIN'), +(-1000911,'This area is known to be full of foul Scourge. You may want to take a moment to prepare any defenses at your disposal.',0,0,0,0,'anchorite truuen SAY_FIRST_STOP'), +(-1000912,'Very well, let us continue.',0,0,0,0,'anchorite truuen SAY_CONTINUE'), +(-1000913,'Beware! We are attacked!',0,0,0,0,'anchorite truuen SAY_FIRST_ATTACK'), +(-1000914,'It must be the purity of the Mark of the Lightbringer that is drawing forth the Scourge to us. We must proceed with caution lest we overwhelmed!',0,0,0,0,'anchorite truuen SAY_PURITY'), +(-1000915,'We are beset upon again! Defend yourself!',0,0,0,0,'anchorite truuen SAY_SECOND_ATTACK'), +(-1000916,'The land truly needs to be cleansed by the Light! Let us continue on the tomb. It isn\'t far now.',0,0,0,0,'anchorite truuen SAY_CLEANSE'), +(-1000917,'Be welcome, friends!',0,0,0,0,'high priest thel\'danis SAY_WELCOME'), +(-1000918,'Thank you for coming in remembrance of me. Your efforts in recovering that symbol, while unnecessary, are certainly touching to an old man\'s heart.',0,0,0,0,'ghost of uther SAY_EPILOGUE_1'), +(-1000919,'Please, rise my friend. Keep the Blessing as a symbol of the strength of the Light and how heroes long gone might once again rise in each of us to inspire.',0,0,0,0,'ghost of uther SAY_EPILOGUE_2'), + +(-1000920,'%s turns to face you.',0,2,0,0,'lich_king_wyrmskull EMOTE_LICH_KING_FACE'), +(-1000921,'Shamanism has brought you here... Its scent permeates the air. *The Lich King laughs* I was once a shaman.',14742,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_1'), +(-1000922,'Shall we prepare it for you, my lord?',0,0,0,0,'valkyr_soulclaimer SAY_PREPARE'), +(-1000923,'No, minion. This one is not ready.',14743,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_2'), +(-1000924,'Do you feel it, mortal? Death seeps through me, enveloping all that I touch. With just a snap of my finger your soul will languish in damnation for all eternity.',14744,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_3'), +(-1000925,'But... It is not yet your time to serve the Lich King. Yes, a greater destiny awaits you. Power... You must become more powerful before you are to serve me.',14745,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_4'), +(-1000926,'Now watch, val\'kyr. Observe as I apply pressure. Can you see that it is not yet ripe? Watch as it pops and falls lifeless to the floor.',14746,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_5'), +(-1000927,'Persistence or stupidity? It matters not. Let this be a lesson learned, mortal!',14747,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_6'), + +(-1000928,'%s motions for silence.',0,3,0,25,'king_ymiron EMOTE_KING_SILENCE'), +(-1000929,'Vrykul, your king implores you listen!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_1'), +(-1000930,'The Gods have abandonned us!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_2'), +(-1000931,'The crowd gasps in horror.',0,2,0,0,'king_ymiron EMOTE_YMIRON_CROWD_1'), +(-1000932,'Even now, in our darkest hour, they mock us!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_3'), +(-1000933,'Where are the titans in out time of greatest need? Our women birth abberations - disfigured runts unable to even stand on their own! Weak and ugly... Useless...',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_4'), +(-1000934,'Ymiron has toiled. Long have I sat upon my throne and thought hard of our plight. There is only one answer... One reason...',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_5'), +(-1000935,'For who but the titans themselves could bestow such a curse? What could have such power?',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_6'), +(-1000936,'And the answer is nothing... For it is the titans who have cursed us!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_7'), +(-1000937,'The crowd clamours.',0,2,0,0,'king_ymiron EMOTE_YMIRON_CROWD_2'), +(-1000938,'On this day all Vrykul will shed their old beliefs! We denounce our old gods! All Vrykul will pledge their allegiance to Ymiron! Ymiron will protect our noble race!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_8'), +(-1000939,'The crowd cheers.',0,2,0,0,'king_ymiron EMOTE_YMIRON_CROWD_3'), +(-1000940,'And now my first decree upon the Vrykul! All malformed infants born of Vrykul mother and father are to be destroyed upon birth! Our blood must remain pure always! Those found in violation of Ymiron\'s decree will be taken to Gjalerbron for execution!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_9'), +(-1000941,'Vrykul must remain pure!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_1'), +(-1000942,'Show the aberrations no mercy, Ymiron!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_2'), +(-1000943,'Show them mercy, my king! They are of our flesh and blood!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_3'), +(-1000944,'They weaken us! Our strength is dilluted by their very existence! Destroy them all!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_4'), +(-1000945,'All hail our glorious king, Ymiron!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_5'), +(-1000946,'The King is going to speak!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_6'), +(-1000947,'Let him speak! Be silent!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_7'), + +(-1000948,'Well then, let\'s get this started. The longer we\'re here, the more damage the undead could be doing back in Hilsbrad.',0,0,0,0,'kinelory SAY_START'), +(-1000949,'All right, this is where we really have to be on our paws. Be ready!',0,0,0,0,'kinelory SAY_REACH_BOTTOM'), +(-1000950,'Attack me if you will, but you won\'t stop me from getting back to Quae.',0,0,0,0,'kinelory SAY_AGGRO_KINELORY'), +(-1000951,'You have my word that I shall find a use for your body after I\'ve killed you, Kinelory.',0,0,0,0,'jorell SAY_AGGRO_JORELL'), +(-1000952,'Watch my rear! I\'ll see what I can find in all this junk...',0,0,0,0,'kinelory SAY_WATCH_BACK'), +(-1000953,'%s begins rummaging through the apothecary\'s belongings.',0,2,0,0,'kinelory EMOTE_BELONGINGS'), +(-1000954,'I bet Quae\'ll think this is important. She\'s pretty knowledgeable about these things--no expert, but knowledgable.',0,0,0,0,'kinelory SAY_DATA_FOUND'), +(-1000955,'Okay, let\'s get out of here quick quick! Try and keep up. I\'m going to make a break for it.',0,0,0,0,'kinelory SAY_ESCAPE'), +(-1000956,'We made it! Quae, we made it!',0,0,0,0,'kinelory SAY_FINISH'), +(-1000957,'%s hands her pack to Quae.',0,2,0,0,'kinelory EMOTE_HAND_PACK'), + +(-1000958,'Ok, let\'s get started.',0,0,0,0,'stinky ignatz SAY_STINKY_BEGIN'), +(-1000959,'Now let\'s look for the herb.',0,0,0,0,'stinky ignatz SAY_STINKY_FIRST_STOP'), +(-1000960,'Help! The beast is on me!',0,0,0,0,'stinky ignatz SAY_AGGRO_1'), +(-1000961,'Help! I\'m under attack!',0,0,0,0,'stinky ignatz SAY_AGGRO_2'), +(-1000962,'I can make it from here. Thanks, $N! And talk to my employer about a reward!',0,0,0,0,'stinky ignatz SAY_STINKY_END'), + +(-1000963,'%s looks at you for a moment, then motions for you to follow.',0,2,0,0,'cenarion sparrowhawk EMOTE_FOLLOW'), +(-1000964,'%s surveys the ground for the buried raven stones.',0,2,0,0,'cenarion sparrowhawk EMOTE_SURVEY'), +(-1000965,'%s locates a buried raven stone.',0,2,0,0,'cenarion sparrowhawk EMOTE_LOCATE'), + +(-1000966,'I WILL CRUSH YOU LIKE A GNAT!',0,1,0,0,'reth\'hedron SAY_LOW_HP'), +(-1000967,'You will regret this, mortal! Reth\'hedron will return... I will have my vengeance!',0,1,0,53,'reth\'hedron SAY_EVENT_END'), + +(-1000968,'Very well. Before we head down there, take a moment to prepare yourself.',0,0,0,1,'drijya SAY_DRIJYA_START'), +(-1000969,'Let\'s proceed at a brisk pace.',0,0,0,0,'drijya SAY_DRIJYA_1'), +(-1000970,'We\'ll start at that first energy pylon, straight ahead. Remember, try to keep them off of me.',0,0,0,1,'drijya SAY_DRIJYA_2'), +(-1000971,'Keep them off me!',0,0,0,0,'drijya SAY_DRIJYA_3'), +(-1000972,'I\'m done with this pylon. On to the next.',0,0,0,1,'drijya SAY_DRIJYA_4'), +(-1000973,'Alright, pylon two down. Now for the heat mainfold.',0,0,0,1,'drijya SAY_DRIJYA_5'), +(-1000974,'That should do it. The teleporter should blow any second now!',0,0,0,5,'drijya SAY_DRIJYA_6'), +(-1000975,'Ok, let\'s get out of here!',0,0,0,1,'drijya SAY_DRIJYA_7'), +(-1000976,'Thank you, $n! I couldn\'t have done it without you. You\'ll let Gahruj know?',0,0,0,1,'drijya SAY_DRIJYA_COMPLETE'), + +(-1000977,'Oh, it\'s on now! But you thought I\'d be alone too, huh?!',0,0,0,0,'tapoke slim jahn SAY_AGGRO'), +(-1000978,'Okay, okay! No need to get all violent. I\'ll talk. I\'ll talk!',0,0,0,20,'tapoke slim jahn SAY_DEFEAT'), +(-1000979,'Whoa! This is way more than what I bargained for, you\'re on your own, Slim!',0,0,0,0,'slim\'s friend SAY_FRIEND_DEFEAT'), +(-1000980,'I have a few notes from the job back at my place. I\'ll get them and then meet you back in the inn.',0,0,0,1,'tapoke slim jahn SAY_NOTES'), + +(-1000981,'It is time. The rite of exorcism will now commence...',0,0,0,0,'anchorite barada SAY_EXORCISM_1'), +(-1000982,'Prepare yourself. Do not allow the ritual to be interrupted or we may lose our patient...',0,0,0,1,'anchorite barada SAY_EXORCISM_2'), +(-1000983,'Keep away. The fool is mine.',0,0,0,0,'colonel jules SAY_EXORCISM_3'), +(-1000984,'Back, foul beings of darkness! You have no power here!',0,0,0,0,'anchorite barada SAY_EXORCISM_4'), +(-1000985,'No! Not yet! This soul is ours!',0,0,0,0,'colonel jules SAY_EXORCISM_5'), +(-1000986,'Back! I cast you back... corrupter of faith! Author of pain! Do not return, or suffer the same fate as you did here today!',0,0,0,2,'anchorite barada SAY_EXORCISM_6'), +(-1000987,'I... must not...falter!',0,0,0,0,'anchorite barada SAY_EXORCISM_RANDOM_1'), +(-1000988,'Be cleansed with Light, human! Let not the demonic corruption overwhelm you.',0,0,0,0,'anchorite barada SAY_EXORCISM_RANDOM_2'), +(-1000989,'Back, foul beings of darkness! You have no power here!',0,0,0,0,'anchorite barada SAY_EXORCISM_RANDOM_3'), +(-1000990,'This is fruitless, draenei! You and your little helper cannot wrest control of this pathetic human. He is mine!',0,0,0,0,'colonel jules SAY_EXORCISM_RANDOM_4'), +(-1000991,'I see your ancestors, Anchorite! They writhe and scream in the darkness... they are with us!',0,0,0,0,'colonel jules SAY_EXORCISM_RANDOM_5'), +(-1000992,'I will tear your soul into morsels and slow roast them over demon fire!',0,0,0,0,'colonel jules SAY_EXORCISM_RANDOM_6'), + +(-1000993,'It\'s on! $N, meet my fists. Fists, say hello to $N.',0,0,0,0,'dorius stonetender SAY_AGGRO_1'), +(-1000994,'I\'m about to open a can on this $N.',0,0,0,0,'dorius stonetender SAY_AGGRO_2'), + +(-1000995,'Fhwoor go now, $N. Get ark, come back.',0,0,0,0,'fhwoor SAY_ESCORT_START'), +(-1000996,'Take moment... get ready.',0,0,0,0,'fhwoor SAY_PREPARE'), +(-1000997,'We go!',0,0,0,0,'fhwoor SAY_CAMP_ENTER'), +(-1000998,'Uh oh...',0,0,0,0,'fhwoor SAY_AMBUSH'), +(-1000999,'Ha ha, squishy naga!',0,0,0,0,'fhwoor SAY_AMBUSH_CLEARED'), +(-1001000,'Fhwoor do good!',0,0,0,0,'fhwoor SAY_ESCORT_COMPLETE'), + +(-1001001,'We must leave before more are alerted.',0,0,0,0,'kurenai captive SAY_KUR_START'), +(-1001002,'It\'s an ambush! Defend yourself!',0,0,0,0,'kurenai captive SAY_KUR_AMBUSH_1'), +(-1001003,'We are surrounded!',0,0,0,0,'kurenai captive SAY_KUR_AMBUSH_2'), +(-1001004,'Up ahead is the road to Telaar. We will split up when we reach the fork as they will surely send more Murkblood after us. Hopefully one of us makes it back to Telaar alive.',0,0,0,1,'kurenai captive SAY_KUR_COMPLETE_1'), +(-1001005,'Farewell, stranger. Your heroics will be remembered by my people. Now, hurry to Telaar!',0,0,0,1,'kurenai captive SAY_KUR_COMPLETE_2'), + +(-1001006,'Thanks for your help. Let\'s get out of here!',0,0,0,1,'skyguard prisoner SAY_ESCORT_START'), +(-1001007,'Let\'s keep moving. I don\'t like this place.',0,0,0,1,'skyguard prisoner SAY_AMBUSH_END'), +(-1001008,'Thanks again. Sergeant Doryn will be glad to hear he has one less scout to replace this week.',0,0,0,1,'skyguard prisoner SAY_ESCORT_COMPLETE'), +(-1001009,'Death to our enemies!',0,0,0,0,'skettis wing guard SAY_AMBUSH_1'), +(-1001010,'No one escapes Skettis!',0,0,0,0,'skettis wing guard SAY_AMBUSH_2'), +(-1001011,'Skettis prevails!',0,0,0,0,'skettis wing guard SAY_AMBUSH_3'), +(-1001012,'You\'ll go nowhere, Skyguard scum!',0,0,0,0,'skettis wing guard SAY_AMBUSH_4'), + +(-1001013,'Right then, no time to waste. Let\'s get outa here!',0,0,0,1,'bonker togglevolt SAY_BONKER_START'), +(-1001014,'Here we go.',0,0,0,0,'bonker togglevolt SAY_BONKER_GO'), +(-1001015,'I AM NOT AN APPETIZER!',0,0,0,0,'bonker togglevolt SAY_BONKER_AGGRO'), +(-1001016,'I think it\'s up this way to the left. Let\'s go!',0,0,0,1,'bonker togglevolt SAY_BONKER_LEFT'), +(-1001017,'Ah, fresh air! I can get myself back to the airstrip from here. Be sure to tell Fizzcrank I\'m back and safe. Thanks so much, $N!',0,0,0,1,'sbonker togglevolt SAY_BONKER_COMPLETE'), + +(-1001018,'On the move, men!',0,0,0,0,'kor\'kron squad leader SAY_HORDER_RUN'), +(-1001019,'Alright boys, let\'s do this!',0,0,0,0,'skybreaker squad leader SAY_ALLIANCE_RUN'), +(-1001020,'Incoming!',0,1,0,0,'squad leader SAY_AGGRO_1'), +(-1001021,'Ambush!',0,1,0,0,'squad leader SAY_AGGRO_2'), +(-1001022,'For the Horde!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_1'), +(-1001023,'Time for some blood, men!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_2'), +(-1001024,'Vrykul!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_3'), +(-1001025,'Weapons out!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_4'), +(-1001026,'Find some cover!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_1'), +(-1001027,'Group up!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_2'), +(-1001028,'On your feet, boys!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_3'), +(-1001029,'Vrykul attack!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_4'), +(-1001030,'Quickly, catch your breaths before we press for the gate!',0,0,0,0,'kor\'kron squad leader SAY_HORDE_BREAK'), +(-1001031,'On your feet, men! Move, move move!',0,0,0,0,'kor\'kron squad leader SAY_HORDE_BREAK_DONE'), +(-1001032,'Nice work! We can only rest a moment.',0,0,0,0,'skybreaker squad leader SAY_ALLIANCE_BREAK'), +(-1001033,'On your feet, boys! Move, move move!',0,0,0,0,'skybreaker squad leader SAY_ALLIANCE_BREAK_DONE'), +(-1001034,'Thanks for keeping us covered back there! We\'ll hold the gate while we wait for reinforcements.',0,0,0,1,'squad leader SAY_EVENT_COMPLETE'), +(-1001035,'Die, maggot!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_1'), +(-1001036,'Haraak foln!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_2'), +(-1001037,'I spit on you!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_3'), +(-1001038,'I will feed you to the dogs!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_4'), +(-1001039,'I will take pleasure in gutting you!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_5'), +(-1001040,'I\'ll eat your heart!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_6'), +(-1001041,'Sniveling pig!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_7'), +(-1001042,'Ugglin oo bjorr!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_8'), +(-1001043,'You come to die!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_9'), + +(-1001044,'The Light\'s blessing be upon you for aiding me in my time of need, $N.',0,0,0,0,'father kamaros SAY_ESCORT_START_1'), +(-1001045,'I\'ve had my fill of this place. Let us depart.',0,0,0,1,'father kamaros SAY_ESCORT_START_2'), +(-1001046,'Face your judgment by the Light!',0,0,0,0,'father kamaros SAY_AGGRO_1'), +(-1001047,'The Argent Crusade never surrenders!',0,0,0,0,'father kamaros SAY_AGGRO_2'), +(-1001048,'You will never take me alive!',0,0,0,0,'father kamaros SAY_AGGRO_3'), +(-1001049,'I have you to thank for my life. I will return to my comrades and spread word of your bravery. Fight the Scourge with all the strength you can muster, and we will be by your side.',0,0,0,1,'father kamaros SAY_ESCORT_COMPLETE_2'), +(-1001050,'You must tell my brothers that I live.',0,0,0,1,'father kamaros SAY_ESCORT_COMPLETE_1'), + +(-1001051,'Let me know when you\'re ready. I\'d prefer sooner than later... what with the slowly dying from poison and all.',0,0,0,1,'injured goblin miner SAY_ESCORT_READY'), +(-1001052,'I\'m going to bring the venom sac to Ricket... and then... you know... collapse. Thank you for helping me!',0,0,0,1,'injured goblin miner SAY_ESCORT_COMPLETE'), + +(-1001053,'Alright, kid. Stay behind me and you\'ll be fine.',0,0,0,36,'harrison jones SAY_ESCORT_START'), +(-1001054,'Their ceremonial chamber, where I was to be sacrificed...',0,0,0,1,'harrison jones SAY_CHAMBER_1'), +(-1001055,'Time to put an end to all this!',0,0,0,1,'harrison jones SAY_CHAMBER_2'), +(-1001056,'You\'re free to go, miss.',0,0,0,1,'harrison jones SAY_CHAMBER_RELEASE'), +(-1001057,'Thank you!',0,0,0,71,'Adarrah SAY_THANK_YOU'), +(-1001058,'Odd. That usually does it.',0,0,0,1,'harrison jones SAY_CHAMBER_3'), +(-1001059,'Just as well, I\'ve had enough of this place.',0,0,0,1,'harrison jones SAY_CHAMBER_4'), +(-1001060,'What\'s this?',0,0,0,0,'harrison jones SAY_CHAMBER_5'), +(-1001061,'Aww, not a snake!',0,0,0,1,'harrison jones SAY_CHAMBER_6'), +(-1001062,'Listen, kid. I can handle this thing. You just watch my back!',0,0,0,1,'harrison jones SAY_CHAMBER_7'), +(-1001063,'See ya \'round, kid!',0,0,0,1,'harrison jones SAY_ESCORT_COMPLETE'), + +(-1001064,'You couldn\'t have come at a better time! Let\'s get out of here.',0,0,0,0,'apothecary hanes SAY_ESCORT_START'), +(-1001065,'Yes, let us leave... but not before we leave our Alliance hosts something to remember us by!',0,0,0,0,'apothecary hanes SAY_FIRE_1'), +(-1001066,'They have limited supplies in this camp. It would be a real shame if something were to happen to them.',0,0,0,16,'apothecary hanes SAY_FIRE_2'), +(-1001067,'Ah, yes... watch it burn!',0,0,0,0,'apothecary hanes SAY_SUPPLIES_1'), +(-1001068,'We\'re almost done!',0,0,0,0,'apothecary hanes SAY_SUPPLIES_2'), +(-1001069,'Let\'s high-tail it out of here.',0,0,0,0,'apothecary hanes SAY_SUPPLIES_ESCAPE'), +(-1001070,'That\'ll teach you to mess with an apothecary, you motherless Alliance dogs!',0,1,0,22,'apothecary hanes SAY_SUPPLIES_COMPLETE'), +(-1001071,'Don\'t shoot! Apothecary coming through!',0,1,0,0,'apothecary hanes SAY_ARRIVE_BASE'), + +(-1001072,'Something is wrong with the Highlord. Do something!',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_1'), +(-1001073,'Hey, what is going on over there? Sir, are you alright?',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_2'), +(-1001074,'What the....',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_3'), +(-1001075,'Sir?',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_4'), +(-1001076,'NOOOOOOOOOOOOO!',0,1,0,15,'taelan fordring SAY_SCARLET_COMPLETE_1'), +(-1001077,'I will lead us through Hearthglen to the forest\'s edge. From there, you will take me to my father.',0,0,0,1,'taelan fordring SAY_SCARLET_COMPLETE_2'), +(-1001078,'Remove your disguise, lest you feel the bite of my blade when the fury has taken control.',0,0,0,1,'taelan fordring SAY_ESCORT_START'), +(-1001079,'Halt.',0,0,0,0,'taelan fordring SAY_TAELAN_MOUNT'), +(-1001080,'%s calls for his mount.',0,2,0,22,'taelan fordring EMOTE_TAELAN_MOUNT'), +(-1001081,'It\'s not much further. The main road is just up ahead.',0,0,0,1,'taelan fordring SAY_REACH_TOWER'), +(-1001082,'You will not make it to the forest\'s edge, Fordring.',0,0,0,1,'isillien SAY_ISILLIEN_1'), +(-1001083,'Isillien!',0,1,0,25,'taelan fordring SAY_ISILLIEN_2'), +(-1001084,'This is not your fight, stranger. Protect yourself from the attacks of the Crimson Elite. I shall battle the Grand Inquisitor.',0,0,0,1,'taelan fordring SAY_ISILLIEN_3'), +(-1001085,'You disappoint me, Taelan. I had plans for you... grand plans. Alas, it was only a matter of time before your filthy bloodline would catch up with you.',0,0,0,1,'isillien SAY_ISILLIEN_4'), +(-1001086,'It is as they say: Like father, like son. You are as weak of will as Tirion... perhaps more so. I can only hope my assassins finally succeeded in ending his pitiful life.',0,0,0,1,'isillien SAY_ISILLIEN_5'), +(-1001087,'The Grand Crusader has charged me with destroying you and your newfound friends, Taelan, but know this: I do this for pleasure, not of obligation or duty.',0,0,0,1,'isillien SAY_ISILLIEN_6'), +(-1001088,'%s calls for his guardsman.',0,2,0,0,'isillien EMOTE_ISILLIEN_ATTACK'), +(-1001089,'The end is now, Fordring.',0,0,0,1,'isillien SAY_ISILLIEN_ATTACK'), +(-1001090,'Enough!',0,0,0,0,'isillien SAY_KILL_TAELAN_1'), +(-1001091,'%s laughs.',0,2,0,11,'isillien EMOTE_ISILLIEN_LAUGH'), +(-1001092,'Did you really believe that you could defeat me? Your friends are soon to join you, Taelan.',0,0,0,0,'isillien SAY_KILL_TAELAN_2'), +(-1001093,'% turns his attention towards you.',0,2,0,0,'isillien EMOTE_ATTACK_PLAYER'), +(-1001094,'What have you done, Isillien? You once fought with honor, for the good of our people... and now... you have murdered my boy...',0,0,0,0,'tirion fordring SAY_TIRION_1'), +(-1001095,'Tragic. The elder Fordring lives on... You are too late, old man. Retreat back to your cave, hermit, unless you wish to join your son in the Twisting Nether.',0,0,0,0,'isillien SAY_TIRION_2'), +(-1001096,'May your soul burn in anguish, Isillien! Light give me strength to battle this fiend.',0,0,0,0,'tirion fordring SAY_TIRION_3'), +(-1001097,'Face me, coward. Face the faith and strength that you once embodied.',0,0,0,0,'tirion fordring SAY_TIRION_4'), +(-1001098,'Then come, hermit!',0,0,0,0,'isillien SAY_TIRION_5'), +(-1001099,'A thousand more like him exist. Ten thousand. Should one fall, another will rise to take the seat of power.',0,0,0,0,'tirion fordring SAY_EPILOG_1'), +(-1001100,'%s falls to one knee.',0,2,0,16,'tirion fordring EMOTE_FALL_KNEE'), +(-1001101,'Look what they did to my boy.',0,0,0,0,'tirion fordring SAY_EPILOG_2'), +(-1001102,'%s holds the limp body of Taelan Fordring and softly sobs.',0,2,0,0,'tirion fordring EMOTE_HOLD_TAELAN'), +(-1001103,'Too long have I sat idle, gripped in this haze... this malaise, lamenting what could have been... what should have been.',0,0,0,0,'tirion fordring SAY_EPILOG_3'), +(-1001104,'Your death will not have been in vain, Taelan. A new Order is born on this day... an Order which will dedicate itself to extinguising the evil that plagues this world. An evil that cannot hide behind politics and pleasantries.',0,0,0,0,'tirion fordring SAY_EPILOG_4'), +(-1001105,'This I promise... This I vow...',0,0,0,0,'tirion fordring SAY_EPILOG_5'), + +(-1001106,'Don\'t forget to get my bell out of the chest here. And remember, if do happen to wander off, just ring it and I\'ll find you again.',0,0,0,1,'shay leafrunner SAY_ESCORT_START'), +(-1001107,'Are we taking the scenic route?',0,0,0,0,'shay leafrunner SAY_WANDER_1'), +(-1001108,'Oh, what a beautiful flower over there...',0,0,0,0,'shay leafrunner SAY_WANDER_2'), +(-1001109,'Are you sure this is the right way? Maybe we should go this way instead...',0,0,0,0,'shay leafrunner SAY_WANDER_3'), +(-1001110,'Hmmm, I wonder what\'s over this way?',0,0,0,0,'shay leafrunner SAY_WANDER_4'), +(-1001111,'This is quite an adventure!',0,0,0,0,'shay leafrunner SAY_WANDER_DONE_1'), +(-1001112,'Oh, I wandered off again. I\'m sorry.',0,0,0,0,'shay leafrunner SAY_WANDER_DONE_2'), +(-1001113,'The bell again, such a sweet sound.',0,0,0,0,'shay leafrunner SAY_WANDER_DONE_3'), +(-1001114,'%s begins to wander off.',0,2,0,0,'shay leafrunner EMOTE_WANDER'), +(-1001115,'Oh, here you are, Rockbiter! I\'m sorry, I know I\'m not supposed to wander off.',0,0,0,1,'shay leafrunner SAY_EVENT_COMPLETE_1'), +(-1001116,'I\'m so glad yer back Shay. Please, don\'t ever run off like that again! What would I tell yer parents if I lost ya?',0,0,0,1,'rockbiter SAY_EVENT_COMPLETE_2'), + +(-1001117,'AHAHAHAHA... you\'ll join us soon enough!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_1'), +(-1001118,'I don\'t want to leave! I want to stay here!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_2'), +(-1001119,'I must get further underground to where he is. I must jump!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_3'), +(-1001120,'I won\'t leave!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_4'), +(-1001121,'I\'ll never return. The whole reason for my existence awaits below!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_5'), +(-1001122,'I\'m coming, master!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_6'), +(-1001123,'My life for you!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_7'), +(-1001124,'NO! You\'re wrong! The voices in my head are beautiful!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_8'), + +(-1001125,'Beginning the distillation in 5 seconds.',0,0,0,0,'tipsy mcmanus SAY_DISTILLATION_START'), +(-1001126,'Add another orange! Quickly!',0,0,0,25,'tipsy mcmanus SAY_ADD_ORANGE'), +(-1001127,'Add bananas!',0,0,0,25,'tipsy mcmanus SAY_ADD_BANANAS'), +(-1001128,'Put a papaya in the still!',0,0,0,25,'tipsy mcmanus SAY_ADD_PAPAYA'), +(-1001129,'The still needs heat! Light the brazier!',0,0,0,5,'tipsy mcmanus SAY_LIGHT_BRAZIER'), +(-1001130,'Pressure\'s too high! Open the pressure valve!',0,0,0,5,'tipsy mcmanus SAY_OPEN_VALVE'), +(-1001131,'Good job! Keep your eyes open, now.',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_1'), +(-1001132,'Nicely handled! Stay on your toes!',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_2'), +(-1001133,'Well done! Be ready for anything!',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_3'), +(-1001134,'That\'ll do. Never know what it\'ll need next...',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_4'), +(-1001135,'It\'s no good! I\'m shutting it down...',0,0,0,0,'tipsy mcmanus SAY_DISTILLATION_FAIL'), +(-1001136,'We\'ve done it! Come get the cask.',0,0,0,0,'tipsy mcmanus SAY_DISTILLATION_COMPLETE'), + +(-1001137,'The duel will begin in...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN'), +(-1001138,'3...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN_3'), +(-1001139,'2...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN_2'), +(-1001140,'1...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN_1'), + +(-1001141,'Nope, not here...',0,0,0,0,'stinky ignatz SAY_SECOND_STOP'), +(-1001142,'There must be one around here somewhere...',0,0,0,0,'stinky ignatz SAY_THIRD_STOP_1'), +(-1001143,'Ah, there\'s one!',0,0,0,0,'stinky ignatz SAY_THIRD_STOP_2'), +(-1001144,'Come, $N! Let\'s go over there and collect it!',0,0,0,0,'stinky ignatz SAY_THIRD_STOP_3'), +(-1001145,'Ok, let\'s get out of here!',0,0,0,0,'stinky ignatz SAY_PLANT_GATHERED'), +(-1001146,'I\'m glad you\'re here! Because I need your help!!',0,0,0,0,'stinky ignatz SAY_AGGRO_3'), +(-1001147,'Look out! The $N attacks!',0,0,0,0,'stinky ignatz SAY_AGGRO_4'), + +(-1001148,'I am ready, $N. Let\'s find my equipment and get out of here. I think I know where it is.',0,0,0,1,'captured arko\'narin SAY_ESCORT_START'), +(-1001149,'Oh my! Look at this... all these candles. I\'m sure they\'re used for some terrible ritual or dark summoning. We best make haste.',0,0,0,18,'captured arko\'narin SAY_FIRST_STOP'), +(-1001150,'There! Over there!',0,0,0,25,'captured arko\'narin SAY_SECOND_STOP'), +(-1001151,'You will not stop me from escaping here, $N!',0,0,0,0,'captured arko\'narin SAY_AGGRO'), +(-1001152,'All I need now is a golden lasso.',0,0,0,0,'captured arko\'narin SAY_EQUIPMENT'), +(-1001153,'DIE DEMON DOGS!',0,0,0,0,'captured arko\'narin SAY_ESCAPE'), +(-1001154,'Ah! Fresh air at last! I never thought I\'d see the day.',0,0,0,4,'captured arko\'narin SAY_FRESH_AIR'), +(-1001155,'BETRAYER!',0,1,0,0,'spirit of trey lightforge SAY_BETRAYER'), +(-1001156,'What was that?! Trey? TREY?',0,0,0,22,'captured arko\'narin SAY_TREY'), +(-1001157,'You kept me in the cell for too long, monster!',0,0,0,0,'captured arko\'narin SAY_ATTACK_TREY'), +(-1001158,'No! My friend... what\'s happened? This is all my fault...',0,0,0,18,'captured arko\'narin SAY_ESCORT_COMPLETE'), + +(-1001159,'Please, help me to get through this cursed forest, $r.',0,0,0,0,'arei SAY_ESCORT_START'), +(-1001160,'This creature suffers from the effect of the fel... We must end its misery.',0,0,0,0,'arei SAY_ATTACK_IRONTREE'), +(-1001161,'The corruption of the fel has not left any of the creatures of Felwood untouched, $N. Please, be on your guard.',0,0,0,0,'arei SAY_ATTACK_TOXIC_HORROR'), +(-1001162,'I sense the taint of corruption upon this $N. Help me detroy it.',0,0,0,0,'arei SAY_EXIT_WOODS'), +(-1001163,'That I must fight against my own kind deeply saddens me.',0,0,0,0,'arei SAY_CLEAR_PATH'), +(-1001164,'I can sens it now, $N. Ashenvale lies down this path.',0,0,0,0,'arei SAY_ASHENVALE'), +(-1001165,'I feel... something strange...',0,0,0,0,'arei SAY_TRANSFORM'), +(-1001166,'$N my form has now changed! The true strength of my spirit is returing to me now... The cursed grasp of the forest is leaving me.',0,0,0,0,'arei SAY_LIFT_CURSE'), +(-1001167,'Thank you, $N. Now my spirit will finally be at peace.',0,0,0,0,'arei SAY_ESCORT_COMPLETE'), + +(-1001168,'The naga torture the spirits of water. They invoke chaos and destruction!',0,0,0,0,'wilda SAY_WIL_PROGRESS_4'), +(-1001169,'The naga do not respect nature. They twist and corrupt it to meet their needs. They live to agitate the spirits.',0,0,0,0,'wilda SAY_WIL_PROGRESS_5'), + +(-1001170,'Time only has meaning to mortals, insect. Dimensius is infinite!',0,1,0,0,'dimensius SAY_AGGRO'), +(-1001171,'I hunger! Feed me the power of this forge, my children!',0,1,0,0,'dimensius SAY_SUMMON'), + +(-1001172,'Spare my life! I will tell you about Arelion\'s secret.',0,0,0,0,'magister_aledis SAY_ALEDIS_DEFEAT'), + +(-1001173,'Are you ready, Mr. Floppy? Stay close to me and watch out for those wolves!',0,0,0,0,'emily SAY_ESCORT_START'), +(-1001174,'Um... I think one of those wolves is back...',0,0,0,0,'emily SAY_FIRST_WOLF'), +(-1001175,'He\'s going for Mr. Floppy!',0,0,0,0,'emily SAY_WOLF_ATTACK'), +(-1001176,'There\'s a big meanie attacking Mr. Floppy! Help!',0,0,0,0,'emily SAY_HELP_FLOPPY_1'), +(-1001177,'Let\'s get out of here before more wolves find us!',0,0,0,0,'emily SAY_FIRST_WOLF_DEFEAT'), +(-1001178,'Oh, no! Look, it\'s another wolf, and it\'s a biiiiiiig one!',0,0,0,0,'emily SAY_SECOND_WOLF'), +(-1001179,'He\'s gonna eat Mr. Floppy! You gotta help Mr. Floppy! You just gotta!',0,0,0,0,'emily SAY_HELP_FLOPPY_2'), +(-1001180,'Don\'t go toward the light, Mr. Floppy!',0,0,0,0,'emily SAY_FLOPPY_ALMOST_DEAD'), +(-1001181,'Mr. Floppy, you\'re ok! Thank you so much for saving Mr. Floppy!',0,0,0,0,'emily SAY_SECOND_WOLF_DEFEAT'), +(-1001182,'I think I see the camp! We\'re almost home, Mr. Floppy! Let\'s go!',0,0,0,0,'emily SAY_RESUME_ESCORT'), +(-1001183,'Thank you for helping me to get back to the camp. Go tell Walter that I\'m safe now!',0,0,0,0,'emily SAY_ESCORT_COMPLETE'), + +(-1001184,'How did you find me? Did Landgren tell?',14201,0,0,0,'admiral_westwind SAY_AGGRO'), +(-1001185,'You thought I would just let you kill me?',14205,0,0,0,'admiral_westwind SAY_SPHERE'), +(-1001186,'WHAT?! No matter. Even without my sphere, I will crush you! Behold my true identity and despair!',14207,1,0,0,'admiral_westwind SAY_NO_MATTER'), +(-1001187,'Gah! I spent too much time in that weak little shell.',14426,1,0,0,'malganis_icecrown SAY_TRANSFORM'), +(-1001188,'Kirel narak! I am Mal\'Ganis. I AM ETERNAL!',14427,1,0,0,'malganis_icecrown SAY_20_HP'), +(-1001189,'ENOUGH! I waste my time here. I must gather my strength on the homeworld.',14428,1,0,0,'malganis_icecrown SAY_DEFEATED'), +(-1001190,'You\'ll never defeat the Lich King without my forces. I\'ll have my revenge... on him AND you!',14429,1,0,0,'malganis_icecrown SAY_ESCAPE'); -- -1 033 000 SHADOWFANG KEEP INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -967,7 +1385,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1070001,'Who dares awaken Archaedas? Who dares the wrath of the makers!',5855,1,0,0,'archaedas SAY_AGGRO'), (-1070002,'Awake ye servants, defend the discs!',5856,1,0,0,'archaedas SAY_AWAKE_GUARDIANS'), (-1070003,'To my side, brothers. For the makers!',5857,1,0,0,'archaedas SAY_AWAKE_WARDERS'), -(-1070004,'Reckless mortal.',5858,1,0,0,'archaedas SAY_UNIT_SLAIN'); +(-1070004,'Reckless mortal.',5858,1,0,0,'archaedas SAY_UNIT_SLAIN'), +(-1070005,'%s breaks free from his stone slumber!',0,2,0,0,'archaedas EMOTE_BREAK_FREE'); -- -1 090 000 GNOMEREGAN INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1022,11 +1441,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen -- -1 129 000 RAZORFEN DOWNS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1129000,'You\'ll never leave this place... alive.',5825,1,0,0,'amnennar SAY_AGGRO'), -(-1129001,'To me, my servants!',5828,1,0,0,'amnennar SAY_SUMMON60'), -(-1129002,'Come, spirits, attend your master!',5829,1,0,0,'amnennar SAY_SUMMON30'), -(-1129003,'I am the hand of the Lich King!',5827,1,0,0,'amnennar SAY_HP'), -(-1129004,'Too...easy!',5826,1,0,0,'amnennar SAY_KILL'), +(-1129000,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129001,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129002,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129003,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129004,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1129005,'All right, stay close. These fiends will jump right out of the shadows at you if you let your guard down.',0,0,0,0,'belnistrasz SAY_READY'), (-1129006,'Okay, here we go. It\'s going to take about five minutes to shut this thing down through the ritual. Once I start, keep the vermin off of me or it will be the end of us all!',0,0,0,0,'belnistrasz SAY_START_RIT'), @@ -1053,20 +1472,21 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1189009,'The Light has spoken!',5839,1,0,0,'whitemane SAY_WH_KILL'), (-1189010,'Arise, my champion!',5840,1,0,0,'whitemane SAY_WH_RESSURECT'), -(-1189011,'Tell me... tell me everything!',5847,1,0,0,'vishas SAY_AGGRO'), -(-1189012,'Naughty secrets!',5849,1,0,0,'vishas SAY_HEALTH1'), -(-1189013,'I\'ll rip the secrets from your flesh!',5850,1,0,0,'vishas SAY_HEALTH2'), -(-1189014,'Purged by pain!',5848,1,0,0,'vishas SAY_KILL'), +(-1189011,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189012,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189013,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189014,'REUSE_ME',0,0,0,0,'REUSE_ME'), + (-1189015,'The monster got what he deserved.',0,0,1,0,'vishas SAY_TRIGGER_VORREL'), -(-1189016,'We hunger for vengeance.',5844,1,0,0,'thalnos SAY_AGGRO'), -(-1189017,'No rest, for the angry dead.',5846,1,0,0,'thalnos SAY_HEALTH'), -(-1189018,'More... More souls.',5845,1,0,0,'thalnos SAY_KILL'), +(-1189016,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189017,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189018,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1189019,'You will not defile these mysteries!',5842,1,0,0,'doan SAY_AGGRO'), (-1189020,'Burn in righteous fire!',5843,1,0,0,'doan SAY_SPECIALAE'), -(-1189021,'Release the hounds!',5841,1,0,0,'loksey SAY_AGGRO'), +(-1189021,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1189022,'It is over, your search is done! Let fate choose now, the righteous one.',11961,1,0,0,'horseman SAY_ENTRANCE'), (-1189023,'Here\'s my body, fit and pure! Now, your blackened souls I\'ll cure!',12567,1,0,0,'horseman SAY_REJOINED'), @@ -1085,6 +1505,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1189035,'The master has fallen! Avenge him my brethren!',5834,1,0,0,'trainee SAY_TRAINEE_SPAWN'); -- -1 209 000 ZUL'FARRAK +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1209000,'How dare you enter my sanctum!',0,0,0,0,'zumrah SAY_INTRO'), +(-1209001,'Sands consume you!',5872,1,14,0,'zumrah SAY_AGGRO'), +(-1209002,'Fall!',5873,1,14,0,'zumrah SAY_KILL'), +(-1209003,'Come to me, my children!',0,0,8,0,'zumrah SAY_SUMMON'); -- -1 229 000 BLACKROCK SPIRE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1109,7 +1534,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1229017,'Taste in my power!',0,1,0,0,'nefarius SAY_BUFF_GYTH'), (-1229018,'Your victory shall be short lived. The days of both the Alliance and Horde are coming to an end. The next time we meet shall be the last.',0,1,0,1,'nefarius SAY_VICTORY'), -(-1229019,'%s is knocked off his drake!',0,2,0,0,'rend EMOTE_KNOCKED_OFF'); +(-1229019,'%s is knocked off his drake!',0,2,0,0,'rend EMOTE_KNOCKED_OFF'), + +(-1229020,'Intruders are destroying our eggs! Stop!!',0,1,0,0,'rookery hatcher - SAY_ROOKERY_EVENT_START'); -- -1 230 000 BLACKROCK DEPTHS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1118,12 +1545,41 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1230002,'Hail to the king, baby!',0,1,0,0,'dagran SAY_SLAY'), (-1230003,'You have challenged the Seven, and now you will die!',0,0,0,0,'doomrel SAY_DOOMREL_START_EVENT'), -(-1230004,'The Sons of Thaurissan shall watch you perish in the Ring of the Law!',0,1,0,0,'grimstone SAY_START_1'), -(-1230005,'You have been sentenced to death for crimes against the Dark Iron Nation!',0,1,0,0,'grimstone SAY_START_2'), -(-1230006,'Unleash the fury and let it be done!',0,1,0,0,'grimstone SAY_OPEN_EAST_GATE'), -(-1230007,'But your real punishment lies ahead.',0,1,0,0,'grimstone SAY_SUMMON_BOSS_1'), -(-1230008,'Haha! I bet you thought you were done!',0,1,0,0,'grimstone SAY_SUMMON_BOSS_2'), -(-1230009,'Good Riddance!',0,1,0,0,'grimstone SAY_OPEN_NORTH_GATE'); +(-1230004,'The Sons of Thaurissan shall watch you perish in the Ring of the Law!',0,1,0,5,'grimstone SAY_START_1'), +(-1230005,'You have been sentenced to death for crimes against the Dark Iron Nation!',0,1,0,25,'grimstone SAY_START_2'), +(-1230006,'Unleash the fury and let it be done!',0,1,0,15,'grimstone SAY_OPEN_EAST_GATE'), +(-1230007,'But your real punishment lies ahead.',0,1,0,1,'grimstone SAY_SUMMON_BOSS_1'), +(-1230008,'Haha! I bet you thought you were done!',0,1,0,153,'grimstone SAY_SUMMON_BOSS_2'), +(-1230009,'Good Riddance!',0,1,0,5,'grimstone SAY_OPEN_NORTH_GATE'), + +(-1230010,'Thank you, $N! I\'m free!!!',0,0,0,0,'dughal SAY_FREE'), +(-1230011,'You locked up the wrong Marshal, $N. Prepare to be destroyed!',0,0,0,0,'windsor SAY_AGGRO_1'), +(-1230012,'I bet you\'re sorry now, aren\'t you?',0,0,0,0,'windsor SAY_AGGRO_2'), +(-1230013,'You better hold me back or $N is going to feel some prison house beatings.',0,0,0,0,'windsor SAY_AGGRO_3'), +(-1230014,'Let\'s get a move on. My gear should be in the storage area up this way...',0,0,0,0,'windsor SAY_START'), +(-1230015,'Check that cell, $N. If someone is alive in there, we need to get them out.',0,0,0,25,'windsor SAY_CELL_DUGHAL_1'), +(-1230016,'Good work! We\'re almost there, $N. This way.',0,0,0,0,'windsor SAY_CELL_DUGHAL_3'), +(-1230017,'This is it, $N. My stuff should be in that room. Cover me, I\'m going in!',0,0,0,0,'windsor SAY_EQUIPMENT_1'), +(-1230018,'Ah, there it is!',0,0,0,0,'windsor SAY_EQUIPMENT_2'), +(-1230019,'Can you feel the power, $N??? It\'s time to ROCK!',0,0,0,0,'reginald_windsor SAY__EQUIPMENT_3'), +(-1230020,'Now we just have to free Tobias and we can get out of here. This way!',0,0,0,0,'reginald_windsor SAY__EQUIPMENT_4'), +(-1230021,'Open it.',0,0,0,25,'reginald_windsor SAY_CELL_JAZ_1'), +(-1230022,'I never did like those two. Let\'s get moving.',0,0,0,0,'reginald_windsor SAY_CELL_JAZ_2'), +(-1230023,'Open it and be careful this time!',0,0,0,25,'reginald_windsor SAY_CELL_SHILL_1'), +(-1230024,'That intolerant dirtbag finally got what was coming to him. Good riddance!',0,0,0,66,'reginald_windsor SAY_CELL_SHILL_2'), +(-1230025,'Alright, let\'s go.',0,0,0,0,'reginald_windsor SAY_CELL_SHILL_3'), +(-1230026,'Open it. We need to hurry up. I can smell those Dark Irons coming a mile away and I can tell you one thing, they\'re COMING!',0,0,0,25,'reginald_windsor SAY_CELL_CREST_1'), +(-1230027,'He has to be in the last cell. Unless... they killed him.',0,0,0,0,'reginald_windsor SAY_CELL_CREST_2'), +(-1230028,'Get him out of there!',0,0,0,25,'reginald_windsor SAY_CELL_TOBIAS_1'), +(-1230029,'Excellent work, $N. Let\'s find the exit. I think I know the way. Follow me!',0,0,0,0,'reginald_windsor SAY_CELL_TOBIAS_2'), +(-1230030,'We made it!',0,0,0,4,'reginald_windsor SAY_FREE_1'), +(-1230031,'Meet me at Maxwell\'s encampment. We\'ll go over the next stages of the plan there and figure out a way to decode my tablets without the decryption ring.',0,0,0,1,'reginald_windsor SAY_FREE_2'), +(-1230032,'Thank you! I will run for safety immediately!',0,0,0,0,'tobias SAY_TOBIAS_FREE_1'), +(-1230033,'Finally!! I can leave this dump.',0,0,0,0,'tobias SAY_TOBIAS_FREE_2'), + +(-1230034,'You\'ll pay for this insult, $c!',0,0,0,15,'coren direbrew SAY_AGGRO'), + +(-1230035,'%s cries out an alarm!',0,2,0,0,'general_angerforge EMOTE_ALARM'); -- -1 249 000 ONYXIA'S LAIR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1207,7 +1663,12 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1309022,'You dare set foot upon Hakkari holy ground? Minions of Hakkar, destroy the infidels!',0,6,0,0,'hakkar SAY_MINION_DESTROY'), (-1309023,'Minions of Hakkar, hear your God. The sanctity of this temple has been compromised. Invaders encroach upon holy ground! The Altar of Blood must be protected. Kill them all!',0,6,0,0,'hakkar SAY_PROTECT_ALTAR'), -(-1309024,'%s goes into a rage after seeing his raptor fall in battle!',0,2,0,0,'mandokir EMOTE_RAGE'); +(-1309024,'%s goes into a rage after seeing his raptor fall in battle!',0,2,0,0,'mandokir EMOTE_RAGE'), + +(-1309025,'The brood shall not fall!',0,1,0,0,'marli SAY_TRANSFORM_BACK'), + +(-1309026,'%s emits a deafening shriek!',0,2,0,0,'jeklik SAY_SHRIEK'), +(-1309027,'%s begins to cast a Great Heal!',0,2,0,0,'jeklik SAY_HEAL'); -- -1 329 000 STRATHOLME INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1275,7 +1736,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1429000,'The demon is loose! Quickly we must restrain him!',0,6,0,0,'highborne summoner SAY_FREE_IMMOLTHAR'), (-1429001,'Who dares disrupt the sanctity of Eldre\'Thalas? Face me, cowards!',0,6,0,0,'prince tortheldrin SAY_KILL_IMMOLTHAR'), -(-1429002,'At last... Freed from his cursed grasp!',0,6,0,0,'old ironbark SAY_IRONBARK_REDEEM'); +(-1429002,'At last... Freed from his cursed grasp!',0,6,0,0,'old ironbark SAY_IRONBARK_REDEEM'), + +(-1429003,'The king is dead - OH NOES! Summon Mizzle da Crafty! He knows what to do next!',0,1,0,0,'cho\'rush SAY_KING_DEAD'); -- -1 469 000 BLACKWING LAIR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1322,7 +1785,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1469033,'%s flee as the controlling power of the orb is drained.',0,2,0,0,'razorgore EMOTE_TROOPS_FLEE'), -(-1469034,'Run! They are coming.',0,1,0,0,'blackwing technician SAY_TECHNICIAN_RUN'); +(-1469034,'Run! They are coming.',0,1,0,0,'blackwing technician SAY_TECHNICIAN_RUN'), + +(-1469035,'Orb of Domination loses power and shuts off!',0,2,0,0,'razorgore EMOTE_ORB_SHUT_OFF'); -- -1 509 000 RUINS OF AHN'QIRAJ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1332,8 +1797,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1509002,'%s sets eyes on $N!',0,2,0,0,'buru EMOTE_TARGET'), -(-1509003,'They come now. Try not to get yourself killed, young blood.',0,1,0,0,'andorov SAY_ANDOROV_INTRO'), -(-1509004,'Remember, Rajaxx, when I said I\'d kill you last? I lied...',0,1,0,0,'andorov SAY_ANDOROV_ATTACK'), +(-1509003,'They come now. Try not to get yourself killed, young blood.',0,1,0,22,'andorov SAY_ANDOROV_INTRO_3'), +(-1509004,'Remember, Rajaxx, when I said I\'d kill you last?',0,1,0,0,'andorov SAY_ANDOROV_INTRO_1'), (-1509005,'The time of our retribution is at hand! Let darkness reign in the hearts of our enemies!',8612,1,0,0,'rajaxx SAY_WAVE3'), (-1509006,'No longer will we wait behind barred doors and walls of stone! No longer will our vengeance be denied! The dragons themselves will tremble before our wrath!',8610,1,0,0,'rajaxx SAY_WAVE4'), @@ -1358,7 +1823,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1509024,'Tresspassers will be terminated.',8601,1,0,0,'ossirian SAY_RAND_INTRO4'), (-1509025,'Sands of the desert rise and block out the sun!',8598,1,0,0,'ossirian SAY_AGGRO'), (-1509026,'You are terminated.',8602,1,0,0,'ossirian SAY_SLAY'), -(-1509027,'I...have...failed.',8594,1,0,0,'ossirian SAY_DEATH'); +(-1509027,'I...have...failed.',8594,1,0,0,'ossirian SAY_DEATH'), +-- 28 (above) = EMOTE_ENERGIZING +(-1509029,'Come get some!',0,0,0,0,'andorov SAY_ANDOROV_INTRO_4'), +(-1509030,'Kill first, ask questions later... Incoming!',0,1,0,0,'andorov SAY_ANDOROV_ATTACK_START'), +(-1509031,'I lied...',0,1,0,0,'andorov SAY_ANDOROV_INTRO_2'); -- -1 531 000 TEMPLE OF AHN'QIRAJ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1375,7 +1844,47 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1531009,'I sentence you to death!',8647,1,0,0,'sartura SAY_SLAY'), (-1531010,'I serve to the last!',8648,1,0,0,'sartura SAY_DEATH'), -(-1531011,'%s is weakened!',0,2,0,0,'cthun EMOTE_WEAKENED'); +(-1531011,'%s is weakened!',0,2,0,0,'cthun EMOTE_WEAKENED'), + +(-1531012,'The massive floating eyeball in the center of the chamber turns its gaze upon you. You stand before a god.',0,2,0,0,'eye cthun EMOTE_INTRO'), +(-1531013,'Only flesh and bone. Mortals are such easy prey...',0,1,0,0,'veklor SAY_INTRO_1'), +(-1531014,'Where are your manners, brother. Let us properly welcome our guests.',0,1,0,0,'veknilash SAY_INTRO_2'), +(-1531015,'There will be pain...',0,1,0,0,'veklor SAY_INTRO_3'), +(-1531016,'Oh so much pain...',0,1,0,0,'veknilash SAY_INTRO_4'), +(-1531017,'Come, little ones.',0,1,0,0,'veklor SAY_INTRO_5'), +(-1531018,'The feast of souls begin now...',0,1,0,0,'veknilash SAY_INTRO_6'), + +(-1531019,'It\'s too late to turn away.',8623,1,0,0,'veklor SAY_AGGRO_1'), +(-1531020,'Prepare to embrace oblivion!',8626,1,0,0,'veklor SAY_AGGRO_2'), +(-1531021,'Like a fly in a web.',8624,1,0,0,'veklor SAY_AGGRO_3'), +(-1531022,'Your brash arrogance!',8628,1,0,0,'veklor SAY_AGGRO_4'), +(-1531023,'You will not escape death!',8629,1,0,0,'veklor SAY_SLAY'), +(-1531024,'My brother...NO!',8625,1,0,0,'veklor SAY_DEATH'), +(-1531025,'To decorate our halls!',8627,1,0,0,'veklor SAY_SPECIAL'), + +(-1531026,'Ah, lambs to the slaughter!',8630,1,0,0,'veknilash SAY_AGGRO_1'), +(-1531027,'Let none survive!',8632,1,0,0,'veknilash SAY_AGGRO_2'), +(-1531028,'Join me brother, there is blood to be shed!',8631,1,0,0,'veknilash SAY_AGGRO_3'), +(-1531029,'Look brother, fresh blood!',8633,1,0,0,'veknilash SAY_AGGRO_4'), +(-1531030,'Your fate is sealed!',8635,1,0,0,'veknilash SAY_SLAY'), +(-1531031,'Vek\'lor, I feel your pain!',8636,1,0,0,'veknilash SAY_DEATH'), +(-1531032,'Shall be your undoing!',8634,1,0,0,'veknilash SAY_SPECIAL'), + +(-1531033,'Death is close...',8580,4,0,0,'cthun SAY_WHISPER_1'), +(-1531034,'You are already dead.',8581,4,0,0,'cthun SAY_WHISPER_2'), +(-1531035,'Your courage will fail.',8582,4,0,0,'cthun SAY_WHISPER_3'), +(-1531036,'Your friends will abandon you.',8583,4,0,0,'cthun SAY_WHISPER_4'), +(-1531037,'You will betray your friends.',8584,4,0,0,'cthun SAY_WHISPER_5'), +(-1531038,'You will die.',8585,4,0,0,'cthun SAY_WHISPER_6'), +(-1531039,'You are weak.',8586,4,0,0,'cthun SAY_WHISPER_7'), +(-1531040,'Your heart will explode.',8587,4,0,0,'cthun SAY_WHISPER_8'), + +(-1531041,'%s begins to slow!',0,2,0,0,'viscidus EMOTE_SLOW'), +(-1531042,'%s is freezing up!',0,2,0,0,'viscidus EMOTE_FREEZE'), +(-1531043,'%s is frozen solid!',0,2,0,0,'viscidus EMOTE_FROZEN'), +(-1531044,'%s begins to crack!',0,2,0,0,'viscidus EMOTE_CRACK'), +(-1531045,'%s looks ready to shatter!',0,2,0,0,'viscidus EMOTE_SHATTER'), +(-1531046,'%s explodes!',0,2,0,0,'viscidus EMOTE_EXPLODE'); -- -1 532 000 KARAZHAN INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1482,8 +1991,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1532087,'At last... The nightmare is.. over...',9244,1,0,0,'aran SAY_DEATH'), (-1532088,'Where did you get that?! Did HE send you?!',9249,1,0,0,'aran SAY_ATIESH'), -(-1532089,'%s cries out in withdrawal, opening gates to the warp.',0,2,0,0,'netherspite EMOTE_PHASE_PORTAL'), -(-1532090,'%s goes into a nether-fed rage!',0,2,0,0,'netherspite EMOTE_PHASE_BANISH'), +(-1532089,'%s cries out in withdrawal, opening gates to the warp.',0,3,0,0,'netherspite EMOTE_PHASE_PORTAL'), +(-1532090,'%s goes into a nether-fed rage!',0,3,0,0,'netherspite EMOTE_PHASE_BANISH'), (-1532091,'Madness has brought you here to me. I shall be your undoing!',9218,1,0,0,'malchezaar SAY_AGGRO'), (-1532092,'Simple fools! Time is the fire in which you\'ll burn!',9220,1,0,0,'malchezaar SAY_AXE_TOSS1'), @@ -1509,7 +2018,28 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1532111,'Welcome, Ladies and Gentlemen, to this evening\'s presentation!',9176,1,0,0,'barnes RAJ1'), (-1532112,'Tonight, we explore a tale of forbidden love!',9341,1,0,0,'barnes RAJ2'), (-1532113,'But beware, for not all love stories end happily, as you may find out. Sometimes, love pricks like a thorn.',9342,1,0,0,'barnes RAJ3'), -(-1532114,'But don\'t take it from me, see for yourself what tragedy lies ahead when the paths of star-crossed lovers meet. And now...on with the show!',9343,1,0,0,'barnes RAJ4'); +(-1532114,'But don\'t take it from me, see for yourself what tragedy lies ahead when the paths of star-crossed lovers meet. And now...on with the show!',9343,1,0,0,'barnes RAJ4'), +(-1532115,'Splendid, I\'m going to get the audience ready. Break a leg!',0,0,0,0,'barnes SAY_EVENT_START'), + +(-1532116,'You\'ve got my attention, dragon. You\'ll find I\'m not as easily scared as the villagers below.',0,1,0,0,'image of medivh SAY_MEDIVH_1'), +(-1532117,'Your dabbling in the arcane has gone too far, Medivh. You\'ve attracted the attention of powers beyond your understanding. You must leave Karazhan at once!',0,1,0,0,'arcanagos SAY_ARCANAGOS_2'), +(-1532118,'You dare challenge me at my own dwelling? Your arrogance is astounding, even for a dragon.',0,1,0,0,'image of medivh SAY_MEDIVH_3'), +(-1532119,'A dark power seeks to use you, Medivh! If you stay, dire days will follow. You must hurry, we don\'t have much time!',0,1,0,0,'arcanagos SAY_ARCANAGOS_4'), +(-1532120,'I do not know what you speak of, dragon... but I will not be bullied by this display of insolence. I\'ll leave Karazhan when it suits me!',0,1,0,0,'image of medivh SAY_MEDIVH_5'), +(-1532121,'You leave me no alternative. I will stop you by force if you wont listen to reason.',0,1,0,0,'arcanagos SAY_ARCANAGOS_6'), +(-1532122,'%s begins to cast a spell of great power, weaving his own essence into the magic.',0,2,0,0,'image of medivh EMOTE_CAST_SPELL'), +(-1532123,'What have you done, wizard? This cannot be! I\'m burning from... within!',0,1,0,0,'arcanagos SAY_ARCANAGOS_7'), +(-1532124,'He should not have angered me. I must go... recover my strength now...',0,0,0,0,'image of medivh SAY_MEDIVH_8'), + +(-1532125,'An ancient being awakens in the distance...',0,2,0,0,'nightbane EMOTE_AWAKEN'), +(-1532126,'What fools! I shall bring a quick end to your suffering!',0,1,0,0,'nightbane SAY_AGGRO'), +(-1532127,'Miserable vermin. I shall exterminate you from the air!',0,1,0,0,'nightbane SAY_AIR_PHASE'), +(-1532128,'Enough! I shall land and crush you myself!',0,1,0,0,'nightbane SAY_LAND_PHASE_1'), +(-1532129,'Insects! Let me show you my strength up close!',0,1,0,0,'nightbane SAY_LAND_PHASE_2'), +(-1532130,'%s takes a deep breath.',0,3,0,0,'nightbane EMOTE_DEEP_BREATH'), + +(-1532131,'The halls of Karazhan shake, as the curse binding the doors of the Gamemaster\'s Hall is lifted.',0,2,0,0,'echo_of_medivh EMOTE_LIFT_CURSE'), +(-1532132,'%s cheats!',0,3,0,0,'echo_of_medivh EMOTE_CHEAT'); -- -1 533 000 NAXXRAMAS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1566,25 +2096,25 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1533043,'I have waited long enough! Now, you face the harvester of souls!',8808,1,0,0,'gothik SAY_TELEPORT'), (-1533044,'Defend youself!',8892,1,0,0,'blaumeux SAY_BLAU_AGGRO'), -(-1533045,'Come, Zeliek, do not drive them out. Not before we\'ve had our fun.',8896,1,0,0,'blaumeux SAY_BLAU_TAUNT1'), -(-1533046,'I do hope they stay alive long enough for me to... introduce myself.',8897,1,0,0,'blaumeux SAY_BLAU_TAUNT2'), -(-1533047,'The first kill goes to me! Anyone care to wager?',8898,1,0,0,'blaumeux SAY_BLAU_TAUNT3'), +(-1533045,'Come, Zeliek, do not drive them out. Not before we\'ve had our fun.',8896,6,0,0,'blaumeux SAY_BLAU_TAUNT1'), +(-1533046,'I do hope they stay alive long enough for me to... introduce myself.',8897,6,0,0,'blaumeux SAY_BLAU_TAUNT2'), +(-1533047,'The first kill goes to me! Anyone care to wager?',8898,6,0,0,'blaumeux SAY_BLAU_TAUNT3'), (-1533048,'Your life is mine!',8895,1,0,0,'blaumeux SAY_BLAU_SPECIAL'), (-1533049,'Who\'s next?',8894,1,0,0,'blaumeux SAY_BLAU_SLAY'), (-1533050,'Tou... che!',8893,1,0,0,'blaumeux SAY_BLAU_DEATH'), (-1533051,'Come out and fight, ye wee ninny!',8899,1,0,0,'korthazz SAY_KORT_AGGRO'), -(-1533052,'To arms, ye roustabouts! We\'ve got company!',8903,1,0,0,'korthazz SAY_KORT_TAUNT1'), -(-1533053,'I heard about enough of yer sniveling. Shut yer fly trap \'afore I shut it for ye!',8904,1,0,0,'korthazz SAY_KORT_TAUNT2'), -(-1533054,'I\'m gonna enjoy killin\' these slack-jawed daffodils!',8905,1,0,0,'korthazz SAY_KORT_TAUNT3'), +(-1533052,'To arms, ye roustabouts! We\'ve got company!',8903,6,0,0,'korthazz SAY_KORT_TAUNT1'), +(-1533053,'I heard about enough of yer sniveling. Shut yer fly trap \'afore I shut it for ye!',8904,6,0,0,'korthazz SAY_KORT_TAUNT2'), +(-1533054,'I\'m gonna enjoy killin\' these slack-jawed daffodils!',8905,6,0,0,'korthazz SAY_KORT_TAUNT3'), (-1533055,'I like my meat extra crispy!',8902,1,0,0,'korthazz SAY_KORT_SPECIAl'), (-1533056,'Next time, bring more friends!',8901,1,0,0,'korthazz SAY_KORT_SLAY'), (-1533057,'What a bloody waste this is!',8900,1,0,0,'korthazz SAY_KORT_DEATH'), (-1533058,'Flee, before it\'s too late!',8913,1,0,0,'zeliek SAY_ZELI_AGGRO'), -(-1533059,'Invaders, cease this foolish venture at once! Turn away while you still can!',8917,1,0,0,'zeliek SAY_ZELI_TAUNT1'), -(-1533060,'Perhaps they will come to their senses, and run away as fast as they can!',8918,1,0,0,'zeliek SAY_ZELI_TAUNT2'), -(-1533061,'Do not continue! Turn back while there\'s still time!',8919,1,0,0,'zeliek SAY_ZELI_TAUNT3'), +(-1533059,'Invaders, cease this foolish venture at once! Turn away while you still can!',8917,6,0,0,'zeliek SAY_ZELI_TAUNT1'), +(-1533060,'Perhaps they will come to their senses, and run away as fast as they can!',8918,6,0,0,'zeliek SAY_ZELI_TAUNT2'), +(-1533061,'Do not continue! Turn back while there\'s still time!',8919,6,0,0,'zeliek SAY_ZELI_TAUNT3'), (-1533062,'I- I have no choice but to obey!',8916,1,0,0,'zeliek SAY_ZELI_SPECIAL'), (-1533063,'Forgive me!',8915,1,0,0,'zeliek SAY_ZELI_SLAY'), (-1533064,'It is... as it should be.',8914,1,0,0,'zeliek SAY_ZELI_DEATH'), @@ -1595,9 +2125,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1533068,'You will find no peace in death.',14574,1,0,0,'rivendare_naxx SAY_RIVE_SLAY1'), (-1533069,'The master\'s will is done.',14575,1,0,0,'rivendare_naxx SAY_RIVE_SLAY2'), (-1533070,'Bow to the might of the scourge!',14576,1,0,0,'rivendare_naxx SAY_RIVE_SPECIAL'), -(-1533071,'Enough prattling. Let them come! We shall grind their bones to dust.',14577,1,0,0,'rivendare_naxx SAY_RIVE_TAUNT1'), -(-1533072,'Conserve your anger! Harness your rage! You will all have outlets for your frustration soon enough.',14578,1,0,0,'rivendare_naxx SAY_RIVE_TAUNT2'), -(-1533073,'Life is meaningless. It is in death that we are truly tested.',14579,1,0,0,'rivendare_naxx SAY_RIVE_TAUNT3'), +(-1533071,'Enough prattling. Let them come! We shall grind their bones to dust.',14577,6,0,0,'rivendare_naxx SAY_RIVE_TAUNT1'), +(-1533072,'Conserve your anger! Harness your rage! You will all have outlets for your frustration soon enough.',14578,6,0,0,'rivendare_naxx SAY_RIVE_TAUNT2'), +(-1533073,'Life is meaningless. It is in death that we are truly tested.',14579,6,0,0,'rivendare_naxx SAY_RIVE_TAUNT3'), (-1533074,'Death... will not stop me...',14580,1,0,0,'rivendare_naxx SAY_RIVE_DEATH'), (-1533075,'Glory to the master!',8845,1,0,0,'noth SAY_AGGRO1'), @@ -1723,7 +2253,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1534016,'We have played our part and done well. It is up to the others now.',11035,1,0,0,'thrall hyjal SUCCESS'), (-1534017,'Uraaa...',11034,1,0,0,'thrall hyjal DEATH'), -(-1534018,'All of your efforts have been in vain, for the draining of the World Tree has already begun. Soon the heart of your world will beat no more.',10986,1,0,0,'archimonde SAY_PRE_EVENTS_COMPLETE'), +(-1534018,'All of your efforts have been in vain, for the draining of the World Tree has already begun. Soon the heart of your world will beat no more.',10986,6,0,0,'archimonde SAY_PRE_EVENTS_COMPLETE'), (-1534019,'Your resistance is insignificant.',10987,1,0,0,'archimonde SAY_AGGRO'), (-1534020,'This world will burn!',10990,1,0,0,'archimonde SAY_DOOMFIRE1'), (-1534021,'Manach sheek-thrish!',11041,1,0,0,'archimonde SAY_DOOMFIRE2'), @@ -1851,12 +2381,12 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen -- -1 544 000 MAGTHERIDON'S LAIR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1544000,'Wretched, meddling insects. Release me and perhaps i will grant you a merciful death!',10247,1,0,0,'magtheridon SAY_TAUNT1'), -(-1544001,'Vermin! Leeches! Take my blood and choke on it!',10248,1,0,0,'magtheridon SAY_TAUNT2'), -(-1544002,'Illidan is an arrogant fool. I will crush him and reclaim Outland as my own.',10249,1,0,0,'magtheridon SAY_TAUNT3'), -(-1544003,'Away, you mindless parasites. My blood is my own!',10250,1,0,0,'magtheridon SAY_TAUNT4'), -(-1544004,'How long do you believe your pathetic sorcery can hold me?',10251,1,0,0,'magtheridon SAY_TAUNT5'), -(-1544005,'My blood will be the end of you!',10252,1,0,0,'magtheridon SAY_TAUNT6'), +(-1544000,'Wretched, meddling insects. Release me and perhaps i will grant you a merciful death!',10247,6,0,0,'magtheridon SAY_TAUNT1'), +(-1544001,'Vermin! Leeches! Take my blood and choke on it!',10248,6,0,0,'magtheridon SAY_TAUNT2'), +(-1544002,'Illidan is an arrogant fool. I will crush him and reclaim Outland as my own.',10249,6,0,0,'magtheridon SAY_TAUNT3'), +(-1544003,'Away, you mindless parasites. My blood is my own!',10250,6,0,0,'magtheridon SAY_TAUNT4'), +(-1544004,'How long do you believe your pathetic sorcery can hold me?',10251,6,0,0,'magtheridon SAY_TAUNT5'), +(-1544005,'My blood will be the end of you!',10252,6,0,0,'magtheridon SAY_TAUNT6'), (-1544006,'I...am...UNLEASHED!!!',10253,1,0,0,'magtheridon SAY_FREED'), (-1544007,'Thank you for releasing me. Now...die!',10254,1,0,0,'magtheridon SAY_AGGRO'), (-1544008,'Not again...NOT AGAIN!',10256,1,0,0,'magtheridon SAY_BANISH'), @@ -1866,7 +2396,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1544012,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1544013,'%s begins to cast Blast Nova!',0,3,0,0,'magtheridon EMOTE_BLASTNOVA'), (-1544014,'%s\'s bonds begin to weaken!',0,2,0,0,'magtheridon EMOTE_BEGIN'), -(-1544015,'%s breaks free!',0,2,0,0,'magtheridon EMOTE_FREED'); +(-1544015,'%s breaks free!',0,2,0,0,'magtheridon EMOTE_FREED'), +(-1544016,'%s is nearly free of his bonds!',0,2,0,0,'magtheridon EMOTE_NEARLY_FREE'); -- -1 545 000 THE STEAMVAULT INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -1947,9 +2478,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1548036,'Strugging only makes it worse.',11327,1,0,0,'morogrim SAY_SLAY2'), (-1548037,'Only the strong survive.',11328,1,0,0,'morogrim SAY_SLAY3'), (-1548038,'Great... currents of... Ageon.',11329,1,0,0,'morogrim SAY_DEATH'), -(-1548039,'%s sends his enemies to their watery graves!',0,2,0,0,'morogrim EMOTE_WATERY_GRAVE'), +(-1548039,'%s sends his enemies to their watery graves!',0,3,0,0,'morogrim EMOTE_WATERY_GRAVE'), (-1548040,'The violent earthquake has alerted nearby murlocs!',0,3,0,0,'morogrim EMOTE_EARTHQUAKE'), -(-1548041,'%s summons Watery Globules!',0,2,0,0,'morogrim EMOTE_WATERY_GLOBULES'), +(-1548041,'%s summons Watery Globules!',0,3,0,0,'morogrim EMOTE_WATERY_GLOBULES'), (-1548042,'Water is life. It has become a rare commodity here in Outland. A commodity that we alone shall control. We are the Highborne, and the time has come at last for us to retake our rightful place in the world!',11531,1,0,0,'vashj SAY_INTRO'), (-1548043,'I\'ll split you from stem to stern!',11532,1,0,0,'vashj SAY_AGGRO1'), @@ -1964,7 +2495,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1548052,'Your time ends now!',11541,1,0,0,'vashj SAY_SLAY1'), (-1548053,'You have failed!',11542,1,0,0,'vashj SAY_SLAY2'), (-1548054,'Be\'lamere an\'delay',11543,1,0,0,'vashj SAY_SLAY3'), -(-1548055,'Lord Illidan, I... I am... sorry.',11544,1,0,0,'vashj SAY_DEATH'); +(-1548055,'Lord Illidan, I... I am... sorry.',11544,1,0,0,'vashj SAY_DEATH'), + +(-1548056,'%s takes a deep breath!',0,3,0,0,'lurker below EMOTE_DEEP_BREATH'); -- -1 550 000 THE EYE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2017,7 +2550,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1550041,'This is not over!',11118,1,0,0,'capernian SAY_CAPERNIAN_DEATH'), (-1550042,'Anar\'alah belore!',11157,1,0,0,'telonicus SAY_TELONICUS_AGGRO'), -(-1550043,'More perils... await',11158,1,0,0,'telonicus SAY_TELONICUS_DEATH'); +(-1550043,'More perils... await',11158,1,0,0,'telonicus SAY_TELONICUS_DEATH'), + +(-1550044,'%s begins to cast Pyroblast!',0,3,0,0,'kaelthas EMOTE_PYROBLAST'); -- -1 552 000 THE ARCATRAZ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2053,7 +2588,35 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1552027,'What is this? A lowly gnome? I will do better, O\'great one.',11226,1,0,0,'mellichar YELL_RELEASE2B'), (-1552028,'Anarchy! Bedlam! Oh, you are so wise! Yes, I see it now, of course!',11227,1,0,0,'mellichar YELL_RELEASE3'), (-1552029,'One final cell remains. Yes, O\'great one, right away!',11228,1,0,0,'mellichar YELL_RELEASE4'), -(-1552030,'Welcome, O\'great one. I am your humble servant.',11229,1,0,0,'mellichar YELL_WELCOME'); +(-1552030,'Welcome, O\'great one. I am your humble servant.',11229,1,0,0,'mellichar YELL_WELCOME'), + +(-1552031,'It is unwise to anger me.',11086,1,0,0,'dalliah SAY_AGGRO'), +(-1552032,'Ahh... That is much better.',11091,1,0,0,'dalliah SAY_HEAL_1'), +(-1552033,'Ahh... Just what I needed.',11092,1,0,0,'dalliah SAY_HEAL_2'), +(-1552034,'Completely ineffective. Just like someone else I know.',11087,1,0,0,'dalliah SAY_KILL_1'), +(-1552035,'You chose the wrong opponent.',11088,1,0,0,'dalliah SAY_KILL_2'), +(-1552036,'I\'ll cut you to pieces!',11090,1,0,0,'dalliah SAY_WHIRLWIND_1'), +(-1552037,'Reap the Whirlwind!',11089,1,0,0,'dalliah SAY_WHIRLWIND_2'), +(-1552038,'Now I\'m really... angry...',11093,1,0,0,'dalliah SAY_DEATH'), + +(-1552039,'Have you come to kill Dalliah? Can I watch?',11237,1,0,1,'soccothrates SAY_DALLIAH_AGGRO_1'), +(-1552040,'This may be the end for you, Dalliah. What a shame that would be.',11245,1,0,1,'soccothrates SAY_DALLIAH_TAUNT_1'), +(-1552041,'Facing difficulties, Dalliah? How nice.',11244,1,0,1,'soccothrates SAY_DALLIAH_TAUNT_2'), +(-1552042,'I suggest a new strategy, you draw the attackers while I gather reinforcements. Hahaha!',11246,1,0,1,'soccothrates SAY_DALLIAH_TAUNT_3'), +(-1552043,'Finally! Well done!',11247,1,0,66,'soccothrates SAY_DALLIAH_DEAD'), +(-1552044,'On guard!',11241,1,0,0,'soccothrates SAY_CHARGE_1'), +(-1552045,'Defend yourself, for all the good it will do...',11242,1,0,0,'soccothrates SAY_CHARGE_2'), +(-1552046,'Knew this was... the only way out',11243,1,0,0,'soccothrates SAY_DEATH'), +(-1552047,'Yes, that was quite satisfying',11239,1,0,0,'soccothrates SAY_KILL'), +(-1552048,'At last, a target for my frustrations!',11238,1,0,0,'soccothrates SAY_AGGRO'), + +(-1552049,'Did you call on me?',11236,1,0,397,'soccothrates SAY_INTRO_1'), +(-1552050,'Why would I call on you?',0,1,0,396,'dalliah SAY_INTRO_2'), +(-1552051,'To do your heavy lifting, most likely.',0,1,0,396,'soccothrates SAY_INTRO_3'), +(-1552052,'When I need someone to prance around like an overstuffed peacock, I''ll call on you.',0,1,0,396,'dalliah SAY_INTRO_4'), +(-1552053,'Then I\'ll commit myself to ignoring you.',0,1,0,396,'soccothrates SAY_INTRO_5'), +(-1552054,'What would you know about commitment, sheet-sah?',0,1,0,396,'dalliah SAY_INTRO_6'), +(-1552055,'You\'re the one who should be-- Wait, we have company...',0,1,0,396,'soccothrates SAY_INTRO_7'); -- -1 553 000 THE BOTANICA INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2081,14 +2644,13 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1554003,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1554004,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1554005,'REUSE_ME',0,0,0,0,'REUSE_ME'), - -(-1554006,'You have approximately five seconds to live.',11109,1,0,0,'ironhand SAY_AGGRO_1'), -(-1554007,'With the precise angle and velocity...',11112,1,0,0,'ironhand SAY_HAMMER_1'), -(-1554008,'Low tech yet quiet effective!',11113,1,0,0,'ironhand SAY_HAMMER_2'), -(-1554009,'A foregone conclusion.',11110,1,0,0,'ironhand SAY_SLAY_1'), -(-1554010,'The processing will continue a schedule!',11111,1,0,0,'ironhand SAY_SLAY_2'), -(-1554011,'My calculations did not...',11114,1,0,0,'ironhand SAY_DEATH_1'), -(-1554012,'%s raises his hammer menacingly...',0,3,0,0,'ironhand EMOTE_HAMMER'), +(-1554006,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554007,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554008,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554009,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554010,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554011,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554012,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1554013,'Don\'t value your life very much, do you?',11186,1,0,0,'sepethrea SAY_AGGRO'), (-1554014,'I am not alone.',11191,1,0,0,'sepethrea SAY_SUMMON'), @@ -2105,7 +2667,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1554024,'I prefeer to be hands-on...',11199,1,0,0,'pathaleon SAY_ENRAGE'), (-1554025,'A minor inconvenience.',11194,1,0,0,'pathaleon SAY_SLAY_1'), (-1554026,'Looks like you lose.',11195,1,0,0,'pathaleon SAY_SLAY_2'), -(-1554027,'The project will... continue.',11200,1,0,0,'pathaleon SAY_DEATH'); +(-1554027,'The project will... continue.',11200,1,0,0,'pathaleon SAY_DEATH'), +(-1554028,'I have been waiting for you!',0,1,0,53,'pathaleon SAY_INTRO'); -- -1 555 000 SHADOW LABYRINTH INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2168,7 +2731,15 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1556011,'You die....stay away from Trinkets',10558,1,0,0,'ikiss SAY_SLAY_1'), (-1556012,'',10559,1,0,0,'ikiss SAY_SLAY_2'), (-1556013,'Ikiss will not....die',10560,1,0,0,'ikiss SAY_DEATH'), -(-1556015,'%s begins to channel arcane energy...',0,3,0,0,'ikiss EMOTE_ARCANE_EXP'); +(-1556015,'%s begins to channel arcane energy...',0,3,0,0,'ikiss EMOTE_ARCANE_EXP'), + +(-1556016,'No! How can this be?',0,1,0,0,'anzu SAY_INTRO_1'), +(-1556017,'Pain will be the price for your insolence! You cannot stop me from claiming the Emerald Dream as my own!',0,1,0,0,'anzu SAY_INTRO_2'), +(-1556018,'Awaken, my children and assist your master!',0,1,0,0,'anzu SAY_BANISH'), +(-1556019,'Your magics shall be your undoing... ak-a-ak...',0,5,0,0,'anzu SAY_WHISPER_MAGIC_1'), +(-1556020,'%s returns to stone.',0,2,0,0,'anzu EMOTE_BIRD_STONE'), +(-1556021,'Your powers... ak-ak... turn against you...',0,5,0,0,'anzu SAY_WHISPER_MAGIC_2'), +(-1556022,'Your spells... ke-kaw... are weak magics... easy to turn against you...',0,5,0,0,'anzu SAY_WHISPER_MAGIC_3'); -- -1 557 000 MANA TOMBS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2206,37 +2777,40 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen -- -1 560 000 ESCAPE FROM DURNHOLDE (OLD HILLSBRAD) INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1560000,'Thrall! You didn\'t really think you would escape did you? You and your allies shall answer to Blackmoore - after I\'ve had my fun!',10406,1,0,0,'skarloc SAY_ENTER'), -(-1560001,'You\'re a slave. That\'s all you\'ll ever be.',10407,1,0,0,'skarloc SAY_TAUNT1'), -(-1560002,'I don\'t know what Blackmoore sees in you. For my money, you\'re just another ignorant savage!',10408,1,0,0,'skarloc SAY_TAUNT2'), -(-1560003,'Thrall will never be free!',10409,1,0,0,'skarloc SAY_SLAY1'), -(-1560004,'Did you really think you would leave here alive?',10410,1,0,0,'skarloc SAY_SLAY2'), -(-1560005,'Guards! Urgh..Guards..!',10411,1,0,0,'skarloc SAY_DEATH'), - -(-1560006,'You there, fetch water quickly! Get these flames out before they spread to the rest of the keep! Hurry, damn you!',10428,1,0,0,'lieutenant_drake SAY_ENTER'), -(-1560007,'I know what you\'re up to, and I mean to put an end to it, permanently!',10429,1,0,0,'lieutenant_drake SAY_AGGRO'), -(-1560008,'No more middling for you.',10432,1,0,0,'lieutenant_drake SAY_SLAY1'), -(-1560009,'You will not interfere!',10433,1,0,0,'lieutenant_drake SAY_SLAY2'), -(-1560010,'Time to bleed!',10430,1,0,0,'lieutenant_drake SAY_MORTAL'), -(-1560011,'Run, you blasted cowards!',10431,1,0,0,'lieutenant_drake SAY_SHOUT'), -(-1560012,'Thrall... must not... go free.',10434,1,0,0,'lieutenant_drake SAY_DEATH'), +(-1560000,'Thrall! You didn\'t really think you would escape did you? You and your allies shall answer to Blackmoore - after I\'ve had my fun!',10406,0,0,1,'skarloc SAY_ENTER'), + +(-1560001,'My magical power can turn back time to before Thrall\'s death, but be careful. My power to manipulate time is limited.',0,0,0,0,'image of eronzion SAY_RESET_THRALL'), +(-1560002,'I have set back the flow of time just once more. If you fail to prevent Thrall\'s death, then all is lost.',0,0,0,0,'image of eronzion SAY_RESET_THRALL_LAST'), + +(-1560003,'What\'s the meaning of this? GUARDS!',0,0,0,0,'armorer SAY_CALL_GUARDS'), +(-1560004,'All that you know... will be undone.',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_1'), +(-1560005,'Let\'s go.',0,0,0,0,'thrall hillsbrad SAY_TH_ARMORY2'), +(-1560006,'%s startles the horse with a fierce yell!',0,2,0,0,'thrall hillsbrad EMOTE_TH_STARTLE_HORSE'), +(-1560007,'I thought I saw something go into the barn.',0,0,0,0,'tarren mill lookout SAY_LOOKOUT_BARN_1'), +(-1560008,'I didn\'t see anything.',0,0,0,0,'tarren mill lookout SAY_PROTECTOR_BARN_2'), +(-1560009,'%s tries to calm the horse down.',0,2,0,0,'thrall hillsbrad EMOTE_TH_CALM_HORSE'), +(-1560010,'Something riled that horse. Let\'s go!',0,0,0,0,'tarren mill lookout SAY_PROTECTOR_BARN_3'), +(-1560011,'Taretha isn\'t here. Let\'s head into town.',0,0,0,0,'thrall hillsbrad SAY_TH_HEAD_TOWN'), +(-1560012,'She\'s not here.',0,0,0,0,'thrall hillsbrad SAY_TH_CHURCH_ENTER'), (-1560013,'Thrall! Come outside and face your fate!',10418,1,0,0,'epoch SAY_ENTER1'), (-1560014,'Taretha\'s life hangs in the balance. Surely you care for her. Surely you wish to save her...',10419,1,0,0,'epoch SAY_ENTER2'), (-1560015,'Ah, there you are. I had hoped to accomplish this with a bit of subtlety, but I suppose direct confrontation was inevitable. Your future, Thrall, must not come to pass and so...you and your troublesome friends must die!',10420,1,0,0,'epoch SAY_ENTER3'), -(-1560016,'Enough! I will erase your very existence!',10421,1,0,0,'epoch SAY_AGGRO1'), -(-1560017,'You cannot fight fate!',10422,1,0,0,'epoch SAY_AGGRO2'), -(-1560018,'You are...irrelevant.',10425,1,0,0,'epoch SAY_SLAY1'), -(-1560019,'Thrall will remain a slave. Taretha will die. You have failed.',10426,1,0,0,'epoch SAY_SLAY2'), -(-1560020,'Not so fast!',10423,1,0,0,'epoch SAY_BREATH1'), -(-1560021,'Struggle as much as you like!',10424,1,0,0,'epoch SAY_BREATH2'), -(-1560022,'No!...The master... will not... be pleased.',10427,1,0,0,'epoch SAY_DEATH'), + +(-1560016,'Thrall\'s trapped himself in the chapel. He can\'t escape now.',0,0,0,0,'tarren mill lookout SAY_LOOKOUT_CHURCH'), +(-1560017,'He\'s here, stop him!',0,0,0,0,'tarren mill lookout SAY_LOOKOUT_INN'), +(-1560018,'We have all the time in the world....',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_2'), +(-1560019,'You cannot escape us!',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_3'), +(-1560020,'Do not think you can win!',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_4'), + +(-1560021,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560022,'REUSE_ME',0,0,0,0,'REUSE_ME'), (-1560023,'Very well then. Let\'s go!',10465,0,0,0,'thrall hillsbrad SAY_TH_START_EVENT_PART1'), (-1560024,'As long as we\'re going with a new plan, I may aswell pick up a weapon and some armor.',0,0,0,0,'thrall hillsbrad SAY_TH_ARMORY'), (-1560025,'A rider approaches!',10466,0,0,0,'thrall hillsbrad SAY_TH_SKARLOC_MEET'), (-1560026,'I\'ll never be chained again!',10467,1,0,0,'thrall hillsbrad SAY_TH_SKARLOC_TAUNT'), -(-1560027,'Very well. Tarren Mill lies just west of here. Since time is of the essence...',10468,1,0,0,'thrall hillsbrad SAY_TH_START_EVENT_PART2'), +(-1560027,'Very well. Tarren Mill lies just west of here. Since time is of the essence...',10468,0,0,0,'thrall hillsbrad SAY_TH_START_EVENT_PART2'), (-1560028,'Let\'s ride!',10469,0,0,1,'thrall hillsbrad SAY_TH_MOUNTS_UP'), (-1560029,'Taretha must be in the inn. Let\'s go.',0,0,0,0,'thrall hillsbrad SAY_TH_CHURCH_END'), (-1560030,'Taretha! What foul magic is this?',0,0,0,0,'thrall hillsbrad SAY_TH_MEET_TARETHA'), @@ -2289,8 +2863,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1564011,'%s punches the ground in anger!',0,3,0,0,'supremus EMOTE_PUNCH_GROUND'), (-1564012,'The ground begins to crack open!',0,3,0,0,'supremus EMOTE_GROUND_CRACK'), -(-1564013,'No! Not yet...',11385,1,0,0,'akama shade SAY_LOW_HEALTH'), -(-1564014,'I will not last much longer...',11386,1,0,0,'akama shade SAY_DEATH'), +(-1564013,'No! Not yet...',11386,1,0,0,'akama shade SAY_LOW_HEALTH'), +(-1564014,'I will not last much longer...',11385,1,0,0,'akama shade SAY_DEATH'), (-1564015,'Come out from the shadows! I\'ve returned to lead you against our true enemy! Shed your chains and raise your weapons against your Illidari masters!',0,1,0,0,'akama shade SAY_FREE'), (-1564016,'Hail our leader! Hail Akama!',0,1,0,0,'akama shade broken SAY_BROKEN_FREE_01'), (-1564017,'Hail Akama!',0,1,0,0,'akama shade broken SAY_BROKEN_FREE_02'), @@ -2387,39 +2961,46 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1564095,'Destiny... awaits.',11485,1,0,0,'council mala DEATH'), (-1564096,'Diel ma\'ahn... oreindel\'o',11443,1,0,0,'council zere DEATH'), -(-1564097,'Akama... your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.',11463,1,0,0,'illidan SAY_CONVO_1'), -(-1564098,'We\'ve come to end your reign, Illidan. My people and all of Outland shall be free!',11389,1,0,25,'illidan SAY_CONVO_2'), -(-1564099,'Boldly said. But I remain unconvinced.',11464,1,0,396,'illidan SAY_CONVO_3'), -(-1564100,'The time has come! The moment is at hand!',11380,1,0,22,'illidan SAY_CONVO_4'), -(-1564101,'You are not prepared!',11466,1,0,406,'illidan SAY_CONVO_5'), -(-1564102,'Is this it, mortals? Is this all the fury you can muster?',11476,1,0,0,'illidan SAY_CONVO_6'), -(-1564103,'Their fury pales before mine, Illidan. We have some unsettled business between us.',11491,1,0,5,'illidan SAY_CONVO_7'), -(-1564104,'Maiev... How is this even possible?',11477,1,0,1,'illidan SAY_CONVO_8'), -(-1564105,'Ah... my long hunt is finally over. Today, Justice will be done!',11492,1,0,15,'illidan SAY_CONVO_9'), -(-1564106,'Feel the hatred of ten thousand years!',11470,1,0,0,'illidan SAY_CONVO_10'), -(-1564107,'Ahh... It is finished. You are beaten.',11496,1,0,0,'illidan SAY_CONVO_11'), -(-1564108,'You have won... Maiev...but the huntress... is nothing...without the hunt... you... are nothing... without me..',11478,1,0,65,'illidan SAY_CONVO_12'), -(-1564109,'He is right. I feel nothing... I am nothing...',11497,1,0,0,'illidan SAY_CONVO_13'), -(-1564110,'Farewell, champions.',11498,1,0,0,'illidan SAY_CONVO_14'), -(-1564111,'The Light will fill these dismal halls once again. I swear it.',11387,1,0,0,'illidan SAY_CONVO_15'), +(-1564097,'Akama. Your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.',11463,1,0,0,'illidan SAY_ILLIDAN_SPEECH_1'), +(-1564098,'We\'ve come to end your reign, Illidan. My people and all of Outland shall be free!',11389,1,0,25,'akama(illidan) SAY_AKAMA_SPEECH_2'), +(-1564099,'Boldly said. But I remain unconvinced.',11464,1,0,6,'illidan SAY_ILLIDAN_SPEECH_3'), +(-1564100,'The time has come! The moment is at hand!',11380,1,0,22,'akama(illidan) SAY_AKAMA_SPEECH_4'), +(-1564101,'You are not prepared!',11466,1,0,406,'illidan SAY_ILLIDAN_SPEECH_5'), +(-1564102,'Is this it, mortals? Is this all the fury you can muster?',11476,1,0,0,'illidan SAY_ILLIDAN_SPEECH_6'), +(-1564103,'Their fury pales before mine, Illidan. We have some unsettled business between us.',11491,1,0,6,'maiev SAY_MAIEV_SPEECH_7'), +(-1564104,'Maiev... How is this even possible?',11477,1,0,1,'illidan SAY_ILLIDAN_SPEECH_8'), +(-1564105,'My long hunt is finally over. Today, Justice will be done!',11492,1,0,5,'maiev SAY_MAIEV_SPEECH_9'), +(-1564106,'Feel the hatred of ten thousand years!',11470,1,0,0,'illidan SAY_FRENZY'), +(-1564107,'It is finished. You are beaten.',11496,1,0,0,'maiev SAY_MAIEV_EPILOGUE_1'), +(-1564108,'You have won... Maiev. But the huntress... is nothing without the hunt. You... are nothing... without me.',11478,1,0,0,'illidan SAY_ILLIDAN_EPILOGUE_2'), +(-1564109,'He\'s right. I feel nothing... I am... nothing.',11497,1,0,0,'maiev SAY_MAIEV_EPILOGUE_3'), +(-1564110,'Farewell, champions.',11498,1,0,0,'maiev SAY_MAIEV_EPILOGUE_4'), +(-1564111,'The Light will fill these dismal halls once again. I swear it.',11387,1,0,0,'akama(illidan) SAY_AKAMA_EPILOGUE_5'), (-1564112,'I can feel your hatred.',11467,1,0,0,'illidan SAY_TAUNT_1'), (-1564113,'Give in to your fear!',11468,1,0,0,'illidan SAY_TAUNT_2'), (-1564114,'You know nothing of power!',11469,1,0,0,'illidan SAY_TAUNT_3'), (-1564115,'Such... arrogance!',11471,1,0,0,'illidan SAY_TAUNT_4'), -(-1564116,'That is for Naisha!',11493,1,0,0,'illidan SAY_MAIEV_TAUNT_1'), -(-1564117,'Bleed as I have bled!',11494,1,0,0,'illidan SAY_MAIEV_TAUNT_2'), -(-1564118,'There shall be no prison for you this time!',11495,1,0,0,'illidan SAY_MAIEV_TAUNT_3'), -(-1564119,'Meet your end, demon!',11500,1,0,0,'illidan SAY_MAIEV_TAUNT_4'), -(-1564120,'Be wary friends, The Betrayer meditates in the court just beyond.',11388,1,0,0,'illidan SAY_AKAMA_BEWARE'), +(-1564116,'That is for Naisha!',11493,1,0,0,'maiev SAY_MAIEV_TAUNT_1'), +(-1564117,'Bleed as I have bled!',11494,1,0,0,'maiev SAY_MAIEV_TAUNT_2'), +(-1564118,'There shall be no prison for you this time!',11495,1,0,0,'maiev SAY_MAIEV_TRAP'), +(-1564119,'Meet your end, demon!',11500,1,0,0,'maiev SAY_MAIEV_TAUNT_4'), +(-1564120,'Be wary friends, The Betrayer meditates in the court just beyond.',11388,1,0,0,'akama(illidan) SAY_AKAMA_BEWARE'), (-1564121,'Come, my minions. Deal with this traitor as he deserves!',11465,1,0,0,'illidan SAY_AKAMA_MINION'), -(-1564122,'I\'ll deal with these mongrels. Strike now, friends! Strike at the betrayer!',11390,1,0,0,'illidan SAY_AKAMA_LEAVE'), +(-1564122,'I\'ll deal with these mongrels. Strike now, friends! Strike at the betrayer!',11390,1,0,22,'akama(illidan) SAY_AKAMA_LEAVE'), (-1564123,'Who shall be next to taste my blades?!',11473,1,0,0,'illidan SAY_KILL1'), (-1564124,'This is too easy!',11472,1,0,0,'illidan SAY_KILL2'), (-1564125,'I will not be touched by rabble such as you!',11479,1,0,254,'illidan SAY_TAKEOFF'), (-1564126,'Behold the flames of Azzinoth!',11480,1,0,0,'illidan SAY_SUMMONFLAMES'), (-1564127,'Stare into the eyes of the Betrayer!',11481,1,0,0,'illidan SAY_EYE_BLAST'), (-1564128,'Behold the power... of the demon within!',11475,1,0,0,'illidan SAY_MORPH'), -(-1564129,'You\'ve wasted too much time mortals, now you shall fall!',11474,1,0,0,'illidan SAY_ENRAGE'); +(-1564129,'You\'ve wasted too much time mortals, now you shall fall!',11474,1,0,0,'illidan SAY_ENRAGE'), + +(-1564130,'Broken of the Ashtongue tribe, your leader speaks!',0,1,0,0,'akama(shade) SAY_FREE_1'), + +(-1564131,'This door is all that stands between us and the Betrayer. Stand aside, friends.',0,0,0,1,'akama(illidan) SAY_OPEN_DOOR_1'), +(-1564132,'I cannot do this alone...',0,0,0,0,'akama(illidan) SAY_OPEN_DOOR_2'), +(-1564133,'You are not alone, Akama.',0,0,0,0,'spirit_Udalo SAY_OPEN_DOOR_3'), +(-1564134,'Your people will always be with you!',0,0,0,0,'spirit_Olum SAY_OPEN_DOOR_4'); -- -1 565 000 GRUUL'S LAIR INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2597,7 +3178,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1575017,'An easy task!',13466,1,0,0,'gortok SAY_SLAY_2'), (-1575018,' ',13467,1,0,0,'gortok SAY_DEATH'), -(-1575019,'What mongrels dare intrude here? Look alive, my brothers! A feast for the one that brings me their heads!',13497,1,0,0,'skadi SAY_AGGRO'), +(-1575019,'What mongrels dare intrude here? Look alive, my brothers! A feast for the one that brings me their heads!',13497,1,0,22,'skadi SAY_AGGRO'), (-1575020,'Sear them to the bone!',13498,1,0,0,'skadi SAY_DRAKEBREATH_1'), (-1575021,'Go now! Leave nothing but ash in your wake!',13499,1,0,0,'skadi SAY_DRAKEBREATH_2'), (-1575022,'Cleanse our sacred halls with flame!',13500,1,0,0,'skadi SAY_DRAKEBREATH_3'), @@ -2619,7 +3200,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1575037,'You have failed your people!',13615,1,0,0,'ymiron SAY_SLAY_2'), (-1575038,'There is a reason I am king!',13616,1,0,0,'ymiron SAY_SLAY_3'), (-1575039,'Bleed no more!',13617,1,0,0,'ymiron SAY_SLAY_4'), -(-1575040,'What... awaits me... now?',13618,1,0,0,'ymiron SAY_DEATH'); +(-1575040,'What... awaits me... now?',13618,1,0,0,'ymiron SAY_DEATH'), + +(-1575041,'%s takes a deep breath.',0,3,0,0,'grauf EMOTE_DEEP_BREATH'); -- -1 576 000 NEXUS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2675,8 +3258,20 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1578018,'Enjoy the fall!',13630,1,0,0,'eregos SAY_KILL_3'), (-1578019,'Savor this small victory, foolish little creatures. You and your dragon allies have won this battle. But we will win... the Nexus War.',13631,1,0,0,'eregos SAY_DEATH'), -(-1578020,'Intruders, your victory will be short-lived. I am Commander Varos Cloudstrider. My drakes control the skies and protect this conduit. I will see to it personally that the Oculus does not fall into your hands!',13648,6,0,0,'varos SAY_VAROS_INTRO'), -(-1578021,'Thank you for freeing us, mortals. Beware, the Blue Flight is alerted to your presence. Even now, Malygos sends Varos Cloudstrider and his ring guardians to defend the Oculus. You will need our help to stand a chance.',0,0,0,1,'belgaristrasz SAY_BELGARISTRASZ_GREET'); +(-1578020,'There will be no mercy!',13649,1,0,0,'varos SAY_AGGRO'), +(-1578021,'Blast them! Destroy them!',13650,1,0,0,'varos SAY_CALL_CAPTAIN_1'), +(-1578022,'Take no prisoners! Attack!',13651,1,0,0,'varos SAY_CALL_CAPTAIN_2'), +(-1578023,'Strike now! Obliterate them!',13652,1,0,0,'varos SAY_CALL_CAPTAIN_3'), + +(-1578024,'Anomalies form as %s shifts into the Astral Plane!',0,3,0,0,'eregos EMOTE_ASTRAL_PLANE'), +(-1578025,'%s begins to cast Empowered Arcane Explosion!',0,3,0,0,'urom EMOTE_EXPLOSION'), + +(-1578026,'You were warned!',13653,1,0,0,'varos SAY_KILL_1'), +(-1578027,'The Oculus is ours!',13654,1,0,0,'varos SAY_KILL_2'), +(-1578028,'They are... too strong! Underestimated their... fortitude.',13655,1,0,0,'varos SAY_DEATH'), +(-1578029,'%s calls an Azure Ring Captain!',0,3,0,0,'varos EMOTE_CAPTAIN'), + +(-1578030,'%s flies away.',0,2,0,0,'drakes EMOTE_FLY_AWAY'); -- -1 580 000 SUNWELL PLATEAU INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2714,7 +3309,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1580030,'Gah! Well done... Now... this gets... interesting...',12471,1,0,0,'brutallus YELL_DEATH'), (-1580031,'Hold, friends! There is information to be had before this devil meets his fate!',12472,1,0,0,'madrigosa YELL_MADR_ICE_BARRIER'), -(-1580032,'Where is Anveena, demon? What has become of Kalec?',12473,1,0,0,'madrigosa YELL_MADR_INTRO'), +(-1580032,'Where is Anveena, demon? What has become of Kalec?',12473,1,0,293,'madrigosa YELL_MADR_INTRO'), (-1580033,'You will tell me where they are!',12474,1,0,0,'madrigosa YELL_MADR_ICE_BLOCK'), (-1580034,'Speak, I grow weary of asking!',12475,1,0,0,'madrigosa YELL_MADR_TRAP'), (-1580035,'Malygos, my lord! I did my best!',12476,1,0,0,'madrigosa YELL_MADR_DEATH'), @@ -2750,11 +3345,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1580062,'De-ek Anur!',12494,1,0,0,'alythess SAY_ALYTHESS_DEAD'), (-1580063,'Your luck has run its course!',12493,1,0,0,'alythess SAY_ALYTHESS_BERSERK'), -(-1580064,'All my plans have led to this!',12495,1,0,0,'kiljaeden SAY_ORDER_1'), -(-1580065,'Stay on task! Do not waste time!',12496,1,0,0,'kiljaeden SAY_ORDER_2'), -(-1580066,'I have waited long enough!',12497,1,0,0,'kiljaeden SAY_ORDER_3'), -(-1580067,'Fail me and suffer for eternity!',12498,1,0,0,'kiljaeden SAY_ORDER_4'), -(-1580068,'Drain the girl! Drain her power until there is nothing but a vacant shell!',12499,1,0,0,'kiljaeden SAY_ORDER_5'), +(-1580064,'All my plans have led to this!',12495,6,0,0,'kiljaeden SAY_ORDER_1'), +(-1580065,'Stay on task! Do not waste time!',12496,6,0,0,'kiljaeden SAY_ORDER_2'), +(-1580066,'I have waited long enough!',12497,6,0,0,'kiljaeden SAY_ORDER_3'), +(-1580067,'Fail me and suffer for eternity!',12498,6,0,0,'kiljaeden SAY_ORDER_4'), +(-1580068,'Drain the girl! Drain her power until there is nothing but a vacant shell!',12499,6,0,0,'kiljaeden SAY_ORDER_5'), (-1580069,'The expendible have perished... So be it! Now I shall succeed where Sargeras could not! I will bleed this wretched world and secure my place as the true master of the Burning Legion. The end has come! Let the unraveling of this world commence!',12500,1,0,0,'kiljaeden SAY_EMERGE'), (-1580070,'Another step towards destruction!',12501,1,0,0,'kiljaeden SAY_SLAY_1'), (-1580071,'Anukh-Kyrie!',12502,1,0,0,'kiljaeden SAY_SLAY_2'), @@ -2793,7 +3388,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1580103,'In time, the light and hope held within - will rebirth more than this mere fount of power... Mayhap, they will rebirth the soul of a nation.',12521,0,0,1,'velen SAY_OUTRO_9'), (-1580104,'Blessed ancestors! I feel it... so much love... so much grace... there are... no words... impossible to describe...',12526,0,0,1,'liadrin SAY_OUTRO_10'), (-1580105,'Salvation, young one. It waits for us all.',12522,0,0,1,'velen SAY_OUTRO_11'), -(-1580106,'Farewell...!',12523,0,0,1,'velen SAY_OUTRO_12'); +(-1580106,'Farewell...!',12523,0,0,1,'velen SAY_OUTRO_12'), + +(-1580107,'%s takes a deep breath.',0,3,0,0,'felmyst EMOTE_DEEP_BREATH'); -- -1 585 000 MAGISTER'S TERRACE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2823,15 +3420,59 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1585021,'It\'s been a kick, really.',12411,1,0,0,'delrissa PlayerDeath5'), (-1585022,'Not what I had... planned...',12397,1,0,0,'delrissa SAY_DEATH'), -(-1585023,'Don\'t look so smug! I know what you\'re thinking, but Tempest Keep was merely a set back. Did you honestly believe I would trust the future to some blind, half-night elf mongrel? Oh no, he was merely an instrument, a stepping stone to a much larger plan! It has all led to this, and this time, you will not interfere!',12413,1,0,0,'kaelthas MT SAY_AGGRO'), +(-1585023,'Don\'t look so smug! I know what you\'re thinking, but Tempest Keep was merely a set back. Did you honestly believe I would trust the future to some blind, half-night elf mongrel?',12413,1,0,0,'kaelthas MT SAY_INTRO_1'), (-1585024,'Vengeance burns!',12415,1,0,0,'kaelthas MT SAY_PHOENIX'), (-1585025,'Felomin ashal!',12417,1,0,0,'kaelthas MT SAY_FLAMESTRIKE'), (-1585026,'I\'ll turn your world... upside... down...',12418,1,0,0,'kaelthas MT SAY_GRAVITY_LAPSE'), (-1585027,'Master... grant me strength.',12419,1,0,0,'kaelthas MT SAY_TIRED'), (-1585028,'Do not... get too comfortable.',12420,1,0,0,'kaelthas MT SAY_RECAST_GRAVITY'), -(-1585029,'My demise accomplishes nothing! The Master will have you! You will drown in your own blood! This world shall burn! Aaaghh!',12421,1,0,0,'kaelthas MT SAY_DEATH'); +(-1585029,'My demise accomplishes nothing! The Master will have you! You will drown in your own blood! This world shall burn! Aaaghh!',12421,1,0,0,'kaelthas MT SAY_DEATH'), +(-1585030,'Oh no, he was merely an instrument, a stepping stone to a much larger plan! It has all led to this, and this time, you will not interfere!',0,1,0,0,'kaelthas MT SAY_INTRO_2'); -- -1 595 000 CULLING OF STRATHOLME +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1595000,'All soldiers of Lordaeron should immediately report to the entrance of Stratholme, and await further orders from Prince Arthas.',0,6,0,0,'lordaeron crier SAY_SOLDIERS_REPORT'), +(-1595001,'Good work with the crates! Come talk to me in front of Stratholme for your next assignment!',0,4,0,0,'chromie WHISPER_CHROMIE_CRATES'), +(-1595002,'Oh, no! Adventurers, something awful has happened! A colleague of mine has been captured by the Infinite Dragonflight, and they\'re doing something horrible to him! Keeping Arthas is still your highest priority, but if you act fast you could help save a Guardian of Time!',0,4,0,0,'chromie WHISPER_CHROMIE_GUARDIAN'), +(-1595003,'Scourge forces have been spotted near the Festival Lane Gate!',0,6,0,0,'lordaeron crier SAY_SCOURGE_FESTIVAL_LANE'), +(-1595004,'Scourge forces have been spotted near the King\'s Square fountain!',0,6,0,0,'lordaeron crier SAY_SCOURGE_KINGS_SQUARE'), +(-1595005,'Scourge forces have been spotted near the Market Row Gate!',0,6,0,0,'lordaeron crier SAY_SCOURGE_MARKET_ROW'), +(-1595006,'Scourge forces have been spotted near the Town Hall!',0,6,0,0,'lordaeron crier SAY_SCOURGE_TOWN_HALL'), +(-1595007,'Scourge forces have been spotted near the Elder\'s Square Gate!',0,6,0,0,'lordaeron crier SAY_SCOURGE_ELDERS_SQUARE'), +(-1595008,'Champions, meet me at the Town Hall at once. We must take the fight to Mal\'Ganis.',14297,6,0,0,'arthas SAY_MEET_TOWN_HALL'), +(-1595009,'Follow me, I know the way through.',14298,0,0,1,'arthas SAY_FOLLOW'), +(-1595010,'Ah, you\'ve finally arrived Prince Arthas. You\'re here just in the nick of time.',0,0,0,1,'citizen SAY_ARRIVED'), +(-1595011,'Yes, I\'m glad I could get to you before the plague.',14299,0,0,0,'arthas SAY_GET_BEFORE_PLAGUE'), +(-1595012,'What is this sorcery?',14300,0,0,0,'arthas SAY_SORCERY'), +(-1595013,'There\'s no need for you to understand, Arthas. All you need to do is die.',0,0,0,1,'citizen SAY_NO_UNDERSTAND'), +(-1595014,'Mal\'Ganis appears to have more than Scourge in his arsenal. We should make haste.',14301,0,0,1,'arthas SAY_MORE_THAN_SCOURGE'), +(-1595015,'More vile sorcery! Be ready for anything!',14302,0,0,0,'arthas SAY_MORE_SORCERY'), +(-1595016,'Let\'s move on.',14303,0,0,396,'arthas SAY_MOVE_ON'), +(-1595017,'Watch your backs: they have us surrounded in this hall.',14304,0,0,1,'arthas SAY_WATCH_BACKS'), +(-1595018,'Mal\'Ganis is not making this easy.',14305,0,0,396,'arthas SAY_NOT_EASY'), +(-1595019,'They\'re very persistent.',14306,0,0,396,'arthas SAY_PERSISTENT'), +(-1595020,'What else can he put in my way?',14307,0,0,396,'arthas SAY_ELSE'), +(-1595021,'Prince Arthas Menethil, on this day, a powerful darkness has taken hold of your soul. The death you are destined to visit upon others will this day be your own.',13408,1,0,0,'chrono-lord SAY_DARKNESS'), +(-1595022,'I do what I must for Lordaeron, and neither your words nor your actions will stop me.',14309,0,0,396,'arthas SAY_DO_WHAT_MUST'), +(-1595023,'The quickest path to Mal\'Ganis lies behind that bookshelf ahead.',14308,0,0,0,'arthas SAY_QUICK_PATH'), +(-1595024,'This will only take a moment.',14310,0,0,432,'arthas SAY_TAKE_A_MOMENT'), +(-1595025,'I\'m relieved this secret passage still works.',14311,0,0,0,'arthas SAY_PASSAGE'), +(-1595026,'Let\'s move through here as quickly as possible. If the undead don\'t kill us, the fires might.',14312,0,0,396,'arthas SAY_MOVE_QUICKLY'), +(-1595027,'Rest a moment and clear your lungs, but we must move again soon.',14313,0,0,396,'arthas SAY_REST'), +(-1595028,'That\'s enough; we must move again. Mal\'Ganis awaits.',14314,0,0,396,'arthas SAY_REST_COMPLETE'), +(-1595029,'At last some good luck. Market Row has not caught fire yet. Mal\'Ganis is supposed to be in Crusaders\' Square, which is just ahead. Tell me when you\'re ready to move forward.',14315,0,0,396,'arthas SAY_CRUSADER_SQUARE'), +(-1595030,'Justice will be done.',14316,0,0,0,'arthas SAY_JUSTICE'), +(-1595031,'We\'re going to finish this right now, Mal\'Ganis. Just you... and me.',14317,0,0,5,'arthas SAY_FINISH_MALGANIS'), +(-1595032,'Your journey has just begun, young prince. Gather your forces and meet me in the arctic land of Northrend. It is there that we shall settle the score between us. It is there that your true destiny will unfold.',14412,1,0,378,'malganis SAY_JOURNEY_BEGUN'), +(-1595033,'I\'ll hunt you to the ends of the earth if I have to! Do you hear me? To the ends of the earth!',14318,0,0,0,'arthas SAY_HUNT_MALGANIS'), +(-1595034,'You performed well this day. Anything that Mal\'Ganis has left behind is yours. Take it as your reward. I must now begin plans for an expedition to Northrend.',14319,0,0,1,'arthas SAY_ESCORT_COMPLETE'), +(-1595035,'Protect your prince, soldiers of Lordaeron! I am in need of aid!',14320,0,0,0,'arthas SAY_HALF_HP'), +(-1595036,'I am being overwhelmed, assist me!',14321,0,0,0,'arthas SAY_LOW_HP'), +(-1595037,'Mal\'Ganis will pay for this.',14322,0,0,0,'arthas SAY_SLAY_1'), +(-1595038,'I can\'t afford to spare you.',14323,0,0,0,'arthas SAY_SLAY_2'), +(-1595039,'One less obstacle to deal with.',14324,0,0,0,'arthas SAY_SLAY_3'), +(-1595040,'Agh! Damn you, Mal\'Ganis! Father...Jaina...I have failed Lordaeron...',14325,0,0,0,'arthas SAY_DEATH'), +(-1595041,'My work here is finished!',0,6,0,0,'infinite corruptor SAY_CORRUPTOR_DESPAWN'); -- -1 599 000 HALLS OF STONE INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2952,7 +3593,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1601010,'They hunger.',14085,1,0,0,'krikthir SAY_SWARM_1'), (-1601011,'Dinner time, my pets.',14086,1,0,0,'krikthir SAY_SWARM_2'), (-1601012,'I should be grateful. But I long ago lost the capacity.',14087,1,0,0,'krikthir SAY_DEATH'), -(-1601013,'REUSE ME',0,0,0,0,'REUSE ME'), + +(-1601013,'%s moves up the tunnel!',0,3,0,0,'hadronox EMOTE_MOVE_TUNNEL'), (-1601014,'I was king of this empire once, long ago. In life I stood as champion. In death I returned as conqueror. Now I protect the kingdom once more. Ironic, yes?',14053,1,0,0,'anubarak SAY_INTRO'), (-1601015,'Eternal agony awaits you!',14054,1,0,0,'anubarak SAY_AGGRO'), @@ -2964,7 +3606,10 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1601021,'Your armor is useless against my locusts!',14060,1,0,0,'anubarak SAY_LOCUST_1'), (-1601022,'The pestilence upon you!',14068,1,0,0,'anubarak SAY_LOCUST_2'), (-1601023,'Uunak-hissss tik-k-k-k-k!',14067,1,0,0,'anubarak SAY_LOCUST_3'), -(-1601024,'Ahhh... RAAAAAGH! Never thought... I would be free of him...',14069,1,0,0,'anubarak SAY_DEATH'); +(-1601024,'Ahhh... RAAAAAGH! Never thought... I would be free of him...',14069,1,0,0,'anubarak SAY_DEATH'), + +(-1601025,'The gate has been breached! Quickly, divert forces to deal with these invaders!',13941,1,0,0,'anub\'ar crusher SAY_AGGRO'), +(-1601026,'There\'s no time left! All remaining forces, attack the invaders!',13942,1,0,0,'anub\'ar crusher SAY_SPECIAL'); -- -1 602 000 HALLS OF LIGHTNING INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -2990,7 +3635,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1602018,'What hope is there for you? None!',14162,1,0,0,'loken SAY_AGGRO0'), (-1602019,'I have witnessed the rise and fall of empires. The birth and extinction of entire species. Over countless millennia the foolishness of mortals has remained beyond a constant. Your presence here confirms this.',14160,1,0,0,'loken SAY_INTRO_1'), -(-1602020,'My master has shown me the future, and you have no place in it. Azeroth will be reborn in darkness. Yogg-Saron shall be released! The Pantheon shall fall!',14162,1,0,0,'loken SAY_INTRO_2'), +(-1602020,'My master has shown me the future, and you have no place in it. Azeroth will be reborn in darkness. Yogg-Saron shall be released! The Pantheon shall fall!',14161,1,0,0,'loken SAY_INTRO_2'), (-1602021,'Only mortal...',14166,1,0,0,'loken SAY_SLAY_1'), (-1602022,'I... am... FOREVER!',14167,1,0,0,'loken SAY_SLAY_2'), (-1602023,'What little time you had, you wasted!',14168,1,0,0,'loken SAY_SLAY_3'), @@ -3029,9 +3674,10 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603009,'Eonar, your servant calls for your blessing!',15535,1,0,0,'freya SAY_HELP_YOGG'), (-1603010,'Allies of Nature have appeared!',0,3,0,0,'freya EMOTE_ALLIES_NATURE'), -(-1603011,'A Lifebinder\'s Gift begins to grow!',0,3,0,0,'freya EMOTE_LIFEBINDER'), -(-1603012,'Freya begins to cast Ground Tremor!',0,3,0,0,'freya EMOTE_TREMOR'), -(-1603013,'Freya casts Strenghtened Iron Roots!',0,3,0,0,'freya EMOTE_IRON_ROOTS'), +(-1603011,'The %s withers into the earth and begins to regenerate.',0,2,0,0,'freya EMOTE_REGEN_ALLIES'), + +(-1603012,'As you wish, $N.',0,0,0,0,'keeper SAY_KEEPER_ACTIVE'), +(-1603013,'REUSE ME',0,0,0,0,'REUSE ME'), (-1603014,'Matron, the Conservatory has been breached!',15483,1,0,0,'brightleaf SAY_AGGRO_BRIGHT'), (-1603015,'Fertilizer.',15485,1,0,0,'brightleaf SAY_SLAY_1_BRIGHT'), @@ -3063,7 +3709,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603037,'Give us a moment to prepare to build the turrets.',0,1,0,0,'razorscale SAY_INTRO_1'), (-1603038,'Be on the lookout! Mole machines will be surfacing soon with those nasty Iron dwarves aboard!',0,1,0,0,'razorscale SAY_INTRO_2'), (-1603039,'Ready to move out, keep those dwarves off of our backs!',0,1,0,0,'razorscale SAY_INTRO_3'), -(-1603040,'Move! Quickly! She won\'t remain grounded for long.',0,1,0,0,'razorscale SAY_GROUNDED'), +(-1603040,'Move quickly! She won\'t remain grounded for long!',15648,1,0,0,'razorscale SAY_GROUNDED'), (-1603041,'Razorscale takes a deep breath...',0,3,0,0,'razorscale EMOTE_BREATH'), (-1603042,'Fires out! Let\'s rebuild those turrets!',0,1,0,0,'razorscale SAY_EXTINGUISH_FIRE'), (-1603043,'Harpoon Turret is ready for use!',0,3,0,0,'razorscale EMOTE_HARPOON_READY'), @@ -3078,8 +3724,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603051,'So tired. I will rest for just a moment!',15725,1,0,0,'xt-002 SAY_HEART_OPEN'), (-1603052,'I\'m ready to play!',15726,1,0,0,'xt-002 SAY_HEART_CLOSE'), (-1603053,'NO! NO! NO! NO! NO!',15727,1,0,0,'xt-002 SAY_TANCTRUM'), -(-1603054,'XT-002 Deconstructor\'s heart is exposed and leaking energy!',0,3,0,0,'xt-002 EMOTE_EXPOSE_HEART'), -(-1603055,'XT-002 Deconstructor consumes a scrapbot to repair himself.',0,3,0,0,'xt-002 EMOTE_REPAIR'), +(-1603054,'%s\'s heart is exposed and leaking energy.',0,3,0,0,'xt-002 EMOTE_EXPOSE_HEART'), +(-1603055,'%s consumes a scrapbot to repair himself!',0,3,0,0,'xt-002 EMOTE_REPAIR'), (-1603056,'Whether the world\'s greatest gnats or the world\'s greatest heroes, you\'re still only mortal.',15684,1,0,0,'brundir SAY_BRUNDIR_AGGRO'), (-1603057,'Stand still and stare into the light!',15687,1,0,0,'brundir SAY_BRUNDIR_WHIRL'), @@ -3137,8 +3783,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603104,'General Vezax roars and surges with dark might!',0,3,0,0,'vezax EMOTE_SURGE'), (-1603105,'The saronite vapors mass and swirl violently, merging into a monstrous form!',0,3,0,0,'vezax EMOTE_ANIMUS'), -(-1603106,'Trans-location complete. Commencing planetary analysis of Azeroth.',15405,1,0,0,'algalon SAY_INTRO_1'), -(-1603107,'Stand back, mortals. I am not here to fight you.',15406,1,0,0,'algalon SAY_INTRO_2'), +(-1603106,'Translocation complete. Commencing planetary analysis of Azeroth.',15405,1,0,0,'algalon SAY_INTRO_1'), +(-1603107,'Stand back, mortals. I\'m not here to fight you.',15406,1,0,0,'algalon SAY_INTRO_2'), (-1603108,'It is in the universe\'s best interest to re-originate this planet should my analysis find systemic corruption. Do not interfere.',15407,1,0,0,'algalon SAY_INTRO_3'), (-1603109,'See your world through my eyes. A universe so vast as to be immeasurable. Incomprehensible even to your greatest minds.',15390,1,0,0,'algalon SAY_ENGAGE'), @@ -3155,11 +3801,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603119,'Begin uplink: Reply Code: \'Omega\'. Planetary re-origination requested.',15399,1,0,0,'algalon SAY_DESPAWN_2'), (-1603120,'Farewell, mortals. Your bravery is admirable, for such flawed creatures.',15400,1,0,0,'algalon SAY_DESPAWN_3'), -(-1603121,'I have seen worlds bathed in the Makers\' flames. Their denizens fading without so much as a whimper. Entire planetary systems born and raised in the time that it takes your mortal hearts to beat once. Yet all throughout, my own heart, devoid of emotion... of empathy. I... have... felt... NOTHING! A million, million lives wasted. Had they all held within them your tenacity? Had they all loved life as you do?',15393,1,0,0,'algalon SAY_OUTRO_1'), -(-1603122,'Perhaps it is your imperfection that which grants you free will. That allows you to persevere against cosmically calculated odds. You prevailed where the Titans\' own perfect creations have failed.',15401,1,0,0,'algalon SAY_OUTRO_2'), -(-1603123,'I\'ve rearranged the reply code. Your planet will be spared. I cannot be certain of my own calculations anymore.',15402,1,0,0,'algalon SAY_OUTRO_3'), -(-1603124,'I lack the strength to transmit this signal. You must hurry. Find a place of power, close to the skies.',15403,1,0,0,'algalon SAY_OUTRO_4'), -(-1603125,'Do not worry about my fate $n. If the signal is not transmitted in time re-origination will proceed regardless. Save. Your. World.',15404,1,0,0,'algalon SAY_OUTRO_5'), +(-1603121,'I have seen worlds bathed in the Makers\' flames, their denizens fading without as much as a whimper. Entire planetary systems born and razed in the time that it takes your mortal hearts to beat once. Yet all throughout, my own heart devoid of emotion... of empathy. I. Have. Felt. Nothing. A million-million lives wasted. Had they all held within them your tenacity? Had they all loved life as you do?',15393,1,0,0,'algalon SAY_OUTRO_1'), +(-1603122,'Perhaps it is your imperfections... that which grants you free will... that allows you to persevere against all cosmically calculated odds. You prevail where the Titan\'s own perfect creations have failed.',15401,1,0,0,'algalon SAY_OUTRO_2'), +(-1603123,'I\'ve rearranged the reply code - your planet will be spared. I cannot be certain of my own calculations anymore.',15402,1,0,0,'algalon SAY_OUTRO_3'), +(-1603124,'I lack the strength to transmit the signal. You must... hurry... find a place of power... close to the skies.',15403,1,0,0,'algalon SAY_OUTRO_4'), +(-1603125,'Do not worry about my fate, Bronzen. If the signal is not transmitted in time, re-origination will proceed regardless. Save... your world...',15404,1,0,0,'algalon SAY_OUTRO_5'), (-1603126,'None shall pass!',15586,1,0,0,'kologarn SAY_AGGRO'), (-1603127,'OBLIVION!',15591,1,0,0,'kologarn SAY_SHOCKWAVE'), @@ -3243,10 +3889,10 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603191,'Gaze upon its magnificence! Bask in its glorious, um, glory! I present you... V-07-TR-0N!',15624,1,0,0,'mimiron SAY_ROBOT_ACTIVE'), (-1603192,'Prognosis: Negative!',15625,1,0,0,'mimiron SAY_ROBOT_SLAY_1'), (-1603193,'You\'re not going to get up from that one, friend.',15626,1,0,0,'mimiron SAY_ROBOT_SLAY_2'), -(-1603194,'It would appear that I\'ve made a slight miscalculation. I allowed my mind to be corrupted by the fiend in the prison, overriding my primary directive. All systems seem to be functional now. Clear.',15627,1,0,0,'mimiron SAY_ROBOT_DEATH'), +(-1603194,'It would appear that I\'ve made a slight miscalculation. I allowed my mind to be corrupted by the fiend in the prison, overriding my primary directive. All systems seem to be functional now. Clear.',15627,1,0,1,'mimiron SAY_ROBOT_DEATH'), (-1603195,'Combat matrix enhanced. Behold wonderous rapidity!',15630,1,0,0,'mimiron SAY_HELP_YOGG'), -(-1603196,'Leviathan Mk II begins to cast Plasma Blast!',0,3,0,0,'mimiron EMOTE_PLASMA_BLAST'), +(-1603196,'%s begins to cast Plasma Blast!',0,3,0,0,'mimiron EMOTE_PLASMA_BLAST'), (-1603197,'Aaaaaaaaaaaaaaaaa... Help me!!! Please got to help me!',15771,1,0,0,'yogg SAY_SARA_INTRO_1'), (-1603198,'What do you want from me? Leave me alone!',15772,1,0,0,'yogg SAY_SARA_INTRO_2'), @@ -3258,13 +3904,13 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603205,'Weak-minded fools!',15780,4,0,0,'yogg SAY_WIPE_PHASE_1'), -(-1603206,'I am the lucid dream. The monster in your nightmares. The fiend of a thousand faces. Cower before my true form. BOW DOWN BEFORE THE GOD OF DEATH!',15754,1,0,0,'yogg SAY_PHASE_2_INTRO'), +(-1603206,'I am the lucid dream.',15754,1,0,457,'yogg SAY_PHASE_2_INTRO_1'), (-1603207,'Tremble, mortals, before the coming of the end!',15777,1,0,0,'yogg SAY_SARA_PHASE_2_INTRO_A'), (-1603208,'Suffocate upon your own hate!',15776,1,0,0,'yogg SAY_SARA_PHASE_2_INTRO_B'), (-1603209,'MADNESS WILL CONSUME YOU!',15756,1,0,0,'yogg SAY_MADNESS'), (-1603210,'Look upon the true face of death and know that your end comes soon!',15755,1,0,0,'yogg SAY_PHASE_3'), -(-1603211,'Hoohehehahahaha... AHAHAHAHAHAHA!',15757,1,0,0,'yogg SAY_SLAY_1'), +(-1603211,'%s prepares to unleash Empowering Shadows!',0,3,0,0,'yogg EMOTE_EMPOWERING_SHADOWS'), (-1603212,'Eternal suffering awaits!',15758,1,0,0,'yogg SAY_SLAY_2'), (-1603213,'Your fate is sealed. The end of days is finally upon you and ALL who inhabit this miserable little seedling. Uulwi ifis halahs gag erh\'ongg w\'ssh.',15761,1,0,0,'yogg SAY_DEATH'), (-1603214,'Your will is no longer you own...',15759,4,0,0,'yogg SAY_TO_INSANE_1'), @@ -3277,22 +3923,61 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1603220,'Yrr n\'lyeth... shuul anagg!',15766,0,0,0,'yogg SAY_YOGG_V3_1'), (-1603221,'He will learn... no king rules forever; only death is eternal!',15767,0,0,0,'yogg SAY_YOGG_V3_2'), -(-1603222,'It is done... All have been given that which must be given. I now seal the Dragon Soul forever...',15631,0,0,0,'yogg SAY_NELTHARION_1'), -(-1603223,'That terrible glow... should that be?',15784,0,0,0,'yogg SAY_YSERA'), -(-1603224,'For it to be as it must, yes.',15632,0,0,0,'yogg SAY_NELTHARION_2'), -(-1603225,'It is a weapon like no other. It must be like no other.',15610,0,0,0,'yogg SAY_MALYGOS'), +(-1603222,'It is done... All have been given that which must be given. I now seal the Dragon Soul forever...',15631,0,0,1,'yogg SAY_NELTHARION_1'), +(-1603223,'That terrible glow... should that be?',15784,0,0,1,'yogg SAY_YSERA'), +(-1603224,'For it to be as it must, yes.',15632,0,0,1,'yogg SAY_NELTHARION_2'), +(-1603225,'It is a weapon like no other. It must be like no other.',15610,0,0,1,'yogg SAY_MALYGOS'), (-1603226,'His brood learned their lesson before too long, you shall soon learn yours!',15765,0,0,0,'yogg SAY_YOGG_V2'), -(-1603227,'Bad news sire. The clans are united under Blackhand in this assault. They will stand together until Stormwind has fallen.',15538,0,0,0,'yogg SAY_GARONA_1'), -(-1603228,'Gul\'dan is bringing up his warlocks by nightfall. Until then, the Blackrock clan will be trying to take the Eastern Wall.',15539,0,0,0,'yogg SAY_GARONA_2'), +(-1603227,'Bad news sire.',15538,0,0,1,'yogg SAY_GARONA_1'), +(-1603228,'Gul\'dan is bringing up his warlocks by nightfall. Until then, the Blackrock clan will be trying to take the Eastern Wall.',15540,0,0,1,'yogg SAY_GARONA_3'), (-1603229,'A thousand deaths... ',15762,0,0,0,'yogg SAY_YOGG_V1_1'), (-1603230,'or one murder.',15763,0,0,0,'yogg SAY_YOGG_V1_2'), -(-1603231,'We will hold until the reinforcements come. As long as men with stout hearts are manning the walls and throne Stormwind will hold.',15540,0,0,0,'yogg SAY_GARONA_3'), +(-1603231,'We will hold until the reinforcements come. As long as men with stout hearts are manning the walls and throne Stormwind will hold.',15585,0,0,1,'yogg SAY_KING_LLANE'), (-1603232,'The orc leaders agree with your assessment.',15541,0,0,0,'yogg SAY_GARONA_4'), (-1603233,'Your petty quarrels only make me stronger!',15764,0,0,0,'yogg SAY_YOGG_V1_3'), (-1603234,'Portals open into Yogg-Saron\'s mind!',0,3,0,0,'yogg EMOTE_VISION_BLAST'), -(-1603235,'The illusion shatters and a path to the central chamber opens!',0,3,0,0,'yogg EMOTE_SHATTER_BLAST'); +(-1603235,'The illusion shatters and a path to the central chamber opens!',0,3,0,0,'yogg EMOTE_SHATTER_BLAST'), + +(-1603236,'%s\'s heart is severed from his body.',0,3,0,0,'xt-002 EMOTE_KILL_HEART'), +(-1603237,'%s begins to cause the earth to quake.',0,3,0,0,'xt-002 EMOTE_EARTH_QUAKE'), +(-1603238,'%s is extinguished by the water!',0,2,0,0,'ignis EMOTE_EXTINGUISH_SCORCH'), + +(-1603239,'You\'ve done it! You\'ve broken the defenses of Ulduar. In a few moments, we will be dropping in to...',15804,0,0,0,'bronzebeard radio SAY_PRE_LEVIATHAN_1'), +(-1603240,'What is that? Be careful! Something\'s headed your way!',15805,0,0,0,'bronzebeard radio SAY_PRE_LEVIATHAN_2'), +(-1603241,'Quickly! Evasive action! Evasive act--',15806,0,0,0,'bronzebeard radio SAY_PRE_LEVIATHAN_3'), + +(-1603242,'%s activates Hodir\'s Fury.',0,3,0,0,'leviathan EMOTE_HODIR_FURY'), +(-1603243,'%s activates Freya\'s Ward.',0,3,0,0,'leviathan EMOTE_FREYA_WARD'), +(-1603244,'%s activates Mimiron\'s Inferno.',0,3,0,0,'leviathan EMOTE_MIMIRON_INFERNO'), +(-1603245,'%s activates Thorim\'s Hammer.',0,3,0,0,'leviathan EMOTE_THORIM_HAMMER'), + +(-1603246,'I know just the place. Will you be all right?',15823,1,0,0,'brann SAY_BRANN_OUTRO'), + +(-1603247,'%s surrounds itself with a crackling Runic Barrier!',0,3,0,0,'thorim EMOTE_RUNIC_BARRIER'), + +(-1603248,'Self-destruct sequence initiated.',15413,1,0,0,'mimiron SAY_SELF_DESTRUCT'), +(-1603249,'This area will self-destruct in ten minutes.',15415,1,0,0,'mimiron SAY_DESTRUCT_10_MIN'), +(-1603250,'This area will self-destruct in nine minutes.',15416,1,0,0,'mimiron SAY_DESTRUCT_9_MIN'), +(-1603251,'This area will self-destruct in eight minutes.',15417,1,0,0,'mimiron SAY_DESTRUCT_8_MIN'), +(-1603252,'This area will self-destruct in seven minutes.',15418,1,0,0,'mimiron SAY_DESTRUCT_7_MIN'), +(-1603253,'This area will self-destruct in six minutes.',15419,1,0,0,'mimiron SAY_DESTRUCT_6_MIN'), +(-1603254,'This area will self-destruct in five minutes.',15420,1,0,0,'mimiron SAY_DESTRUCT_5_MIN'), +(-1603255,'This area will self-destruct in four minutes.',15421,1,0,0,'mimiron SAY_DESTRUCT_4_MIN'), +(-1603256,'This area will self-destruct in three minutes.',15422,1,0,0,'mimiron SAY_DESTRUCT_3_MIN'), +(-1603257,'This area will self-destruct in two minutes.',15423,1,0,0,'mimiron SAY_DESTRUCT_2_MIN'), +(-1603258,'This area will self-destruct in one minute.',15424,1,0,0,'mimiron SAY_DESTRUCT_1_MIN'), +(-1603259,'Self-destruct sequence finalized. Have a nice day.',15425,1,0,0,'mimiron SAY_DESTRUCT_0_MIN'), +(-1603260,'Self-destruct sequence terminated. Overide code A905.',15414,1,0,0,'mimiron SAY_SELF_DESTRUCT_END'), + +(-1603261,'%s begins to boil upon touching $n!',0,2,0,0,'ominous cloud EMOTE_CLOUD_BOIL'), +(-1603262,'The monster in your nightmares.',0,1,0,457,'yogg SAY_PHASE_2_INTRO_2'), +(-1603263,'The fiend of a thousand faces.',0,1,0,457,'yogg SAY_PHASE_2_INTRO_3'), +(-1603264,'Cower before my true form.',0,1,0,457,'yogg SAY_PHASE_2_INTRO_4'), +(-1603265,'BOW DOWN BEFORE THE GOD OF DEATH!',0,1,0,0,'yogg SAY_PHASE_2_INTRO_5'), +(-1603266,'%s opens his mouth wide!',0,3,0,0,'yogg EMOTE_DEAFENING_ROAR'), +(-1603267,'The clans are united under Blackhand in this assault. They will stand together until Stormwind has fallen.',15539,0,0,1,'yogg SAY_GARONA_2'); -- -1 604 000 GUNDRAK INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3335,8 +4020,8 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen -- -1 608 000 VIOLET HOLD INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES -(-1608000,'Prison guards, we are leaving! These adventurers are taking over! Go, go, go!',0,1,0,0,'sinclair SAY_BEGIN'), -(-1608001,'I\'m locking the door. Good luck, and thank you for doing this.',0,0,0,0,'sinclair SAY_LOCK_DOOR'), +(-1608000,'Prison guards, we are leaving! These adventurers are taking over! Go, go, go!',0,1,0,0,'sinclari SAY_BEGIN'), +(-1608001,'I\'m locking the door. Good luck, and thank you for doing this.',0,0,0,1,'sinclari SAY_LOCK_DOOR'), (-1608002,'Adventurers, the door is beinning to weaken!',0,1,0,0,'sinclair SAY_SEAL_75'), (-1608003,'Only half of the door seal\'s strength remains! You must fight on!',0,1,0,0,'sinclair SAY_SEAL_50'), @@ -3363,7 +4048,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1608023,'I shall pass!',14235,1,0,0,'ichoron SAY_SLAY_2'), (-1608024,'You can not stop the tide!',14236,1,0,0,'ichoron SAY_SLAY_3'), (-1608025,'I shall consume,decimate, devastate,and destroy! Yield now to the wrath of the pounding sea!',14231,1,0,0,'ichoron SAY_ENRAGE'), -(-1608026,'I... recede.',14237,1,0,0,'ichoron SAY_DEATH'); +(-1608026,'I... recede.',14237,1,0,0,'ichoron SAY_DEATH'), + +(-1608027,'You did it! You held the Blue Dragonflight back and defeated their commander. Amazing work!',0,0,0,1,'sinclari SAY_VICTORY'), + +(-1608028,'%s\'s Protective Bubble shatters!',0,3,0,0,'ichoron EMOTE_BUBBLE'); -- -1 609 000 EBON HOLD (DK START) INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3459,16 +4148,121 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1609077,'Do it, $N! Put me out of my misery!',0,0,0,1,'special_surprise SAY_EXEC_WAITING'), (-1609078,'%s dies from his wounds.',0,2,0,0,'special_surprise EMOTE_DIES'), -(-1609079,'I\'ll need to get my runeblade and armor... Just need a little more time.',0,0,0,399,'koltira SAY_BREAKOUT1'), -(-1609080,'I\'m still weak, but I think I can get an anti-magic barrier up. Stay inside it or you\'ll be destroyed by their spells.',0,0,0,0,'koltira SAY_BREAKOUT2'), -(-1609081,'Maintaining this barrier will require all of my concentration. Kill them all!',0,0,0,16,'koltira SAY_BREAKOUT3'), -(-1609082,'There are more coming. Defend yourself! Don\'t fall out of the anti-magic field! They\'ll tear you apart without its protection!',0,0,0,0,'koltira SAY_BREAKOUT4'), -(-1609083,'I can\'t keep barrier up much longer... Where is that coward?',0,0,0,0,'koltira SAY_BREAKOUT5'), -(-1609084,'The High Inquisitor comes! Be ready, death knight! Do not let him draw you out of the protective bounds of my anti-magic field! Kill him and take his head!',0,0,0,0,'koltira SAY_BREAKOUT6'), -(-1609085,'Stay in the anti-magic field! Make them come to you!',0,0,0,0,'koltira SAY_BREAKOUT7'), -(-1609086,'The death of the High Inquisitor of New Avalon will not go unnoticed. You need to get out of here at once! Go, before more of them show up. I\'ll be fine on my own.',0,0,0,0,'koltira SAY_BREAKOUT8'), -(-1609087,'I\'ll draw their fire, you make your escape behind me.',0,0,0,0,'koltira SAY_BREAKOUT9'), -(-1609088,'Your High Inquisitor is nothing more than a pile of meat, Crusaders! There are none beyond the grasp of the Scourge!',0,1,0,0,'koltira SAY_BREAKOUT10'); +(-1609079,'Hrm, what a strange tree. I must investigate.',0,0,0,1,'scarlet courier SAY_TREE_1'), +(-1609080,'What\'s this!? This isn\'t a tree at all! Guards! Guards!',0,0,0,5,'scarlet courier SAY_TREE_2'), + +(-1609081,'%s throws rotten apple on $N.',0,2,0,0,'city guard EMOTE_APPLE'), +(-1609082,'%s throws rotten banana on $N.',0,2,0,0,'city guard EMOTE_BANANA'), +(-1609083,'%s spits on $N.',0,2,0,0,'city guard EMOTE_SPIT'), +(-1609084,'Monster!',0,0,0,14,'city guard SAY_RANDOM_1'), +(-1609085,'Murderer!',0,0,0,14,'city guard SAY_RANDOM_2'), +(-1609086,'GET A ROPE!',0,0,0,25,'city guard SAY_RANDOM_3'), +(-1609087,'How dare you set foot in our city!',0,0,0,25,'city guard SAY_RANDOM_4'), +(-1609088,'You disgust me.',0,0,0,14,'city guard SAY_RANDOM_5'), + +(-1609089,'The Eye of Acherus launches towards its destination',0,3,0,0,'eye of acherus EMOTE_DESTIANTION'), +(-1609090,'The Eye of Acherus is in your control',0,3,0,0,'eye of acherus EMOTE_CONTROL'), + +(-1609091,'Mommy?',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_1'), +(-1609092,'GIVE ME BRAINS!',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_2'), +(-1609093,'Must feed...',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_3'), +(-1609094,'So hungry...',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_4'), +(-1609095,'$gPoppy:Mama;!',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_5'), +(-1609096,'It puts the ghoul in the pit or else it gets the lash!',0,0,0,25,'gothik the harvester SAY_GOTHIK_THROW_IN_PIT'), + +(-1609097,'%s rears up, beckoning you to ride it.',0,2,0,0,'Acherus Deathcharger EMOTE_HORSE_READY'), +(-1609098,'Impressive, death knight. Return to me in the world of the living for your reward.',0,0,0,2,'Salanar the Horseman SAY_RACE_FINISHED'), + +(-1609201,'Soldiers of the Scourge, stand ready! Prepare to unleash your fury upon the Argent Dawn!',14677,1,0,0,'Highlord Darion Mograine'), +(-1609202,'The sky weeps at the devastation of these lands! Soon, Azeroth\'s futile tears will rain down upon us!',14678,1,0,0,'Highlord Darion Mograine'), +(-1609203,'Death knights of Acherus, the death march begins!',14681,1,0,0,'Highlord Darion Mograine'), +(-1609204,'Soldiers of the Scourge, death knights of Acherus, minions of the darkness: hear the call of the Highlord!',14679,1,0,22,'Highlord Darion Mograine'), +(-1609205,'RISE!',14680,1,0,15,'Highlord Darion Mograine'), +(-1609206,'The skies turn red with the blood of the fallen! The Lich King watches over us, minions! Leave only ashes and misery in your destructive wake!',14682,1,0,25,'Highlord Darion Mograine'), +(-1609207,'Scourge armies approach!',0,1,0,0,'Korfax, Champion of the Light'), +(-1609208,'Stand fast, brothers and sisters! The Light will prevail!',14487,1,0,0,'Lord Maxwell Tyrosus'), +(-1609209,'Kneel before the Highlord!',14683,0,0,0,'Highlord Darion Mograine'), +(-1609210,'You stand no chance!',14684,0,0,0,'Highlord Darion Mograine'), +(-1609211,'The Scourge will destroy this place!',14685,0,0,0,'Highlord Darion Mograine'), +(-1609212,'Your life is forfeit.',14686,0,0,0,'Highlord Darion Mograine'), +(-1609213,'Life is meaningless without suffering.',14687,0,0,0,'Highlord Darion Mograine'), +(-1609214,'How much longer will your forces hold out?',14688,0,0,0,'Highlord Darion Mograine'), +(-1609215,'The Argent Dawn is finished!"',14689,0,0,0,'Highlord Darion Mograine'), +(-1609216,'Spare no one!',14690,0,0,0,'Highlord Darion Mograine'), +(-1609217,'What is this?! My... I cannot strike...',14691,0,0,0,'Highlord Darion Mograine'), +(-1609218,'Obey me, blade!',14692,1,0,0,'Highlord Darion Mograine'), +(-1609219,'You will do as I command! I am in control here!',14693,0,0,0,'Highlord Darion Mograine'), +(-1609220,'I can not... the blade fights me.',14694,0,0,0,'Highlord Darion Mograine'), +(-1609221,'What is happening to me?',14695,0,0,0,'Highlord Darion Mograine'), +(-1609222,'Power...wanes...',14696,0,0,0,'Highlord Darion Mograine'), +(-1609223,'Ashbringer defies me...',14697,0,0,0,'Highlord Darion Mograine'), +(-1609224,'Minions, come to my aid!',14698,0,0,0,'Highlord Darion Mograine'), +(-1609225,'You cannot win, Darion!',14584,1,0,0,'Highlord Tirion Fordring'), +(-1609226,'Bring them before the chapel!',14585,1,0,0,'Highlord Tirion Fordring'), +(-1609227,'Stand down, death knights. We have lost... The Light... This place... No hope...',14699,0,0,68,'Highlord Darion Mograine'), +(-1609228,'Have you learned nothing, boy? You have become all that your father fought against! Like that coward, Arthas, you allowed yourself to be consumed by the darkness...the hate... Feeding upon the misery of those you tortured and killed!',14586,0,0,1,'Highlord Tirion Fordring'), +(-1609229,'Your master knows what lies beneath the chapel. It is why he dares not show his face! He\'s sent you and your death knights to meet their doom, Darion.',14587,0,0,25,'Highlord Tirion Fordring'), +(-1609230,'What you are feeling right now is the anguish of a thousand lost souls! Souls that you and your master brought here! The Light will tear you apart, Darion!',14588,0,0,1,'Highlord Tirion Fordring'), +(-1609231,'Save your breath, old man. It might be the last you ever draw.',14700,0,0,25,'Highlord Darion Mograine'), +(-1609232,'My son! My dear, beautiful boy!',14493,0,0,0,'Highlord Alexandros Mograine'), +(-1609233,'Father!',14701,0,0,5,'Highlord Darion Mograine'), +(-1609234,'Argh...what...is...',14702,0,0,68,'Highlord Darion Mograine'), +(-1609235,'Father, you have returned!',14703,0,0,0,'Darion Mograine'), +(-1609236,'You have been gone a long time, father. I thought...',14704,0,0,0,'Darion Mograine'), +(-1609237,'Nothing could have kept me away from here, Darion. Not from my home and family.',14494,0,0,1,'Highlord Alexandros Mograine'), +(-1609238,'Father, I wish to join you in the war against the undead. I want to fight! I can sit idle no longer!',14705,0,0,6,'Darion Mograine'), +(-1609239,'Darion Mograine, you are barely of age to hold a sword, let alone battle the undead hordes of Lordaeron! I couldn\'t bear losing you. Even the thought...',14495,0,0,1,'Highlord Alexandros Mograine'), +(-1609240,'If I die, father, I would rather it be on my feet, standing in defiance against the undead legions! If I die, father, I die with you!',14706,0,0,6,'Darion Mograine'), +(-1609241,'My son, there will come a day when you will command the Ashbringer and, with it, mete justice across this land. I have no doubt that when that day finally comes, you will bring pride to our people and that Lordaeron will be a better place because of you. But, my son, that day is not today.',14496,0,0,1,'Highlord Alexandros Mograine'), +(-1609242,'Do not forget...',14497,0,0,6,'Highlord Alexandros Mograine'), +(-1609243,'Touching...',14803,1,0,0,'The Lich King'), +(-1609244,'You have\'ve betrayed me! You betrayed us all you monster! Face the might of Mograine!',14707,1,0,0,'Highlord Darion Mograine'), +(-1609245,'He\'s mine now...',14805,0,0,0,'The Lich King'), +(-1609246,'Pathetic...',14804,0,0,0,'The Lich King'), +(-1609247,'You\'re a damned monster, Arthas!',14589,0,0,25,'Highlord Tirion Fordring'), +(-1609248,'You were right, Fordring. I did send them in to die. Their lives are meaningless, but yours...',14806,0,0,1,'The Lich King'), +(-1609249,'How simple it was to draw the great Tirion Fordring out of hiding. You\'ve left yourself exposed, paladin. Nothing will save you...',14807,0,0,1,'The Lich King'), +(-1609250,'ATTACK!!!',14488,1,0,0,'Lord Maxwell Tyrosus'), +(-1609251,'APOCALYPSE!',14808,1,0,0,'The Lich King'), +(-1609252,'That day is not today...',14708,0,0,0,'Highlord Darion Mograine'), +(-1609253,'Tirion!',14709,1,0,0,'Highlord Darion Mograine'), +(-1609254,'ARTHAS!!!!',14591,1,0,0,'Highlord Tirion Fordring'), +(-1609255,'What is this?',14809,1,0,0,'The Lich King'), +(-1609256,'Your end.',14592,1,0,0,'Highlord Tirion Fordring'), +(-1609257,'Impossible...',14810,1,0,0,'The Lich King'), +(-1609258,'This... isn\'t... over...',14811,1,0,25,'The Lich King'), +(-1609259,'When next we meet it won\'t be on holy ground, paladin.',14812,1,0,1,'The Lich King'), +(-1609260,'Rise, Darion, and listen...',14593,0,0,0,'Highlord Tirion Fordring'), +(-1609261,'We have all been witness to a terrible tragedy. The blood of good men has been shed upon this soil! Honorable knights, slain defending their lives - our lives!',14594,0,0,0,'Highlord Tirion Fordring'), +(-1609262,'And while such things can never be forgotten, we must remain vigilant in our cause!',14595,0,0,0,'Highlord Tirion Fordring'), +(-1609263,'The Lich King must answer for what he has done and must not be allowed to cause further destruction to our world.',14596,0,0,0,'Highlord Tirion Fordring'), +(-1609264,'I make a promise to you now, brothers and sisters: The Lich King will be defeated! On this day, I call for a union.',14597,0,0,0,'Highlord Tirion Fordring'), +(-1609265,'The Argent Dawn and the Order of the Silver Hand will come together as one! We will succeed where so many before us have failed!',14598,0,0,0,'Highlord Tirion Fordring'), +(-1609266,'We will take the fight to Arthas and tear down the walls of Icecrown!',14599,0,0,15,'Highlord Tirion Fordring'), +(-1609267,'The Argent Crusade comes for you, Arthas!',14600,1,0,15,'Highlord Tirion Fordring'), +(-1609268,'So too do the Knights of the Ebon Blade... While our kind has no place in your world, we will fight to bring an end to the Lich King. This I vow!',14710,0,0,1,'Highlord Darion Mograine'), +(-1609269,'Thousands of Scourge rise up at the Highlord\'s command.',0,3,0,0,''), +(-1609270,'The army marches towards Light\'s Hope Chapel.',0,3,0,0,''), +(-1609271,'After over a hundred Defenders of the Light fall, Highlord Tirion Fordring arrives.',0,3,0,0,''), +(-1609272,'%s flee',0,2,0,0,'Orbaz'), +(-1609273,'%s kneels in defeat before Tirion Fordring.',0,3,0,0,'Highlord Darion Mograine'), +(-1609274,'%s arrives.',0,2,0,0,'Highlord Alexandros Mograine'), +(-1609275,'%s becomes a shade of his past, and walks up to his father.',0,2,0,0,'Highlord Darion Mograine'), +(-1609276,'%s hugs his father.',0,2,0,0,'Darion Mograine'), +(-1609277,'%s disappears, and the Lich King appears.',0,2,0,0,'Alexandros'), +(-1609278,'%s becomes himself again...and is now angry.',0,2,0,0,'Highlord Darion Mograine'), +(-1609279,'%s casts a spell on Tirion.',0,2,0,0,'The Lich King'), +(-1609280,'%s gasps for air.',0,2,0,0,'Highlord Tirion Fordring'), +(-1609281,'%s casts a powerful spell, killing the Defenders and knocking back the others.',0,2,0,0,'The Lich King'), +(-1609282,'%s throws the Corrupted Ashbringer to Tirion, who catches it. Tirion becomes awash with Light, and the Ashbringer is cleansed.',0,2,0,0,'Highlord Darion Mograine'), +(-1609283,'%s collapses.',0,2,0,0,'Highlord Darion Mograine'), +(-1609284,'%s charges towards the Lich King, Ashbringer in hand and strikes the Lich King.',0,2,0,0,'Highlord Tirion Fordring'), +(-1609285,'%s disappears. Tirion walks over to where Darion lay',0,2,0,0,'The Lich King'), +(-1609286,'Light washes over the chapel -- the Light of Dawn is uncovered.',0,2,0,0,''), + +(-1609287,'Looks like we\'re going to have ourselves an execution.',0,0,0,25,'city guard SAY_RANDOM_6'), +(-1609288,'Traitorous dog.',0,0,0,14,'city guard SAY_RANDOM_7'), +(-1609289,'My family was wiped out by the Scourge! MONSTER!',0,0,0,25,'city guard SAY_RANDOM_8'); -- -1 615 000 OBSIDIAN SANCTUM INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3480,7 +4274,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1615005,'I will take pity on you Sartharion, just this once.',14117,1,0,0,'shadron SAY_SHADRON_RESPOND'), (-1615006,'Father tought me well!',14115,1,0,0,'shadron SAY_SHADRON_SPECIAL_1'), (-1615007,'On your knees!',14116,1,0,0,'shadron SAY_SHADRON_SPECIAL_2'), -(-1615008,'A Shadron Disciple appears in the Twilight!',0,5,0,0,'shadron WHISPER_SHADRON_DICIPLE'), +(-1615008,'A Shadron Disciple appears in the Twilight!',0,3,0,0,'shadron WHISPER_SHADRON_DICIPLE'), (-1615009,'You have no place here. Your place is among the departed.',14122,1,0,0,'tenebron SAY_TENEBRON_AGGRO'), (-1615010,'No contest.',14123,1,0,0,'tenebron SAY_TENEBRON_SLAY_1'), @@ -3490,7 +4284,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1615014,'It is amusing to watch you struggle. Very well, witness how it is done.',14128,1,0,0,'tenebron SAY_TENEBRON_RESPOND'), (-1615015,'Arrogant little creatures! To challenge powers you do not yet understand...',14126,1,0,0,'tenebron SAY_TENEBRON_SPECIAL_1'), (-1615016,'I am no mere dragon! You will find I am much, much, more...',14127,1,0,0,'tenebron SAY_TENEBRON_SPECIAL_2'), -(-1615017,'%s begins to hatch eggs in the twilight!',0,5,0,0,'tenebron WHISPER_HATCH_EGGS'), +(-1615017,'%s begins to hatch eggs in the twilight!',0,3,0,0,'tenebron WHISPER_HATCH_EGGS'), (-1615018,'It is my charge to watch over these eggs. I will see you burn before any harm comes to them!',14093,1,0,0,'sartharion SAY_SARTHARION_AGGRO'), (-1615019,'This pathetic siege ends NOW!',14103,1,0,0,'sartharion SAY_SARTHARION_BERSERK'), @@ -3506,7 +4300,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1615029,'You will make a fine meal for the hatchlings.',14094,1,0,0,'sartharion SAY_SARTHARION_SLAY_1'), (-1615030,'You are the grave disadvantage.',14096,1,0,0,'sartharion SAY_SARTHARION_SLAY_2'), (-1615031,'This is why we call you lesser beeings.',14097,1,0,0,'sartharion SAY_SARTHARION_SLAY_3'), -(-1615032,'The lava surrounding %s churns!',0,5,0,0,'sartharion WHISPER_LAVA_CHURN'), +(-1615032,'The lava surrounding %s churns!',0,3,0,0,'sartharion WHISPER_LAVA_CHURN'), (-1615033,'You pose no threat, lesser beings...give me your worst!',14133,1,0,0,'vesperon SAY_VESPERON_AGGRO'), (-1615034,'The least you could do is put up a fight...',14134,1,0,0,'vesperon SAY_VESPERON_SLAY_1'), @@ -3516,9 +4310,9 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1615038,'Father was right about you, Sartharion...You are a weakling!',14139,1,0,0,'vesperon SAY_VESPERON_RESPOND'), (-1615039,'Aren\'t you tricky...I have a few tricks of my own...',14137,1,0,0,'vesperon SAY_VESPERON_SPECIAL_1'), (-1615040,'Unlike, I have many talents.',14138,1,0,0,'vesperon SAY_VESPERON_SPECIAL_2'), -(-1615041,'A Vesperon Disciple appears in the Twilight!',0,5,0,0,'shadron WHISPER_VESPERON_DICIPLE'), +(-1615041,'A Vesperon Disciple appears in the Twilight!',0,3,0,0,'shadron WHISPER_VESPERON_DICIPLE'), -(-1615042,'%s begins to open a Twilight Portal!',0,5,0,0,'sartharion drake WHISPER_OPEN_PORTAL'); +(-1615042,'%s begins to open a Twilight Portal!',0,3,0,0,'sartharion drake WHISPER_OPEN_PORTAL'); -- -1 616 000 EYE OF ETERNITY INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,comment) VALUES @@ -3535,7 +4329,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,commen (-1616010,' How very... naive...',14521,1,0,0,'malygos SAY_SLAY_1_C'), (-1616011,'I had hoped to end your lives quickly, but you have proven more...resilient then I had anticipated. Nonetheless, your efforts are in vain, it is you reckless, careless mortals who are to blame for this war! I do what I must...And if it means your...extinction...THEN SO BE IT!',14522,1,0,0,'malygos SAY_END_PHASE_1'), (-1616012,'Few have experienced the pain I will now inflict upon you!',14523,1,0,0,'malygos SAY_START_PHASE_2'), -(-1616013,'YOU WILL NOT SUCCEED WHILE I DRAW BREATH!',14518,1,0,0,'malygos SAY_DEEP_BREATH'), +(-1616013,'You will not succeed while I draw breath!',14518,1,0,0,'malygos SAY_DEEP_BREATH'), (-1616014,'I will teach you IGNORANT children just how little you know of magic...',14524,1,0,0,'malygos SAY_SHELL'), (-1616015,'Your energy will be put to good use!',14526,1,0,0,'malygos SAY_SLAY_2_A'), (-1616016,'I am the spell-weaver! My power is infinite!',14527,1,0,0,'malygos SAY_SLAY_2_B'), @@ -3556,7 +4350,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,commen (-1616031,'This resolution pains me deeply, but the destruction, the monumental loss of life had to end. Regardless of Malygos\' recent transgressions, I will mourn his loss. He was once a guardian, a protector. This day, one of the world\'s mightiest has fallen.',14408,1,0,1,'alextrasza SAY_OUTRO_3'), (-1616032,'The red dragonflight will take on the burden of mending the devastation wrought on Azeroth. Return home to your people and rest. Tomorrow will bring you new challenges, and you must be ready to face them. Life...goes on.',14409,1,0,1,'alextrasza SAY_OUTRO_4'), (-1616033,'A Power Spark forms from a nearby rift!',0,3,0,0,'malygos SAY_EMOTE_SPARK'), -(-1616034,'%s takes a deep breath...',0,3,0,0,'malygos SAY_EMOTE_BREATH'); +(-1616034,'%s takes a deep breath.',0,3,0,0,'malygos SAY_EMOTE_BREATH'); -- -1 619 000 AHN'KAHET INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3712,7 +4506,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1631099,'Great news, everyone!',17118,1,0,0,'putricide SAY_BERSERK'), (-1631100,'Bad news, everyone! I don\'t think I\'m going to make it',17117,1,0,0,'putricide SAY_DEATH'), -(-1631101,'Foolish mortals. You thought us defeated so easily? The San\'layn are the Lich King\'s immortal soldiers! Now you shall face their might combined!',16795,6,0,0,'lanathel SAY_COUNCIL_INTRO_1'), +(-1631101,'Foolish mortals. You thought us defeated so easily? The San\'layn are the Lich King\'s immortal soldiers! Now you shall face their might combined!',16795,6,0,1,'lanathel SAY_COUNCIL_INTRO_1'), (-1631102,'Rise up, brothers, and destroy our enemies',16796,6,0,0,'lanathel SAY_COUNCIL_INTRO_2'), (-1631103,'Such wondrous power! The Darkfallen Orb has made me INVINCIBLE!',16727,1,0,0,'keleseth SAY_KELESETH_INVOCATION'), @@ -3811,7 +4605,16 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1631189,'THE LICH KING...MUST...FALL!',17389,1,0,0,'tirion SAY_OUTRO_11'), (-1631190,'Now I stand, the lion before the lambs... and they do not fear.',17361,1,0,0,'lich_king SAY_OUTRO_12'), (-1631191,'They cannot fear.',17362,1,0,0,'lich_king SAY_OUTRO_13'), -(-1631192,'%s dies',17374,2,0,0,'lich_king SAY_OUTRO_14'); -- TODO Can be wrong +(-1631192,'%s dies',17374,2,0,0,'lich_king SAY_OUTRO_14'), -- TODO Can be wrong + +(-1631193,'%s goes into a frenzy!',0,3,0,0,'saurfang EMOTE_FRENZY'), +(-1631194,'%s\'s Blood Beasts gain the scent of blood!',0,3,0,0,'saurfang EMOTE_SCENT'), +(-1631195,'Really... Is that all you got?',16791,1,0,0,'blood_queen SAY_SLAY_1'), +(-1631196,'Such a pity...',16792,1,0,0,'blood_queen SAY_SLAY_2'), + +(-1631197,'Invocation of Blood jumps to %s!',0,3,0,0,'blood_princes EMOTE_INVOCATION'), +(-1631198,'%s begins casting Empowered Shock Vortex!',0,3,0,0,'valanar EMOTE_SHOCK_VORTEX'), +(-1631199,'%s speed toward $N!',0,3,0,0,'taldaram EMOTE_FLAMES'); -- -1 632 000 ICC: FORGE OF SOULS INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3849,44 +4652,44 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1649001,'Welcome to the trials of the crusader. Only the most powerful combatants of azeroth are allowed to undergo these trials. You are among the worthy few.',16053,1,0,0,'tirion SAY_RAID_TRIALS_INTRO'), (-1649002,'Hailing from the deepest, darkest carverns of the storm peaks, Gormok the Impaler! Battle on, heroes!',16038,1,0,0,'tirion SAY_TIRION_BEAST_1'), -(-1649003,'Your beast will be no match for my champions Tirion.',16069,1,0,0,'varian SAY_VARIAN_BEAST_1'), -(-1649004,'I have seen more worthy challenges in the ring of blood, you waste our time paladin.',16026,1,0,0,'garrosh SAY_GARROSH_BEAST_1'), +(-1649003,'Your beast will be no match for my champions Tirion.',16069,1,0,1,'varian SAY_VARIAN_BEAST_1'), +(-1649004,'I have seen more worthy challenges in the ring of blood, you waste our time paladin.',16026,1,0,1,'garrosh SAY_GARROSH_BEAST_1'), (-1649005,'Steel yourselves, heroes, for the twin terrors Acidmaw and Dreadscale. Enter the arena!',16039,1,0,0,'tirion SAY_TIRION_BEAST_2'), (-1649006,'The air freezes with the introduction of our next combatant, Icehowl! Kill or be killed, champions!',16040,1,0,0,'tirion SAY_TIRION_BEAST_3'), (-1649007,'The monstrous menagerie has been vanquished!',16041,1,0,0,'tirion SAY_TIRION_BEAST_SLAY'), (-1649008,'Tragic... They fought valiantly, but the beasts of Northrend triumphed. Let us observe a moment of silence for our fallen heroes.',16042,1,0,0,'tirion SAY_TIRION_BEAST_WIPE'), (-1649009,'Grand Warlock Wilfred Fizzlebang will summon forth your next challenge. Stand by for his entry!',16043,1,0,0,'tirion SAY_TIRION_JARAXXUS_INTRO_1'), -(-1649010,'Thank you, Highlord! Now challengers, I will begin the ritual of summoning! When I am done, a fearsome Doomguard will appear!',16268,1,0,0,'wilfred SAY_WILFRED_JARAXXUS_INTRO_1'), +(-1649010,'Thank you, Highlord. Now, challengers, I will begin the ritual of summoning. When I am done a fearsome doomguard will appear!',16268,1,0,2,'wilfred SAY_WILFRED_JARAXXUS_INTRO_1'), (-1649011,'Prepare for oblivion!',16269,1,0,0,'wilfred SAY_WILFRED_JARAXXUS_INTRO_2'), -(-1649012,'Ah ha! Behold the absolute power of Wilfred Fizzlebang, master summoner! You are bound to ME, demon!',16270,1,0,0,'wilfred SAY_WILFRED_JARAXXUS_INTRO_3'), -(-1649013,'Trifling gnome, your arrogance will be your undoing!',16143,1,0,0,'jaraxxus SAY_JARAXXUS_JARAXXAS_INTRO_1'), -(-1649014,'But I\'m in charge her-',16271,1,0,0,'wilfred SAY_WILFRED_DEATH'), -(-1649015,'Quickly, heroes! Destroy the demon lord before it can open a portal to its twisted demonic realm!',16044,1,0,0,'tirion SAY_TIRION_JARAXXUS_INTRO_2'), +(-1649012,'Ah ha! Behold the absolute power of Wilfred Fizzlebang, master summoner! You are bound to ME, demon!',16270,1,0,5,'wilfred SAY_WILFRED_JARAXXUS_INTRO_3'), +(-1649013,'Trifling gnome, your arrogance will be your undoing!',16143,1,0,397,'jaraxxus SAY_JARAXXUS_JARAXXAS_INTRO_1'), +(-1649014,'But I\'m in charge her-',16271,1,0,5,'wilfred SAY_WILFRED_DEATH'), +(-1649015,'Quickly, heroes! Destroy the demon lord before it can open a portal to its twisted demonic realm!',16044,1,0,5,'tirion SAY_TIRION_JARAXXUS_INTRO_2'), (-1649016,'The loss of Wilfred Fizzlebang, while unfortunate, should be a lesson to those that dare dabble in dark magic. Alas, you are victorious and must now face the next challenge.',16045,1,0,0,'tirion SAY_TIRION_JARAXXUS_EXIT_1'), -(-1649017,'Treacherous Alliance dogs! You summon a demon lord against warriors of the Horde!? Your deaths will be swift!',16021,1,0,0,'garrosh SAY_GARROSH_JARAXXUS_EXIT_1'), -(-1649018,'The Alliance doesn\'t need the help of a demon lord to deal with Horde filth. Come, pig!',16064,1,0,0,'varian SAY_VARIAN_JARAXXUS_SLAY'), -(-1649019,'Everyone, calm down! Compose yourselves! There is no conspiracy at play here. The warlock acted on his own volition - outside of influences from the Alliance. The tournament must go on!',16046,1,0,0,'tirion SAY_TIRION_JARAXXUS_EXIT_2'), +(-1649017,'Treacherous Alliance dogs! You summon a demon lord against warriors of the Horde!? Your deaths will be swift!',16021,1,0,5,'garrosh SAY_GARROSH_JARAXXUS_EXIT_1'), +(-1649018,'The Alliance doesn\'t need the help of a demon lord to deal with Horde filth. Come, pig!',16064,1,0,5,'varian SAY_VARIAN_JARAXXUS_SLAY'), +(-1649019,'Everyone, calm down! Compose yourselves! There is no conspiracy at play here. The warlock acted on his own volition - outside of influences from the Alliance. The tournament must go on!',16046,1,0,5,'tirion SAY_TIRION_JARAXXUS_EXIT_2'), (-1649020,'The next battle will be against the Argent Crusade\'s most powerful knights! Only by defeating them will you be deemed worthy...',16047,1,0,0,'tirion SAY_TIRION_PVP_INTRO_1'), -(-1649021,'The Horde demands justice! We challenge the Alliance. Allow us to battle in place of your knights, paladin. We will show these dogs what it means to insult the Horde!',16023,1,0,0,'garrosh SAY_GARROSH_PVP_A_INTRO_1'), -(-1649022,'Our honor has been besmirched! They make wild claims and false accusations against us. I demand justice! Allow my champions to fight in place of your knights, Tirion. We challenge the Horde!',16066,1,0,0,'varian SAY_VARIAN_PVP_H_INTRO_1'), -(-1649023,'Very well, I will allow it. Fight with honor!',16048,1,0,0,'tirion SAY_TIRION_PVP_INTRO_2'), -(-1649024,'Fight for the glory of the Alliance, heroes! Honor your king and your people!',16065,1,0,0,'varian SAY_VARIAN_PVP_H_INTRO_2'), -(-1649025,'Show them no mercy, Horde champions! LOK\'TAR OGAR!',16022,1,0,0,'garrosh SAY_GARROSH_PVP_A_INTRO_2'), -(-1649026,'GLORY TO THE ALLIANCE!',16067,1,0,0,'varian SAY_VARIAN_PVP_A_WIN'), -(-1649027,'That was just a taste of what the future brings. FOR THE HORDE!',16024,1,0,0,'garrosh SAY_GARROSH_PVP_H_WIN'), +(-1649021,'The Horde demands justice! We challenge the Alliance. Allow us to battle in place of your knights, paladin. We will show these dogs what it means to insult the Horde!',16023,1,0,5,'garrosh SAY_GARROSH_PVP_A_INTRO_1'), +(-1649022,'Our honor has been besmirched! They make wild claims and false accusations against us. I demand justice! Allow my champions to fight in place of your knights, Tirion. We challenge the Horde!',16066,1,0,5,'varian SAY_VARIAN_PVP_H_INTRO_1'), +(-1649023,'Very well, I will allow it. Fight with honor!',16048,1,0,1,'tirion SAY_TIRION_PVP_INTRO_2'), +(-1649024,'Fight for the glory of the Alliance, heroes! Honor your king and your people!',16065,1,0,5,'varian SAY_VARIAN_PVP_H_INTRO_2'), +(-1649025,'Show them no mercy, Horde champions! LOK\'TAR OGAR!',16022,1,0,1,'garrosh SAY_GARROSH_PVP_A_INTRO_2'), +(-1649026,'GLORY TO THE ALLIANCE!',16067,1,0,5,'varian SAY_VARIAN_PVP_A_WIN'), +(-1649027,'That was just a taste of what the future brings. FOR THE HORDE!',16024,1,0,1,'garrosh SAY_GARROSH_PVP_H_WIN'), (-1649028,'A shallow and tragic victory. We are weaker as a whole from the losses suffered today. Who but the Lich King could benefit from such foolishness? Great warriors have lost their lives. And for what? The true threat looms ahead - the Lich King awaits us all in death.',16049,1,0,0,'tirion SAY_TIRION_PVP_WIN'), (-1649029,'Only by working together will you overcome the final challenge. From the depths of Icecrown come two of the Scourge\'s most powerful lieutenants: fearsome val\'kyr, winged harbingers of the Lich King!',16050,1,0,0,'tirion SAY_TIRION_TWINS_INTRO'), (-1649030,'Let the games begin!',16037,1,0,0,'tirion SAY_RAID_INTRO_SHORT'), -(-1649031,'Not even the lich king\'s most powerful minions could stand against the alliance. All hail our victors.',16068,1,0,0,'varian SAY_VARIAN_TWINS_A_WIN'), +(-1649031,'Not even the lich king\'s most powerful minions could stand against the alliance. All hail our victors.',16068,1,0,1,'varian SAY_VARIAN_TWINS_A_WIN'), (-1649032,'Do you still question the might of the Horde, paladin? We will take on all comers!',16025,1,0,0,'garrosh SAY_GARROSH_TWINS_H_WIN'), -(-1649033,'A mighty blow has been dealt to the Lich King! You have proven yourselves able bodied champions of the Argent Crusade. Together we will strike at Icecrown Citadel and destroy what remains of the Scourge! There is no challenge that we cannot face united!',16051,1,0,0,'tirion SAY_TIRION_TWINS_WIN'), +(-1649033,'A mighty blow has been dealt to the Lich King! You have proven yourselves able bodied champions of the Argent Crusade. Together we will strike at Icecrown Citadel and destroy what remains of the Scourge! There is no challenge that we cannot face united!',16051,1,0,5,'tirion SAY_TIRION_TWINS_WIN'), (-1649034,'You will have your challenge, Fordring.',16321,1,0,0,'lich_king SAY_LKING_ANUB_INTRO_1'), -(-1649035,'Arthas! You are hopelessly outnumbered! Lay down Frostmourne and I will grant you a just death.',16052,1,0,0,'tirion SAY_TIRION_ABUN_INTRO_1'), -(-1649036,'The Nerubians built an empire beneath the frozen wastes of Northrend. An empire that you so foolishly built your structures upon. MY EMPIRE.',16322,1,0,0,'lich_king SAY_LKING_ANUB_INTRO_2'), +(-1649035,'Arthas! You are hopelessly outnumbered! Lay down Frostmourne and I will grant you a just death.',16052,1,0,25,'tirion SAY_TIRION_ABUN_INTRO_1'), +(-1649036,'The Nerubians built an empire beneath the frozen wastes of Northrend. An empire that you so foolishly built your structures upon. MY EMPIRE.',16322,1,0,11,'lich_king SAY_LKING_ANUB_INTRO_2'), (-1649037,'The souls of your fallen champions will be mine, Fordring.',16323,1,0,0,'lich_king SAY_LKING_ANUB_INTRO_3'), (-1649038,'Ahhh, our guests have arrived, just as the master promised.',16235,1,0,0,'anubarak SAY_ANUB_ANUB_INTRO_1'), @@ -3902,13 +4705,13 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1649047,'Inferno!',16151,1,0,0,'jaraxxus SAY_INFERNO'), (-1649048,'Weakling!',16017,1,0,0,'garrosh SAY_GARROSH_PVP_A_SLAY_1'), -(-1649049,'Pathetic!',16018,1,0,0,'garrosh SAY_GARROSH_PVP_A_SLAY_2'), -(-1649050,'Overpowered.',16019,1,0,0,'garrosh SAY_GARROSH_PVP_A_SLAY_3'), -(-1649051,'Lok\'tar!',16020,1,0,0,'garrosh SAY_GARROSH_PVP_A_SLAY_4'), -(-1649052,'Hah!',16060,1,0,0,'varian SAY_VARIAN_PVP_H_SLAY_1'), -(-1649053,'Hardly a challenge!',16061,1,0,0,'varian SAY_VARIAN_PVP_H_SLAY_2'), -(-1649054,'Worthless scrub.',16062,1,0,0,'varian SAY_VARIAN_PVP_H_SLAY_3'), -(-1649055,'Is this the best the Horde has to offer?',16063,1,0,0,'varian SAY_VARIAN_PVP_H_SLAY_4'), +(-1649049,'Pathetic!',16018,1,0,274,'garrosh SAY_GARROSH_PVP_A_SLAY_2'), +(-1649050,'Overpowered.',16019,1,0,25,'garrosh SAY_GARROSH_PVP_A_SLAY_3'), +(-1649051,'Lok\'tar!',16020,1,0,5,'garrosh SAY_GARROSH_PVP_A_SLAY_4'), +(-1649052,'Hah!',16060,1,0,5,'varian SAY_VARIAN_PVP_H_SLAY_1'), +(-1649053,'Hardly a challenge!',16061,1,0,274,'varian SAY_VARIAN_PVP_H_SLAY_2'), +(-1649054,'Worthless scrub.',16062,1,0,25,'varian SAY_VARIAN_PVP_H_SLAY_3'), +(-1649055,'Is this the best the Horde has to offer?',16063,1,0,6,'varian SAY_VARIAN_PVP_H_SLAY_4'), (-1649056,'In the name of our dark master. For the Lich King. You. Will. Die.',16272,1,0,0,'twin_valkyr SAY_AGGRO'), (-1649057,'You are finished!',16273,1,0,0,'twin_valkyr SAY_BERSERK'), @@ -3925,9 +4728,100 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1649067,'I have failed you, master...',16238,1,0,0,'anubarak SAY_DEATH'), (-1649068,'',16239,1,0,0,'anubarak SAY_BERSERK'), (-1649069,'Auum na-l ak-k-k-k, isshhh. Rise, minions. Devour...',16240,1,0,0,'anubarak SAY_SUBMERGE'), -(-1649070,'The swarm shall overtake you!',16241,1,0,0,'anubarak SAY_LEECHING_SWARM'); +(-1649070,'The swarm shall overtake you!',16241,1,0,0,'anubarak SAY_LEECHING_SWARM'), + +(-1649071,'%s burrows into the ground!',0,3,0,0,'anubarak EMOTE_BURROW'), +(-1649072,'%s spikes pursue $N!',0,3,0,0,'anubarak EMOTE_PURSUE'), +(-1649073,'%s emerges from the ground!',0,3,0,0,'anubarak EMOTE_EMERGE'), +(-1649074,'%s unleashes a Leeching Swarm to heal himself!',0,3,0,0,'anubarak EMOTE_SWARM'), + +(-1649075,'Champions, you\'re alive! Not only have you defeated every challenge of the Trial of the Crusader, but also thwarted Arthas\' plans! Your skill and cunning will prove to be a powerful weapon against the Scourge. Well done! Allow one of the Crusade\'s mages to transport you to the surface!',0,0,0,1,'tirion SAY_EPILOGUE'), + +(-1649076,'As its companion perishes, %s becomes enraged!',0,3,0,0,'twin jormungars EMOTE_JORMUNGAR_ENRAGE'), +(-1649077,'%s crashes into the Coliseum wall and is stunned!',0,3,0,0,'icehowl EMOTE_WALL_CRASH'); -- -1 650 000 TRIAL OF THE CHAMPION +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1650000,'The Silver Covenant is pleased to present their contenders for this event, Highlord.',0,1,0,396,'toc herald SAY_HORDE_CHALLENGE'), +(-1650001,'Presenting the fierce Grand Champion of Orgrimmar, Mokra the Skullcrusher!',0,0,0,0,'toc herald SAY_HORDE_WARRIOR'), +(-1650002,'Coming out of the gate is Eressea Dawnsinger, skilled mage and Grand Champion of Silvermoon!',0,0,0,0,'toc herald SAY_HORDE_MAGE'), +(-1650003,'Tall in the saddle of his kodo, here is the venerable Runok Wildmane, Grand Champion of Thunder Bluff!',0,0,0,0,'toc herald SAY_HORDE_SHAMAN'), +(-1650004,'Entering the arena is the lean and dangerous Zul\'tore, Grand Champion of Sen\'jin!',0,0,0,0,'toc herald SAY_HORDE_HUNTER'), +(-1650005,'Representing the tenacity of the Forsaken, here is the Grand Champion of the Undercity, Deathstalker Visceri!',0,0,0,0,'toc herald SAY_HORDE_ROGUE'), + +(-1650006,'The Sunreavers are proud to present their representatives in this trial by combat.',0,1,0,396,'toc herald SAY_ALLIANCE_CHALLENGE'), +(-1650007,'Proud and strong, give a cheer for Marshal Jacob Alerius, the Grand Champion of Stormwind!',0,0,0,0,'toc herald SAY_ALLIANCE_WARRIOR'), +(-1650008,'Here comes the small but deadly Ambrose Boltspark, Grand Champion of Gnomeregan!',0,0,0,0,'toc herald SAY_ALLIANCE_MAGE'), +(-1650009,'Coming out of the gate is Colosos, the towering Grand Champion of the Exodar!',0,0,0,0,'toc herald SAY_ALLIANCE_SHAMAN'), +(-1650010,'Entering the arena is the Grand Champion of Darnassus, the skilled sentinel Jaelyne Evensong!',0,0,0,0,'toc herald SAY_ALLIANCE_HUNTER'), +(-1650011,'The might of the dwarves is represented today by the Grand Champion of Ironforge, Lana Stouthammer!',0,0,0,0,'toc herald SAY_ALLIANCE_ROGUE'), + +(-1650012,'Welcome, champions. Today, before the eyes of your leaders and peers, you will prove yourselves worthy combatants.',0,1,0,1,'tirion SAY_TIRION_WELCOME'), +(-1650013,'You will first be facing three of the Grand Champions of the Tournament! These fierce contenders have beaten out all others to reach the pinnacle of skill in the joust.',0,1,0,1,'tirion SAY_TIRION_FIRST_CHALLENGE'), +(-1650014,'Fight well, Horde! Lok\'tar Ogar!',0,1,0,22,'thrall SAY_THRALL_ALLIANCE_CHALLENGE'), +(-1650015,'Finally, a fight worth watching.',0,1,0,396,'garrosh SAY_GARROSH_ALLIANCE_CHALLENGE'), +(-1650016,'I have no taste for these games, Tirion. Still... I trust they will perform admirably.',0,1,0,1,'king varian SAY_VARIAN_HORDE_CHALLENGE'), +(-1650017,'Begin!',0,1,0,0,'tirion SAY_TIRION_CHAMPIONS_BEGIN'), +(-1650018,'The blood elves of Silvermoon cheer for $n.',0,2,0,0,'raid spectator EMOTE_BLOOD_ELVES'), +(-1650019,'The trolls of the Sen\'jin Village begin a chant to celebrate $n.',0,2,0,0,'raid spectator EMOTE_TROLLS'), +(-1650020,'The tauren of Thunder Bluff cheer for $n.',0,2,0,0,'raid spectator EMOTE_TAUREN'), +(-1650021,'The forsaken of the Undercity cheer for $n.',0,2,0,0,'raid spectator EMOTE_UNDEAD'), +(-1650022,'The orcs of Orgrimmar cheer for $n.',0,2,0,0,'raid spectator EMOTE_ORCS'), +(-1650023,'The dwarves of Ironforge begin a cheer for $n.',0,2,0,0,'raid spectator EMOTE_BLOOD_DWARVES'), +(-1650024,'The gnomes of Gnomeregan cheer for $n.',0,2,0,0,'raid spectator EMOTE_GNOMES'), +(-1650025,'The night elves of Darnassus cheer for $n.',0,2,0,0,'raid spectator EMOTE_NIGHT_ELVES'), +(-1650026,'The humans of Stormwind cheer for $n.',0,2,0,0,'raid spectator EMOTE_HUMANS'), +(-1650027,'The draenei of the Exodar cheer for $n.',0,2,0,0,'raid spectator EMOTE_DRAENEI'), + +(-1650028,'Well fought! Your next challenge comes from the Crusade\'s own ranks. You will be tested against their considerable prowess.',0,1,0,0,'tirion SAY_TIRION_ARGENT_CHAMPION'), +(-1650029,'You may begin!',0,1,0,22,'tirion SAY_TIRION_ARGENT_CHAMPION_BEGIN'), +(-1650030,'Entering the arena, a paladin who is no stranger to the battlefield or tournament ground, the Grand Champion of the Argent Crusade, Eadric the Pure!',0,1,0,0,'toc herald SAY_EADRIC'), +(-1650031,'The next combatant is second to none in her passion for upholding the Light. I give you Argent Confessor Paletress!',0,1,0,0,'toc herald SAY_PALETRESS'), +(-1650032,'The Horde spectators cheer for $n.',0,2,0,0,'raid spectator EMOTE_HORDE_ARGENT_CHAMPION'), +(-1650033,'The Alliance spectators cheer for $n.',0,2,0,0,'raid spectator EMOTE_ALLIANCE_ARGENT_CHAMPION'), +(-1650034,'Are you up to the challenge? I will not hold back.',16134,0,0,397,'eadric SAY_EADRIC_INTRO'), +(-1650035,'Thank you, good herald. Your words are too kind.',16245,0,0,2,'paletress SAY_PALETRESS_INTRO_1'), +(-1650036,'May the Light give me strength to provide a worthy challenge.',16246,0,0,16,'paletress SAY_PALETRESS_INTRO_2'), + +(-1650037,'Well done. You have proven yourself today-',0,1,0,0,'tirion SAY_ARGENT_CHAMPION_COMPLETE'), +(-1650038,'What\'s that, up near the rafters?',0,0,0,25,'toc herald SAY_BLACK_KNIGHT_SPAWN'), +(-1650039,'You spoiled my grand entrance, rat.',16256,0,0,0,'black knight SAY_BLACK_KNIGHT_INTRO_1'), +(-1650040,'What is the meaning of this?',0,1,0,0,'tirion SAY_TIRION_BLACK_KNIGHT_INTRO_2'), +(-1650041,'Did you honestly think an agent of the Lich King would be bested on the field of your pathetic little tournament?',16257,0,0,396,'black knight SAY_BLACK_KNIGHT_INTRO_3'), +(-1650042,'I\'ve come to finish my task.',16258,0,0,396,'black knight SAY_BLACK_KNIGHT_INTRO_4'), + +(-1650043,'My congratulations, champions. Through trials both planned and unexpected, you have triumphed.',0,1,0,0,'tirion SAY_EPILOG_1'), +(-1650044,'Go now and rest; you\'ve earned it.',0,1,0,0,'tirion SAY_EPILOG_2'), +(-1650045,'You fought well.',0,1,0,66,'king varian SAY_VARIAN_EPILOG_3'), +(-1650046,'Well done, Horde!',0,1,0,66,'thrall SAY_THRALL_HORDE_EPILOG_3'), + +(-1650047,'Tear him apart!',0,1,0,22,'garrosh SAY_GARROSH_OTHER_1'), +(-1650048,'Garrosh, enough.',0,1,0,396,'thrall SAY_THRALL_OTHER_2'), +(-1650049,'Admirably? Hah! I will enjoy watching your weak little champions fail, human.',0,1,0,22,'garrosh SAY_GARROSH_OTHER_3'), +(-1650050,'Don\'t just stand there; kill him!',0,1,0,22,'king varian SAY_VARIAN_OTHER_4'), +(-1650051,'I did not come here to watch animals tear at each other senselessly, Tirion.',0,1,0,1,'king varian SAY_VARIAN_OTHER_5'), + +(-1650052,'Prepare yourselves!',16135,1,0,0,'eadric SAY_AGGRO'), +(-1650053,'Hammer of the Righteous!',16136,1,0,0,'eadric SAY_HAMMER'), +(-1650054,'You... You need more practice.',16137,1,0,0,'eadric SAY_KILL_1'), +(-1650055,'Nay! Nay! And I say yet again nay! Not good enough!',16138,1,0,0,'eadric SAY_KILL_2'), +(-1650056,'I yield! I submit. Excellent work. May I run away now?',16139,1,0,0,'eadric SAY_DEFEAT'), +(-1650057,'%s begins to radiate light. Shield your eyes!',0,3,0,0,'eadric EMOTE_RADIATE'), +(-1650058,'%s targets $N with the Hammer of the Righteous!',0,3,0,0,'eadric EMOTE_HAMMER'), + +(-1650059,'Well then, let us begin.',16247,1,0,0,'paletress SAY_AGGRO'), +(-1650060,'Take this time to consider your past deeds.',16248,1,0,0,'paletress SAY_MEMORY'), +(-1650061,'Even the darkest memory fades when confronted.',16249,1,0,0,'paletress SAY_MEMORY_DIES'), +(-1650062,'Take your rest.',16250,1,0,0,'paletress SAY_KILL_1'), +(-1650063,'Be at ease.',16251,1,0,0,'paletress SAY_KILL_2'), +(-1650064,'Excellent work!',16252,1,0,0,'paletress SAY_DEFEAT'), + +(-1650065,'This farce ends here!',16259,1,0,0,'black knight SAY_AGGRO'), +(-1650066,'My rotting flesh was just getting in the way!',16262,1,0,0,'black knight SAY_PHASE_2'), +(-1650067,'I have no need for bones to best you!',16263,1,0,0,'black knight SAY_PHASE_3'), +(-1650068,'A waste of flesh.',16260,1,0,0,'black knight SAY_KILL_1'), +(-1650069,'Pathetic.',16261,1,0,0,'black knight SAY_KILL_2'), +(-1650070,'No! I must not fail... again...',16264,1,0,0,'black knight SAY_DEATH'); -- -1 658 000 ICC: PIT OF SARON INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES @@ -3937,11 +4831,11 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1658004,'Hrmph, fodder. Not even fit to labor in the quarry. Relish these final moments for soon you will be nothing more than mindless undead.',16748,1,0,0,'tyrannus SAY_TYRANNUS_INTRO_2'), (-1658005,'Your last waking memory will be of agonizing pain.',16749,1,0,0,'tyrannus SAY_TYRANNUS_INTRO_3'), (-1658006,'No! You monster!',16627,1,0,0,'jaina SAY_JAINA_INTRO_2'), -(-1658007,'Pathetic weaklings!',17046,1,0,0,'sylvanas SAY_SYLVANAS_INTRO_2'), +(-1658007,'Pathetic weaklings!',17046,1,0,1,'sylvanas SAY_SYLVANAS_INTRO_2'), (-1658008,'Minions, destroy these interlopers!',16751,1,0,0,'tyrannus SAY_TYRANNUS_INTRO_4'), (-1658009,'I do what I must. Please forgive me, noble soldiers.',16628,1,0,0,'jaina SAY_JAINA_INTRO_3'), -(-1658010,'You will have to make your way across this quarry on your own.',16629,0,0,0,'jaina SAY_JAINA_INTRO_4'), -(-1658011,'You will have to battle your way through this cesspit on your own.',17047,0,0,0,'sylvanas SAY_SYLVANAS_INTRO_3'), +(-1658010,'You will have to make your way across this quarry on your own.',16629,0,0,1,'jaina SAY_JAINA_INTRO_4'), +(-1658011,'You will have to battle your way through this cesspit on your own.',17047,0,0,1,'sylvanas SAY_SYLVANAS_INTRO_3'), (-1658012,'Free any Alliance slaves that you come across. We will most certainly need their assistance in battling Tyrannus. I will gather reinforcements and join you on the other side of the quarry.',16630,0,0,0,'jaina SAY_JAINA_INTRO_5'), (-1658013,'Free any Horde slaves that you come across. We will most certainly need their assistance in battling Tyrannus. I will gather reinforcements and join you on the other side of the quarry.',17048,0,0,0,'sylvanas SAY_SYLVANAS_INTRO_4'), @@ -3951,7 +4845,7 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1658017,'Garfrost hope giant underpants clean. Save boss great shame. For later.',16915,1,0,0,'garfrost SAY_DEATH'), (-1658018,'Axe too weak. Garfrost make better and CRUSH YOU!',16916,1,0,0,'garfrost SAY_FORGE_1'), (-1658019,'That one maybe not so good to eat now. Stupid Garfrost! BAD! BAD!',16917,1,0,0,'garfrost SAY_FORGE_2'), -(-1658020,'Another shall take his place. You waste your time.',16752,1,0,0,'tyrannus SAY_TYRANNUS_GARFROST'), +(-1658020,'Another shall take his place. You waste your time.',16752,6,0,0,'tyrannus SAY_TYRANNUS_GARFROST'), (-1658021,'The forgemaster is dead! Get geared up men, we have a Scourgelord to kill.',0,1,0,0,'victus_or_ironskull SAY_GENERAL_GARFROST'), (-1658022,'%s hurls a massive saronite boulder at you!',0,5,0,0,'garfrost EMOTE_THROW_SARONITE'), -- TODO emote only displayed to target (-1658023,'%s casts Deep Freeze at $N.',0,3,0,0,'garfrost EMOTE_DEEP_FREEZE'), @@ -3968,25 +4862,25 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1658033,'%s begins to unleash a toxic poison cloud!',0,3,0,0,'ick EMOTE_ICK_POISON'), (-1658034,'%s is chasing you!',0,5,0,0,'ick EMOTE_ICK_CHASING'), -- TODO emote type? -(-1658035,'Wait! Stop! Don\'t kill me, please! I\'ll tell you everything!',16934,1,0,0,'krick SAY_OUTRO_1'), +(-1658035,'Wait! Stop! Don\'t kill me, please! I\'ll tell you everything!',16934,1,0,431,'krick SAY_OUTRO_1'), (-1658036,'I\'m not so naive as to believe your appeal for clemency, but I will listen.',16611,1,0,0,'jaina SAY_JAINA_KRICK_1'), -(-1658037,'Why should the Banshee Queen spare your miserable life?',17033,1,0,0,'sylvanas SAY_SYLVANAS_KRICK_1'), +(-1658037,'Why should the Banshee Queen spare your miserable life?',17033,1,0,396,'sylvanas SAY_SYLVANAS_KRICK_1'), (-1658038,'What you seek is in the master\'s lair, but you must destroy Tyrannus to gain entry. Within the Halls of Reflection you will find Frostmourne. It... it holds the truth.',16935,1,0,0,'krick SAY_OUTRO_2'), (-1658039,'Frostmourne lies unguarded? Impossible!',16612,1,0,0,'jaina SAY_JAINA_KRICK_2'), -(-1658040,'Frostmourne? The Lich King is never without his blade! If you are lying to me...',17034,1,0,0,'sylvanas SAY_SYLVANAS_KRICK_2'), +(-1658040,'Frostmourne? The Lich King is never without his blade! If you are lying to me...',17034,1,0,15,'sylvanas SAY_SYLVANAS_KRICK_2'), (-1658041,'I swear it is true! Please, don\'t kill me!!',16936,1,0,0,'krick SAY_OUTRO_3'), (-1658042,'Worthless gnat! Death is all that awaits you!',16753,1,0,0,'tyrannus SAY_TYRANNUS_KRICK_1'), (-1658043,'Urg... no!!',16937,1,0,0,'krick SAY_OUTRO_4'), (-1658044,'Do not think that I shall permit you entry into my master\'s sanctum so easily. Pursue me if you dare.',16754,1,0,0,'tyrannus SAY_TYRANNUS_KRICK_2'), (-1658045,'What a cruel end. Come, heroes. We must see if the gnome\'s story is true. If we can separate Arthas from Frostmourne, we might have a chance at stopping him.',16613,1,0,0,'jaina SAY_JAINA_KRICK_3'), -(-1658046,'A fitting end for a traitor. Come, we must free the slaves and see what is within the Lich King\'s chamber for ourselves.',17035,1,0,0,'sylvanas SAY_SYLVANAS_KRICK_3'), +(-1658046,'A fitting end for a traitor. Come, we must free the slaves and see what is within the Lich King\'s chamber for ourselves.',17035,1,0,396,'sylvanas SAY_SYLVANAS_KRICK_3'), -(-1658047,'Your pursuit shall be in vain, adventurers, for the Lich King has placed an army of undead at my command! Behold!',16755,1,0,0,'tyrannus SAY_TYRANNUS_AMBUSH_1'), -(-1658048,'Persistent whelps! You will not reach the entrance of my lord\'s lair! Soldiers, destroy them!',16756,1,0,0,'tyrannus SAY_TYRANNUS_AMBUSH_2'), -(-1658049,'Rimefang! Trap them within the tunnel! Bury them alive!',16757,1,0,0,'tyrannus SAY_GAUNTLET'), +(-1658047,'Your pursuit shall be in vain, adventurers, for the Lich King has placed an army of undead at my command! Behold!',16755,6,0,0,'tyrannus SAY_TYRANNUS_AMBUSH_1'), +(-1658048,'Persistent whelps! You will not reach the entrance of my lord\'s lair! Soldiers, destroy them!',16756,6,0,0,'tyrannus SAY_TYRANNUS_AMBUSH_2'), +(-1658049,'Rimefang! Trap them within the tunnel! Bury them alive!',16757,6,0,0,'tyrannus SAY_GAUNTLET'), (-1658050,'Alas, brave, brave adventurers, your meddling has reached its end. Do you hear the clatter of bone and steel coming up the tunnel behind you? That is the sound of your impending demise.',16758,1,0,0,'tyrannus SAY_PREFIGHT_1'), -(-1658051,'Heroes! We will hold off the undead as long as we can, even to our dying breath. Deal with the Scourgelord!',0,1,0,0,'victus_or_ironskull SAY_GENERAL_TRASH'), +(-1658051,'Heroes! We will hold off the undead as long as we can, even to our dying breath. Deal with the Scourgelord!',17148,1,0,0,'victus SAY_VICTUS_TRASH'), (-1658052,'Ha, such an amusing gesture from the rabble. When I have finished with you, my master\'s blade will feast upon your souls. Die!',16759,1,0,0,'tyrannus SAY_PREFIGHT_2'), (-1658053,'I shall not fail The Lich King! Come and meet your end!',16760,1,0,0,'tyrannus SAY_AGGRO'), (-1658054,'Such a shameful display...',16761,1,0,0,'tyrannus SAY_SLAY_1'), @@ -3997,13 +4891,16 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,commen (-1658059,'The frostwyrm %s gazes at $N and readies an icy attack!',0,3,0,0,'rimefang EMOTE_RIMEFANG_ICEBOLT'), (-1658060,'%s roars and swells with dark might!',0,3,0,0,'tyrannus EMOTE_SMASH'), -(-1658061,'Brave champions, we owe you our lives, our freedom... Though it be a tiny gesture in the face of this enormous debt, I pledge that from this day forth, all will know of your deeds, and the blazing path of light you cut through the shadow of this dark citadel.',0,1,0,0,'victus_or_ironskull SAY_GENERAL_OUTRO_1'), +(-1658061,'Brave champions, we owe you our lives, our freedom... Though it be a tiny gesture in the face of this enormous debt, I pledge that from this day forth, all will know of your deeds, and the blazing path of light you cut through the shadow of this dark citadel.',17149,1,0,0,'victus SAY_VICTUS_OUTRO_1'), (-1658062,'This day will stand as a testament not only to your valor, but to the fact that no foe, not even the Lich King himself, can stand when Alliance and Horde set aside their differences and ---',0,1,0,0,'victus_or_ironskull SAY_GENERAL_OUTRO_2'), -(-1658063,'Heroes, to me!',16614,0,0,0,'jaina SAY_JAINA_OUTRO_1'), -(-1658064,'Take cover behind me! Quickly!',17037,0,0,0,'sylvanas SAY_SYLVANAS_OUTRO_1'), +(-1658063,'Heroes, to me!',16614,0,0,5,'jaina SAY_JAINA_OUTRO_1'), +(-1658064,'Take cover behind me! Quickly!',17037,0,0,5,'sylvanas SAY_SYLVANAS_OUTRO_1'), (-1658065,'The Frost Queen is gone. We must keep moving - our objective is near.',16615,0,0,0,'jaina SAY_JAINA_OUTRO_2'), (-1658066,'I... I could not save them... Damn you, Arthas! DAMN YOU!',16616,0,0,0,'jaina SAY_JAINA_OUTRO_3'), -(-1658067,'I thought he\'d never shut up. At last, Sindragosa silenced that long-winded fool. To the Halls of Reflection, champions! Our objective is near... I can sense it.',17036,0,0,0,'sylvanas SAY_SYLVANAS_OUTRO_2'); +(-1658067,'I thought he\'d never shut up. At last, Sindragosa silenced that long-winded fool. To the Halls of Reflection, champions! Our objective is near... I can sense it.',17036,0,0,396,'sylvanas SAY_SYLVANAS_OUTRO_2'), + +(-1658068,'Heroes! We will hold off the undead as long as we can, even to our dying breath. Deal with the Scourgelord!',17150,1,0,0,'ironskull SAY_IRONSKULL_TRASH'), +(-1658069,'Brave champions, we owe you our lives, our freedom... Though it be a tiny gesture in the face of this enormous debt, I pledge that from this day forth, all will know of your deeds, and the blazing path of light you cut through the shadow of this dark citadel.',17151,1,0,0,'ironskull SAY_IRONSKULL_OUTRO_1'); -- -1 668 000 ICC: HALLS OF REFLECTION @@ -4107,10 +5004,15 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3000103,'I am ready to travel to you village now.','rainspeaker GOSSIP_ITEM_READY'), (-3000104,'','mosswalker victim GOSSIP_ITEM_PULSE'), (-3000105,'Ezekiel said that you might have a certain book...','dirty larry GOSSIP_ITEM_BOOK'), -(-3000106,'Show me where I can fly.','greer orehammer GOSSIP_ITEM_TAXI'), -(-3000107,'[PH] Get Presicion Bombs','greer orehammer GOSSIP_ITEM_GET_BOMBS'), -(-3000108,'[PH] Start bombing mission','greer orehammer GOSSIP_ITEM_FLIGHT'), -(-3000109,'I am ready, Oronok. Let us destroy Cyrukh and free the elements!','oronok torn-heart GOSSIP_ITEM_FIGHT'); +(-3000106,'Let Marshal Windsor know that I am ready.','squire rowe GOSSIP_ITEM_WINDSOR'), +(-3000107,'I am ready, as are my forces. Let us end this masquerade!','reginald windsor GOSSIP_ITEM_START'), +(-3000108,'I need a moment of your time, sir.','prospector anvilward GOSSIP_ITEM_MOMENT'), +(-3000109,'I am ready, Oronok. Let us destroy Cyrukh and free the elements!','oronok torn-heart GOSSIP_ITEM_FIGHT'), +(-3000110,'Why... yes, of course. I\'ve something to show you right inside this building, Mr. Anvilward.','prospector anvilward GOSSIP_ITEM_SHOW'), +(-3000111,'I am ready, Anchorite. Let us begin the exorcism.','anchorite barada GOSSIP_ITEM_EXORCISM'), +(-3000112,'I\'m ready - let\'s get out of here.','injured goblin miner GOSSIP_ITEM_ESCORT_READY'), +(-3000113,'Go on, you\'re free. Get out of here!','saronite mine slave GOSSIP_ITEM_SLAVE_FREE'), +(-3000114,'I\'m ready to start the distillation, uh, Tipsy.','tipsy mcmanus GOSSIP_ITEM_START_DISTILLATION'); -- -3 033 000 SHADOWFANG KEEP INSERT INTO gossip_texts (entry,content_default,comment) VALUES @@ -4124,6 +5026,12 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3090000,'I am ready to begin.','emi shortfuse GOSSIP_ITEM_START'); +-- -3 230 000 BLACKROCK DEPTHS +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3230000,'You\'re free, Dughal! Get out of here!','dughal GOSSIP_ITEM_DUGHAL'), +(-3230001,'Get out of here, Tobias, you\'re free!','tobias GOSSIP_ITEM_TOBIAS'), +(-3230002,'Your bondage is at an end, Doom\'rel. I challenge you!','doomrel GOSSIP_ITEM_CHALLENGE'); + -- -3 409 000 MOLTEN CORE INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3409000,'Tell me more.','majordomo_executus GOSSIP_ITEM_SUMMON_1'), @@ -4139,20 +5047,64 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3469003,'I cannot, Vaelastrasz! Surely something can be done to heal you!','vaelastrasz GOSSIP_ITEM_VAEL_1'), (-3469004,'Vaelastrasz, no!!!','vaelastrasz GOSSIP_ITEM_VAEL_2'); +-- -3 509 000 RUINS OF AHN'QIRAJ +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3509000,'Let\'s find out.','andorov GOSSIP_ITEM_START'), +(-3509001,'Let\'s see what you have.','andorov GOSSIP_ITEM_TRADE'); + +-- -3 532 000 KARAZHAN +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3532000,'Teleport me to the Guardian\'s Library','berthold GOSSIP_ITEM_TELEPORT'), +(-3532001,'I\'m not an actor.','barnes GOSSIP_ITEM_OPERA_1'), +(-3532002,'Ok, I\'ll give it a try, then.','barnes GOSSIP_ITEM_OPERA_2'), +(-3532003,'I\'ve never been more ready.','barnes GOSSIP_ITEM_OPERA_JULIANNE_WIPE'), +(-3532004,'The wolf\'s going down.','barnes GOSSIP_ITEM_OPERA_WOLF_WIPE'), +(-3532005,'What phat lewtz you have grandmother?','grandma GOSSIP_ITEM_GRANDMA'), + +(-3532006,'Control Orc Grunt','orc grunt GOSSIP_ITEM_ORC_GRUNT'), +(-3532007,'Control Orc Wolf','orc wolf GOSSIP_ITEM_ORC_WOLF'), +(-3532008,'Control Summoned Daemon','summoned deamon GOSSIP_ITEM_SUMMONED_DEAMON'), +(-3532009,'Control Orc Warlock','orc warlock GOSSIP_ITEM_ORC_WARLOCK'), +(-3532010,'Control Orc Necrolyte','orc necrolyte GOSSIP_ITEM_ORC_NECROLYTE'), +(-3532011,'Control Warchief Blackhand','warchief blackhand GOSSIP_ITEM_WARCHIEF_BLACKHAND'), +(-3532012,'Control Human Footman','human footman GOSSIP_ITEM_HUMAN_FOOTMAN'), +(-3532013,'Control Human Charger','human charger GOSSIP_ITEM_HUMAN_CHARGER'), +(-3532014,'Control Conjured Water Elemental','conjured water elemental GOSSIP_ITEM_WATER_ELEMENTAL'), +(-3532015,'Control Human Conjurer','human conjurer GOSSIP_ITEM_HUMAN_CONJURER'), +(-3532016,'Control Human Cleric','human cleric GOSSIP_ITEM_HUMAN_CLERIC'), +(-3532017,'Control King Llane','king llane GOSSIP_ITEM_KING_LLANE'), +(-3532018,'Please reset the chess board, we would like to play again.','medivh GOSSIP_ITEM_RESET_BOARD'); + +-- -3 534 000 THE BATTLE OF MT. HYJAL +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3534000,'My companions and I are with you, Lady Proudmoore.','jaina GOSSIP_ITEM_JAIN_START'), +(-3534001,'We are ready for whatever Archimonde might send our way, Lady Proudmoore.','jaina GOSSIP_ITEM_ANATHERON'), +(-3534002,'Until we meet again, Lady Proudmoore.','jaina GOSSIP_ITEM_SUCCESS'), +(-3534003,'I am with you, Thrall.','thrall GOSSIP_ITEM_THRALL_START'), +(-3534004,'We have nothing to fear.','thrall GOSSIP_ITEM_AZGALOR'), +(-3534005,'Until we meet again, Thrall.','thrall GOSSIP_ITEM_SUCCESS'), +(-3534006,'I would be grateful for any aid you can provide, Priestess.','tyrande GOSSIP_ITEM_AID'); + -- -3 560 000 ESCAPE FROM DURNHOLDE (OLD HILLSBRAD) INSERT INTO gossip_texts (entry,content_default,comment) VALUES -(-3560000,'I am ready to go to Durnholde Keep.','brazen GOSSIP_ITEM_READY'), +(-3560000,'We are ready to get you out of here, Thrall. Let\'s go!','thrall GOSSIP_ITEM_START'), (-3560001,'I need a pack of Incendiary Bombs.','erozion GOSSIP_ITEM_NEED_BOMBS'), (-3560002,'Taretha cannot see you, Thrall.','thrall GOSSIP_ITEM_SKARLOC1'), (-3560003,'The situation is rather complicated, Thrall. It would be best for you to head into the mountains now, before more of Blackmoore\'s men show up. We\'ll make sure Taretha is safe.','thrall GOSSIP_ITEM_SKARLOC2'), -(-3560004,'We\'re ready, Thrall.','thrall GOSSIP_ITEM_TARREN'), +(-3560004,'We\'re ready, Thrall.','thrall GOSSIP_ITEM_TARREN_2'), (-3560005,'Strange wizard?','taretha GOSSIP_ITEM_EPOCH1'), -(-3560006,'We\'ll get you out. Taretha. Don\'t worry. I doubt the wizard would wander too far away.','taretha GOSSIP_ITEM_EPOCH2'); +(-3560006,'We\'ll get you out. Taretha. Don\'t worry. I doubt the wizard would wander too far away.','taretha GOSSIP_ITEM_EPOCH2'), +(-3560007,'Tarren Mill.','thrall GOSSIP_ITEM_TARREN_1'); -- -3 564 000 BLACK TEMPLE INSERT INTO gossip_texts (entry,content_default,comment) VALUES -(-3564000,'We are ready to fight alongside you, Akama','akama(shade) GOSSIP_ITEM_START_ENCOUNTER'); +(-3564000,'I\'m with you, Akama.','akama(shade) GOSSIP_ITEM_START_ENCOUNTER'), +(-3564001,'I\'m ready, Akama.','akama(illidan) GOSSIP_ITEM_PREPARE'), +(-3564002,'We\'re ready to face Illidan.','akama(illidan) GOSSIP_ITEM_START_EVENT'); +-- -3 568 000 ZUL'AMAN +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3568000,'Thanks for the concern, but we intend to explore Zul\'Aman.','harrison jones GOSSIP_ITEM_BEGIN'); -- -3 595 000 CULLING OF STRATHOLME INSERT INTO gossip_texts (entry,content_default,comment) VALUES @@ -4161,7 +5113,20 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3595002,'Very well, Chromie.','chromie GOSSIP_ITEM_ENTRANCE_3'), (-3595003,'Why have I been sent back to this particular place and time?','chromie GOSSIP_ITEM_INN_1'), (-3595004,'What was this decision?','chromie GOSSIP_ITEM_INN_2'), -(-3595005,'So how does the Infinite Dragonflight plan to interfere?','chromie GOSSIP_ITEM_INN_3'); +(-3595005,'So how does the Infinite Dragonflight plan to interfere?','chromie GOSSIP_ITEM_INN_3'), +(-3595006,'Chromie, you and I both know what\'s going to happen in this time stream. We\'ve seen this all before. Can you just skip us ahead to all the real action?','chromie GOSSIP_ITEM_INN_SKIP'), +(-3595007,'Yes, please!','chromie GOSSIP_ITEM_INN_TELEPORT'), +(-3595008,'Yes, my Prince. We are ready.','arthas GOSSIP_ITEM_CITY_GATES'), +(-3595009,'We\'re only doing what is best for Lordaeron, your Highness.','arthas GOSSIP_ITEM_TOWN_HALL'), +(-3595010,'Lead the way, Prince Arthas','arthas GOSSIP_ITEM_TOWN_HALL_2'), +(-3595011,'I\'m ready.','arthas GOSSIP_ITEM_EPOCH'), +(-3595012,'For Lordaeron!','arthas GOSSIP_ITEM_ESCORT'), +(-3595013,'I\'m ready to battle the dreadlord, sire.','arthas GOSSIP_ITEM_DREADLORD'); + +-- -3 599 000 HALLS OF STONE +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3599000,'Brann, it would be our honor!','brann GOSSIP_ITEM_ID_START'), +(-3599001,'Let\'s move Brann, enough of the history lessons!','brann GOSSIP_ITEM_ID_PROGRESS'); -- -3 603 000 ULDUAR INSERT INTO gossip_texts (entry,content_default,comment) VALUES @@ -4173,12 +5138,26 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3603005,'Teleport to the Shattered Walkway.','GOSSIP_ITEM_TELE_WALKWAY'), (-3603006,'Teleport to the Conservatory of Life.','GOSSIP_ITEM_TELE_CONSERVATORY'), (-3603007,'Teleport to the Spark of Imagination.','GOSSIP_ITEM_TELE_SPARK_IMAGINATION'), -(-3603008,'Teleport to the Prison of Yogg-Saron.','GOSSIP_ITEM_TELE_YOGG_SARON'); +(-3603008,'Teleport to the Prison of Yogg-Saron.','GOSSIP_ITEM_TELE_YOGG_SARON'), + +(-3603009,'We are ready to help!','Expedition Commander GOSSIP_ITEM_START_RAZORSCALE'), +(-3603010,'Activate secondary defensive systems.','Lore Keeper of Norgannon GOSSIP_ITEM_ACTIVATE_SYSTEMS'), +(-3603011,'Confirmed.','Lore Keeper of Norgannon GOSSIP_ITEM_CONFIRMED'), +(-3603012,'We\'re ready. Begin the assault!','Brann Bronzebeard GOSSIP_ITEM_BEGIN_ASSAULT'), + +(-3603013,'Lend us your aid, keeper. Together we will defeat Yogg-Saron.','Ulduar Keeper GOSSIP_ITEM_LEND_AID'), +(-3603014,'Yes.','Ulduar Keeper GOSSIP_ITEM_KEEPER_CONFIRM'); -- -3 608 000 VIOLET HOLD INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3608000,'Activate the crystals when we get in trouble, right?','sinclari GOSSIP_ITEM_INTRO'), -(-3608001,'Get your people to safety, we\'ll keep the Blue Dragonflight\'s forces at bay.','sinclari GOSSIP_ITEM_START'); +(-3608001,'Get your people to safety, we\'ll keep the Blue Dragonflight\'s forces at bay.','sinclari GOSSIP_ITEM_START'), +(-3608002,'I\'m not fighting, so send me in now!','sinclari GOSSIP_ITEM_TELEPORT'); + +-- -3 609 000 EBON HOLD (DK START) +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3609000,'I challenge you, death knight!','Death Knight Initiate GOSSIP_ITEM_ACCEPT_DUEL'), +(-3609001,'I am ready, Highlord. Let the siege of Light\'s Hope begin!','Highlord Darion Mograine GOSSIP_ITEM_READY'); -- -3 649 000 TRIAL OF CRUSADER INSERT INTO gossip_texts (entry,content_default,comment) VALUES @@ -4192,8 +5171,20 @@ INSERT INTO gossip_texts (entry,content_default,comment) VALUES (-3649007,'That tough, huh?','barrett GOSSIP_ITEM_TWINS_INIT'), (-3649008,'Val\'kyr? We\'re ready for them','barrett GOSSIP_ITEM_TWINS_START'), (-3649009,'Your words of praise are appreciated, Coliseum Master.','barrett GOSSIP_ITEM_ANUB_INIT'), -(-3649010,'That is strange...','barrett GOSSIP_ITEM_ANUB_START'); - +(-3649010,'That is strange...','barrett GOSSIP_ITEM_ANUB_START'), +(-3649011,'We\'re ready for the next challenge.','barrett GOSSIP_ITEM_JARAXXUS_START'), +(-3649012,'You\'ll be even more amazed after we take them out!','barrett GOSSIP_ITEM_PVP_WIPE_INIT'), +(-3649013,'We\'re ready for anything!','barrett GOSSIP_ITEM_PVP_WIPE_START'), +(-3649014,'We\'re ready. This time things will be different.','barrett GOSSIP_ITEM_BEAST_WIPE_START'), +(-3649015,'Now.','barrett GOSSIP_ITEM_JARAXXUS_WIPE_START'), +(-3649016,'We\'ll just have to improve our teamwork to match the two of them.','barrett GOSSIP_ITEM_TWINS_WIPE_INIT'), +(-3649017,'Just bring them out again, then watch.','barrett GOSSIP_ITEM_TWINS_WIPE_START'); + +-- -3 650 000 TRIAL OF THE CHAMPION +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3650000,'I am ready.','herald GOSSIP_ITEM_READY'), +(-3650001,'I am ready. However, I\'d like to skip the pageantry.','herald GOSSIP_ITEM_READY_SKIP_INTRO'), +(-3650002,'I am ready for the next challenge.','herald GOSSIP_ITEM_READY_NEXT_CHALLENGE'); -- -- Below just for beautiful view in table, run at own desire @@ -5241,7 +6232,7 @@ INSERT INTO script_waypoint VALUES DELETE FROM script_waypoint WHERE entry=17876; INSERT INTO script_waypoint VALUES -(17876, 0, 2230.91, 118.765, 82.2947,5000, ''), +(17876, 0, 2230.91, 118.765, 82.2947, 2000, 'open the prison door'), (17876, 1, 2230.33, 114.980, 82.2946, 0, ''), (17876, 2, 2233.36, 111.057, 82.2996, 0, ''), (17876, 3, 2231.17, 108.486, 82.6624, 0, ''), @@ -5249,107 +6240,119 @@ INSERT INTO script_waypoint VALUES (17876, 5, 2215.23, 115.990, 89.4549, 0, ''), (17876, 6, 2210.00, 106.849, 89.4549, 0, ''), (17876, 7, 2205.66, 105.234, 89.4549, 0, ''), -(17876, 8, 2192.26, 112.618, 89.4549, 0, 'spawn armorer'), -(17876, 9, 2181.28, 118.612, 89.4549,8000, 'get weapon'), -(17876, 10, 2181.62, 120.385, 89.4549,5000, 'get armor'), -(17876, 11, 2189.44, 113.922, 89.4549, 0, ''), -(17876, 12, 2195.63, 110.584, 89.4549, 0, ''), -(17876, 13, 2201.09, 115.115, 89.4549, 0, ''), -(17876, 14, 2204.34, 121.036, 89.4355, 0, ''), -(17876, 15, 2208.66, 129.127, 87.9560, 0, 'first ambush'), -(17876, 16, 2193.09, 137.940, 88.2164, 0, ''), -(17876, 17, 2173.39, 149.064, 87.9227, 0, ''), -(17876, 18, 2164.25, 137.965, 85.0595, 0, ''), -(17876, 19, 2149.31, 125.645, 77.0858, 0, ''), -(17876, 20, 2142.78, 127.173, 75.5954, 0, ''), -(17876, 21, 2139.28, 133.952, 73.6386, 0, 'second ambush'), -(17876, 22, 2139.54, 155.235, 67.1269, 0, ''), -(17876, 23, 2145.38, 167.551, 64.8974, 0, ''), -(17876, 24, 2134.28, 175.304, 67.9446, 0, ''), -(17876, 25, 2118.08, 187.387, 68.8141, 0, ''), -(17876, 26, 2105.88, 195.461, 65.1854, 0, 'third ambush'), -(17876, 27, 2096.77, 196.939, 65.2117, 0, ''), -(17876, 28, 2083.90, 209.395, 64.8736, 0, ''), -(17876, 29, 2067.84, 224.376, 64.8022,30000, 'meeting scarloc'), -(17876, 30, 2055.40, 242.90, 63.3418, 0, 'after skarloc'), -(17876, 31, 2039.20, 266.460, 63.0182,10000, 'mount up'), -(17876, 32, 2011.77, 278.478, 65.3388, 0, ''), -(17876, 33, 2005.08, 289.676, 66.1179, 0, ''), -(17876, 34, 2033.11, 337.450, 66.0948, 0, ''), -(17876, 35, 2070.30, 416.208, 66.0893, 0, ''), -(17876, 36, 2086.76, 469.768, 65.9182, 0, ''), -(17876, 37, 2101.70, 497.955, 61.7881, 0, 'road ambush'), -(17876, 38, 2133.39, 530.933, 55.3700,5000, ''), -(17876, 39, 2157.91, 559.635, 48.5157, 0, ''), -(17876, 40, 2167.34, 586.191, 42.4394, 0, ''), -(17876, 41, 2174.17, 637.643, 33.9002, 0, ''), -(17876, 42, 2179.31, 656.053, 34.723, 0, ''), -(17876, 43, 2183.65, 670.941, 34.0318, 0, ''), -(17876, 44, 2201.50, 668.616, 36.1236, 0, ''), -(17876, 45, 2221.56, 652.747, 36.6153, 0, ''), -(17876, 46, 2238.97, 640.125, 37.2214, 0, ''), -(17876, 47, 2251.17, 620.574, 40.1473, 0, ''), -(17876, 48, 2261.98, 595.303, 41.4117, 0, ''), -(17876, 49, 2278.67, 560.172, 38.9090, 0, ''), -(17876, 50, 2336.72, 528.327, 40.9369, 0, ''), -(17876, 51, 2381.04, 519.612, 37.7312, 0, ''), -(17876, 52, 2412.20, 515.425, 39.2068, 0, ''), -(17876, 53, 2452.39, 516.174, 42.9387, 0, ''), -(17876, 54, 2467.38, 539.389, 47.4992, 0, ''), -(17876, 55, 2470.70, 554.333, 46.6668, 0, ''), -(17876, 56, 2478.07, 575.321, 55.4549, 0, ''), -(17876, 57, 2480.00, 585.408, 56.6921, 0, ''), -(17876, 58, 2482.67, 608.817, 55.6643, 0, ''), -(17876, 59, 2485.62, 626.061, 58.0132, 2000, 'dismount'), -(17876, 60, 2486.91, 626.356, 58.0761, 0, 'scare horse'), -(17876, 61, 2488.58, 660.940, 57.3913, 0, ''), -(17876, 62, 2502.56, 686.059, 55.6252, 0, ''), -(17876, 63, 2502.08, 694.360, 55.5083, 0, ''), -(17876, 64, 2491.46, 694.321, 55.7163, 0, ''), -(17876, 65, 2491.10, 703.300, 55.7630, 0, ''), -(17876, 66, 2485.64, 702.992, 55.7917, 0, ''), -(17876, 67, 2479.10, 695.291, 55.7901, 10000, ''), -(17876, 68, 2476.75, 693.689, 55.7960, 0, 'spawn mobs'), -(17876, 69, 2475.39, 695.983, 55.8146, 0, ''), -(17876, 70, 2477.75, 694.473, 55.7945, 0, ''), -(17876, 71, 2481.27, 697.747, 55.7910, 0, 'mobs in doorway'), -(17876, 72, 2486.31, 703.131, 55.7861, 5000, ''), -(17876, 73, 2490.76, 703.511, 55.7662, 0, ''), -(17876, 74, 2491.30, 694.792, 55.7195, 0, ''), -(17876, 75, 2518.69, 693.876, 55.1383, 0, ''), -(17876, 76, 2531.33, 681.914, 55.1383, 0, ''), -(17876, 77, 2568.25, 682.654, 55.1778, 0, ''), -(17876, 78, 2589.61, 689.981, 55.1421, 0, ''), -(17876, 79, 2634.74, 679.833, 54.6613, 0, ''), -(17876, 80, 2630.41, 661.464, 54.2761, 0, ''), -(17876, 81, 2629.00, 656.982, 56.0651, 0, ''), -(17876, 82, 2620.84, 633.007, 56.0300, 3000, 'stop in church'), -(17876, 83, 2622.99, 639.178, 56.0300, 0, 'summon'), -(17876, 84, 2628.73, 656.693, 56.0610, 5000, ''), -(17876, 85, 2630.34, 661.135, 54.2738, 0, ''), -(17876, 86, 2635.38, 672.243, 54.4508, 0, ''), -(17876, 87, 2644.13, 668.158, 55.3797, 0, ''), -(17876, 88, 2646.82, 666.740, 56.9898, 0, ''), -(17876, 89, 2658.22, 665.432, 57.1725, 0, ''), -(17876, 90, 2661.88, 674.849, 57.1725, 0, ''), -(17876, 91, 2656.23, 677.208, 57.1725, 0, ''), -(17876, 92, 2652.28, 670.270, 61.9353, 0, ''), -(17876, 93, 2650.79, 664.290, 61.9302, 0, 'summon inn'), -(17876, 94, 2658.19, 660.454, 61.9320, 5000, ''), -(17876, 95, 2660.57, 659.173, 61.9370, 0, 'speak with Taretha'), -(17876, 96, 2658.19, 660.454, 61.9320, 15000, 'epoch calls'), -(17876, 97, 2659.84, 659.482, 61.9361, 10000, 'taretha "dies"'), -(17876, 98, 2654.28, 662.722, 61.9313, 0, ''), -(17876, 99, 2652.37, 670.561, 61.9368, 0, ''), -(17876, 100, 2656.05, 676.761, 57.1727, 0, ''), -(17876, 101, 2658.49, 677.166, 57.1727, 0, ''), -(17876, 102, 2659.28, 667.117, 57.1727, 0, ''), -(17876, 103, 2649.71, 665.387, 57.1727, 0, ''), -(17876, 104, 2634.79, 672.964, 54.4577, 0, 'outside inn'), -(17876, 105, 2635.06, 673.892, 54.4713, 30000, 'getting ready'), -(17876, 106, 2630.45, 674.420, 54.4943, 5000, 'when all dead and meet Taretha'), -(17876, 107, 2634.30, 661.698, 54.4147, 0, 'run off'), -(17876, 108, 2652.21, 644.396, 56.1906, 0, ''); +(17876, 8, 2192.26, 112.618, 89.4549, 2000, 'SAY_ARMORER_CALL_GUARDS'), +(17876, 9, 2185.32, 116.593, 89.4548, 2000, 'SAY_TH_ARMORER_HIT'), +(17876, 10, 2182.11, 120.328, 89.4548, 3000, 'SAY_TH_ARMORY_1'), +(17876, 11, 2182.11, 120.328, 89.4548, 5000, ''), +(17876, 12, 2182.11, 120.328, 89.4548, 3000, 'SAY_TH_ARMORY_2'), +(17876, 13, 2189.44, 113.922, 89.4549, 0, ''), +(17876, 14, 2195.63, 110.584, 89.4549, 0, ''), +(17876, 15, 2201.09, 115.115, 89.4549, 0, ''), +(17876, 16, 2204.34, 121.036, 89.4355, 0, ''), +(17876, 17, 2208.66, 129.127, 87.9560, 0, 'first ambush'), +(17876, 18, 2193.09, 137.940, 88.2164, 0, ''), +(17876, 19, 2173.39, 149.064, 87.9227, 0, ''), +(17876, 20, 2164.25, 137.965, 85.0595, 0, 'second ambush'), +(17876, 21, 2149.31, 125.645, 77.0858, 0, ''), +(17876, 22, 2142.78, 127.173, 75.5954, 0, ''), +(17876, 23, 2139.28, 133.952, 73.6386, 0, 'third ambush'), +(17876, 24, 2139.54, 155.235, 67.1269, 0, ''), +(17876, 25, 2145.38, 167.551, 64.8974, 0, 'fourth ambush'), +(17876, 26, 2134.28, 175.304, 67.9446, 0, ''), +(17876, 27, 2118.08, 187.387, 68.8141, 0, ''), +(17876, 28, 2105.88, 195.461, 65.1854, 0, ''), +(17876, 29, 2096.77, 196.939, 65.2117, 0, ''), +(17876, 30, 2083.90, 209.395, 64.8736, 0, ''), +(17876, 31, 2063.40, 229.509, 64.4883, 0, 'summon Skarloc'), +(17876, 32, 2063.40, 229.509, 64.4883, 10000, 'SAY_SKARLOC_ENTER'), +(17876, 33, 2063.40, 229.509, 64.4883, 5000, 'attack Skarloc'), +(17876, 34, 2063.40, 229.509, 64.4883, 0, 'gossip after skarloc'), +(17876, 35, 2046.70, 251.941, 62.7851, 4000, 'mount up'), +(17876, 36, 2046.70, 251.941, 62.7851, 3000, 'SAY_TH_MOUNTS_UP'), +(17876, 37, 2011.77, 278.478, 65.3388, 0, ''), +(17876, 38, 2005.08, 289.676, 66.1179, 0, ''), +(17876, 39, 2033.11, 337.450, 66.0948, 0, ''), +(17876, 40, 2070.30, 416.208, 66.0893, 0, ''), +(17876, 41, 2086.76, 469.768, 65.9182, 0, ''), +(17876, 42, 2101.70, 497.955, 61.7881, 0, ''), +(17876, 43, 2133.39, 530.933, 55.3700, 0, ''), +(17876, 44, 2157.91, 559.635, 48.5157, 0, ''), +(17876, 45, 2167.34, 586.191, 42.4394, 0, ''), +(17876, 46, 2174.17, 637.643, 33.9002, 0, ''), +(17876, 47, 2179.31, 656.053, 34.723, 0, ''), +(17876, 48, 2183.65, 670.941, 34.0318, 0, ''), +(17876, 49, 2201.50, 668.616, 36.1236, 0, ''), +(17876, 50, 2221.56, 652.747, 36.6153, 0, ''), +(17876, 51, 2238.97, 640.125, 37.2214, 0, ''), +(17876, 52, 2251.17, 620.574, 40.1473, 0, ''), +(17876, 53, 2261.98, 595.303, 41.4117, 0, ''), +(17876, 54, 2278.67, 560.172, 38.9090, 0, ''), +(17876, 55, 2336.72, 528.327, 40.9369, 0, ''), +(17876, 56, 2381.04, 519.612, 37.7312, 0, ''), +(17876, 57, 2412.20, 515.425, 39.2068, 0, ''), +(17876, 58, 2452.39, 516.174, 42.9387, 0, ''), +(17876, 59, 2467.38, 539.389, 47.4992, 0, ''), +(17876, 60, 2470.70, 554.333, 46.6668, 0, ''), +(17876, 61, 2478.07, 575.321, 55.4549, 0, ''), +(17876, 62, 2480.00, 585.408, 56.6921, 0, ''), +(17876, 63, 2482.67, 608.817, 55.6643, 0, ''), +(17876, 64, 2485.62, 626.061, 58.0132, 2000, 'dismount'), +(17876, 65, 2486.91, 626.356, 58.0761, 2000, 'EMOTE_TH_STARTLE_HORSE'), +(17876, 66, 2486.91, 626.356, 58.0761, 0, 'gossip before barn'), +(17876, 67, 2488.58, 660.940, 57.3913, 0, ''), +(17876, 68, 2502.56, 686.059, 55.6252, 0, ''), +(17876, 69, 2502.08, 694.360, 55.5083, 0, ''), +(17876, 70, 2491.46, 694.321, 55.7163, 0, 'enter barn'), +(17876, 71, 2491.10, 703.300, 55.7630, 0, ''), +(17876, 72, 2485.64, 702.992, 55.7917, 0, ''), +(17876, 73, 2479.63, 696.521, 55.7901, 0, 'spawn mobs'), +(17876, 74, 2476.24, 696.204, 55.8093, 0, 'start dialogue'), +(17876, 75, 2475.39, 695.983, 55.8146, 0, ''), +(17876, 76, 2477.75, 694.473, 55.7945, 0, ''), +(17876, 77, 2481.27, 697.747, 55.7910, 0, ''), +(17876, 78, 2486.31, 703.131, 55.7861, 0, ''), +(17876, 79, 2490.76, 703.511, 55.7662, 0, ''), +(17876, 80, 2491.30, 694.792, 55.7195, 0, 'exit barn'), +(17876, 81, 2502.08, 694.360, 55.5083, 0, ''), +(17876, 82, 2507.99, 679.298, 56.3760, 0, ''), +(17876, 83, 2524.79, 669.919, 54.9258, 0, ''), +(17876, 84, 2543.19, 665.289, 56.2957, 0, ''), +(17876, 85, 2566.49, 664.354, 54.5034, 0, ''), +(17876, 86, 2592.00, 664.611, 56.4394, 0, ''), +(17876, 87, 2614.43, 663.806, 55.3921, 2000, ''), +(17876, 88, 2616.14, 665.499, 55.1610, 0, ''), +(17876, 89, 2623.56, 666.965, 54.3983, 0, ''), +(17876, 90, 2629.99, 661.059, 54.2738, 0, ''), +(17876, 91, 2629.00, 656.982, 56.0651, 0, 'enter the church'), +(17876, 92, 2620.84, 633.007, 56.0300, 3000, 'SAY_TH_CHURCH_ENTER'), +(17876, 93, 2620.84, 633.007, 56.0300, 5000, 'church ambush'), +(17876, 94, 2620.84, 633.007, 56.0300, 0, 'SAY_TH_CHURCH_END'), +(17876, 95, 2622.99, 639.178, 56.0300, 0, ''), +(17876, 96, 2628.73, 656.693, 56.0610, 0, ''), +(17876, 97, 2630.34, 661.135, 54.2738, 0, ''), +(17876, 98, 2635.38, 672.243, 54.4508, 0, ''), +(17876, 99, 2644.13, 668.158, 55.3797, 0, ''), +(17876, 100, 2646.82, 666.740, 56.9898, 0, ''), +(17876, 101, 2658.22, 665.432, 57.1725, 0, ''), +(17876, 102, 2661.88, 674.849, 57.1725, 0, ''), +(17876, 103, 2656.23, 677.208, 57.1725, 0, ''), +(17876, 104, 2652.28, 670.270, 61.9353, 0, ''), +(17876, 105, 2650.79, 664.290, 61.9302, 0, 'inn ambush'), +(17876, 106, 2660.48, 659.409, 61.9370, 5000, 'SAY_TA_ESCAPED'), +(17876, 107, 2660.48, 659.409, 61.9370, 0, 'SAY_TH_MEET_TARETHA - gossip before epoch'), +(17876, 108, 2660.48, 659.409, 61.9370, 0, 'SAY_EPOCH_ENTER1'), +(17876, 109, 2650.62, 666.643, 61.9305, 0, ''), +(17876, 110, 2652.37, 670.561, 61.9368, 0, ''), +(17876, 111, 2656.05, 676.761, 57.1727, 0, ''), +(17876, 112, 2658.49, 677.166, 57.1727, 0, ''), +(17876, 113, 2659.28, 667.117, 57.1727, 0, ''), +(17876, 114, 2649.71, 665.387, 57.1727, 0, ''), +(17876, 115, 2634.79, 672.964, 54.4577, 0, 'outside inn'), +(17876, 116, 2635.06, 673.892, 54.4713, 18000, 'SAY_EPOCH_ENTER3'), +(17876, 117, 2635.06, 673.892, 54.4713, 0, 'fight begins'), +(17876, 118, 2635.06, 673.892, 54.4713, 0, 'fight ends'), +(17876, 119, 2634.30, 661.698, 54.4147, 0, 'run off'), +(17876, 120, 2652.21, 644.396, 56.1906, 0, ''); DELETE FROM script_waypoint WHERE entry=17969; INSERT INTO script_waypoint VALUES @@ -5380,6 +6383,29 @@ INSERT INTO script_waypoint VALUES (17969, 24, -472.463959, 5449.546875, 22.561453, 0, ''), (17969, 25, -454.533264, 5461.302246, 22.602837, 30000, 'quest complete'); +DELETE FROM script_waypoint WHERE entry=18209; +INSERT INTO script_waypoint VALUES +(18209, 0, -1518.092407, 8465.188477, -4.102, 0, ''), +(18209, 1, -1516.741699, 8472.000977, -4.101, 0, ''), +(18209, 2, -1516.330444, 8473.119141, -4.102, 0, ''), +(18209, 3, -1514.117310, 8476.740234, -4.100, 0, ''), +(18209, 4, -1512.199951, 8481.147461, -4.015, 0, ''), +(18209, 5, -1514.709839, 8488.281250, -3.544, 0, ''), +(18209, 6, -1516.556274, 8495.236328, -2.463, 0, ''), +(18209, 7, -1515.730957, 8506.528320, -0.609, 7000, 'SAY_KUR_AMBUSH'), +(18209, 8, -1505.038940, 8513.247070, 0.672, 0, ''), +(18209, 9, -1476.161133, 8496.066406, 2.157, 0, ''), +(18209, 10, -1464.450684, 8492.601563, 3.529, 0, ''), +(18209, 11, -1457.568359, 8492.183594, 4.449, 0, ''), +(18209, 12, -1444.100342, 8499.031250, 6.177, 0, ''), +(18209, 13, -1426.472168, 8510.116211, 7.686, 0, ''), +(18209, 14, -1403.685303, 8524.146484, 9.680, 0, ''), +(18209, 15, -1384.890503, 8542.014648, 11.180, 0, ''), +(18209, 16, -1385.107422, 8547.194336, 11.297, 5000, 'SAY_KUR_COMPLETE'), +(18209, 17, -1387.814453, 8556.652344, 11.735, 0, ''), +(18209, 18, -1397.817749, 8574.999023, 13.204, 0, ''), +(18209, 19, -1411.961304, 8598.225586, 14.990, 0, ''); + DELETE FROM script_waypoint WHERE entry=18210; INSERT INTO script_waypoint VALUES (18210, 0, -1581.410034, 8557.933594, 2.726, 0, ''), @@ -5412,7 +6438,7 @@ INSERT INTO script_waypoint VALUES (18887, 4, 2651.75, 664.482, 57.1725, 0, ''), (18887, 5, 2647.49, 666.595, 57.0824, 0, ''), (18887, 6, 2644.37, 668.167, 55.4182, 0, ''), -(18887, 7, 2638.57, 671.231, 54.5200, 60000, ''), +(18887, 7, 2638.57, 671.231, 54.5200, 0, 'start dialogue - escort paused'), (18887, 8, 2636.56, 679.894, 54.6595, 0, ''), (18887, 9, 2640.79, 689.647, 55.3215, 0, ''), (18887, 10, 2639.35, 706.777, 56.0667, 0, ''), @@ -5593,49 +6619,51 @@ INSERT INTO script_waypoint VALUES (21027, 5, -2745.077148, 1311.108765, 33.630898, 0, ''), (21027, 6, -2749.855225, 1302.737915, 33.475632, 0, ''), (21027, 7, -2753.639648, 1294.059448, 33.314930, 0, ''), -(21027, 8, -2756.796387, 1285.122192, 33.391262, 0, ''), +(21027, 8, -2756.796387, 1285.122192, 33.391262, 0, 'spawn assassin'), (21027, 9, -2750.042969, 1273.661987, 33.188259, 0, ''), (21027, 10, -2740.378418, 1258.846680, 33.212521, 0, ''), (21027, 11, -2733.629395, 1248.259766, 33.640598, 0, ''), (21027, 12, -2727.212646, 1238.606445, 33.520847, 0, ''), -(21027, 13, -2726.377197, 1237.264526, 33.461823, 3000, 'SAY_WIL_PROGRESS1'), -(21027, 14, -2746.383301, 1266.390625, 33.191952, 2000, ''), -(21027, 15, -2746.383301, 1266.390625, 33.191952, 4000, 'SAY_WIL_FIND_EXIT'), -(21027, 16, -2758.927734, 1285.134155, 33.341728, 0, ''), -(21027, 17, -2761.845703, 1292.313599, 33.209042, 0, ''), -(21027, 18, -2758.871826, 1300.677612, 33.285332, 0, ''), -(21027, 19, -2753.928955, 1307.755859, 33.452457, 0, ''), -(21027, 20, -2738.612061, 1316.191284, 33.482975, 0, ''), -(21027, 21, -2727.897461, 1320.013916, 33.381111, 0, ''), -(21027, 22, -2709.458740, 1315.739990, 33.301838, 0, ''), -(21027, 23, -2704.658936, 1301.620361, 32.463303, 0, ''), -(21027, 24, -2704.120117, 1298.922607, 32.768162, 0, ''), -(21027, 25, -2691.798340, 1292.846436, 33.852642, 0, ''), -(21027, 26, -2682.879639, 1288.853882, 32.995399, 0, ''), -(21027, 27, -2661.869141, 1279.682495, 26.686783, 0, ''), -(21027, 28, -2648.943604, 1270.272827, 24.147522, 0, ''), -(21027, 29, -2642.506836, 1262.938721, 23.512444, 0, ''), -(21027, 30, -2636.984863, 1252.429077, 20.418257, 0, ''), -(21027, 31, -2648.113037, 1224.984863, 8.691818, 0, ''), -(21027, 32, -2658.393311, 1200.136719, 5.492243, 0, ''), -(21027, 33, -2668.504395, 1190.450562, 3.127407, 0, ''), -(21027, 34, -2685.930420, 1174.360840, 5.163924, 0, ''), -(21027, 35, -2701.613770, 1160.026367, 5.611311, 0, ''), -(21027, 36, -2714.659668, 1149.980347, 4.342373, 0, ''), -(21027, 37, -2721.443359, 1145.002808, 1.913474, 0, ''), -(21027, 38, -2733.962158, 1143.436279, 2.620415, 0, ''), -(21027, 39, -2757.876709, 1146.937500, 6.184002, 2000, 'SAY_WIL_JUST_AHEAD'), -(21027, 40, -2772.300537, 1166.052734, 6.331811, 0, ''), -(21027, 41, -2790.265381, 1189.941650, 5.207958, 0, ''), -(21027, 42, -2805.448975, 1208.663940, 5.557623, 0, ''), -(21027, 43, -2820.617676, 1225.870239, 6.266103, 0, ''), -(21027, 44, -2831.926758, 1237.725830, 5.808506, 0, ''), -(21027, 45, -2842.578369, 1252.869629, 6.807481, 0, ''), -(21027, 46, -2846.344971, 1258.727295, 7.386168, 0, ''), -(21027, 47, -2847.556396, 1266.771729, 8.208790, 0, ''), -(21027, 48, -2841.654541, 1285.809204, 7.933223, 0, ''), -(21027, 49, -2841.754883, 1289.832520, 6.990304, 0, ''), -(21027, 50, -2871.398438, 1302.348145, 6.807335, 7500, 'SAY_WIL_END'); +(21027, 13, -2726.377197, 1237.264526, 33.461823, 4000, 'SAY_WIL_PROGRESS1'), +(21027, 14, -2726.377197, 1237.264526, 33.461823, 4000, 'SAY_WIL_FIND_EXIT'), +(21027, 15, -2746.383301, 1266.390625, 33.191952, 0, 'spawn assassin'), +(21027, 16, -2746.383301, 1266.390625, 33.191952, 0, ''), +(21027, 17, -2758.927734, 1285.134155, 33.341728, 0, ''), +(21027, 18, -2761.845703, 1292.313599, 33.209042, 0, ''), +(21027, 19, -2758.871826, 1300.677612, 33.285332, 0, ''), +(21027, 20, -2753.928955, 1307.755859, 33.452457, 0, ''), +(21027, 21, -2738.612061, 1316.191284, 33.482975, 0, ''), +(21027, 22, -2727.897461, 1320.013916, 33.381111, 0, ''), +(21027, 23, -2709.458740, 1315.739990, 33.301838, 0, ''), +(21027, 24, -2704.658936, 1301.620361, 32.463303, 0, ''), +(21027, 25, -2704.120117, 1298.922607, 32.768162, 0, ''), +(21027, 26, -2691.798340, 1292.846436, 33.852642, 0, 'spawn assassin'), +(21027, 27, -2682.879639, 1288.853882, 32.995399, 0, ''), +(21027, 28, -2661.869141, 1279.682495, 26.686783, 0, ''), +(21027, 29, -2648.943604, 1270.272827, 24.147522, 0, ''), +(21027, 30, -2642.506836, 1262.938721, 23.512444, 0, 'spawn assassin'), +(21027, 31, -2636.984863, 1252.429077, 20.418257, 0, ''), +(21027, 32, -2648.113037, 1224.984863, 8.691818, 0, 'spawn assassin'), +(21027, 33, -2658.393311, 1200.136719, 5.492243, 0, ''), +(21027, 34, -2668.504395, 1190.450562, 3.127407, 0, ''), +(21027, 35, -2685.930420, 1174.360840, 5.163924, 0, ''), +(21027, 36, -2701.613770, 1160.026367, 5.611311, 0, ''), +(21027, 37, -2714.659668, 1149.980347, 4.342373, 0, ''), +(21027, 38, -2721.443359, 1145.002808, 1.913474, 0, ''), +(21027, 39, -2733.962158, 1143.436279, 2.620415, 0, 'spawn assassin'), +(21027, 40, -2757.876709, 1146.937500, 6.184002, 2000, 'SAY_WIL_JUST_AHEAD'), +(21027, 41, -2772.300537, 1166.052734, 6.331811, 0, ''), +(21027, 42, -2790.265381, 1189.941650, 5.207958, 0, ''), +(21027, 43, -2805.448975, 1208.663940, 5.557623, 0, 'spawn assassin'), +(21027, 44, -2820.617676, 1225.870239, 6.266103, 0, ''), +(21027, 45, -2831.926758, 1237.725830, 5.808506, 0, ''), +(21027, 46, -2842.578369, 1252.869629, 6.807481, 0, ''), +(21027, 47, -2846.344971, 1258.727295, 7.386168, 0, ''), +(21027, 48, -2847.556396, 1266.771729, 8.208790, 0, ''), +(21027, 49, -2841.654541, 1285.809204, 7.933223, 0, ''), +(21027, 50, -2841.754883, 1289.832520, 6.990304, 0, ''), +(21027, 51, -2861.973145, 1298.774536, 6.807335, 0, 'spawn assassin'), +(21027, 52, -2871.398438, 1302.348145, 6.807335, 7500, 'SAY_WIL_END'); DELETE FROM script_waypoint WHERE entry=22377; INSERT INTO script_waypoint VALUES @@ -5903,27 +6931,14 @@ INSERT INTO script_waypoint (entry, pointid, location_x, location_y, location_z, (28787, 21, 5824.738770, 5315.712891, -97.758018, 0, ''), (28787, 22, 5819.650879, 5305.409668, -97.481796, 10000, 'SAY_HELICE_COMPLETE'); -DELETE FROM script_waypoint WHERE entry=28912; -INSERT INTO script_waypoint VALUES -(28912, 0, 1653.518, -6038.374, 127.585, 0, 'Jump off'), -(28912, 1, 1653.978, -6034.614, 127.585, 5000, 'To Box'), -(28912, 2, 1653.854, -6034.726, 127.585, 500, 'Equip'), -(28912, 3, 1652.297, -6035.671, 127.585, 3000, 'Recover'), -(28912, 4, 1639.762, -6046.343, 127.948, 0, 'Escape'), -(28912, 5, 1640.963, -6028.119, 134.740, 0, ''), -(28912, 6, 1625.805, -6029.197, 134.740, 0, ''), -(28912, 7, 1626.845, -6015.085, 134.740, 0, ''), -(28912, 8, 1649.150, -6016.975, 133.240, 0, ''), -(28912, 9, 1653.063, -5974.844, 132.652, 5000, 'Mount'), -(28912, 10, 1654.747, -5926.424, 121.191, 0, 'Disappear'); - DELETE FROM script_waypoint WHERE entry=30658; INSERT INTO script_waypoint VALUES (30658, 0, 1830.504517, 799.356506, 44.341801, 5000, 'use activation'), (30658, 1, 1832.461792, 800.431396, 44.311745, 10000, 'SAY_BEGIN call back guards'), -(30658, 2, 1824.786987, 803.828369, 44.363434, 0, 'SAY_LOCK_DOOR close door'), -(30658, 3, 1807.245483, 803.904114, 44.363434, 0, ''), -(30658, 4, 1785.160400, 803.856873, 44.364830, 30000, ''); +(30658, 2, 1824.786987, 803.828369, 44.363434, 3000, 'SAY_LOCK_DOOR'), +(30658, 3, 1824.786987, 803.828369, 44.363434, 0, 'close door'), +(30658, 4, 1817.315674, 804.060608, 44.363998, 0, 'escort paused - allow teleport inside'), +(30658, 5, 1826.889648, 803.929993, 44.363239, 30000, 'SAY_VICTORY'); DELETE FROM script_waypoint WHERE entry = 349; INSERT INTO script_waypoint VALUES @@ -6276,6 +7291,15 @@ INSERT INTO script_waypoint VALUES (8516, 24,2575.60, 950.138, 52.8460, 0, ''), (8516, 25,2575.60, 950.138, 52.8460, 0, ''); +DELETE FROM `script_waypoint` WHERE entry=29173; +INSERT INTO `script_waypoint` VALUES +(29173, 0, 2411.322, -5152.227, 83.777, 0,''), +(29173, 1, 2386.443, -5177.385, 74.049, 0,''), +(29173, 2, 2357.140, -5209.571, 79.642, 0,'SAY_LIGHT_OF_DAWN_STAND_1'), +(29173, 3, 2342.683, -5232.791, 85.259, 0,'SAY_LIGHT_OF_DAWN_STAND_2'), +(29173, 4, 2281.354, -5278.533, 82.227, 0,'Start battle'), +(29173, 5, 2280.302, -5284.489, 82.657, 600000,'Go in front of the chapel for outro'); + DELETE FROM script_waypoint WHERE entry=11832; INSERT INTO script_waypoint VALUES (11832, 0, 7848.385645, -2216.356670, 470.888333, 15000, 'SAY_REMULOS_INTRO_1'), @@ -6410,20 +7434,30 @@ INSERT INTO script_waypoint VALUES DELETE FROM script_waypoint WHERE entry=3692; INSERT INTO script_waypoint VALUES -(3692, 1, 4608.54, -6.47, 69.69, 4000, 'SAY_START'), -(3692, 2, 4604.54, -5.17, 69.51, 0, ''), -(3692, 3, 4604.26, -2.02, 69.42, 0, ''), -(3692, 4, 4607.75, 3.79, 70.13, 1000, 'first ambush'), -(3692, 5, 4607.75, 3.79, 70.13, 0, 'SAY_FIRST_AMBUSH'), -(3692, 6, 4619.77, 27.47, 70.40, 0, ''), -(3692, 7, 4626.28, 42.46, 68.75, 0, ''), -(3692, 8, 4633.13, 51.17, 67.40, 0, ''), -(3692, 9, 4639.67, 79.03, 61.74, 0, ''), -(3692, 10, 4647.54, 94.25, 59.92, 0, 'second ambush'), -(3692, 11, 4682.08, 113.47, 54.83, 0, ''), -(3692, 12, 4705.28, 137.81, 53.36, 0, 'last ambush'), -(3692, 13, 4730.30, 158.76, 52.33, 0, ''), -(3692, 14, 4756.47, 195.65, 53.61, 10000, 'SAY_END'); +(3692, 1, 4608.43, -6.32, 69.74, 1000, 'stand up'), +(3692, 2, 4608.43, -6.32, 69.74, 4000, 'SAY_START'), +(3692, 3, 4604.54, -5.17, 69.51, 0, ''), +(3692, 4, 4604.26, -2.02, 69.42, 0, ''), +(3692, 5, 4607.75, 3.79, 70.13, 1000, 'first ambush'), +(3692, 6, 4607.75, 3.79, 70.13, 0, 'SAY_FIRST_AMBUSH'), +(3692, 7, 4619.77, 27.47, 70.40, 0, ''), +(3692, 8, 4626.28, 42.46, 68.75, 0, ''), +(3692, 9, 4633.13, 51.17, 67.40, 0, ''), +(3692, 10, 4639.67, 79.03, 61.74, 0, ''), +(3692, 11, 4647.54, 94.25, 59.92, 0, 'second ambush'), +(3692, 12, 4682.08, 113.47, 54.83, 0, ''), +(3692, 13, 4705.28, 137.81, 53.36, 0, 'last ambush'), +(3692, 14, 4730.30, 158.76, 52.33, 0, ''), +(3692, 15, 4756.47, 195.65, 53.61, 10000, 'SAY_END'), +(3692, 16, 4608.43, -6.32, 69.74, 1000, 'bow'), +(3692, 17, 4608.43, -6.32, 69.74, 4000, 'SAY_ESCAPE'), +(3692, 18, 4608.43, -6.32, 69.74, 4000, 'SPELL_MOONSTALKER_FORM'), +(3692, 19, 4604.54, -5.17, 69.51, 0, ''), +(3692, 20, 4604.26, -2.02, 69.42, 0, ''), +(3692, 21, 4607.75, 3.79, 70.13, 0, ''), +(3692, 22, 4607.75, 3.79, 70.13, 0, ''), +(3692, 23, 4619.77, 27.47, 70.40, 0, ''), +(3692, 24, 4640.33, 33.74, 68.22, 0, 'quest complete'); DELETE FROM script_waypoint WHERE entry=22424; INSERT INTO script_waypoint VALUES @@ -6510,4 +7544,1254 @@ INSERT INTO script_waypoint VALUES (22424, 81, -3504.23, 4080.47, 92.92, 7000, 'SPELL_TRANSFORM'), (22424, 82, -3504.23, 4080.47, 92.92, 20000, 'SAY_SKYWING_END'); +DELETE FROM script_waypoint WHERE entry=17804; +INSERT INTO script_waypoint VALUES +(17804, 0, -9054.86, 443.58, 93.05, 0, ''), +(17804, 1, -9079.33, 424.49, 92.52, 0, ''), +(17804, 2, -9086.21, 419.02, 92.32, 3000, ''), +(17804, 3, -9086.21, 419.02, 92.32, 1000, ''), +(17804, 4, -9079.33, 424.49, 92.52, 0, ''), +(17804, 5, -9054.38, 436.30, 93.05, 0, ''), +(17804, 6, -9042.23, 434.24, 93.37, 5000, 'SAY_SIGNAL_SENT'); + +DELETE FROM script_waypoint WHERE entry=12580; +INSERT INTO script_waypoint VALUES +(12580, 0, -8997.63, 486.402, 96.622, 0, ''), +(12580, 1, -8971.08, 507.541, 96.349, 0, 'SAY_DIALOG_1'), +(12580, 2, -8953.17, 518.537, 96.355, 0, ''), +(12580, 3, -8936.33, 501.777, 94.066, 0, ''), +(12580, 4, -8922.52, 498.45, 93.869, 0, ''), +(12580, 5, -8907.64, 509.941, 93.840, 0, ''), +(12580, 6, -8925.26, 542.51, 94.274, 0, ''), +(12580, 7, -8832.28, 622.285, 93.686, 0, ''), +(12580, 8, -8824.8, 621.713, 94.084, 0, ''), +(12580, 9, -8796.46, 590.922, 97.466, 0, ''), +(12580, 10, -8769.85, 607.883, 97.118, 0, ''), +(12580, 11, -8737.14, 574.741, 97.398, 0, 'reset jonathan'), +(12580, 12, -8746.27, 563.446, 97.399, 0, ''), +(12580, 13, -8745.5, 557.877, 97.704, 0, ''), +(12580, 14, -8730.95, 541.477, 101.12, 0, ''), +(12580, 15, -8713.16, 520.692, 97.227, 0, ''), +(12580, 16, -8677.09, 549.614, 97.438, 0, ''), +(12580, 17, -8655.72, 552.732, 96.941, 0, ''), +(12580, 18, -8641.68, 540.516, 98.972, 0, ''), +(12580, 19, -8620.08, 520.120, 102.812, 0, ''), +(12580, 20, -8591.09, 492.553, 104.032, 0, ''), +(12580, 21, -8562.45, 463.583, 104.517, 0, ''), +(12580, 22, -8548.63, 467.38, 104.517, 0, 'SAY_WINDSOR_BEFORE_KEEP'), +(12580, 23, -8487.77, 391.44, 108.386, 0, ''), +(12580, 24, -8455.95, 351.225, 120.88, 0, ''), +(12580, 25, -8446.87, 339.904, 121.33, 0, 'SAY_WINDSOR_KEEP_1'), +(12580, 26, -8446.87, 339.904, 121.33, 10000, ''); + +DELETE FROM script_waypoint WHERE entry=9520; +INSERT INTO script_waypoint VALUES +(9520, 1, -7699.62, -1444.29, 139.87, 4000, 'SAY_START'), +(9520, 2, -7670.67, -1458.25, 140.74, 0, ''), +(9520, 3, -7675.26, -1465.58, 140.74, 0, ''), +(9520, 4, -7685.84, -1472.66, 140.75, 0, ''), +(9520, 5, -7700.08, -1473.41, 140.79, 0, ''), +(9520, 6, -7712.55, -1470.19, 140.79, 0, ''), +(9520, 7, -7717.27, -1481.70, 140.72, 5000, 'SAY_PAY'), +(9520, 8, -7726.23, -1500.78, 132.99, 0, ''), +(9520, 9, -7744.61, -1531.61, 132.69, 0, ''), +(9520, 10, -7763.08, -1536.22, 131.93, 0, ''), +(9520, 11, -7815.32, -1522.61, 134.16, 0, ''), +(9520, 12, -7850.26, -1516.87, 138.17, 0, 'SAY_FIRST_AMBUSH_START'), +(9520, 13, -7850.26, -1516.87, 138.17, 3000, 'SAY_FIRST_AMBUSH_END'), +(9520, 14, -7881.01, -1508.49, 142.37, 0, ''), +(9520, 15, -7888.91, -1458.09, 144.79, 0, ''), +(9520, 16, -7889.18, -1430.21, 145.31, 0, ''), +(9520, 17, -7900.53, -1427.01, 150.26, 0, ''), +(9520, 18, -7904.15, -1429.91, 150.27, 0, ''), +(9520, 19, -7921.48, -1425.47, 140.54, 0, ''), +(9520, 20, -7941.43, -1413.10, 134.35, 0, ''), +(9520, 21, -7964.85, -1367.45, 132.99, 0, ''), +(9520, 22, -7989.95, -1319.121, 133.71, 0, ''), +(9520, 23, -8010.43, -1270.23, 133.42, 0, ''), +(9520, 24, -8025.62, -1243.78, 133.91, 0, 'SAY_SEC_AMBUSH_START'), +(9520, 25, -8025.62, -1243.78, 133.91, 3000, 'SAY_SEC_AMBUSH_END'), +(9520, 26, -8015.22, -1196.98, 146.76, 0, ''), +(9520, 27, -7994.68, -1151.38, 160.70, 0, ''), +(9520, 28, -7970.91, -1132.81, 170.16, 0, 'summon Searscale Drakes'), +(9520, 29, -7927.59, -1122.79, 185.86, 0, ''), +(9520, 30, -7897.67, -1126.67, 194.32, 0, 'SAY_THIRD_AMBUSH_START'), +(9520, 31, -7897.67, -1126.67, 194.32, 3000, 'SAY_THIRD_AMBUSH_END'), +(9520, 32, -7864.11, -1135.98, 203.29, 0, ''), +(9520, 33, -7837.31, -1137.73, 209.63, 0, ''), +(9520, 34, -7808.72, -1134.90, 214.84, 0, ''), +(9520, 35, -7786.85, -1127.24, 214.84, 0, ''), +(9520, 36, -7746.58, -1125.16, 215.08, 5000, 'EMOTE_LAUGH'), +(9520, 37, -7746.41, -1103.62, 215.62, 0, ''), +(9520, 38, -7740.25, -1090.51, 216.69, 0, ''), +(9520, 39, -7730.97, -1085.55, 217.12, 0, ''), +(9520, 40, -7697.89, -1089.43, 217.62, 0, ''), +(9520, 41, -7679.30, -1059.15, 220.09, 0, ''), +(9520, 42, -7661.39, -1038.24, 226.24, 0, ''), +(9520, 43, -7634.49, -1020.96, 234.30, 0, ''), +(9520, 44, -7596.22, -1013.16, 244.03, 0, ''), +(9520, 45, -7556.53, -1021.74, 253.21, 0, 'SAY_LAST_STAND'); + +DELETE FROM script_waypoint WHERE entry=9023; +INSERT INTO script_waypoint VALUES +(9023, 1, 316.336, -225.528, -77.7258, 2000, 'SAY_WINDSOR_START'), +(9023, 2, 322.96, -207.13, -77.87, 0, ''), +(9023, 3, 281.05, -172.16, -75.12, 0, ''), +(9023, 4, 272.19, -139.14, -70.61, 0, ''), +(9023, 5, 283.62, -116.09, -70.21, 0, ''), +(9023, 6, 296.18, -94.30, -74.08, 0, ''), +(9023, 7, 294.57, -93.11, -74.08, 0, 'escort paused - SAY_WINDSOR_CELL_DUGHAL_1'), +(9023, 8, 294.57, -93.11, -74.08, 10000, ''), +(9023, 9, 294.57, -93.11, -74.08, 3000, 'SAY_WINDSOR_CELL_DUGHAL_3'), +(9023, 10, 314.31, -74.31, -76.09, 0, ''), +(9023, 11, 360.22, -62.93, -66.77, 0, ''), +(9023, 12, 383.38, -69.40, -63.25, 0, ''), +(9023, 13, 389.99, -67.86, -62.57, 0, ''), +(9023, 14, 400.98, -72.01, -62.31, 0, 'SAY_WINDSOR_EQUIPMENT_1'), +(9023, 15, 404.22, -62.30, -63.50, 2000, ''), +(9023, 16, 404.22, -62.30, -63.50, 1500, 'open supply door'), +(9023, 17, 407.65, -51.86, -63.96, 0, ''), +(9023, 18, 403.61, -51.71, -63.92, 1000, 'SAY_WINDSOR_EQUIPMENT_2'), +(9023, 19, 403.61, -51.71, -63.92, 2000, ''), +(9023, 20, 403.61, -51.71, -63.92, 1000, 'open supply crate'), +(9023, 21, 403.61, -51.71, -63.92, 1000, 'update entry to Reginald Windsor'), +(9023, 22, 403.61, -52.71, -63.92, 4000, 'SAY_WINDSOR_EQUIPMENT_3'), +(9023, 23, 403.61, -52.71, -63.92, 4000, 'SAY_WINDSOR_EQUIPMENT_4'), +(9023, 24, 406.33, -54.87, -63.95, 0, ''), +(9023, 25, 403.86, -73.88, -62.02, 0, ''), +(9023, 26, 428.80, -81.34, -64.91, 0, ''), +(9023, 27, 557.03, -119.71, -61.83, 0, ''), +(9023, 28, 573.40, -124.39, -65.07, 0, ''), +(9023, 29, 593.91, -130.29, -69.25, 0, ''), +(9023, 30, 593.21, -132.16, -69.25, 0, 'escort paused - SAY_WINDSOR_CELL_JAZ_1'), +(9023, 31, 593.21, -132.16, -69.25, 1000, ''), +(9023, 32, 593.21, -132.16, -69.25, 3000, 'SAY_WINDSOR_CELL_JAZ_2'), +(9023, 33, 622.81, -135.55, -71.92, 0, ''), +(9023, 34, 634.68, -151.29, -70.32, 0, ''), +(9023, 35, 635.06, -153.25, -70.32, 0, 'escort paused - SAY_WINDSOR_CELL_SHILL_1'), +(9023, 36, 635.06, -153.25, -70.32, 3000, ''), +(9023, 37, 635.06, -153.25, -70.32, 5000, 'SAY_WINDSOR_CELL_SHILL_2'), +(9023, 38, 635.06, -153.25, -70.32, 2000, 'SAY_WINDSOR_CELL_SHILL_3'), +(9023, 39, 655.25, -172.39, -73.72, 0, ''), +(9023, 40, 654.79, -226.30, -83.06, 0, ''), +(9023, 41, 622.85, -268.85, -83.96, 0, ''), +(9023, 42, 579.45, -275.56, -80.44, 0, ''), +(9023, 43, 561.19, -266.85, -75.59, 0, ''), +(9023, 44, 547.91, -253.92, -70.34, 0, ''), +(9023, 45, 549.20, -252.40, -70.34, 0, 'escort paused - SAY_WINDSOR_CELL_CREST_1'), +(9023, 46, 549.20, -252.40, -70.34, 1000, ''), +(9023, 47, 549.20, -252.40, -70.34, 4000, 'SAY_WINDSOR_CELL_CREST_2'), +(9023, 48, 555.33, -269.16, -74.40, 0, ''), +(9023, 49, 554.31, -270.88, -74.40, 0, 'escort paused - SAY_WINDSOR_CELL_TOBIAS_1'), +(9023, 50, 554.31, -270.88, -74.40, 10000, ''), +(9023, 51, 554.31, -270.88, -74.40, 4000, 'SAY_WINDSOR_CELL_TOBIAS_2'), +(9023, 52, 536.10, -249.60, -67.47, 0, ''), +(9023, 53, 520.94, -216.65, -59.28, 0, ''), +(9023, 54, 505.99, -148.74, -62.17, 0, ''), +(9023, 55, 484.21, -56.24, -62.43, 0, ''), +(9023, 56, 470.39, -6.01, -70.10, 0, ''), +(9023, 57, 452.45, 29.85, -70.37, 1500, 'SAY_WINDSOR_FREE_1'), +(9023, 58, 452.45, 29.85, -70.37, 15000, 'SAY_WINDSOR_FREE_2'); + +DELETE FROM script_waypoint WHERE entry=17225; +INSERT INTO script_waypoint VALUES +(17225, 0, -11033.51, -1784.65, 182.284, 3000, ''), +(17225, 1, -11107.57, -1873.36, 136.878, 0, ''), +(17225, 2, -11118.71, -1883.65, 132.441, 0, ''), +(17225, 3, -11132.92, -1888.12, 128.969, 0, ''), +(17225, 4, -11150.31, -1890.54, 126.557, 0, ''), +(17225, 5, -11160.64, -1891.63, 124.793, 0, ''), +(17225, 6, -11171.52, -1889.45, 123.417, 0, ''), +(17225, 7, -11183.46, -1884.09, 119.754, 0, ''), +(17225, 8, -11196.25, -1874.01, 115.227, 0, ''), +(17225, 9, -11205.59, -1859.66, 110.216, 0, ''), +(17225, 10, -11236.53, -1818.03, 97.3972, 0, ''), +(17225, 11, -11253.11, -1794.48, 93.3101, 0, ''), +(17225, 12, -11254.86, -1787.13, 92.5174, 0, ''), +(17225, 13, -11253.32, -1777.08, 91.7739, 0, ''), +(17225, 14, -11247.48, -1770.27, 92.4183, 0, ''), +(17225, 15, -11238.61, -1766.51, 94.6417, 0, ''), +(17225, 16, -11227.56, -1767.22, 100.256, 0, ''), +(17225, 17, -11218.41, -1770.55, 107.859, 0, ''), +(17225, 18, -11204.81, -1781.77, 110.383, 0, ''), +(17225, 19, -11195.77, -1801.07, 110.833, 0, ''), +(17225, 20, -11195.81, -1824.66, 113.936, 0, ''), +(17225, 21, -11197.11, -1860.01, 117.945, 0, ''), +(17225, 22, -11194.60, -1884.23, 121.401, 0, ''), +(17225, 23, -11184.21, -1894.78, 120.326, 0, ''), +(17225, 24, -11176.91, -1899.84, 119.844, 0, ''), +(17225, 25, -11168.13, -1901.77, 118.958, 0, ''), +(17225, 26, -11154.91, -1901.66, 117.218, 0, ''), +(17225, 27, -11143.15, -1901.22, 115.885, 0, ''), +(17225, 28, -11131.19, -1897.59, 113.722, 0, ''), +(17225, 29, -11121.31, -1890.25, 111.643, 0, ''), +(17225, 30, -11118.22, -1883.83, 110.595, 3000, ''), +(17225, 31, -11118.45, -1883.68, 91.473, 0, 'start combat'); + +DELETE FROM script_waypoint WHERE entry=20802; +INSERT INTO script_waypoint VALUES +(20802, 0, 4017.864, 2325.038, 114.029, 3000, 'SAY_INTRO'), +(20802, 1, 4006.373, 2324.593, 111.455, 0, ''), +(20802, 2, 3998.391, 2326.364, 113.164, 0, ''), +(20802, 3, 3982.309, 2330.261, 113.846, 7000, 'SAY_STAGING_GROUNDS'), +(20802, 4, 3950.646, 2329.249, 113.924, 0, 'SAY_TOXIC_HORROR'), +(20802, 5, 3939.229, 2330.994, 112.197, 0, ''), +(20802, 6, 3927.858, 2333.644, 111.330, 0, ''), +(20802, 7, 3917.851, 2337.696, 113.493, 0, ''), +(20802, 8, 3907.743, 2343.336, 114.062, 0, ''), +(20802, 9, 3878.760, 2378.611, 114.037, 8000, 'SAY_SALHADAAR'), +(20802, 10, 3863.153, 2355.876, 114.987, 0, ''), +(20802, 11, 3861.241, 2344.893, 115.201, 0, ''), +(20802, 12, 3872.463, 2323.114, 114.671, 0, 'escort paused - SAY_DISRUPTOR'), +(20802, 13, 3863.740, 2349.790, 115.382, 0, 'SAY_FINISH_2'); + +DELETE FROM script_waypoint WHERE entry=20763; +INSERT INTO script_waypoint VALUES +(20763, 0, 4084.092, 2297.254, 110.277, 0, ''), +(20763, 1, 4107.174, 2294.916, 106.625, 0, ''), +(20763, 2, 4154.129, 2296.789, 102.331, 0, ''), +(20763, 3, 4166.021, 2302.819, 103.422, 0, ''), +(20763, 4, 4195.039, 2301.094, 113.786, 0, ''), +(20763, 5, 4205.246, 2297.116, 117.992, 0, ''), +(20763, 6, 4230.429, 2294.642, 127.307, 0, ''), +(20763, 7, 4238.981, 2293.579, 129.332, 0, ''), +(20763, 8, 4250.184, 2293.272, 129.009, 0, ''), +(20763, 9, 4262.810, 2290.768, 126.485, 0, ''), +(20763, 10, 4265.845, 2278.562, 128.235, 0, ''), +(20763, 11, 4265.609, 2265.734, 128.452, 0, ''), +(20763, 12, 4258.838, 2245.354, 132.804, 0, ''), +(20763, 13, 4247.976, 2221.211, 137.668, 0, ''), +(20763, 14, 4247.973, 2213.876, 137.721, 0, ''), +(20763, 15, 4249.876, 2204.265, 137.121, 4000, ''), +(20763, 16, 4249.876, 2204.265, 137.121, 0, 'SAY_VANGUARD_FINISH'), +(20763, 17, 4252.455, 2170.885, 137.677, 3000, 'EMOTE_VANGUARD_FINISH'), +(20763, 18, 4252.455, 2170.885, 137.677, 5000, ''); + +DELETE FROM script_waypoint WHERE entry=23089; +INSERT INTO script_waypoint VALUES +(23089, 0, 660.22, 305.74, 271.688, 0, 'escort paused - GOSSIP_ITEM_PREPARE'), +(23089, 1, 675.10, 343.30, 271.688, 0, ''), +(23089, 2, 694.01, 374.84, 271.687, 0, ''), +(23089, 3, 706.22, 375.75, 274.888, 0, ''), +(23089, 4, 720.48, 370.38, 281.300, 0, ''), +(23089, 5, 733.30, 357.66, 292.477, 0, ''), +(23089, 6, 740.40, 344.39, 300.920, 0, ''), +(23089, 7, 747.54, 329.03, 308.509, 0, ''), +(23089, 8, 748.24, 318.78, 311.781, 0, ''), +(23089, 9, 752.41, 304.31, 312.077, 0, 'escort paused - SAY_AKAMA_OPEN_DOOR_1'), +(23089, 10, 770.27, 304.89, 312.35, 0, ''), +(23089, 11, 780.18, 305.26, 319.71, 0, ''), +(23089, 12, 791.45, 289.27, 319.80, 0, ''), +(23089, 13, 790.41, 262.70, 341.42, 0, ''), +(23089, 14, 782.88, 250.20, 341.60, 0, ''), +(23089, 15, 765.35, 241.40, 353.62, 0, ''), +(23089, 16, 750.61, 235.63, 353.02, 0, 'escort paused - GOSSIP_ITEM_START_EVENT'), +(23089, 17, 748.87, 304.93, 352.99, 0, 'escort paused - SAY_ILLIDAN_SPEECH_1'), +(23089, 18, 737.92, 368.15, 352.99, 0, ''), +(23089, 19, 749.64, 378.69, 352.99, 0, ''), +(23089, 20, 766.49, 371.79, 353.63, 0, ''), +(23089, 21, 784.98, 361.89, 341.41, 0, ''), +(23089, 22, 791.44, 347.10, 341.41, 0, ''), +(23089, 23, 794.80, 319.47, 319.75, 0, ''), +(23089, 24, 794.34, 304.34, 319.75, 0, 'escort paused - fight illidari elites'), +(23089, 25, 794.80, 319.47, 319.75, 0, ''), +(23089, 26, 791.44, 347.10, 341.41, 0, ''), +(23089, 27, 784.98, 361.89, 341.41, 0, ''), +(23089, 28, 766.49, 371.79, 353.63, 0, ''), +(23089, 29, 749.64, 378.69, 352.99, 0, ''), +(23089, 30, 737.92, 368.15, 352.99, 0, 'escort paused'); + +DELETE FROM script_waypoint WHERE entry=3584; +INSERT INTO script_waypoint VALUES +(3584, 0, 4520.4, 420.235, 33.5284, 2000, ''), +(3584, 1, 4512.26, 408.881, 32.9308, 0, ''), +(3584, 2, 4507.94, 396.47, 32.9476, 0, ''), +(3584, 3, 4507.53, 383.781, 32.995, 0, ''), +(3584, 4, 4512.1, 374.02, 33.166, 0, ''), +(3584, 5, 4519.75, 373.241, 33.1574, 0, ''), +(3584, 6, 4592.41, 369.127, 31.4893, 0, ''), +(3584, 7, 4598.55, 364.801, 31.4947, 0, ''), +(3584, 8, 4602.76, 357.649, 32.9265, 0, ''), +(3584, 9, 4597.88, 352.629, 34.0317, 0, ''), +(3584, 10, 4590.23, 350.9, 36.2977, 0, ''), +(3584, 11, 4581.5, 348.254, 38.3878, 0, ''), +(3584, 12, 4572.05, 348.059, 42.3539, 0, ''), +(3584, 13, 4564.75, 344.041, 44.2463, 0, ''), +(3584, 14, 4556.63, 341.003, 47.6755, 0, ''), +(3584, 15, 4554.38, 334.968, 48.8003, 0, ''), +(3584, 16, 4557.63, 329.783, 49.9532, 0, ''), +(3584, 17, 4563.32, 316.829, 53.2409, 0, ''), +(3584, 18, 4566.09, 303.127, 55.0396, 0, ''), +(3584, 19, 4561.65, 295.456, 57.0984, 4000, 'SAY_THERYLUNE_FINISH'), +(3584, 20, 4551.03, 293.333, 57.1534, 2000, ''); + +DELETE FROM script_waypoint WHERE entry=17238; +INSERT INTO script_waypoint VALUES +(17238, 0, 954.21, -1433.72, 63.00, 0, ''), +(17238, 1, 972.70, -1438.85, 65.56, 0, ''), +(17238, 2, 984.79, -1444.15, 64.13, 0, ''), +(17238, 3, 999.00, -1451.74, 61.20, 0, ''), +(17238, 4, 1030.94, -1470.39, 63.49, 25000, 'SAY_FIRST_STOP'), +(17238, 5, 1030.94, -1470.39, 63.49, 3000, 'SAY_CONTINUE'), +(17238, 6, 1036.50, -1484.25, 64.60, 0, ''), +(17238, 7, 1039.11, -1501.22, 65.32, 0, ''), +(17238, 8, 1038.44, -1522.18, 64.55, 0, ''), +(17238, 9, 1037.19, -1543.15, 62.33, 0, ''), +(17238, 10, 1036.79, -1563.88, 61.93, 5000, 'SAY_FIRST_ATTACK'), +(17238, 11, 1036.79, -1563.88, 61.93, 5000, 'SAY_PURITY'), +(17238, 12, 1035.61, -1587.64, 61.66, 0, ''), +(17238, 13, 1035.43, -1612.97, 61.54, 0, ''), +(17238, 14, 1035.36, -1630.66, 61.53, 0, ''), +(17238, 15, 1038.85, -1653.02, 60.35, 0, ''), +(17238, 16, 1042.27, -1669.36, 60.75, 0, ''), +(17238, 17, 1050.41, -1687.22, 60.52, 0, ''), +(17238, 18, 1061.15, -1704.45, 60.59, 0, ''), +(17238, 19, 1073.51, -1716.99, 60.65, 0, ''), +(17238, 20, 1084.20, -1727.24, 60.95, 0, ''), +(17238, 21, 1100.71, -1739.89, 60.64, 5000, 'SAY_SECOND_ATTACK'), +(17238, 22, 1100.71, -1739.89, 60.64, 0, 'SAY_CLEANSE'), +(17238, 23, 1117.03, -1749.01, 60.87, 0, ''), +(17238, 24, 1123.58, -1762.29, 62.40, 0, ''), +(17238, 25, 1123.36, -1769.29, 62.83, 0, ''), +(17238, 26, 1115.78, -1779.59, 62.09, 0, ''), +(17238, 27, 1109.56, -1789.78, 61.03, 0, ''), +(17238, 28, 1094.81, -1797.62, 61.22, 0, ''), +(17238, 29, 1079.30, -1801.58, 64.95, 0, ''), +(17238, 30, 1060.24, -1803.40, 70.36, 0, ''), +(17238, 31, 1047.69, -1804.49, 73.92, 0, ''), +(17238, 32, 1032.59, -1805.99, 76.13, 0, ''), +(17238, 33, 1013.60, -1812.36, 77.32, 0, ''), +(17238, 34, 1007.01, -1814.38, 80.48, 0, ''), +(17238, 35, 999.93, -1816.39, 80.48, 2000, 'SAY_WELCOME'), +(17238, 36, 984.72, -1822.05, 80.48, 0, ''), +(17238, 37, 977.77, -1824.80, 80.79, 0, ''), +(17238, 38, 975.33, -1824.91, 81.24, 12000, 'event complete'), +(17238, 39, 975.33, -1824.91, 81.24, 10000, 'SAY_EPILOGUE_1'), +(17238, 40, 975.33, -1824.91, 81.24, 8000, 'SAY_EPILOGUE_2'), +(17238, 41, 975.33, -1824.91, 81.24, 30000, ''); + +DELETE FROM script_waypoint WHERE entry=2713; +INSERT INTO script_waypoint VALUES +(2713, 0, -1416.91, -3044.12, 36.21, 0, ''), +(2713, 1, -1408.43, -3051.35, 37.79, 0, ''), +(2713, 2, -1399.45, -3069.20, 31.25, 0, ''), +(2713, 3, -1400.28, -3083.14, 27.06, 0, ''), +(2713, 4, -1405.30, -3096.72, 26.36, 0, ''), +(2713, 5, -1406.12, -3105.95, 24.82, 0, ''), +(2713, 6, -1417.41, -3106.80, 16.61, 0, ''), +(2713, 7, -1433.06, -3101.55, 12.56, 0, ''), +(2713, 8, -1439.86, -3086.36, 12.29, 0, ''), +(2713, 9, -1450.48, -3065.16, 12.58, 5000, 'SAY_REACH_BOTTOM'), +(2713, 10, -1456.15, -3055.53, 12.54, 0, ''), +(2713, 11, -1459.41, -3035.16, 12.11, 0, ''), +(2713, 12, -1472.47, -3034.18, 12.44, 0, ''), +(2713, 13, -1495.57, -3034.48, 12.55, 0, ''), +(2713, 14, -1524.91, -3035.47, 13.15, 0, ''), +(2713, 15, -1549.05, -3037.77, 12.98, 0, ''), +(2713, 16, -1555.69, -3028.02, 13.64, 3000, 'SAY_WATCH_BACK'), +(2713, 17, -1555.69, -3028.02, 13.64, 5000, 'SAY_DATA_FOUND'), +(2713, 18, -1555.69, -3028.02, 13.64, 2000, 'SAY_ESCAPE'), +(2713, 19, -1551.19, -3037.78, 12.96, 0, ''), +(2713, 20, -1584.60, -3048.77, 13.67, 0, ''), +(2713, 21, -1602.14, -3042.82, 15.12, 0, ''), +(2713, 22, -1610.68, -3027.42, 17.22, 0, ''), +(2713, 23, -1601.65, -3007.97, 24.65, 0, ''), +(2713, 24, -1581.05, -2992.32, 30.85, 0, ''), +(2713, 25, -1559.95, -2979.51, 34.30, 0, ''), +(2713, 26, -1536.51, -2969.78, 32.64, 0, ''), +(2713, 27, -1511.81, -2961.09, 29.12, 0, ''), +(2713, 28, -1484.83, -2960.87, 32.54, 0, ''), +(2713, 29, -1458.23, -2966.80, 40.52 , 0, ''), +(2713, 30, -1440.20, -2971.20, 43.15, 0, ''), +(2713, 31, -1427.85, -2989.15, 38.09, 0, ''), +(2713, 32, -1420.27, -3008.91, 35.01, 0, ''), +(2713, 33, -1427.58, -3032.53, 32.31, 5000, 'SAY_FINISH'), +(2713, 34, -1427.40, -3035.17, 32.26, 0, ''); + +DELETE FROM script_waypoint WHERE entry=4880; +INSERT INTO script_waypoint VALUES +(4880, 0, -2670.221, -3446.189, 34.085, 0, ''), +(4880, 1, -2683.958, -3451.094, 34.707, 0, ''), +(4880, 2, -2703.241, -3454.822, 33.395, 0, ''), +(4880, 3, -2721.615, -3457.408, 33.626, 0, ''), +(4880, 4, -2739.977, -3459.843, 33.329, 0, ''), +(4880, 5, -2756.240, -3460.516, 32.037, 5000, 'SAY_STINKY_FIRST_STOP'), +(4880, 6, -2764.517, -3472.714, 33.750, 0, ''), +(4880, 7, -2773.679, -3482.913, 32.840, 0, ''), +(4880, 8, -2781.394, -3490.613, 32.598, 0, ''), +(4880, 9, -2788.308, -3492.904, 30.761, 0, ''), +(4880, 10, -2794.578, -3489.185, 31.119, 5000, 'SAY_SECOND_STOP'), +(4880, 11, -2789.427, -3498.043, 31.050, 0, ''), +(4880, 12, -2786.968, -3508.168, 31.983, 0, ''), +(4880, 13, -2786.770, -3519.953, 31.079, 0, ''), +(4880, 14, -2789.359, -3525.025, 31.831, 0, ''), +(4880, 15, -2797.950, -3523.693, 31.697, 0, ''), +(4880, 16, -2812.971, -3519.838, 29.864, 0, ''), +(4880, 17, -2818.331, -3521.396, 30.563, 0, ''), +(4880, 18, -2824.771, -3528.728, 32.399, 0, ''), +(4880, 19, -2830.697, -3539.875, 32.505, 0, ''), +(4880, 20, -2836.235, -3549.962, 31.180, 0, ''), +(4880, 21, -2837.576, -3561.052, 30.740, 0, ''), +(4880, 22, -2834.445, -3568.264, 30.751, 0, ''), +(4880, 23, -2827.351, -3569.807, 31.316, 0, ''), +(4880, 24, -2817.380, -3566.961, 30.947, 5000, 'SAY_THIRD_STOP_1'), +(4880, 25, -2817.380, -3566.961, 30.947, 2000, 'SAY_THIRD_STOP_2'), +(4880, 26, -2817.380, -3566.961, 30.947, 0, 'SAY_THIRD_STOP_3'), +(4880, 27, -2818.815, -3579.415, 28.525, 0, ''), +(4880, 28, -2820.205, -3590.640, 30.269, 0, ''), +(4880, 29, -2820.849, -3593.938, 31.150, 3000, ''), +(4880, 30, -2820.849, -3593.938, 31.150, 3000, 'SAY_PLANT_GATHERED'), +(4880, 31, -2834.209, -3592.041, 33.790, 0, ''), +(4880, 32, -2840.306, -3586.207, 36.288, 0, ''), +(4880, 33, -2847.491, -3576.416, 37.660, 0, ''), +(4880, 34, -2855.718, -3565.184, 39.390, 0, ''), +(4880, 35, -2861.785, -3552.902, 41.243, 0, ''), +(4880, 36, -2869.542, -3545.579, 40.701, 0, ''), +(4880, 37, -2877.784, -3538.372, 37.274, 0, ''), +(4880, 38, -2882.677, -3534.165, 34.844, 0, ''), +(4880, 39, -2888.567, -3534.117, 34.298, 4000, 'SAY_STINKY_END'), +(4880, 40, -2888.567, -3534.117, 34.298, 0, ''); + +DELETE FROM script_waypoint WHERE entry=20281; +INSERT INTO script_waypoint VALUES +(20281, 0, 3096.416, 2801.408, 118.149, 7000, 'SAY_DRIJYA_START'), +(20281, 1, 3096.516, 2801.065, 118.128, 0, 'SAY_DRIJYA_1'), +(20281, 2, 3099.995, 2796.665, 118.118, 0, ''), +(20281, 3, 3098.759, 2786.174, 117.125, 0, ''), +(20281, 4, 3087.792, 2754.602, 115.441, 0, ''), +(20281, 5, 3080.718, 2730.793, 115.930, 9000, 'SAY_DRIJYA_2'), +(20281, 6, 3060.235, 2731.306, 115.122, 0, ''), +(20281, 7, 3050.863, 2727.388, 114.054, 0, ''), +(20281, 8, 3050.863, 2727.388, 114.054, 8000, 'SAY_DRIJYA_4'), +(20281, 9, 3055.008, 2724.972, 113.687, 0, ''), +(20281, 10, 3053.777, 2718.427, 113.684, 0, ''), +(20281, 11, 3028.622, 2693.375, 114.670, 0, ''), +(20281, 12, 3022.430, 2695.297, 113.406, 0, ''), +(20281, 13, 3022.430, 2695.297, 113.406, 8000, 'SAY_DRIJYA_5'), +(20281, 14, 3025.463, 2700.755, 113.514, 0, ''), +(20281, 15, 3011.336, 2716.782, 113.691, 0, ''), +(20281, 16, 3010.882, 2726.991, 114.239, 0, ''), +(20281, 17, 3009.178, 2729.083, 114.324, 0, ''), +(20281, 18, 3009.178, 2729.083, 114.324, 15000, 'SAY_DRIJYA_6'), +(20281, 19, 3009.178, 2729.083, 114.324, 6000, 'SPELL_EXPLOSION_VISUAL'), +(20281, 20, 3009.178, 2729.083, 114.324, 8000, 'SAY_DRIJYA_7'), +(20281, 21, 3033.888, 2736.437, 114.369, 0, ''), +(20281, 22, 3071.492, 2741.502, 116.462, 0, ''), +(20281, 23, 3087.792, 2754.602, 115.441, 0, ''), +(20281, 24, 3094.505, 2770.198, 115.744, 0, ''), +(20281, 25, 3103.510, 2784.362, 116.857, 0, ''), +(20281, 26, 3099.995, 2796.665, 118.118, 0, ''), +(20281, 27, 3096.290, 2801.027, 118.096, 0, 'SAY_DRIJYA_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=8284; +INSERT INTO script_waypoint VALUES +(8284, 0, -7007.209, -1749.160, 234.182, 3000, 'stand up'), +(8284, 1, -7007.324, -1729.849, 234.162, 0, ''), +(8284, 2, -7006.394, -1726.522, 234.099, 0, ''), +(8284, 3, -7003.256, -1726.903, 234.594, 0, ''), +(8284, 4, -6994.778, -1733.571, 238.281, 0, ''), +(8284, 5, -6987.904, -1735.935, 240.727, 0, ''), +(8284, 6, -6978.704, -1736.991, 241.809, 0, ''), +(8284, 7, -6964.261, -1740.251, 241.713, 0, ''), +(8284, 8, -6946.701, -1746.284, 241.667, 0, ''), +(8284, 9, -6938.751, -1749.381, 240.744, 0, ''), +(8284, 10, -6927.004, -1768.782, 240.744, 0, ''), +(8284, 11, -6909.453, -1791.258, 240.744, 0, ''), +(8284, 12, -6898.225, -1804.870, 240.744, 0, ''), +(8284, 13, -6881.280, -1821.788, 240.744, 0, ''), +(8284, 14, -6867.653, -1832.672, 240.706, 0, ''), +(8284, 15, -6850.184, -1839.254, 243.006, 0, ''), +(8284, 16, -6829.381, -1847.635, 244.190, 0, ''), +(8284, 17, -6804.618, -1857.535, 244.209, 0, ''), +(8284, 18, -6776.421, -1868.879, 244.142, 0, ''), +(8284, 19, -6753.471, -1876.906, 244.170, 10000, 'stop'), +(8284, 20, -6753.471, -1876.906, 244.170, 0, 'ambush'), +(8284, 21, -6731.033, -1884.944, 244.144, 0, ''), +(8284, 22, -6705.738, -1896.779, 244.144, 0, ''), +(8284, 23, -6678.956, -1909.607, 244.369, 0, ''), +(8284, 24, -6654.263, -1916.758, 244.145, 0, ''), +(8284, 25, -6620.604, -1917.608, 244.149, 0, ''), +(8284, 26, -6575.958, -1922.408, 244.149, 0, ''), +(8284, 27, -6554.811, -1929.883, 244.162, 0, ''), +(8284, 28, -6521.856, -1947.322, 244.151, 0, ''), +(8284, 29, -6493.320, -1962.654, 244.151, 0, ''), +(8284, 30, -6463.350, -1975.537, 244.213, 0, ''), +(8284, 31, -6435.428, -1983.847, 244.548, 0, ''), +(8284, 32, -6418.380, -1985.778, 246.554, 0, ''), +(8284, 33, -6389.783, -1986.544, 246.771, 30000, 'quest complete'); + +DELETE FROM script_waypoint WHERE entry=17877; +INSERT INTO script_waypoint VALUES +(17877, 0, 231.403, 8479.940, 17.928, 3000, ''), +(17877, 1, 214.645, 8469.645, 23.121, 0, ''), +(17877, 2, 208.538, 8463.481, 24.738, 0, ''), +(17877, 3, 196.524, 8446.077, 24.814, 0, ''), +(17877, 4, 188.186, 8431.674, 22.625, 0, ''), +(17877, 5, 181.196, 8420.152, 23.730, 0, ''), +(17877, 6, 171.919, 8406.290, 21.844, 0, ''), +(17877, 7, 166.613, 8396.479, 23.585, 0, ''), +(17877, 8, 167.237, 8386.686, 21.546, 0, ''), +(17877, 9, 169.401, 8372.670, 19.599, 0, ''), +(17877, 10, 174.148, 8342.325, 20.409, 0, ''), +(17877, 11, 173.195, 8324.177, 21.126, 0, ''), +(17877, 12, 172.415, 8310.290, 21.702, 0, ''), +(17877, 13, 173.233, 8298.755, 19.564, 0, ''), +(17877, 14, 173.984, 8287.925, 18.839, 0, ''), +(17877, 15, 189.984, 8266.263, 18.500, 0, ''), +(17877, 16, 204.057, 8256.019, 19.701, 0, ''), +(17877, 17, 212.950, 8248.737, 21.583, 0, ''), +(17877, 18, 223.152, 8240.160, 20.001, 0, ''), +(17877, 19, 230.730, 8232.994, 18.990, 0, ''), +(17877, 20, 238.261, 8223.804, 20.720, 0, ''), +(17877, 21, 247.651, 8214.208, 19.146, 0, ''), +(17877, 22, 259.231, 8207.796, 19.278, 0, ''), +(17877, 23, 272.360, 8204.755, 19.980, 0, ''), +(17877, 24, 282.211, 8202.087, 22.090, 20000, 'SAY_PREPARE'), +(17877, 25, 282.211, 8202.087, 22.090, 0, 'SAY_CAMP_ENTER'), +(17877, 26, 296.006, 8191.644, 21.680, 0, ''), +(17877, 27, 304.472, 8188.048, 20.707, 0, ''), +(17877, 28, 317.574, 8182.044, 18.296, 0, ''), +(17877, 29, 340.046, 8178.776, 17.937, 0, ''), +(17877, 30, 353.799, 8181.222, 18.557, 0, ''), +(17877, 31, 368.231, 8186.324, 22.450, 0, ''), +(17877, 32, 375.737, 8187.030, 23.916, 0, ''), +(17877, 33, 390.067, 8186.638, 21.190, 0, ''), +(17877, 34, 398.699, 8181.824, 18.648, 0, ''), +(17877, 35, 412.325, 8172.612, 17.927, 0, ''), +(17877, 36, 424.541, 8161.957, 19.575, 0, ''), +(17877, 37, 436.900, 8157.407, 22.115, 0, ''), +(17877, 38, 444.548, 8155.414, 23.553, 0, ''), +(17877, 39, 457.201, 8154.233, 23.429, 0, ''), +(17877, 40, 470.989, 8154.142, 21.650, 0, ''), +(17877, 41, 483.435, 8154.151, 20.706, 0, ''), +(17877, 42, 507.558, 8157.515, 21.729, 0, ''), +(17877, 43, 528.036, 8162.028, 22.795, 0, ''), +(17877, 44, 542.402, 8161.099, 22.914, 0, ''), +(17877, 45, 557.286, 8160.273, 23.708, 13000, ''), +(17877, 46, 557.286, 8160.273, 23.708, 0, 'take the Ark'), +(17877, 47, 539.767, 8144.839, 22.217, 0, ''), +(17877, 48, 531.296, 8139.475, 22.146, 0, ''), +(17877, 49, 509.056, 8139.262, 20.705, 0, ''), +(17877, 50, 499.975, 8136.228, 20.408, 0, ''), +(17877, 51, 485.511, 8129.389, 22.010, 0, ''), +(17877, 52, 474.371, 8128.534, 22.657, 0, ''), +(17877, 53, 460.708, 8130.115, 20.946, 0, ''), +(17877, 54, 449.248, 8129.271, 21.033, 0, ''), +(17877, 55, 433.670, 8125.064, 18.440, 0, ''), +(17877, 56, 412.822, 8121.581, 17.603, 0, ''), +(17877, 57, 391.150, 8117.812, 17.736, 0, ''), +(17877, 58, 379.024, 8114.185, 17.889, 0, ''), +(17877, 59, 365.110, 8106.992, 18.220, 0, ''), +(17877, 60, 352.531, 8108.944, 17.932, 0, ''), +(17877, 61, 340.894, 8120.636, 17.374, 0, ''), +(17877, 62, 328.480, 8134.929, 18.112, 0, ''), +(17877, 63, 317.573, 8143.246, 20.604, 0, ''), +(17877, 64, 311.146, 8146.796, 21.097, 0, ''), +(17877, 65, 299.359, 8152.583, 18.676, 0, ''), +(17877, 66, 276.115, 8160.440, 17.735, 0, ''), +(17877, 67, 262.704, 8170.509, 17.478, 0, ''), +(17877, 68, 243.755, 8177.747, 17.744, 0, ''), +(17877, 69, 233.496, 8178.426, 17.528, 0, ''), +(17877, 70, 219.874, 8182.550, 19.637, 0, 'SAY_AMBUSH - escort paused'), +(17877, 71, 219.874, 8182.550, 19.637, 20000, 'SAY_AMBUSH_CLEARED'), +(17877, 72, 210.978, 8193.978, 20.777, 0, ''), +(17877, 73, 203.699, 8213.042, 22.768, 0, ''), +(17877, 74, 199.246, 8225.537, 24.847, 0, ''), +(17877, 75, 195.064, 8239.906, 22.640, 0, ''), +(17877, 76, 193.198, 8253.617, 20.083, 0, ''), +(17877, 77, 189.151, 8264.834, 18.714, 0, ''), +(17877, 78, 178.814, 8281.036, 19.070, 0, ''), +(17877, 79, 173.952, 8293.241, 18.533, 0, ''), +(17877, 80, 174.399, 8305.458, 21.006, 0, ''), +(17877, 81, 175.124, 8319.509, 21.626, 0, ''), +(17877, 82, 175.690, 8339.654, 20.375, 0, ''), +(17877, 83, 172.754, 8362.673, 19.181, 0, ''), +(17877, 84, 176.465, 8379.798, 18.445, 0, ''), +(17877, 85, 186.433, 8393.126, 18.933, 0, ''), +(17877, 86, 199.438, 8407.825, 18.763, 0, ''), +(17877, 87, 211.874, 8422.383, 18.785, 0, ''), +(17877, 88, 219.900, 8436.264, 21.927, 0, ''), +(17877, 89, 225.062, 8450.565, 22.832, 0, ''), +(17877, 90, 226.942, 8464.410, 19.822, 0, ''), +(17877, 91, 231.403, 8479.940, 17.928, 0, ''), +(17877, 92, 247.625, 8483.801, 22.464, 13000, ''), +(17877, 93, 231.403, 8479.940, 17.928, 10000, 'SAY_ESCORT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=23383; +INSERT INTO script_waypoint VALUES +(23383, 0, -4109.424, 3034.155, 344.168, 5000, 'SAY_ESCORT_START'), +(23383, 1, -4113.265, 3035.989, 344.071, 0, ''), +(23383, 2, -4120.018, 3032.223, 344.074, 0, ''), +(23383, 3, -4124.412, 3026.332, 344.151, 0, ''), +(23383, 4, -4128.823, 3026.645, 344.035, 0, ''), +(23383, 5, -4138.909, 3028.952, 338.920, 0, ''), +(23383, 6, -4152.592, 3031.234, 336.913, 0, ''), +(23383, 7, -4169.812, 3034.305, 342.047, 0, ''), +(23383, 8, -4174.631, 3036.044, 343.457, 0, ''), +(23383, 9, -4174.399, 3044.983, 343.862, 0, ''), +(23383, 10, -4176.635, 3052.014, 344.077, 0, ''), +(23383, 11, -4183.662, 3058.895, 344.150, 0, ''), +(23383, 12, -4182.916, 3065.411, 342.574, 0, ''), +(23383, 13, -4182.055, 3070.558, 337.644, 5000, 'ambush'), +(23383, 14, -4182.055, 3070.558, 337.644, 5000, 'SAY_AMBUSH_END'), +(23383, 15, -4181.256, 3077.131, 331.590, 0, ''), +(23383, 16, -4179.994, 3086.101, 325.571, 0, ''), +(23383, 17, -4178.770, 3090.101, 323.955, 0, ''), +(23383, 18, -4177.965, 3093.867, 323.839, 5000, 'SAY_ESCORT_COMPLETE'), +(23383, 19, -4166.252, 3106.508, 320.961, 0, ''); + +DELETE FROM script_waypoint WHERE entry=25589; +INSERT INTO script_waypoint VALUES +(25589, 0, 4414.220, 5367.299, -15.494, 13000, 'SAY_BONKER_START'), +(25589, 1, 4414.220, 5367.299, -15.494, 0, 'SAY_BONKER_GO'), +(25589, 2, 4429.033, 5366.662, -17.198, 0, ''), +(25589, 3, 4454.772, 5371.562, -16.385, 10000, 'SAY_BONKER_LEFT'), +(25589, 4, 4467.889, 5372.425, -15.236, 0, ''), +(25589, 5, 4481.388, 5378.616, -14.997, 0, ''), +(25589, 6, 4484.985, 5392.241, -15.310, 0, ''), +(25589, 7, 4473.114, 5414.899, -15.272, 0, ''), +(25589, 8, 4461.070, 5427.644, -16.163, 0, ''), +(25589, 9, 4441.339, 5435.530, -15.367, 0, ''), +(25589, 10, 4427.119, 5436.604, -15.149 , 0, ''), +(25589, 11, 4408.939, 5428.320, -14.629, 0, ''), +(25589, 12, 4396.607, 5415.876, -13.552, 0, ''), +(25589, 13, 4392.921, 5405.893, -10.506, 0, ''), +(25589, 14, 4390.492, 5390.298, -5.628, 0, ''), +(25589, 15, 4393.429, 5358.273, 2.967, 0, ''), +(25589, 16, 4400.138, 5345.599, 4.656, 0, ''), +(25589, 17, 4412.080, 5336.678, 7.272, 0, ''), +(25589, 18, 4436.494, 5335.233, 12.415, 0, ''), +(25589, 19, 4454.602, 5341.273, 15.560, 0, ''), +(25589, 20, 4471.045, 5352.314, 18.686, 0, ''), +(25589, 21, 4478.235, 5367.257, 20.225, 0, ''), +(25589, 22, 4481.352, 5387.544, 24.537, 0, ''), +(25589, 23, 4483.067, 5405.131, 27.576, 0, ''), +(25589, 24, 4475.878, 5414.829, 29.965, 0, ''), +(25589, 25, 4466.598, 5423.731, 32.224, 0, ''), +(25589, 26, 4451.211, 5431.026, 36.189, 0, ''), +(25589, 27, 4428.056, 5434.374, 38.946, 0, ''), +(25589, 28, 4398.915, 5443.864, 44.214, 0, ''), +(25589, 29, 4386.822, 5451.893, 48.935, 0, ''), +(25589, 30, 4379.861, 5457.215, 51.371, 0, ''), +(25589, 31, 4372.712, 5461.347, 48.541, 0, ''), +(25589, 32, 4364.523, 5465.798, 48.661, 10000, 'SAY_BONKER_COMPLETE'), +(25589, 33, 4337.198, 5472.948, 46.035, 0, ''); + +DELETE FROM script_waypoint WHERE entry=31737; +INSERT INTO script_waypoint VALUES +(31737, 0, 7269.769, 1509.434, 320.903, 0, ''), +(31737, 1, 7258.117, 1526.602, 324.304, 0, ''), +(31737, 2, 7260.972, 1549.837, 335.689, 1000, 'SAY_ALLIANCE_RUN'), +(31737, 3, 7264.854, 1564.689, 341.974, 0, ''), +(31737, 4, 7255.504, 1579.524, 351.389, 0, ''), +(31737, 5, 7246.569, 1583.333, 358.133, 0, ''), +(31737, 6, 7232.839, 1581.032, 367.501, 0, 'first attack'), +(31737, 7, 7223.732, 1580.088, 373.346, 0, ''), +(31737, 8, 7218.684, 1586.349, 377.490, 0, ''), +(31737, 9, 7217.367, 1593.943, 379.455, 0, ''), +(31737, 10, 7225.456, 1598.870, 379.647, 0, ''), +(31737, 11, 7237.810, 1601.123, 381.088, 0, ''), +(31737, 12, 7251.413, 1609.023, 383.766, 0, ''), +(31737, 13, 7265.517, 1611.843, 382.620, 0, ''), +(31737, 14, 7277.738, 1609.804, 383.899, 0, ''), +(31737, 15, 7290.876, 1608.956, 390.451, 0, 'second attack'), +(31737, 16, 7310.857, 1615.485, 400.580, 0, ''), +(31737, 17, 7327.588, 1622.280, 411.449, 0, ''), +(31737, 18, 7343.151, 1629.884, 423.033, 0, ''), +(31737, 19, 7347.384, 1636.286, 428.066, 0, ''), +(31737, 20, 7343.727, 1644.666, 430.427, 8000, 'SAY_ALLIANCE_BREAK'), +(31737, 21, 7343.727, 1644.666, 430.427, 1000, 'SAY_ALLIANCE_BREAK_DONE'), +(31737, 22, 7301.614, 1649.022, 434.578, 0, ''), +(31737, 23, 7291.128, 1653.633, 435.176, 0, ''), +(31737, 24, 7278.780, 1657.080, 434.619, 0, ''), +(31737, 25, 7259.066, 1651.533, 433.942, 0, 'gate attack'), +(31737, 26, 7243.214, 1662.610, 438.890, 0, ''), +(31737, 27, 7211.633, 1684.327, 462.316, 0, 'SAY_EVENT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=31833; +INSERT INTO script_waypoint VALUES +(31833, 0, 7504.983, 1806.833, 355.928, 0, ''), +(31833, 1, 7500.186, 1817.217, 355.494, 0, ''), +(31833, 2, 7492.701, 1828.367, 361.420, 1000, 'SAY_HORDER_RUN'), +(31833, 3, 7481.528, 1836.774, 370.704, 0, ''), +(31833, 4, 7463.597, 1840.573, 383.662, 0, 'first attack'), +(31833, 5, 7449.448, 1839.822, 394.694, 0, ''), +(31833, 6, 7432.161, 1847.350, 406.290, 0, ''), +(31833, 7, 7415.067, 1845.623, 419.790, 0, ''), +(31833, 8, 7409.832, 1839.991, 423.997, 0, ''), +(31833, 9, 7403.585, 1822.599, 428.435, 0, 'second attack'), +(31833, 10, 7398.860, 1810.257, 430.373, 0, ''), +(31833, 11, 7396.572, 1789.399, 432.286, 0, ''), +(31833, 12, 7397.816, 1769.238, 432.947, 0, ''), +(31833, 13, 7399.105, 1745.266, 433.108, 8000, 'SAY_HORDE_BREAK'), +(31833, 14, 7399.105, 1745.266, 433.108, 1000, 'SAY_HORDE_BREAK_DONE'), +(31833, 15, 7393.293, 1729.907, 435.058, 0, ''), +(31833, 16, 7385.299, 1720.183, 437.602, 0, ''), +(31833, 17, 7370.189, 1715.580, 442.425, 0, ''), +(31833, 18, 7358.270, 1719.352, 446.378, 0, ''), +(31833, 19, 7348.808, 1723.011, 449.727, 0, ''), +(31833, 20, 7333.273, 1724.842, 453.621, 0, ''), +(31833, 21, 7325.701, 1725.662, 456.896, 0, ''), +(31833, 22, 7319.808, 1725.676, 459.731, 0, 'gate attack'), +(31833, 23, 7308.107, 1726.708, 465.138, 0, ''), +(31833, 24, 7297.754, 1727.792, 467.980, 0, ''), +(31833, 25, 7288.278, 1726.889, 469.816, 0, ''), +(31833, 26, 7278.187, 1722.632, 472.149, 0, ''), +(31833, 27, 7253.084, 1729.579, 474.225, 0, 'SAY_EVENT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=31279; +INSERT INTO script_waypoint VALUES +(31279, 0, 6717.810, 3451.979, 683.747, 5000, 'SAY_ESCORT_START_1'), +(31279, 1, 6717.810, 3451.979, 683.747, 2000, 'SAY_ESCORT_START_2'), +(31279, 2, 6718.854, 3436.952, 682.197, 0, ''), +(31279, 3, 6725.714, 3432.644, 682.197, 0, ''), +(31279, 4, 6733.117, 3435.033, 682.136, 0, ''), +(31279, 5, 6744.931, 3445.788, 679.032, 0, ''), +(31279, 6, 6760.190, 3459.459, 674.487, 0, ''), +(31279, 7, 6773.156, 3469.683, 673.155, 0, ''), +(31279, 8, 6783.855, 3480.482, 674.481, 0, ''), +(31279, 9, 6790.618, 3484.064, 676.671, 0, ''), +(31279, 10, 6805.924, 3483.840, 682.128, 0, ''), +(31279, 11, 6818.427, 3483.294, 686.889, 0, ''), +(31279, 12, 6832.831, 3480.982, 690.189, 0, ''), +(31279, 13, 6854.910, 3479.888, 693.181, 0, ''), +(31279, 14, 6873.589, 3478.932, 694.618, 0, ''), +(31279, 15, 6895.129, 3478.388, 698.266, 0, ''), +(31279, 16, 6916.835, 3478.487, 702.575, 0, ''), +(31279, 17, 6937.283, 3477.337, 707.257, 0, ''), +(31279, 18, 6959.092, 3472.777, 710.180, 0, ''), +(31279, 19, 6969.530, 3470.091, 710.401, 0, ''), +(31279, 20, 6980.068, 3466.872, 710.831, 0, ''), +(31279, 21, 7008.199, 3457.296, 696.672, 0, ''), +(31279, 22, 7020.182, 3452.484, 696.518, 0, ''), +(31279, 23, 7031.362, 3445.230, 696.108, 3000, 'SAY_KAMAROS_COMPLETE_1'), +(31279, 24, 7031.362, 3445.230, 696.108, 7000, 'SAY_KAMAROS_COMPLETE_2'), +(31279, 25, 7067.656, 3420.741, 694.879, 0, ''); + +DELETE FROM script_waypoint WHERE entry=32800; +INSERT INTO script_waypoint VALUES +(32800, 0, 6736.090, 3422.160, 683.457, 5000, 'SAY_ESCORT_START_1'), +(32800, 1, 6736.090, 3422.160, 683.457, 2000, 'SAY_ESCORT_START_2'), +(32800, 2, 6734.518, 3425.644, 682.517, 0, ''), +(32800, 3, 6733.167, 3430.796, 682.156, 0, ''), +(32800, 4, 6733.117, 3435.033, 682.136, 0, ''), +(32800, 5, 6744.931, 3445.788, 679.032, 0, ''), +(32800, 6, 6760.190, 3459.459, 674.487, 0, ''), +(32800, 7, 6773.156, 3469.683, 673.155, 0, ''), +(32800, 8, 6783.855, 3480.482, 674.481, 0, ''), +(32800, 9, 6790.618, 3484.064, 676.671, 0, ''), +(32800, 10, 6805.924, 3483.840, 682.128, 0, ''), +(32800, 11, 6818.427, 3483.294, 686.889, 0, ''), +(32800, 12, 6832.831, 3480.982, 690.189, 0, ''), +(32800, 13, 6854.910, 3479.888, 693.181, 0, ''), +(32800, 14, 6873.589, 3478.932, 694.618, 0, ''), +(32800, 15, 6895.129, 3478.388, 698.266, 0, ''), +(32800, 16, 6916.835, 3478.487, 702.575, 0, ''), +(32800, 17, 6937.283, 3477.337, 707.257, 0, ''), +(32800, 18, 6959.092, 3472.777, 710.180, 0, ''), +(32800, 19, 6969.530, 3470.091, 710.401, 0, ''), +(32800, 20, 6980.068, 3466.872, 710.831, 0, ''), +(32800, 21, 7008.199, 3457.296, 696.672, 0, ''), +(32800, 22, 7020.182, 3452.484, 696.518, 0, ''), +(32800, 23, 7031.362, 3445.230, 696.108, 3000, 'SAY_KAMAROS_COMPLETE_1'), +(32800, 24, 7031.362, 3445.230, 696.108, 7000, 'SAY_KAMAROS_COMPLETE_2'), +(32800, 25, 7067.656, 3420.741, 694.879, 0, ''); + +DELETE FROM script_waypoint WHERE entry=29434; +INSERT INTO script_waypoint VALUES +(29434, 0, 6643.662, -1258.140, 396.812, 0, 'SAY_ESCORT_READY'), +(29434, 1, 6669.843, -1261.131, 396.362, 0, ''), +(29434, 2, 6672.479, -1244.102, 396.644, 0, ''), +(29434, 3, 6665.353, -1229.893, 399.214, 0, ''), +(29434, 4, 6656.884, -1210.856, 399.819, 0, ''), +(29434, 5, 6658.687, -1187.532, 398.761, 0, ''), +(29434, 6, 6664.340, -1166.372, 398.633, 0, ''), +(29434, 7, 6667.770, -1157.029, 398.136, 0, ''), +(29434, 8, 6670.005, -1145.671, 398.019, 0, ''), +(29434, 9, 6678.494, -1120.105, 397.160, 0, ''), +(29434, 10, 6685.051, -1100.975, 396.287, 0, ''), +(29434, 11, 6682.745, -1087.736, 396.795, 0, ''), +(29434, 12, 6679.602, -1073.343, 404.633, 0, ''), +(29434, 13, 6680.316, -1066.258, 405.499, 0, ''), +(29434, 14, 6689.714, -1053.830, 407.333, 0, ''), +(29434, 15, 6696.244, -1043.514, 411.230, 0, ''), +(29434, 16, 6695.093, -1032.211, 414.625, 0, ''), +(29434, 17, 6690.720, -1016.449, 414.825, 0, ''), +(29434, 18, 6679.976, -1009.805, 414.836, 0, ''), +(29434, 19, 6664.816, -1009.983, 414.840, 0, ''), +(29434, 20, 6647.982, -1010.354, 418.831, 0, ''), +(29434, 21, 6635.366, -1010.637, 423.007, 0, ''), +(29434, 22, 6615.762, -1001.898, 426.584, 0, ''), +(29434, 23, 6597.334, -1002.802, 429.766, 0, ''), +(29434, 24, 6581.178, -1009.971, 433.705, 0, ''), +(29434, 25, 6562.826, -1016.122, 433.558, 0, ''), +(29434, 26, 6535.386, -1024.189, 433.084, 0, ''), +(29434, 27, 6520.094, -1030.279, 433.506, 0, ''), +(29434, 28, 6505.704, -1028.766, 436.897, 0, ''), +(29434, 29, 6496.504, -1027.350, 437.309, 0, ''), +(29434, 30, 6489.653, -1026.457, 434.885, 0, ''), +(29434, 31, 6474.284, -1024.466, 434.650, 0, ''), +(29434, 32, 6456.688, -1022.172, 432.239, 0, ''), +(29434, 33, 6449.764, -1021.355, 431.501, 6000, 'SAY_ESCORT_COMPLETE'), +(29434, 34, 6418.638, -1018.385, 427.910, 0, 'despawn'), +(29434, 35, 6639.769, -1109.591, 427.193, 0, ''), +(29434, 36, 6641.524, -1104.348, 426.970, 0, ''), +(29434, 37, 6659.703, -1106.495, 423.005, 0, ''), +(29434, 38, 6670.649, -1118.345, 424.474, 0, ''), +(29434, 39, 6666.202, -1130.105, 423.113, 0, ''), +(29434, 40, 6642.683, -1129.107, 416.779, 0, ''), +(29434, 41, 6628.478, -1127.415, 414.923, 0, ''), +(29434, 42, 6619.763, -1113.337, 412.185, 0, ''), +(29434, 43, 6622.960, -1101.692, 409.846, 0, ''), +(29434, 44, 6640.454, -1088.525, 403.227, 0, ''), +(29434, 45, 6659.586, -1073.823, 402.945, 0, ''), +(29434, 46, 6671.060, -1064.829, 405.381, 0, 'continue at wp 13'); + +DELETE FROM script_waypoint WHERE entry=26814; +INSERT INTO script_waypoint VALUES +(26814, 0, 4905.259, -4758.709, 27.316, 2000, 'open cage - SAY_ESCORT_START'), +(26814, 1, 4895.403, -4754.880, 27.233, 0, ''), +(26814, 2, 4887.629, -4761.870, 27.233, 0, ''), +(26814, 3, 4881.628, -4768.923, 32.142, 0, ''), +(26814, 4, 4878.448, -4772.853, 32.646, 0, ''), +(26814, 5, 4876.892, -4787.923, 32.531, 0, ''), +(26814, 6, 4877.230, -4792.542, 32.532, 0, ''), +(26814, 7, 4878.416, -4793.893, 32.549, 5000, 'SAY_CHAMBER_1'), +(26814, 8, 4878.416, -4793.893, 32.549, 5000, 'SAY_CHAMBER_2'), +(26814, 9, 4883.791, -4796.650, 32.575, 0, ''), +(26814, 10, 4908.433, -4797.975, 32.514, 4000, 'open cage'), +(26814, 11, 4908.433, -4797.975, 32.514, 3000, 'SAY_CHAMBER_RELEASE'), +(26814, 12, 4908.433, -4797.975, 32.514, 2000, 'SAY_THANK_YOU'), +(26814, 13, 4908.678, -4806.945, 32.283, 0, ''), +(26814, 14, 4911.196, -4817.785, 32.491, 0, ''), +(26814, 15, 4914.571, -4823.823, 32.666, 3000, ''), +(26814, 16, 4914.571, -4823.823, 32.666, 7000, 'bang gong'), +(26814, 17, 4908.558, -4820.374, 32.550, 5000, 'SAY_CHAMBER_3'), +(26814, 18, 4908.558, -4820.374, 32.550, 0, 'SAY_CHAMBER_4'), +(26814, 19, 4899.099, -4816.810, 32.029, 0, ''), +(26814, 20, 4891.287, -4813.185, 32.029, 0, ''), +(26814, 21, 4886.007, -4803.263, 32.029, 0, 'close door'), +(26814, 22, 4883.618, -4799.119, 32.556, 1000, 'SAY_CHAMBER_5 - set run'), +(26814, 23, 4900.580, -4806.635, 32.029, 7000, 'SAY_CHAMBER_6'), +(26814, 24, 4900.580, -4806.635, 32.029, 6000, 'SAY_CHAMBER_7'), +(26814, 25, 4900.580, -4806.635, 32.029, 0, 'snake attack'), +(26814, 26, 4886.463, -4799.330, 32.552, 0, ''), +(26814, 27, 4862.184, -4782.641, 32.605, 0, ''), +(26814, 28, 4843.930, -4771.764, 32.602, 0, ''), +(26814, 29, 4831.872, -4775.357, 32.581, 0, ''), +(26814, 30, 4819.254, -4788.892, 25.473, 0, ''), +(26814, 31, 4814.696, -4798.355, 25.483, 0, ''), +(26814, 32, 4824.520, -4822.539, 25.492, 0, ''), +(26814, 33, 4826.834, -4838.310, 25.511, 0, ''), +(26814, 34, 4822.480, -4846.951, 25.473, 0, ''), +(26814, 35, 4812.121, -4852.343, 25.622, 0, ''), +(26814, 36, 4779.916, -4848.937, 25.442, 0, ''), +(26814, 37, 4770.701, -4848.962, 25.428, 0, ''), +(26814, 38, 4758.476, -4857.186, 25.848, 0, ''), +(26814, 39, 4737.023, -4857.752, 26.292, 0, ''), +(26814, 40, 4722.875, -4857.749, 26.495, 0, ''), +(26814, 41, 4715.862, -4857.869, 24.707, 0, ''), +(26814, 42, 4705.447, -4858.532, 28.910, 0, ''), +(26814, 43, 4691.578, -4858.917, 33.103, 0, ''), +(26814, 44, 4681.879, -4860.041, 35.440, 0, ''), +(26814, 45, 4670.293, -4861.545, 35.480, 0, ''), +(26814, 46, 4667.317, -4878.836, 35.480, 0, ''), +(26814, 47, 4661.148, -4895.541, 35.499, 0, ''), +(26814, 48, 4656.874, -4907.395, 38.980, 0, ''), +(26814, 49, 4656.184, -4916.478, 44.398, 0, ''), +(26814, 50, 4656.566, -4927.874, 47.576, 0, ''), +(26814, 51, 4660.753, -4938.885, 47.992, 0, ''), +(26814, 52, 4667.464, -4954.763, 47.993, 0, ''), +(26814, 53, 4673.411, -4967.304, 47.791, 3000, 'SAY_ESCORT_COMPLETE'), +(26814, 54, 4694.427, -4979.960, 44.715, 0, ''); + +DELETE FROM script_waypoint WHERE entry=23784; +INSERT INTO script_waypoint VALUES +(23784, 0, 1377.875, -6421.482, 1.323, 0, 'SAY_ESCORT_START'), +(23784, 1, 1377.523, -6415.196, 1.515, 0, ''), +(23784, 2, 1379.988, -6401.920, 2.428, 8000, 'SAY_FIRE_1'), +(23784, 3, 1379.988, -6401.920, 2.428, 5000, 'SAY_FIRE_2'), +(23784, 4, 1379.749, -6398.577, 2.829, 0, ''), +(23784, 5, 1383.767, -6392.131, 3.639, 0, ''), +(23784, 6, 1395.301, -6381.135, 4.711, 0, ''), +(23784, 7, 1407.236, -6372.452, 6.434, 0, ''), +(23784, 8, 1421.052, -6363.196, 6.430, 0, ''), +(23784, 9, 1424.191, -6358.807, 6.443, 0, ''), +(23784, 10, 1422.745, -6350.552, 6.138, 0, ''), +(23784, 11, 1419.152, -6342.663, 5.811, 0, ''), +(23784, 12, 1414.308, -6336.418, 5.865, 0, ''), +(23784, 13, 1405.468, -6336.249, 6.210, 0, ''), +(23784, 14, 1400.868, -6340.454, 6.415, 4000, 'set fire'), +(23784, 15, 1400.868, -6340.454, 6.415, 15000, 'SAY_SUPPLIES_1'), +(23784, 16, 1406.004, -6335.554, 6.190, 0, ''), +(23784, 17, 1421.080, -6337.905, 5.517, 0, ''), +(23784, 18, 1436.049, -6341.191, 6.772, 0, ''), +(23784, 19, 1449.407, -6344.460, 8.267, 0, ''), +(23784, 20, 1465.833, -6345.101, 7.695, 2000, 'set fire'), +(23784, 21, 1470.890, -6347.974, 7.576, 3000, 'set fire'), +(23784, 22, 1470.890, -6347.974, 7.576, 4000, 'SAY_SUPPLIES_2'), +(23784, 23, 1464.277, -6345.285, 7.896, 0, ''), +(23784, 24, 1463.023, -6339.777, 7.718, 0, ''), +(23784, 25, 1465.487, -6335.771, 7.332, 0, ''), +(23784, 26, 1479.166, -6325.064, 7.440, 0, ''), +(23784, 27, 1489.401, -6315.133, 8.296, 0, ''), +(23784, 28, 1502.828, -6311.045, 6.770, 0, ''), +(23784, 29, 1506.398, -6317.246, 7.299, 4000, 'set fire'), +(23784, 30, 1506.398, -6317.246, 7.299, 2000, 'laugh'), +(23784, 31, 1506.398, -6317.246, 7.299, 10000, 'SAY_SUPPLIES_COMPLETE'), +(23784, 32, 1506.398, -6317.246, 7.299, 5000, 'SAY_SUPPLIES_ESCAPE'), +(23784, 33, 1511.000, -6295.903, 6.193, 0, ''), +(23784, 34, 1517.061, -6275.862, 5.202, 0, ''), +(23784, 35, 1523.781, -6258.195, 4.561, 0, ''), +(23784, 36, 1529.622, -6244.452, 5.823, 0, ''), +(23784, 37, 1537.658, -6224.802, 6.349, 0, ''), +(23784, 38, 1545.301, -6214.430, 6.917, 0, ''), +(23784, 39, 1556.078, -6203.805, 6.566, 0, ''), +(23784, 40, 1567.203, -6194.417, 7.262, 0, 'SAY_ARRIVE_BASE'), +(23784, 41, 1582.464, -6183.626, 7.145, 0, ''), +(23784, 42, 1593.279, -6173.173, 7.319, 0, ''), +(23784, 43, 1604.470, -6164.387, 8.379, 0, ''), +(23784, 44, 1617.776, -6157.249, 9.323, 2000, 'quest complete'), +(23784, 45, 1644.696, -6149.582, 7.357, 0, ''); + +DELETE FROM script_waypoint WHERE entry=1842; +INSERT INTO script_waypoint VALUES +(1842, 0, 2941.748, -1391.816, 167.237, 0, 'SAY_ESCORT_START'), +(1842, 1, 2940.561, -1393.641, 165.943, 0, ''), +(1842, 2, 2932.194, -1410.657, 165.943, 0, ''), +(1842, 3, 2921.808, -1405.087, 165.943, 0, ''), +(1842, 4, 2916.479, -1402.582, 165.943, 0, ''), +(1842, 5, 2918.523, -1398.121, 165.943, 0, ''), +(1842, 6, 2922.801, -1389.494, 160.842, 0, ''), +(1842, 7, 2924.931, -1385.645, 160.842, 0, ''), +(1842, 8, 2930.931, -1388.654, 160.842, 0, ''), +(1842, 9, 2946.701, -1396.646, 160.842, 0, ''), +(1842, 10, 2948.721, -1392.789, 160.842, 0, ''), +(1842, 11, 2951.979, -1386.616, 155.948, 0, ''), +(1842, 12, 2953.836, -1383.326, 155.948, 0, ''), +(1842, 13, 2951.192, -1381.740, 155.948, 0, ''), +(1842, 14, 2946.675, -1379.287, 152.020, 0, ''), +(1842, 15, 2942.795, -1377.661, 152.020, 0, ''), +(1842, 16, 2935.488, -1392.522, 152.020, 0, ''), +(1842, 17, 2921.167, -1384.796, 152.020, 0, ''), +(1842, 18, 2915.331, -1395.354, 152.020, 0, ''), +(1842, 19, 2926.250, -1401.263, 152.028, 0, ''), +(1842, 20, 2930.321, -1403.479, 150.521, 0, ''), +(1842, 21, 2933.936, -1405.357, 150.521, 0, ''), +(1842, 22, 2929.221, -1415.786, 150.504, 0, ''), +(1842, 23, 2921.173, -1431.680, 150.781, 0, ''), +(1842, 24, 2917.470, -1438.781, 150.781, 0, ''), +(1842, 25, 2913.048, -1453.524, 148.098, 0, 'SAY_TAELAN_MOUNT'), +(1842, 26, 2913.832, -1474.930, 146.224, 0, ''), +(1842, 27, 2906.815, -1487.061, 146.224, 0, ''), +(1842, 28, 2900.644, -1496.575, 146.306, 0, ''), +(1842, 29, 2885.249, -1501.585, 146.020, 0, ''), +(1842, 30, 2863.877, -1500.380, 146.681, 0, ''), +(1842, 31, 2846.509, -1487.183, 146.332, 0, ''), +(1842, 32, 2823.752, -1490.987, 145.782, 0, ''), +(1842, 33, 2800.984, -1510.907, 145.049, 0, ''), +(1842, 34, 2789.488, -1525.215, 143.729, 0, ''), +(1842, 35, 2776.964, -1542.305, 139.435, 0, ''), +(1842, 36, 2762.032, -1561.804, 133.763, 0, ''), +(1842, 37, 2758.741, -1569.599, 131.514, 0, ''), +(1842, 38, 2765.488, -1588.793, 129.721, 0, ''), +(1842, 39, 2779.613, -1613.120, 129.132, 0, ''), +(1842, 40, 2757.654, -1638.032, 128.236, 0, ''), +(1842, 41, 2741.308, -1659.790, 126.457, 0, ''), +(1842, 42, 2729.797, -1677.571, 126.499, 0, ''), +(1842, 43, 2716.778, -1694.648, 126.301, 0, ''), +(1842, 44, 2706.658, -1709.474, 123.420, 0, ''), +(1842, 45, 2699.506, -1720.572, 120.265, 0, ''), +(1842, 46, 2691.977, -1738.466, 114.994, 0, ''), +(1842, 47, 2690.514, -1757.045, 108.764, 0, ''), +(1842, 48, 2691.953, -1780.309, 99.890, 0, ''), +(1842, 49, 2689.344, -1803.264, 89.130, 0, ''), +(1842, 50, 2697.849, -1820.550, 80.681, 0, ''), +(1842, 51, 2701.934, -1836.706, 73.700, 0, ''), +(1842, 52, 2698.088, -1853.866, 68.999, 0, ''), +(1842, 53, 2693.657, -1870.237, 66.882, 0, ''), +(1842, 54, 2682.347, -1885.251, 66.009, 0, ''), +(1842, 55, 2668.229, -1900.796, 66.256, 0, 'SAY_REACH_TOWER - escort paused'); + +DELETE FROM script_waypoint WHERE entry=1840; +INSERT INTO script_waypoint VALUES +(1840, 0, 2689.677, -1937.474, 72.14, 0, ''), +(1840, 1, 2683.112, -1926.823, 72.14, 0, ''), +(1840, 2, 2678.725, -1919.416, 68.86, 0, 'escort paused'); + +DELETE FROM script_waypoint WHERE entry=12126; +INSERT INTO script_waypoint VALUES +(12126, 0, 2631.229, -1917.927, 72.59, 0, ''), +(12126, 1, 2643.529, -1914.072, 71.00, 0, ''), +(12126, 2, 2653.827, -1907.536, 69.34, 0, 'escort paused'); + +DELETE FROM script_waypoint WHERE entry=11016; +INSERT INTO script_waypoint VALUES +(11016, 0, 5004.985, -440.237, 319.059, 4000, 'SAY_ESCORT_START'), +(11016, 1, 4992.224, -449.964, 317.057, 0, ''), +(11016, 2, 4988.549, -457.438, 316.289, 0, ''), +(11016, 3, 4989.978, -464.297, 316.846, 0, ''), +(11016, 4, 4994.038, -467.754, 318.055, 0, ''), +(11016, 5, 5002.307, -466.318, 319.965, 0, ''), +(11016, 6, 5011.801, -462.889, 321.501, 0, ''), +(11016, 7, 5020.533, -460.797, 321.970, 0, ''), +(11016, 8, 5026.836, -463.171, 321.345, 0, ''), +(11016, 9, 5028.663, -476.805, 318.726, 0, ''), +(11016, 10, 5029.503, -487.131, 318.179, 0, ''), +(11016, 11, 5031.178, -497.678, 316.533, 0, ''), +(11016, 12, 5032.720, -504.748, 314.744, 0, ''), +(11016, 13, 5034.997, -513.138, 314.372, 0, ''), +(11016, 14, 5037.493, -521.733, 313.221, 6000, 'SAY_FIRST_STOP'), +(11016, 15, 5049.055, -519.546, 313.221, 0, ''), +(11016, 16, 5059.170, -522.930, 313.221, 0, ''), +(11016, 17, 5062.755, -529.933, 313.221, 0, ''), +(11016, 18, 5063.896, -538.827, 313.221, 0, ''), +(11016, 19, 5062.223, -545.635, 313.221, 0, ''), +(11016, 20, 5061.690, -552.333, 313.101, 0, ''), +(11016, 21, 5060.333, -560.349, 310.873, 0, ''), +(11016, 22, 5055.621, -565.541, 308.737, 0, ''), +(11016, 23, 5049.803, -567.604, 306.537, 0, ''), +(11016, 24, 5043.011, -564.946, 303.682, 0, ''), +(11016, 25, 5038.221, -559.823, 301.463, 0, ''), +(11016, 26, 5039.456, -548.675, 297.824, 0, ''), +(11016, 27, 5043.437, -538.807, 297.801, 0, ''), +(11016, 28, 5056.397, -528.954, 297.801, 0, ''), +(11016, 29, 5064.397, -521.904, 297.801, 0, ''), +(11016, 30, 5067.616, -512.999, 297.196, 0, ''), +(11016, 31, 5065.990, -505.329, 297.214, 0, ''), +(11016, 32, 5062.238, -499.086, 297.448, 0, ''), +(11016, 33, 5065.087, -492.069, 298.054, 0, ''), +(11016, 34, 5071.195, -491.173, 297.666, 5000, 'SAY_SECOND_STOP'), +(11016, 35, 5087.474, -496.478, 296.677, 0, ''), +(11016, 36, 5095.552, -508.639, 296.677, 0, ''), +(11016, 37, 5104.300, -521.014, 296.677, 0, ''), +(11016, 38, 5110.132, -532.123, 296.677, 4000, 'open equipment chest'), +(11016, 39, 5110.132, -532.123, 296.677, 4000, 'cast SPELL_STRENGHT_ARKONARIN'), +(11016, 40, 5110.132, -532.123, 296.677, 4000, 'SAY_EQUIPMENT'), +(11016, 41, 5110.132, -532.123, 296.677, 0, 'SAY_ESCAPE'), +(11016, 42, 5099.748, -510.823, 296.677, 0, ''), +(11016, 43, 5091.944, -497.516, 296.677, 0, ''), +(11016, 44, 5079.375, -486.811, 297.638, 0, ''), +(11016, 45, 5069.212, -488.770, 298.082, 0, ''), +(11016, 46, 5064.242, -496.051, 297.275, 0, ''), +(11016, 47, 5065.084, -505.239, 297.361, 0, ''), +(11016, 48, 5067.818, -515.245, 297.125, 0, ''), +(11016, 49, 5064.617, -521.170, 297.801, 0, ''), +(11016, 50, 5053.221, -530.739, 297.801, 0, ''), +(11016, 51, 5045.725, -538.311, 297.801, 0, ''), +(11016, 52, 5039.695, -548.112, 297.801, 0, ''), +(11016, 53, 5038.778, -557.588, 300.787, 0, ''), +(11016, 54, 5042.014, -566.749, 303.838, 0, ''), +(11016, 55, 5050.555, -568.149, 306.782, 0, ''), +(11016, 56, 5056.979, -564.674, 309.342, 0, ''), +(11016, 57, 5060.791, -556.801, 311.936, 0, ''), +(11016, 58, 5059.581, -551.626, 313.221, 0, ''), +(11016, 59, 5062.826, -541.994, 313.221, 0, ''), +(11016, 60, 5063.554, -531.288, 313.221, 0, ''), +(11016, 61, 5057.934, -523.088, 313.221, 0, ''), +(11016, 62, 5049.471, -519.360, 313.221, 0, ''), +(11016, 63, 5040.789, -519.809, 313.221, 0, ''), +(11016, 64, 5034.299, -515.361, 313.948, 0, ''), +(11016, 65, 5032.001, -505.532, 314.663, 0, ''), +(11016, 66, 5029.915, -495.645, 316.821, 0, ''), +(11016, 67, 5028.871, -487.000, 318.179, 0, ''), +(11016, 68, 5028.109, -475.531, 318.839, 0, ''), +(11016, 69, 5027.759, -465.442, 320.643, 0, ''), +(11016, 70, 5019.955, -460.892, 321.969, 0, ''), +(11016, 71, 5009.426, -464.793, 321.248, 0, ''), +(11016, 72, 4999.567, -468.062, 319.426, 0, ''), +(11016, 73, 4992.034, -468.128, 317.894, 0, ''), +(11016, 74, 4988.168, -461.293, 316.369, 0, ''), +(11016, 75, 4990.624, -447.459, 317.104, 0, ''), +(11016, 76, 4993.475, -438.643, 318.272, 0, ''), +(11016, 77, 4995.451, -430.178, 318.462, 0, ''), +(11016, 78, 4993.564, -422.876, 318.864, 0, ''), +(11016, 79, 4985.401, -420.864, 320.205, 0, ''), +(11016, 80, 4976.515, -426.168, 323.112, 0, ''), +(11016, 81, 4969.832, -429.755, 325.029, 0, ''), +(11016, 82, 4960.702, -425.440, 325.834, 0, ''), +(11016, 83, 4955.447, -418.765, 327.433, 0, ''), +(11016, 84, 4949.702, -408.796, 328.004, 0, ''), +(11016, 85, 4940.017, -403.222, 329.956, 0, ''), +(11016, 86, 4934.982, -401.475, 330.898, 0, ''), +(11016, 87, 4928.693, -399.302, 331.744, 0, ''), +(11016, 88, 4926.935, -398.436, 333.079, 0, ''), +(11016, 89, 4916.163, -393.822, 333.729, 0, ''), +(11016, 90, 4908.393, -396.217, 333.217, 0, ''), +(11016, 91, 4905.610, -396.535, 335.050, 0, ''), +(11016, 92, 4897.876, -395.245, 337.346, 0, ''), +(11016, 93, 4895.206, -388.203, 339.295, 0, ''), +(11016, 94, 4896.945, -382.429, 341.040, 0, ''), +(11016, 95, 4901.885, -378.799, 342.771, 0, ''), +(11016, 96, 4908.087, -380.635, 344.597, 0, ''), +(11016, 97, 4911.910, -385.818, 346.491, 0, ''), +(11016, 98, 4910.104, -393.444, 348.798, 0, ''), +(11016, 99, 4903.500, -396.947, 350.812, 0, ''), +(11016, 100, 4898.083, -394.226, 351.821, 0, ''), +(11016, 101, 4891.333, -393.436, 351.801, 0, ''), +(11016, 102, 4881.203, -395.211, 351.590, 0, ''), +(11016, 103, 4877.843, -395.536, 349.713, 0, ''), +(11016, 104, 4873.972, -394.919, 349.844, 5000, 'SAY_FRESH_AIR'), +(11016, 105, 4873.972, -394.919, 349.844, 3000, 'SAY_BETRAYER'), +(11016, 106, 4873.972, -394.919, 349.844, 2000, 'SAY_TREY'), +(11016, 107, 4873.972, -394.919, 349.844, 0, 'SAY_ATTACK_TREY'), +(11016, 108, 4873.972, -394.919, 349.844, 5000, 'SAY_ESCORT_COMPLETE'), +(11016, 109, 4873.972, -394.919, 349.844, 1000, ''), +(11016, 110, 4863.016, -394.521, 350.650, 0, ''), +(11016, 111, 4848.696, -397.612, 351.215, 0, ''); + +DELETE FROM script_waypoint WHERE entry=9598; +INSERT INTO script_waypoint VALUES +(9598, 0, 6004.265, -1180.494, 376.377, 0, 'SAY_ESCORT_START'), +(9598, 1, 6002.512, -1157.294, 381.407, 0, ''), +(9598, 2, 6029.228, -1139.720, 383.127, 0, ''), +(9598, 3, 6042.479, -1128.963, 386.582, 0, ''), +(9598, 4, 6062.820, -1115.522, 386.850, 0, ''), +(9598, 5, 6089.188, -1111.907, 383.105, 0, ''), +(9598, 6, 6104.390, -1114.561, 380.490, 0, ''), +(9598, 7, 6115.080, -1128.572, 375.779, 0, ''), +(9598, 8, 6119.352, -1147.314, 372.518, 0, ''), +(9598, 9, 6119.003, -1176.082, 371.072, 0, ''), +(9598, 10, 6120.982, -1198.408, 373.432, 0, ''), +(9598, 11, 6123.521, -1226.636, 374.119, 0, ''), +(9598, 12, 6127.737, -1246.035, 373.574, 0, ''), +(9598, 13, 6133.433, -1253.642, 369.100, 0, ''), +(9598, 14, 6150.787, -1269.151, 369.240, 0, ''), +(9598, 15, 6155.805, -1275.029, 373.627, 0, ''), +(9598, 16, 6163.544, -1307.130, 376.234, 0, ''), +(9598, 17, 6174.800, -1340.885, 379.039, 0, ''), +(9598, 18, 6191.144, -1371.260, 378.453, 0, ''), +(9598, 19, 6215.652, -1397.517, 376.012, 0, ''), +(9598, 20, 6243.784, -1407.675, 371.594, 0, ''), +(9598, 21, 6280.775, -1408.259, 370.554, 0, ''), +(9598, 22, 6325.360, -1406.688, 370.082, 0, ''), +(9598, 23, 6355.000, -1404.337, 370.646, 0, ''), +(9598, 24, 6374.679, -1399.176, 372.105, 0, ''), +(9598, 25, 6395.803, -1367.057, 374.910, 0, ''), +(9598, 26, 6408.569, -1333.487, 376.616, 0, ''), +(9598, 27, 6409.075, -1312.168, 379.598, 0, ''), +(9598, 28, 6418.689, -1277.697, 381.638, 0, ''), +(9598, 29, 6441.689, -1247.316, 387.246, 0, ''), +(9598, 30, 6462.136, -1226.316, 397.610, 0, ''), +(9598, 31, 6478.021, -1216.260, 408.284, 0, ''), +(9598, 32, 6499.632, -1217.087, 419.461, 0, ''), +(9598, 33, 6523.165, -1220.780, 430.549, 0, ''), +(9598, 34, 6542.716, -1216.997, 437.788, 0, ''), +(9598, 35, 6557.279, -1211.125, 441.452, 0, ''), +(9598, 36, 6574.568, -1204.589, 443.216, 0, 'SAY_EXIT_IRONTREE'); + +DELETE FROM script_waypoint WHERE entry=26588; +INSERT INTO script_waypoint VALUES +(26588, 0, 4322.890, -3693.610, 263.910, 4000, 'SAY_ESCORT_START'), +(26588, 1, 4330.509, -3689.442, 263.627, 0, ''), +(26588, 2, 4341.477, -3684.207, 257.441, 0, ''), +(26588, 3, 4346.749, -3685.898, 256.866, 0, ''), +(26588, 4, 4347.176, -3694.563, 256.560, 0, ''), +(26588, 5, 4335.924, -3704.452, 258.113, 0, ''), +(26588, 6, 4317.913, -3722.990, 256.835, 0, ''), +(26588, 7, 4309.215, -3736.347, 257.451, 0, ''), +(26588, 8, 4301.650, -3751.553, 257.810, 0, ''), +(26588, 9, 4296.501, -3769.056, 251.977, 0, ''), +(26588, 10, 4291.985, -3785.022, 245.880, 2000, 'SAY_FIRST_WOLF'), +(26588, 11, 4291.985, -3785.022, 245.880, 0, 'SAY_WOLF_ATTACK'), +(26588, 12, 4291.985, -3785.022, 245.880, 3000, ''), +(26588, 13, 4299.542, -3807.021, 237.238, 0, ''), +(26588, 14, 4308.171, -3835.070, 226.317, 0, ''), +(26588, 15, 4312.530, -3847.574, 222.333, 0, ''), +(26588, 16, 4317.506, -3861.733, 214.915, 0, ''), +(26588, 17, 4325.013, -3882.172, 208.888, 0, ''), +(26588, 18, 4332.627, -3893.466, 203.584, 0, ''), +(26588, 19, 4338.521, -3899.447, 199.843, 0, ''), +(26588, 20, 4344.693, -3911.864, 197.886, 0, ''), +(26588, 21, 4349.635, -3922.679, 195.293, 0, ''), +(26588, 22, 4351.970, -3934.677, 191.418, 0, 'SAY_SECOND_WOLF'), +(26588, 23, 4351.970, -3934.677, 191.418, 3000, ''), +(26588, 24, 4351.970, -3934.677, 191.418, 2000, 'SAY_RESUME_ESCORT'), +(26588, 25, 4350.807, -3944.965, 190.528, 0, 'SAY_ESCORT_COMPLETE'), +(26588, 26, 4347.947, -3958.875, 193.360, 0, ''), +(26588, 27, 4345.956, -3988.083, 187.320, 0, ''); + +DELETE FROM script_waypoint WHERE entry=26499; +INSERT INTO script_waypoint VALUES +(26499, 0, 2366.184, 1197.285, 132.150, 0, ''), +(26499, 1, 2371.608, 1199.006, 134.727, 0, ''), +(26499, 2, 2376.157, 1200.552, 134.042, 0, ''), +(26499, 3, 2391.321, 1203.153, 134.125, 10000, 'SAY_ARRIVED'), +(26499, 4, 2391.321, 1203.153, 134.125, 0, 'SAY_GET_BEFORE_PLAGUE'), +(26499, 5, 2396.739, 1205.993, 134.125, 0, 'escort paused'), +(26499, 6, 2396.739, 1205.993, 134.125, 8000, ''), +(26499, 7, 2396.739, 1205.993, 134.125, 5000, 'SAY_MORE_THAN_SCOURGE'), +(26499, 8, 2412.033, 1207.823, 134.034, 0, ''), +(26499, 9, 2426.958, 1212.363, 134.000, 0, ''), +(26499, 10, 2438.589, 1217.005, 133.957, 0, ''), +(26499, 11, 2441.247, 1215.506, 133.951, 0, ''), +(26499, 12, 2446.155, 1197.135, 148.064, 0, ''), +(26499, 13, 2446.861, 1193.559, 148.076, 0, 'SAY_MORE_SORCERY'), +(26499, 14, 2443.582, 1189.773, 148.076, 0, 'escort paused'), +(26499, 15, 2443.582, 1189.773, 148.076, 8000, ''), +(26499, 16, 2443.582, 1189.773, 148.076, 5000, 'SAY_MOVE_ON'), +(26499, 17, 2430.986, 1193.844, 148.076, 0, ''), +(26499, 18, 2418.701, 1195.074, 148.076, 0, ''), +(26499, 19, 2410.825, 1193.033, 148.076, 0, ''), +(26499, 20, 2405.178, 1177.300, 148.076, 0, ''), +(26499, 21, 2409.676, 1155.144, 148.187, 0, 'SAY_WATCH_BACKS - escort paused'), +(26499, 22, 2409.676, 1155.144, 148.187, 8000, ''), +(26499, 23, 2409.676, 1155.144, 148.187, 3000, 'SAY_NOT_EASY'), +(26499, 24, 2413.030, 1138.769, 148.075, 0, ''), +(26499, 25, 2421.589, 1122.539, 148.125, 0, ''), +(26499, 26, 2425.375, 1119.325, 148.075, 0, 'SAY_PERSISTENT'), +(26499, 27, 2425.375, 1119.325, 148.075, 8000, ''), +(26499, 28, 2425.375, 1119.325, 148.075, 0, 'SAY_ELSE - escort paused'), +(26499, 29, 2447.376, 1114.935, 148.075, 0, ''), +(26499, 30, 2454.853, 1117.053, 150.007, 0, ''), +(26499, 31, 2459.909, 1125.710, 150.007, 0, ''), +(26499, 32, 2468.208, 1124.426, 150.027, 5000, 'SAY_TAKE_A_MOMENT'), +(26499, 33, 2468.208, 1124.426, 150.027, 0, 'SAY_PASSAGE'), +(26499, 34, 2482.697, 1122.354, 149.905, 0, ''), +(26499, 35, 2485.536, 1111.682, 149.907, 0, ''), +(26499, 36, 2486.997, 1103.307, 145.335, 0, ''), +(26499, 37, 2490.222, 1100.452, 144.860, 0, ''), +(26499, 38, 2496.676, 1102.510, 144.474, 0, ''), +(26499, 39, 2495.006, 1115.535, 143.825, 0, ''), +(26499, 40, 2493.206, 1123.732, 140.302, 0, ''), +(26499, 41, 2496.522, 1128.798, 140.010, 0, ''), +(26499, 42, 2500.956, 1127.101, 139.982, 0, ''), +(26499, 43, 2504.459, 1120.400, 139.976, 0, ''), +(26499, 44, 2506.478, 1120.344, 139.970, 0, ''), +(26499, 45, 2517.028, 1122.504, 132.064, 0, ''), +(26499, 46, 2523.487, 1124.808, 132.080, 0, 'encounter complete - despawn'), +(26499, 47, 2551.116, 1135.607, 129.797, 0, ''), +(26499, 48, 2562.692, 1147.900, 128.003, 0, ''), +(26499, 49, 2565.026, 1168.818, 127.007, 0, ''), +(26499, 50, 2562.405, 1189.934, 126.189, 0, ''), +(26499, 51, 2558.311, 1212.633, 125.739, 0, ''), +(26499, 52, 2551.082, 1231.603, 125.554, 0, ''), +(26499, 53, 2543.631, 1250.385, 126.103, 0, ''), +(26499, 54, 2534.270, 1272.281, 126.993, 0, ''), +(26499, 55, 2521.446, 1290.463, 130.194, 0, ''), +(26499, 56, 2517.060, 1312.327, 130.156, 0, ''), +(26499, 57, 2513.198, 1324.149, 131.843, 20000, 'SAY_REST'), +(26499, 58, 2513.198, 1324.149, 131.843, 0, 'SAY_REST_COMPLETE'), +(26499, 59, 2503.484, 1347.347, 132.952, 0, ''), +(26499, 60, 2491.935, 1367.205, 130.717, 0, ''), +(26499, 61, 2482.922, 1386.118, 130.029, 0, ''), +(26499, 62, 2471.576, 1404.726, 130.681, 0, ''), +(26499, 63, 2459.646, 1418.801, 130.662, 0, ''), +(26499, 64, 2440.002, 1423.901, 130.632, 0, ''), +(26499, 65, 2416.750, 1419.929, 130.669, 0, ''), +(26499, 66, 2401.423, 1415.888, 130.840, 0, ''), +(26499, 67, 2381.814, 1410.022, 128.147, 0, ''), +(26499, 68, 2367.663, 1406.689, 128.529, 0, ''), +(26499, 69, 2361.863, 1405.020, 128.714, 0, 'SAY_CRUSADER_SQUARE - escort paused'), +(26499, 70, 2341.932, 1406.359, 128.268, 0, ''), +(26499, 71, 2328.375, 1413.144, 127.687, 0, ''), +(26499, 72, 2319.288, 1435.609, 127.887, 0, ''), +(26499, 73, 2308.846, 1460.503, 127.840, 0, ''), +(26499, 74, 2301.277, 1487.081, 128.361, 0, 'SAY_FINISH_MALGANIS - escort paused'), +(26499, 75, 2301.277, 1487.081, 128.361, 18000, 'SAY_JOURNEY_BEGUN'), +(26499, 76, 2293.693, 1506.805, 128.737, 18000, 'SAY_HUNT_MALGANIS'), +(26499, 77, 2300.743, 1487.231, 128.362, 0, ''), +(26499, 78, 2308.582, 1460.863, 127.839, 0, ''), +(26499, 79, 2326.608, 1420.555, 127.780, 0, ''); + -- EOF diff --git a/sql/updates/r1543_scriptdev2.sql b/sql/updates/0.6/r1543_scriptdev2.sql similarity index 100% rename from sql/updates/r1543_scriptdev2.sql rename to sql/updates/0.6/r1543_scriptdev2.sql diff --git a/sql/updates/r1544_mangos.sql b/sql/updates/0.6/r1544_mangos.sql similarity index 100% rename from sql/updates/r1544_mangos.sql rename to sql/updates/0.6/r1544_mangos.sql diff --git a/sql/updates/r1545_scriptdev2.sql b/sql/updates/0.6/r1545_scriptdev2.sql similarity index 100% rename from sql/updates/r1545_scriptdev2.sql rename to sql/updates/0.6/r1545_scriptdev2.sql diff --git a/sql/updates/r1548_scriptdev2.sql b/sql/updates/0.6/r1548_scriptdev2.sql similarity index 100% rename from sql/updates/r1548_scriptdev2.sql rename to sql/updates/0.6/r1548_scriptdev2.sql diff --git a/sql/updates/r1549_mangos.sql b/sql/updates/0.6/r1549_mangos.sql similarity index 100% rename from sql/updates/r1549_mangos.sql rename to sql/updates/0.6/r1549_mangos.sql diff --git a/sql/updates/r1549_scriptdev2.sql b/sql/updates/0.6/r1549_scriptdev2.sql similarity index 100% rename from sql/updates/r1549_scriptdev2.sql rename to sql/updates/0.6/r1549_scriptdev2.sql diff --git a/sql/updates/r1551_mangos.sql b/sql/updates/0.6/r1551_mangos.sql similarity index 100% rename from sql/updates/r1551_mangos.sql rename to sql/updates/0.6/r1551_mangos.sql diff --git a/sql/updates/r1554_mangos.sql b/sql/updates/0.6/r1554_mangos.sql similarity index 100% rename from sql/updates/r1554_mangos.sql rename to sql/updates/0.6/r1554_mangos.sql diff --git a/sql/updates/r1554_scriptdev2.sql b/sql/updates/0.6/r1554_scriptdev2.sql similarity index 100% rename from sql/updates/r1554_scriptdev2.sql rename to sql/updates/0.6/r1554_scriptdev2.sql diff --git a/sql/updates/r1555_scriptdev2.sql b/sql/updates/0.6/r1555_scriptdev2.sql similarity index 100% rename from sql/updates/r1555_scriptdev2.sql rename to sql/updates/0.6/r1555_scriptdev2.sql diff --git a/sql/updates/r1556_mangos.sql b/sql/updates/0.6/r1556_mangos.sql similarity index 100% rename from sql/updates/r1556_mangos.sql rename to sql/updates/0.6/r1556_mangos.sql diff --git a/sql/updates/r1557_scriptdev2.sql b/sql/updates/0.6/r1557_scriptdev2.sql similarity index 100% rename from sql/updates/r1557_scriptdev2.sql rename to sql/updates/0.6/r1557_scriptdev2.sql diff --git a/sql/updates/r1563_mangos.sql b/sql/updates/0.6/r1563_mangos.sql similarity index 100% rename from sql/updates/r1563_mangos.sql rename to sql/updates/0.6/r1563_mangos.sql diff --git a/sql/updates/r1567_mangos.sql b/sql/updates/0.6/r1567_mangos.sql similarity index 100% rename from sql/updates/r1567_mangos.sql rename to sql/updates/0.6/r1567_mangos.sql diff --git a/sql/updates/r1567_scriptdev2.sql b/sql/updates/0.6/r1567_scriptdev2.sql similarity index 100% rename from sql/updates/r1567_scriptdev2.sql rename to sql/updates/0.6/r1567_scriptdev2.sql diff --git a/sql/updates/r1570_scriptdev2.sql b/sql/updates/0.6/r1570_scriptdev2.sql similarity index 100% rename from sql/updates/r1570_scriptdev2.sql rename to sql/updates/0.6/r1570_scriptdev2.sql diff --git a/sql/updates/r1577_mangos.sql b/sql/updates/0.6/r1577_mangos.sql similarity index 100% rename from sql/updates/r1577_mangos.sql rename to sql/updates/0.6/r1577_mangos.sql diff --git a/sql/updates/r1577_scriptdev2.sql b/sql/updates/0.6/r1577_scriptdev2.sql similarity index 100% rename from sql/updates/r1577_scriptdev2.sql rename to sql/updates/0.6/r1577_scriptdev2.sql diff --git a/sql/updates/r1583_scriptdev2.sql b/sql/updates/0.6/r1583_scriptdev2.sql similarity index 100% rename from sql/updates/r1583_scriptdev2.sql rename to sql/updates/0.6/r1583_scriptdev2.sql diff --git a/sql/updates/r1584_scriptdev2.sql b/sql/updates/0.6/r1584_scriptdev2.sql similarity index 100% rename from sql/updates/r1584_scriptdev2.sql rename to sql/updates/0.6/r1584_scriptdev2.sql diff --git a/sql/updates/r1587_scriptdev2.sql b/sql/updates/0.6/r1587_scriptdev2.sql similarity index 100% rename from sql/updates/r1587_scriptdev2.sql rename to sql/updates/0.6/r1587_scriptdev2.sql diff --git a/sql/updates/r1589_mangos.sql b/sql/updates/0.6/r1589_mangos.sql similarity index 100% rename from sql/updates/r1589_mangos.sql rename to sql/updates/0.6/r1589_mangos.sql diff --git a/sql/updates/r1590_mangos.sql b/sql/updates/0.6/r1590_mangos.sql similarity index 100% rename from sql/updates/r1590_mangos.sql rename to sql/updates/0.6/r1590_mangos.sql diff --git a/sql/updates/r1591_mangos.sql b/sql/updates/0.6/r1591_mangos.sql similarity index 100% rename from sql/updates/r1591_mangos.sql rename to sql/updates/0.6/r1591_mangos.sql diff --git a/sql/updates/r1592_mangos.sql b/sql/updates/0.6/r1592_mangos.sql similarity index 100% rename from sql/updates/r1592_mangos.sql rename to sql/updates/0.6/r1592_mangos.sql diff --git a/sql/updates/r1593_mangos.sql b/sql/updates/0.6/r1593_mangos.sql similarity index 100% rename from sql/updates/r1593_mangos.sql rename to sql/updates/0.6/r1593_mangos.sql diff --git a/sql/updates/r1594_mangos.sql b/sql/updates/0.6/r1594_mangos.sql similarity index 100% rename from sql/updates/r1594_mangos.sql rename to sql/updates/0.6/r1594_mangos.sql diff --git a/sql/updates/r1595_mangos.sql b/sql/updates/0.6/r1595_mangos.sql similarity index 100% rename from sql/updates/r1595_mangos.sql rename to sql/updates/0.6/r1595_mangos.sql diff --git a/sql/updates/r1596_mangos.sql b/sql/updates/0.6/r1596_mangos.sql similarity index 100% rename from sql/updates/r1596_mangos.sql rename to sql/updates/0.6/r1596_mangos.sql diff --git a/sql/updates/r1599_mangos.sql b/sql/updates/0.6/r1599_mangos.sql similarity index 100% rename from sql/updates/r1599_mangos.sql rename to sql/updates/0.6/r1599_mangos.sql diff --git a/sql/updates/r1600_scriptdev2.sql b/sql/updates/0.6/r1600_scriptdev2.sql similarity index 100% rename from sql/updates/r1600_scriptdev2.sql rename to sql/updates/0.6/r1600_scriptdev2.sql diff --git a/sql/updates/r1602_mangos.sql b/sql/updates/0.6/r1602_mangos.sql similarity index 100% rename from sql/updates/r1602_mangos.sql rename to sql/updates/0.6/r1602_mangos.sql diff --git a/sql/updates/r1604_mangos.sql b/sql/updates/0.6/r1604_mangos.sql similarity index 100% rename from sql/updates/r1604_mangos.sql rename to sql/updates/0.6/r1604_mangos.sql diff --git a/sql/updates/r1605_mangos.sql b/sql/updates/0.6/r1605_mangos.sql similarity index 100% rename from sql/updates/r1605_mangos.sql rename to sql/updates/0.6/r1605_mangos.sql diff --git a/sql/updates/r1607_mangos.sql b/sql/updates/0.6/r1607_mangos.sql similarity index 100% rename from sql/updates/r1607_mangos.sql rename to sql/updates/0.6/r1607_mangos.sql diff --git a/sql/updates/r1608_mangos.sql b/sql/updates/0.6/r1608_mangos.sql similarity index 100% rename from sql/updates/r1608_mangos.sql rename to sql/updates/0.6/r1608_mangos.sql diff --git a/sql/updates/r1615_mangos.sql b/sql/updates/0.6/r1615_mangos.sql similarity index 100% rename from sql/updates/r1615_mangos.sql rename to sql/updates/0.6/r1615_mangos.sql diff --git a/sql/updates/r1615_scriptdev2.sql b/sql/updates/0.6/r1615_scriptdev2.sql similarity index 100% rename from sql/updates/r1615_scriptdev2.sql rename to sql/updates/0.6/r1615_scriptdev2.sql diff --git a/sql/updates/r1616_mangos.sql b/sql/updates/0.6/r1616_mangos.sql similarity index 100% rename from sql/updates/r1616_mangos.sql rename to sql/updates/0.6/r1616_mangos.sql diff --git a/sql/updates/r1617_mangos.sql b/sql/updates/0.6/r1617_mangos.sql similarity index 100% rename from sql/updates/r1617_mangos.sql rename to sql/updates/0.6/r1617_mangos.sql diff --git a/sql/updates/r1621_scriptdev2.sql b/sql/updates/0.6/r1621_scriptdev2.sql similarity index 100% rename from sql/updates/r1621_scriptdev2.sql rename to sql/updates/0.6/r1621_scriptdev2.sql diff --git a/sql/updates/r1622_mangos.sql b/sql/updates/0.6/r1622_mangos.sql similarity index 100% rename from sql/updates/r1622_mangos.sql rename to sql/updates/0.6/r1622_mangos.sql diff --git a/sql/updates/r1622_scriptdev2.sql b/sql/updates/0.6/r1622_scriptdev2.sql similarity index 100% rename from sql/updates/r1622_scriptdev2.sql rename to sql/updates/0.6/r1622_scriptdev2.sql diff --git a/sql/updates/r1624_mangos.sql b/sql/updates/0.6/r1624_mangos.sql similarity index 100% rename from sql/updates/r1624_mangos.sql rename to sql/updates/0.6/r1624_mangos.sql diff --git a/sql/updates/r1624_scriptdev2.sql b/sql/updates/0.6/r1624_scriptdev2.sql similarity index 100% rename from sql/updates/r1624_scriptdev2.sql rename to sql/updates/0.6/r1624_scriptdev2.sql diff --git a/sql/updates/r1627_mangos.sql b/sql/updates/0.6/r1627_mangos.sql similarity index 100% rename from sql/updates/r1627_mangos.sql rename to sql/updates/0.6/r1627_mangos.sql diff --git a/sql/updates/r1627_scriptdev2.sql b/sql/updates/0.6/r1627_scriptdev2.sql similarity index 100% rename from sql/updates/r1627_scriptdev2.sql rename to sql/updates/0.6/r1627_scriptdev2.sql diff --git a/sql/updates/r1629_mangos.sql b/sql/updates/0.6/r1629_mangos.sql similarity index 100% rename from sql/updates/r1629_mangos.sql rename to sql/updates/0.6/r1629_mangos.sql diff --git a/sql/updates/r1629_scriptdev2.sql b/sql/updates/0.6/r1629_scriptdev2.sql similarity index 100% rename from sql/updates/r1629_scriptdev2.sql rename to sql/updates/0.6/r1629_scriptdev2.sql diff --git a/sql/updates/r1632_mangos.sql b/sql/updates/0.6/r1632_mangos.sql similarity index 100% rename from sql/updates/r1632_mangos.sql rename to sql/updates/0.6/r1632_mangos.sql diff --git a/sql/updates/r1636_mangos.sql b/sql/updates/0.6/r1636_mangos.sql similarity index 100% rename from sql/updates/r1636_mangos.sql rename to sql/updates/0.6/r1636_mangos.sql diff --git a/sql/updates/r1637_scriptdev2.sql b/sql/updates/0.6/r1637_scriptdev2.sql similarity index 100% rename from sql/updates/r1637_scriptdev2.sql rename to sql/updates/0.6/r1637_scriptdev2.sql diff --git a/sql/updates/r1642_scriptdev2.sql b/sql/updates/0.6/r1642_scriptdev2.sql similarity index 100% rename from sql/updates/r1642_scriptdev2.sql rename to sql/updates/0.6/r1642_scriptdev2.sql diff --git a/sql/updates/r1644_scriptdev2.sql b/sql/updates/0.6/r1644_scriptdev2.sql similarity index 100% rename from sql/updates/r1644_scriptdev2.sql rename to sql/updates/0.6/r1644_scriptdev2.sql diff --git a/sql/updates/r1647_mangos.sql b/sql/updates/0.6/r1647_mangos.sql similarity index 100% rename from sql/updates/r1647_mangos.sql rename to sql/updates/0.6/r1647_mangos.sql diff --git a/sql/updates/r1647_scriptdev2.sql b/sql/updates/0.6/r1647_scriptdev2.sql similarity index 100% rename from sql/updates/r1647_scriptdev2.sql rename to sql/updates/0.6/r1647_scriptdev2.sql diff --git a/sql/updates/r1650_mangos.sql b/sql/updates/0.6/r1650_mangos.sql similarity index 100% rename from sql/updates/r1650_mangos.sql rename to sql/updates/0.6/r1650_mangos.sql diff --git a/sql/updates/r1651_scriptdev2.sql b/sql/updates/0.6/r1651_scriptdev2.sql similarity index 100% rename from sql/updates/r1651_scriptdev2.sql rename to sql/updates/0.6/r1651_scriptdev2.sql diff --git a/sql/updates/r1652_scriptdev2.sql b/sql/updates/0.6/r1652_scriptdev2.sql similarity index 100% rename from sql/updates/r1652_scriptdev2.sql rename to sql/updates/0.6/r1652_scriptdev2.sql diff --git a/sql/updates/r1653_mangos.sql b/sql/updates/0.6/r1653_mangos.sql similarity index 100% rename from sql/updates/r1653_mangos.sql rename to sql/updates/0.6/r1653_mangos.sql diff --git a/sql/updates/r1658_scriptdev2.sql b/sql/updates/0.6/r1658_scriptdev2.sql similarity index 100% rename from sql/updates/r1658_scriptdev2.sql rename to sql/updates/0.6/r1658_scriptdev2.sql diff --git a/sql/updates/r1660_scriptdev2.sql b/sql/updates/0.6/r1660_scriptdev2.sql similarity index 100% rename from sql/updates/r1660_scriptdev2.sql rename to sql/updates/0.6/r1660_scriptdev2.sql diff --git a/sql/updates/r1661_mangos.sql b/sql/updates/0.6/r1661_mangos.sql similarity index 100% rename from sql/updates/r1661_mangos.sql rename to sql/updates/0.6/r1661_mangos.sql diff --git a/sql/updates/r1662_scriptdev2.sql b/sql/updates/0.6/r1662_scriptdev2.sql similarity index 100% rename from sql/updates/r1662_scriptdev2.sql rename to sql/updates/0.6/r1662_scriptdev2.sql diff --git a/sql/updates/r1665_mangos.sql b/sql/updates/0.6/r1665_mangos.sql similarity index 100% rename from sql/updates/r1665_mangos.sql rename to sql/updates/0.6/r1665_mangos.sql diff --git a/sql/updates/r1667_mangos.sql b/sql/updates/0.6/r1667_mangos.sql similarity index 100% rename from sql/updates/r1667_mangos.sql rename to sql/updates/0.6/r1667_mangos.sql diff --git a/sql/updates/r1667_scriptdev2.sql b/sql/updates/0.6/r1667_scriptdev2.sql similarity index 100% rename from sql/updates/r1667_scriptdev2.sql rename to sql/updates/0.6/r1667_scriptdev2.sql diff --git a/sql/updates/r1668_mangos.sql b/sql/updates/0.6/r1668_mangos.sql similarity index 100% rename from sql/updates/r1668_mangos.sql rename to sql/updates/0.6/r1668_mangos.sql diff --git a/sql/updates/r1671_mangos.sql b/sql/updates/0.6/r1671_mangos.sql similarity index 100% rename from sql/updates/r1671_mangos.sql rename to sql/updates/0.6/r1671_mangos.sql diff --git a/sql/updates/r1671_scriptdev2.sql b/sql/updates/0.6/r1671_scriptdev2.sql similarity index 100% rename from sql/updates/r1671_scriptdev2.sql rename to sql/updates/0.6/r1671_scriptdev2.sql diff --git a/sql/updates/r1679_mangos.sql b/sql/updates/0.6/r1679_mangos.sql similarity index 100% rename from sql/updates/r1679_mangos.sql rename to sql/updates/0.6/r1679_mangos.sql diff --git a/sql/updates/r1680_mangos.sql b/sql/updates/0.6/r1680_mangos.sql similarity index 100% rename from sql/updates/r1680_mangos.sql rename to sql/updates/0.6/r1680_mangos.sql diff --git a/sql/updates/r1681_mangos.sql b/sql/updates/0.6/r1681_mangos.sql similarity index 100% rename from sql/updates/r1681_mangos.sql rename to sql/updates/0.6/r1681_mangos.sql diff --git a/sql/updates/r1683_scriptdev2.sql b/sql/updates/0.6/r1683_scriptdev2.sql similarity index 100% rename from sql/updates/r1683_scriptdev2.sql rename to sql/updates/0.6/r1683_scriptdev2.sql diff --git a/sql/updates/r1685_mangos.sql b/sql/updates/0.6/r1685_mangos.sql similarity index 100% rename from sql/updates/r1685_mangos.sql rename to sql/updates/0.6/r1685_mangos.sql diff --git a/sql/updates/r1685_scriptdev2.sql b/sql/updates/0.6/r1685_scriptdev2.sql similarity index 100% rename from sql/updates/r1685_scriptdev2.sql rename to sql/updates/0.6/r1685_scriptdev2.sql diff --git a/sql/updates/r1687_mangos.sql b/sql/updates/0.6/r1687_mangos.sql similarity index 100% rename from sql/updates/r1687_mangos.sql rename to sql/updates/0.6/r1687_mangos.sql diff --git a/sql/updates/r1691_mangos.sql b/sql/updates/0.6/r1691_mangos.sql similarity index 100% rename from sql/updates/r1691_mangos.sql rename to sql/updates/0.6/r1691_mangos.sql diff --git a/sql/updates/r1694_mangos.sql b/sql/updates/0.6/r1694_mangos.sql similarity index 100% rename from sql/updates/r1694_mangos.sql rename to sql/updates/0.6/r1694_mangos.sql diff --git a/sql/updates/r1698_mangos.sql b/sql/updates/0.6/r1698_mangos.sql similarity index 100% rename from sql/updates/r1698_mangos.sql rename to sql/updates/0.6/r1698_mangos.sql diff --git a/sql/updates/r1704_mangos.sql b/sql/updates/0.6/r1704_mangos.sql similarity index 100% rename from sql/updates/r1704_mangos.sql rename to sql/updates/0.6/r1704_mangos.sql diff --git a/sql/updates/r1705_mangos.sql b/sql/updates/0.6/r1705_mangos.sql similarity index 100% rename from sql/updates/r1705_mangos.sql rename to sql/updates/0.6/r1705_mangos.sql diff --git a/sql/updates/r1705_scriptdev2.sql b/sql/updates/0.6/r1705_scriptdev2.sql similarity index 100% rename from sql/updates/r1705_scriptdev2.sql rename to sql/updates/0.6/r1705_scriptdev2.sql diff --git a/sql/updates/r1706_scriptdev2.sql b/sql/updates/0.6/r1706_scriptdev2.sql similarity index 100% rename from sql/updates/r1706_scriptdev2.sql rename to sql/updates/0.6/r1706_scriptdev2.sql diff --git a/sql/updates/r1711_scriptdev2.sql b/sql/updates/0.6/r1711_scriptdev2.sql similarity index 100% rename from sql/updates/r1711_scriptdev2.sql rename to sql/updates/0.6/r1711_scriptdev2.sql diff --git a/sql/updates/r1715_mangos.sql b/sql/updates/0.6/r1715_mangos.sql similarity index 100% rename from sql/updates/r1715_mangos.sql rename to sql/updates/0.6/r1715_mangos.sql diff --git a/sql/updates/r1715_scriptdev2.sql b/sql/updates/0.6/r1715_scriptdev2.sql similarity index 100% rename from sql/updates/r1715_scriptdev2.sql rename to sql/updates/0.6/r1715_scriptdev2.sql diff --git a/sql/updates/r1720_mangos.sql b/sql/updates/0.6/r1720_mangos.sql similarity index 100% rename from sql/updates/r1720_mangos.sql rename to sql/updates/0.6/r1720_mangos.sql diff --git a/sql/updates/r1720_scriptdev2.sql b/sql/updates/0.6/r1720_scriptdev2.sql similarity index 100% rename from sql/updates/r1720_scriptdev2.sql rename to sql/updates/0.6/r1720_scriptdev2.sql diff --git a/sql/updates/r1726_mangos.sql b/sql/updates/0.6/r1726_mangos.sql similarity index 100% rename from sql/updates/r1726_mangos.sql rename to sql/updates/0.6/r1726_mangos.sql diff --git a/sql/updates/r1727_scriptdev2.sql b/sql/updates/0.6/r1727_scriptdev2.sql similarity index 100% rename from sql/updates/r1727_scriptdev2.sql rename to sql/updates/0.6/r1727_scriptdev2.sql diff --git a/sql/updates/r1728_mangos.sql b/sql/updates/0.6/r1728_mangos.sql similarity index 100% rename from sql/updates/r1728_mangos.sql rename to sql/updates/0.6/r1728_mangos.sql diff --git a/sql/updates/r1729_scriptdev2.sql b/sql/updates/0.6/r1729_scriptdev2.sql similarity index 100% rename from sql/updates/r1729_scriptdev2.sql rename to sql/updates/0.6/r1729_scriptdev2.sql diff --git a/sql/updates/r1734_scriptdev2.sql b/sql/updates/0.6/r1734_scriptdev2.sql similarity index 100% rename from sql/updates/r1734_scriptdev2.sql rename to sql/updates/0.6/r1734_scriptdev2.sql diff --git a/sql/updates/r1736_scriptdev2.sql b/sql/updates/0.6/r1736_scriptdev2.sql similarity index 100% rename from sql/updates/r1736_scriptdev2.sql rename to sql/updates/0.6/r1736_scriptdev2.sql diff --git a/sql/updates/r1737_scriptdev2.sql b/sql/updates/0.6/r1737_scriptdev2.sql similarity index 100% rename from sql/updates/r1737_scriptdev2.sql rename to sql/updates/0.6/r1737_scriptdev2.sql diff --git a/sql/updates/r1741_mangos.sql b/sql/updates/0.6/r1741_mangos.sql similarity index 100% rename from sql/updates/r1741_mangos.sql rename to sql/updates/0.6/r1741_mangos.sql diff --git a/sql/updates/r1750_scriptdev2.sql b/sql/updates/0.6/r1750_scriptdev2.sql similarity index 100% rename from sql/updates/r1750_scriptdev2.sql rename to sql/updates/0.6/r1750_scriptdev2.sql diff --git a/sql/updates/r1751_scriptdev2.sql b/sql/updates/0.6/r1751_scriptdev2.sql similarity index 100% rename from sql/updates/r1751_scriptdev2.sql rename to sql/updates/0.6/r1751_scriptdev2.sql diff --git a/sql/updates/r1752_mangos.sql b/sql/updates/0.6/r1752_mangos.sql similarity index 100% rename from sql/updates/r1752_mangos.sql rename to sql/updates/0.6/r1752_mangos.sql diff --git a/sql/updates/r1753_scriptdev2.sql b/sql/updates/0.6/r1753_scriptdev2.sql similarity index 100% rename from sql/updates/r1753_scriptdev2.sql rename to sql/updates/0.6/r1753_scriptdev2.sql diff --git a/sql/updates/r1754_scriptdev2.sql b/sql/updates/0.6/r1754_scriptdev2.sql similarity index 100% rename from sql/updates/r1754_scriptdev2.sql rename to sql/updates/0.6/r1754_scriptdev2.sql diff --git a/sql/updates/r1759_mangos.sql b/sql/updates/0.6/r1759_mangos.sql similarity index 100% rename from sql/updates/r1759_mangos.sql rename to sql/updates/0.6/r1759_mangos.sql diff --git a/sql/updates/r1763_mangos.sql b/sql/updates/0.6/r1763_mangos.sql similarity index 100% rename from sql/updates/r1763_mangos.sql rename to sql/updates/0.6/r1763_mangos.sql diff --git a/sql/updates/r1767_mangos.sql b/sql/updates/0.6/r1767_mangos.sql similarity index 100% rename from sql/updates/r1767_mangos.sql rename to sql/updates/0.6/r1767_mangos.sql diff --git a/sql/updates/r1771_scriptdev2.sql b/sql/updates/0.6/r1771_scriptdev2.sql similarity index 100% rename from sql/updates/r1771_scriptdev2.sql rename to sql/updates/0.6/r1771_scriptdev2.sql diff --git a/sql/updates/r1777_scriptdev2.sql b/sql/updates/0.6/r1777_scriptdev2.sql similarity index 100% rename from sql/updates/r1777_scriptdev2.sql rename to sql/updates/0.6/r1777_scriptdev2.sql diff --git a/sql/updates/r1780_scriptdev2.sql b/sql/updates/0.6/r1780_scriptdev2.sql similarity index 100% rename from sql/updates/r1780_scriptdev2.sql rename to sql/updates/0.6/r1780_scriptdev2.sql diff --git a/sql/updates/r1782_scriptdev2.sql b/sql/updates/0.6/r1782_scriptdev2.sql similarity index 100% rename from sql/updates/r1782_scriptdev2.sql rename to sql/updates/0.6/r1782_scriptdev2.sql diff --git a/sql/updates/r1783_scriptdev2.sql b/sql/updates/0.6/r1783_scriptdev2.sql similarity index 100% rename from sql/updates/r1783_scriptdev2.sql rename to sql/updates/0.6/r1783_scriptdev2.sql diff --git a/sql/updates/r1784_scriptdev2.sql b/sql/updates/0.6/r1784_scriptdev2.sql similarity index 100% rename from sql/updates/r1784_scriptdev2.sql rename to sql/updates/0.6/r1784_scriptdev2.sql diff --git a/sql/updates/r1785_scriptdev2.sql b/sql/updates/0.6/r1785_scriptdev2.sql similarity index 100% rename from sql/updates/r1785_scriptdev2.sql rename to sql/updates/0.6/r1785_scriptdev2.sql diff --git a/sql/updates/r1786_scriptdev2.sql b/sql/updates/0.6/r1786_scriptdev2.sql similarity index 100% rename from sql/updates/r1786_scriptdev2.sql rename to sql/updates/0.6/r1786_scriptdev2.sql diff --git a/sql/updates/r1789_scriptdev2.sql b/sql/updates/0.6/r1789_scriptdev2.sql similarity index 100% rename from sql/updates/r1789_scriptdev2.sql rename to sql/updates/0.6/r1789_scriptdev2.sql diff --git a/sql/updates/r1791_scriptdev2.sql b/sql/updates/0.6/r1791_scriptdev2.sql similarity index 100% rename from sql/updates/r1791_scriptdev2.sql rename to sql/updates/0.6/r1791_scriptdev2.sql diff --git a/sql/updates/r1797_mangos.sql b/sql/updates/0.6/r1797_mangos.sql similarity index 100% rename from sql/updates/r1797_mangos.sql rename to sql/updates/0.6/r1797_mangos.sql diff --git a/sql/updates/r1798_mangos.sql b/sql/updates/0.6/r1798_mangos.sql similarity index 100% rename from sql/updates/r1798_mangos.sql rename to sql/updates/0.6/r1798_mangos.sql diff --git a/sql/updates/r1800_mangos.sql b/sql/updates/0.6/r1800_mangos.sql similarity index 100% rename from sql/updates/r1800_mangos.sql rename to sql/updates/0.6/r1800_mangos.sql diff --git a/sql/updates/r1800_scriptdev2.sql b/sql/updates/0.6/r1800_scriptdev2.sql similarity index 100% rename from sql/updates/r1800_scriptdev2.sql rename to sql/updates/0.6/r1800_scriptdev2.sql diff --git a/sql/updates/r1807_scriptdev2.sql b/sql/updates/0.6/r1807_scriptdev2.sql similarity index 100% rename from sql/updates/r1807_scriptdev2.sql rename to sql/updates/0.6/r1807_scriptdev2.sql diff --git a/sql/updates/r1810_scriptdev2.sql b/sql/updates/0.6/r1810_scriptdev2.sql similarity index 100% rename from sql/updates/r1810_scriptdev2.sql rename to sql/updates/0.6/r1810_scriptdev2.sql diff --git a/sql/updates/r1813_mangos.sql b/sql/updates/0.6/r1813_mangos.sql similarity index 100% rename from sql/updates/r1813_mangos.sql rename to sql/updates/0.6/r1813_mangos.sql diff --git a/sql/updates/r1816_scriptdev2.sql b/sql/updates/0.6/r1816_scriptdev2.sql similarity index 100% rename from sql/updates/r1816_scriptdev2.sql rename to sql/updates/0.6/r1816_scriptdev2.sql diff --git a/sql/updates/r1818_mangos.sql b/sql/updates/0.6/r1818_mangos.sql similarity index 100% rename from sql/updates/r1818_mangos.sql rename to sql/updates/0.6/r1818_mangos.sql diff --git a/sql/updates/r1818_scriptdev2.sql b/sql/updates/0.6/r1818_scriptdev2.sql similarity index 100% rename from sql/updates/r1818_scriptdev2.sql rename to sql/updates/0.6/r1818_scriptdev2.sql diff --git a/sql/updates/r1819_mangos.sql b/sql/updates/0.6/r1819_mangos.sql similarity index 100% rename from sql/updates/r1819_mangos.sql rename to sql/updates/0.6/r1819_mangos.sql diff --git a/sql/updates/r1822_scriptdev2.sql b/sql/updates/0.6/r1822_scriptdev2.sql similarity index 100% rename from sql/updates/r1822_scriptdev2.sql rename to sql/updates/0.6/r1822_scriptdev2.sql diff --git a/sql/updates/r1824_mangos.sql b/sql/updates/0.6/r1824_mangos.sql similarity index 100% rename from sql/updates/r1824_mangos.sql rename to sql/updates/0.6/r1824_mangos.sql diff --git a/sql/updates/r1825_mangos.sql b/sql/updates/0.6/r1825_mangos.sql similarity index 100% rename from sql/updates/r1825_mangos.sql rename to sql/updates/0.6/r1825_mangos.sql diff --git a/sql/updates/r1825_scriptdev2.sql b/sql/updates/0.6/r1825_scriptdev2.sql similarity index 100% rename from sql/updates/r1825_scriptdev2.sql rename to sql/updates/0.6/r1825_scriptdev2.sql diff --git a/sql/updates/r1826_mangos.sql b/sql/updates/0.6/r1826_mangos.sql similarity index 100% rename from sql/updates/r1826_mangos.sql rename to sql/updates/0.6/r1826_mangos.sql diff --git a/sql/updates/r1826_scriptdev2.sql b/sql/updates/0.6/r1826_scriptdev2.sql similarity index 100% rename from sql/updates/r1826_scriptdev2.sql rename to sql/updates/0.6/r1826_scriptdev2.sql diff --git a/sql/updates/r1827_scriptdev2.sql b/sql/updates/0.6/r1827_scriptdev2.sql similarity index 100% rename from sql/updates/r1827_scriptdev2.sql rename to sql/updates/0.6/r1827_scriptdev2.sql diff --git a/sql/updates/r1828_scriptdev2.sql b/sql/updates/0.6/r1828_scriptdev2.sql similarity index 100% rename from sql/updates/r1828_scriptdev2.sql rename to sql/updates/0.6/r1828_scriptdev2.sql diff --git a/sql/updates/r1829_mangos.sql b/sql/updates/0.6/r1829_mangos.sql similarity index 100% rename from sql/updates/r1829_mangos.sql rename to sql/updates/0.6/r1829_mangos.sql diff --git a/sql/updates/r1830_scriptdev2.sql b/sql/updates/0.6/r1830_scriptdev2.sql similarity index 100% rename from sql/updates/r1830_scriptdev2.sql rename to sql/updates/0.6/r1830_scriptdev2.sql diff --git a/sql/updates/r1831_scriptdev2.sql b/sql/updates/0.6/r1831_scriptdev2.sql similarity index 100% rename from sql/updates/r1831_scriptdev2.sql rename to sql/updates/0.6/r1831_scriptdev2.sql diff --git a/sql/updates/r1836_mangos.sql b/sql/updates/0.6/r1836_mangos.sql similarity index 100% rename from sql/updates/r1836_mangos.sql rename to sql/updates/0.6/r1836_mangos.sql diff --git a/sql/updates/r1842_scriptdev2.sql b/sql/updates/0.6/r1842_scriptdev2.sql similarity index 100% rename from sql/updates/r1842_scriptdev2.sql rename to sql/updates/0.6/r1842_scriptdev2.sql diff --git a/sql/updates/r1843_mangos.sql b/sql/updates/0.6/r1843_mangos.sql similarity index 100% rename from sql/updates/r1843_mangos.sql rename to sql/updates/0.6/r1843_mangos.sql diff --git a/sql/updates/r1843_scriptdev2.sql b/sql/updates/0.6/r1843_scriptdev2.sql similarity index 100% rename from sql/updates/r1843_scriptdev2.sql rename to sql/updates/0.6/r1843_scriptdev2.sql diff --git a/sql/updates/r1844_mangos.sql b/sql/updates/0.6/r1844_mangos.sql similarity index 100% rename from sql/updates/r1844_mangos.sql rename to sql/updates/0.6/r1844_mangos.sql diff --git a/sql/updates/r1845_mangos.sql b/sql/updates/0.6/r1845_mangos.sql similarity index 100% rename from sql/updates/r1845_mangos.sql rename to sql/updates/0.6/r1845_mangos.sql diff --git a/sql/updates/r1845_scriptdev2.sql b/sql/updates/0.6/r1845_scriptdev2.sql similarity index 100% rename from sql/updates/r1845_scriptdev2.sql rename to sql/updates/0.6/r1845_scriptdev2.sql diff --git a/sql/updates/r1850_mangos.sql b/sql/updates/0.6/r1850_mangos.sql similarity index 100% rename from sql/updates/r1850_mangos.sql rename to sql/updates/0.6/r1850_mangos.sql diff --git a/sql/updates/r1850_scriptdev2.sql b/sql/updates/0.6/r1850_scriptdev2.sql similarity index 100% rename from sql/updates/r1850_scriptdev2.sql rename to sql/updates/0.6/r1850_scriptdev2.sql diff --git a/sql/updates/r1851_mangos.sql b/sql/updates/0.6/r1851_mangos.sql similarity index 100% rename from sql/updates/r1851_mangos.sql rename to sql/updates/0.6/r1851_mangos.sql diff --git a/sql/updates/r1852_scriptdev2.sql b/sql/updates/0.6/r1852_scriptdev2.sql similarity index 100% rename from sql/updates/r1852_scriptdev2.sql rename to sql/updates/0.6/r1852_scriptdev2.sql diff --git a/sql/updates/r1853_mangos.sql b/sql/updates/0.6/r1853_mangos.sql similarity index 100% rename from sql/updates/r1853_mangos.sql rename to sql/updates/0.6/r1853_mangos.sql diff --git a/sql/updates/r1855_scriptdev2.sql b/sql/updates/0.6/r1855_scriptdev2.sql similarity index 100% rename from sql/updates/r1855_scriptdev2.sql rename to sql/updates/0.6/r1855_scriptdev2.sql diff --git a/sql/updates/r1858_scriptdev2.sql b/sql/updates/0.6/r1858_scriptdev2.sql similarity index 100% rename from sql/updates/r1858_scriptdev2.sql rename to sql/updates/0.6/r1858_scriptdev2.sql diff --git a/sql/updates/r1859_mangos.sql b/sql/updates/0.6/r1859_mangos.sql similarity index 100% rename from sql/updates/r1859_mangos.sql rename to sql/updates/0.6/r1859_mangos.sql diff --git a/sql/updates/r1860_scriptdev2.sql b/sql/updates/0.6/r1860_scriptdev2.sql similarity index 100% rename from sql/updates/r1860_scriptdev2.sql rename to sql/updates/0.6/r1860_scriptdev2.sql diff --git a/sql/updates/r1862_mangos.sql b/sql/updates/0.6/r1862_mangos.sql similarity index 100% rename from sql/updates/r1862_mangos.sql rename to sql/updates/0.6/r1862_mangos.sql diff --git a/sql/updates/r1863_mangos.sql b/sql/updates/0.6/r1863_mangos.sql similarity index 100% rename from sql/updates/r1863_mangos.sql rename to sql/updates/0.6/r1863_mangos.sql diff --git a/sql/updates/r1864_mangos.sql b/sql/updates/0.6/r1864_mangos.sql similarity index 100% rename from sql/updates/r1864_mangos.sql rename to sql/updates/0.6/r1864_mangos.sql diff --git a/sql/updates/r1864_scriptdev2.sql b/sql/updates/0.6/r1864_scriptdev2.sql similarity index 100% rename from sql/updates/r1864_scriptdev2.sql rename to sql/updates/0.6/r1864_scriptdev2.sql diff --git a/sql/updates/r1865_mangos.sql b/sql/updates/0.6/r1865_mangos.sql similarity index 100% rename from sql/updates/r1865_mangos.sql rename to sql/updates/0.6/r1865_mangos.sql diff --git a/sql/updates/r1865_scriptdev2.sql b/sql/updates/0.6/r1865_scriptdev2.sql similarity index 100% rename from sql/updates/r1865_scriptdev2.sql rename to sql/updates/0.6/r1865_scriptdev2.sql diff --git a/sql/updates/r1866_scriptdev2.sql b/sql/updates/0.6/r1866_scriptdev2.sql similarity index 100% rename from sql/updates/r1866_scriptdev2.sql rename to sql/updates/0.6/r1866_scriptdev2.sql diff --git a/sql/updates/r1868_scriptdev2.sql b/sql/updates/0.6/r1868_scriptdev2.sql similarity index 100% rename from sql/updates/r1868_scriptdev2.sql rename to sql/updates/0.6/r1868_scriptdev2.sql diff --git a/sql/updates/r1869_mangos.sql b/sql/updates/0.6/r1869_mangos.sql similarity index 100% rename from sql/updates/r1869_mangos.sql rename to sql/updates/0.6/r1869_mangos.sql diff --git a/sql/updates/r1871_mangos.sql b/sql/updates/0.6/r1871_mangos.sql similarity index 100% rename from sql/updates/r1871_mangos.sql rename to sql/updates/0.6/r1871_mangos.sql diff --git a/sql/updates/r1875_mangos.sql b/sql/updates/0.6/r1875_mangos.sql similarity index 100% rename from sql/updates/r1875_mangos.sql rename to sql/updates/0.6/r1875_mangos.sql diff --git a/sql/updates/r1875_scriptdev2.sql b/sql/updates/0.6/r1875_scriptdev2.sql similarity index 100% rename from sql/updates/r1875_scriptdev2.sql rename to sql/updates/0.6/r1875_scriptdev2.sql diff --git a/sql/updates/r1876_mangos.sql b/sql/updates/0.6/r1876_mangos.sql similarity index 100% rename from sql/updates/r1876_mangos.sql rename to sql/updates/0.6/r1876_mangos.sql diff --git a/sql/updates/r1876_scriptdev2.sql b/sql/updates/0.6/r1876_scriptdev2.sql similarity index 100% rename from sql/updates/r1876_scriptdev2.sql rename to sql/updates/0.6/r1876_scriptdev2.sql diff --git a/sql/updates/r1878_mangos.sql b/sql/updates/0.6/r1878_mangos.sql similarity index 100% rename from sql/updates/r1878_mangos.sql rename to sql/updates/0.6/r1878_mangos.sql diff --git a/sql/updates/r1881_mangos.sql b/sql/updates/0.6/r1881_mangos.sql similarity index 100% rename from sql/updates/r1881_mangos.sql rename to sql/updates/0.6/r1881_mangos.sql diff --git a/sql/updates/r1882_scriptdev2.sql b/sql/updates/0.6/r1882_scriptdev2.sql similarity index 100% rename from sql/updates/r1882_scriptdev2.sql rename to sql/updates/0.6/r1882_scriptdev2.sql diff --git a/sql/updates/r1886_scriptdev2.sql b/sql/updates/0.6/r1886_scriptdev2.sql similarity index 100% rename from sql/updates/r1886_scriptdev2.sql rename to sql/updates/0.6/r1886_scriptdev2.sql diff --git a/sql/updates/r1888_mangos.sql b/sql/updates/0.6/r1888_mangos.sql similarity index 100% rename from sql/updates/r1888_mangos.sql rename to sql/updates/0.6/r1888_mangos.sql diff --git a/sql/updates/r1888_scriptdev2.sql b/sql/updates/0.6/r1888_scriptdev2.sql similarity index 100% rename from sql/updates/r1888_scriptdev2.sql rename to sql/updates/0.6/r1888_scriptdev2.sql diff --git a/sql/updates/r1889_mangos.sql b/sql/updates/0.6/r1889_mangos.sql similarity index 100% rename from sql/updates/r1889_mangos.sql rename to sql/updates/0.6/r1889_mangos.sql diff --git a/sql/updates/r1889_scriptdev2.sql b/sql/updates/0.6/r1889_scriptdev2.sql similarity index 100% rename from sql/updates/r1889_scriptdev2.sql rename to sql/updates/0.6/r1889_scriptdev2.sql diff --git a/sql/updates/r1890_mangos.sql b/sql/updates/0.6/r1890_mangos.sql similarity index 100% rename from sql/updates/r1890_mangos.sql rename to sql/updates/0.6/r1890_mangos.sql diff --git a/sql/updates/r1890_scriptdev2.sql b/sql/updates/0.6/r1890_scriptdev2.sql similarity index 100% rename from sql/updates/r1890_scriptdev2.sql rename to sql/updates/0.6/r1890_scriptdev2.sql diff --git a/sql/updates/r1891_mangos.sql b/sql/updates/0.6/r1891_mangos.sql similarity index 100% rename from sql/updates/r1891_mangos.sql rename to sql/updates/0.6/r1891_mangos.sql diff --git a/sql/updates/r1899_mangos.sql b/sql/updates/0.6/r1899_mangos.sql similarity index 100% rename from sql/updates/r1899_mangos.sql rename to sql/updates/0.6/r1899_mangos.sql diff --git a/sql/updates/r1899_scriptdev2.sql b/sql/updates/0.6/r1899_scriptdev2.sql similarity index 100% rename from sql/updates/r1899_scriptdev2.sql rename to sql/updates/0.6/r1899_scriptdev2.sql diff --git a/sql/updates/r1908_scriptdev2.sql b/sql/updates/0.6/r1908_scriptdev2.sql similarity index 100% rename from sql/updates/r1908_scriptdev2.sql rename to sql/updates/0.6/r1908_scriptdev2.sql diff --git a/sql/updates/r1913_mangos.sql b/sql/updates/0.6/r1913_mangos.sql similarity index 100% rename from sql/updates/r1913_mangos.sql rename to sql/updates/0.6/r1913_mangos.sql diff --git a/sql/updates/r1914_scriptdev2.sql b/sql/updates/0.6/r1914_scriptdev2.sql similarity index 100% rename from sql/updates/r1914_scriptdev2.sql rename to sql/updates/0.6/r1914_scriptdev2.sql diff --git a/sql/updates/r1918_scriptdev2.sql b/sql/updates/0.6/r1918_scriptdev2.sql similarity index 100% rename from sql/updates/r1918_scriptdev2.sql rename to sql/updates/0.6/r1918_scriptdev2.sql diff --git a/sql/updates/r1921_scriptdev2.sql b/sql/updates/0.6/r1921_scriptdev2.sql similarity index 100% rename from sql/updates/r1921_scriptdev2.sql rename to sql/updates/0.6/r1921_scriptdev2.sql diff --git a/sql/updates/r1924_mangos.sql b/sql/updates/0.6/r1924_mangos.sql similarity index 100% rename from sql/updates/r1924_mangos.sql rename to sql/updates/0.6/r1924_mangos.sql diff --git a/sql/updates/r1924_scriptdev2.sql b/sql/updates/0.6/r1924_scriptdev2.sql similarity index 100% rename from sql/updates/r1924_scriptdev2.sql rename to sql/updates/0.6/r1924_scriptdev2.sql diff --git a/sql/updates/r1936_mangos.sql b/sql/updates/0.6/r1936_mangos.sql similarity index 100% rename from sql/updates/r1936_mangos.sql rename to sql/updates/0.6/r1936_mangos.sql diff --git a/sql/updates/r1940_mangos.sql b/sql/updates/0.6/r1940_mangos.sql similarity index 100% rename from sql/updates/r1940_mangos.sql rename to sql/updates/0.6/r1940_mangos.sql diff --git a/sql/updates/r1946_scriptdev2.sql b/sql/updates/0.6/r1946_scriptdev2.sql similarity index 100% rename from sql/updates/r1946_scriptdev2.sql rename to sql/updates/0.6/r1946_scriptdev2.sql diff --git a/sql/updates/r1949_scriptdev2.sql b/sql/updates/0.6/r1949_scriptdev2.sql similarity index 100% rename from sql/updates/r1949_scriptdev2.sql rename to sql/updates/0.6/r1949_scriptdev2.sql diff --git a/sql/updates/r1951_scriptdev2.sql b/sql/updates/0.6/r1951_scriptdev2.sql similarity index 100% rename from sql/updates/r1951_scriptdev2.sql rename to sql/updates/0.6/r1951_scriptdev2.sql diff --git a/sql/updates/r1954_mangos.sql b/sql/updates/0.6/r1954_mangos.sql similarity index 100% rename from sql/updates/r1954_mangos.sql rename to sql/updates/0.6/r1954_mangos.sql diff --git a/sql/updates/r1962_mangos.sql b/sql/updates/0.6/r1962_mangos.sql similarity index 100% rename from sql/updates/r1962_mangos.sql rename to sql/updates/0.6/r1962_mangos.sql diff --git a/sql/updates/r1962_scriptdev2.sql b/sql/updates/0.6/r1962_scriptdev2.sql similarity index 100% rename from sql/updates/r1962_scriptdev2.sql rename to sql/updates/0.6/r1962_scriptdev2.sql diff --git a/sql/updates/r1963_scriptdev2.sql b/sql/updates/0.6/r1963_scriptdev2.sql similarity index 100% rename from sql/updates/r1963_scriptdev2.sql rename to sql/updates/0.6/r1963_scriptdev2.sql diff --git a/sql/updates/r1965_mangos.sql b/sql/updates/0.6/r1965_mangos.sql similarity index 100% rename from sql/updates/r1965_mangos.sql rename to sql/updates/0.6/r1965_mangos.sql diff --git a/sql/updates/r1965_scriptdev2.sql b/sql/updates/0.6/r1965_scriptdev2.sql similarity index 100% rename from sql/updates/r1965_scriptdev2.sql rename to sql/updates/0.6/r1965_scriptdev2.sql diff --git a/sql/updates/r1968_scriptdev2.sql b/sql/updates/0.6/r1968_scriptdev2.sql similarity index 100% rename from sql/updates/r1968_scriptdev2.sql rename to sql/updates/0.6/r1968_scriptdev2.sql diff --git a/sql/updates/r1972_scriptdev2.sql b/sql/updates/0.6/r1972_scriptdev2.sql similarity index 100% rename from sql/updates/r1972_scriptdev2.sql rename to sql/updates/0.6/r1972_scriptdev2.sql diff --git a/sql/updates/r1973_mangos.sql b/sql/updates/0.6/r1973_mangos.sql similarity index 100% rename from sql/updates/r1973_mangos.sql rename to sql/updates/0.6/r1973_mangos.sql diff --git a/sql/updates/r1974_mangos.sql b/sql/updates/0.6/r1974_mangos.sql similarity index 100% rename from sql/updates/r1974_mangos.sql rename to sql/updates/0.6/r1974_mangos.sql diff --git a/sql/updates/r1975_scriptdev2.sql b/sql/updates/0.6/r1975_scriptdev2.sql similarity index 100% rename from sql/updates/r1975_scriptdev2.sql rename to sql/updates/0.6/r1975_scriptdev2.sql diff --git a/sql/updates/r1979_scriptdev2.sql b/sql/updates/0.6/r1979_scriptdev2.sql similarity index 100% rename from sql/updates/r1979_scriptdev2.sql rename to sql/updates/0.6/r1979_scriptdev2.sql diff --git a/sql/updates/r1982_mangos.sql b/sql/updates/0.6/r1982_mangos.sql similarity index 100% rename from sql/updates/r1982_mangos.sql rename to sql/updates/0.6/r1982_mangos.sql diff --git a/sql/updates/r1982_scriptdev2.sql b/sql/updates/0.6/r1982_scriptdev2.sql similarity index 100% rename from sql/updates/r1982_scriptdev2.sql rename to sql/updates/0.6/r1982_scriptdev2.sql diff --git a/sql/updates/r1984_mangos.sql b/sql/updates/0.6/r1984_mangos.sql similarity index 100% rename from sql/updates/r1984_mangos.sql rename to sql/updates/0.6/r1984_mangos.sql diff --git a/sql/updates/r1984_scriptdev2.sql b/sql/updates/0.6/r1984_scriptdev2.sql similarity index 100% rename from sql/updates/r1984_scriptdev2.sql rename to sql/updates/0.6/r1984_scriptdev2.sql diff --git a/sql/updates/r1987_mangos.sql b/sql/updates/0.6/r1987_mangos.sql similarity index 100% rename from sql/updates/r1987_mangos.sql rename to sql/updates/0.6/r1987_mangos.sql diff --git a/sql/updates/r1990_mangos.sql b/sql/updates/0.6/r1990_mangos.sql similarity index 100% rename from sql/updates/r1990_mangos.sql rename to sql/updates/0.6/r1990_mangos.sql diff --git a/sql/updates/r1990_scriptdev2.sql b/sql/updates/0.6/r1990_scriptdev2.sql similarity index 100% rename from sql/updates/r1990_scriptdev2.sql rename to sql/updates/0.6/r1990_scriptdev2.sql diff --git a/sql/updates/r1992_mangos.sql b/sql/updates/0.6/r1992_mangos.sql similarity index 100% rename from sql/updates/r1992_mangos.sql rename to sql/updates/0.6/r1992_mangos.sql diff --git a/sql/updates/r1992_scriptdev2.sql b/sql/updates/0.6/r1992_scriptdev2.sql similarity index 100% rename from sql/updates/r1992_scriptdev2.sql rename to sql/updates/0.6/r1992_scriptdev2.sql diff --git a/sql/updates/r1993_mangos.sql b/sql/updates/0.6/r1993_mangos.sql similarity index 100% rename from sql/updates/r1993_mangos.sql rename to sql/updates/0.6/r1993_mangos.sql diff --git a/sql/updates/r1993_scriptdev2.sql b/sql/updates/0.6/r1993_scriptdev2.sql similarity index 100% rename from sql/updates/r1993_scriptdev2.sql rename to sql/updates/0.6/r1993_scriptdev2.sql diff --git a/sql/updates/r2004_mangos.sql b/sql/updates/0.6/r2004_mangos.sql similarity index 100% rename from sql/updates/r2004_mangos.sql rename to sql/updates/0.6/r2004_mangos.sql diff --git a/sql/updates/r2008_mangos.sql b/sql/updates/0.6/r2008_mangos.sql similarity index 100% rename from sql/updates/r2008_mangos.sql rename to sql/updates/0.6/r2008_mangos.sql diff --git a/sql/updates/r2008_scriptdev2.sql b/sql/updates/0.6/r2008_scriptdev2.sql similarity index 100% rename from sql/updates/r2008_scriptdev2.sql rename to sql/updates/0.6/r2008_scriptdev2.sql diff --git a/sql/updates/r2009_mangos.sql b/sql/updates/0.6/r2009_mangos.sql similarity index 100% rename from sql/updates/r2009_mangos.sql rename to sql/updates/0.6/r2009_mangos.sql diff --git a/sql/updates/r2009_scriptdev2.sql b/sql/updates/0.6/r2009_scriptdev2.sql similarity index 100% rename from sql/updates/r2009_scriptdev2.sql rename to sql/updates/0.6/r2009_scriptdev2.sql diff --git a/sql/updates/r2010_mangos.sql b/sql/updates/0.6/r2010_mangos.sql similarity index 100% rename from sql/updates/r2010_mangos.sql rename to sql/updates/0.6/r2010_mangos.sql diff --git a/sql/updates/r2013_mangos.sql b/sql/updates/0.6/r2013_mangos.sql similarity index 100% rename from sql/updates/r2013_mangos.sql rename to sql/updates/0.6/r2013_mangos.sql diff --git a/sql/updates/r2013_scriptdev2.sql b/sql/updates/0.6/r2013_scriptdev2.sql similarity index 100% rename from sql/updates/r2013_scriptdev2.sql rename to sql/updates/0.6/r2013_scriptdev2.sql diff --git a/sql/updates/r2015_mangos.sql b/sql/updates/0.6/r2015_mangos.sql similarity index 100% rename from sql/updates/r2015_mangos.sql rename to sql/updates/0.6/r2015_mangos.sql diff --git a/sql/updates/r2017_mangos.sql b/sql/updates/0.6/r2017_mangos.sql similarity index 100% rename from sql/updates/r2017_mangos.sql rename to sql/updates/0.6/r2017_mangos.sql diff --git a/sql/updates/r2018_scriptdev2.sql b/sql/updates/0.6/r2018_scriptdev2.sql similarity index 100% rename from sql/updates/r2018_scriptdev2.sql rename to sql/updates/0.6/r2018_scriptdev2.sql diff --git a/sql/updates/r2020_scriptdev2.sql b/sql/updates/0.6/r2020_scriptdev2.sql similarity index 100% rename from sql/updates/r2020_scriptdev2.sql rename to sql/updates/0.6/r2020_scriptdev2.sql diff --git a/sql/updates/r2021_mangos.sql b/sql/updates/0.6/r2021_mangos.sql similarity index 100% rename from sql/updates/r2021_mangos.sql rename to sql/updates/0.6/r2021_mangos.sql diff --git a/sql/updates/r2024_mangos.sql b/sql/updates/0.6/r2024_mangos.sql similarity index 100% rename from sql/updates/r2024_mangos.sql rename to sql/updates/0.6/r2024_mangos.sql diff --git a/sql/updates/r2025_mangos.sql b/sql/updates/0.6/r2025_mangos.sql similarity index 100% rename from sql/updates/r2025_mangos.sql rename to sql/updates/0.6/r2025_mangos.sql diff --git a/sql/updates/r2028_scriptdev2.sql b/sql/updates/0.6/r2028_scriptdev2.sql similarity index 100% rename from sql/updates/r2028_scriptdev2.sql rename to sql/updates/0.6/r2028_scriptdev2.sql diff --git a/sql/updates/r2031_mangos.sql b/sql/updates/0.6/r2031_mangos.sql similarity index 100% rename from sql/updates/r2031_mangos.sql rename to sql/updates/0.6/r2031_mangos.sql diff --git a/sql/updates/r2031_scriptdev2.sql b/sql/updates/0.6/r2031_scriptdev2.sql similarity index 100% rename from sql/updates/r2031_scriptdev2.sql rename to sql/updates/0.6/r2031_scriptdev2.sql diff --git a/sql/updates/r2033_scriptdev2.sql b/sql/updates/0.6/r2033_scriptdev2.sql similarity index 100% rename from sql/updates/r2033_scriptdev2.sql rename to sql/updates/0.6/r2033_scriptdev2.sql diff --git a/sql/updates/r2036_scriptdev2.sql b/sql/updates/0.6/r2036_scriptdev2.sql similarity index 100% rename from sql/updates/r2036_scriptdev2.sql rename to sql/updates/0.6/r2036_scriptdev2.sql diff --git a/sql/updates/r2037_mangos.sql b/sql/updates/0.6/r2037_mangos.sql similarity index 100% rename from sql/updates/r2037_mangos.sql rename to sql/updates/0.6/r2037_mangos.sql diff --git a/sql/updates/r2038_mangos.sql b/sql/updates/0.6/r2038_mangos.sql similarity index 100% rename from sql/updates/r2038_mangos.sql rename to sql/updates/0.6/r2038_mangos.sql diff --git a/sql/updates/r2039_mangos.sql b/sql/updates/0.6/r2039_mangos.sql similarity index 100% rename from sql/updates/r2039_mangos.sql rename to sql/updates/0.6/r2039_mangos.sql diff --git a/sql/updates/r2043_scriptdev2.sql b/sql/updates/0.6/r2043_scriptdev2.sql similarity index 100% rename from sql/updates/r2043_scriptdev2.sql rename to sql/updates/0.6/r2043_scriptdev2.sql diff --git a/sql/updates/r2044_mangos.sql b/sql/updates/0.6/r2044_mangos.sql similarity index 100% rename from sql/updates/r2044_mangos.sql rename to sql/updates/0.6/r2044_mangos.sql diff --git a/sql/updates/r2044_scriptdev2.sql b/sql/updates/0.6/r2044_scriptdev2.sql similarity index 100% rename from sql/updates/r2044_scriptdev2.sql rename to sql/updates/0.6/r2044_scriptdev2.sql diff --git a/sql/updates/r2050_mangos.sql b/sql/updates/0.6/r2050_mangos.sql similarity index 100% rename from sql/updates/r2050_mangos.sql rename to sql/updates/0.6/r2050_mangos.sql diff --git a/sql/updates/r2051_scriptdev2.sql b/sql/updates/0.6/r2051_scriptdev2.sql similarity index 100% rename from sql/updates/r2051_scriptdev2.sql rename to sql/updates/0.6/r2051_scriptdev2.sql diff --git a/sql/updates/r2057_scriptdev2.sql b/sql/updates/0.6/r2057_scriptdev2.sql similarity index 100% rename from sql/updates/r2057_scriptdev2.sql rename to sql/updates/0.6/r2057_scriptdev2.sql diff --git a/sql/updates/r2059_mangos.sql b/sql/updates/0.6/r2059_mangos.sql similarity index 100% rename from sql/updates/r2059_mangos.sql rename to sql/updates/0.6/r2059_mangos.sql diff --git a/sql/updates/r2059_scriptdev2.sql b/sql/updates/0.6/r2059_scriptdev2.sql similarity index 100% rename from sql/updates/r2059_scriptdev2.sql rename to sql/updates/0.6/r2059_scriptdev2.sql diff --git a/sql/updates/r2061_mangos.sql b/sql/updates/0.6/r2061_mangos.sql similarity index 100% rename from sql/updates/r2061_mangos.sql rename to sql/updates/0.6/r2061_mangos.sql diff --git a/sql/updates/r2064_mangos.sql b/sql/updates/0.6/r2064_mangos.sql similarity index 100% rename from sql/updates/r2064_mangos.sql rename to sql/updates/0.6/r2064_mangos.sql diff --git a/sql/updates/r2064_scriptdev2.sql b/sql/updates/0.6/r2064_scriptdev2.sql similarity index 100% rename from sql/updates/r2064_scriptdev2.sql rename to sql/updates/0.6/r2064_scriptdev2.sql diff --git a/sql/updates/r2070_mangos.sql b/sql/updates/0.6/r2070_mangos.sql similarity index 100% rename from sql/updates/r2070_mangos.sql rename to sql/updates/0.6/r2070_mangos.sql diff --git a/sql/updates/r2072_scriptdev2.sql b/sql/updates/0.6/r2072_scriptdev2.sql similarity index 100% rename from sql/updates/r2072_scriptdev2.sql rename to sql/updates/0.6/r2072_scriptdev2.sql diff --git a/sql/updates/r2073_mangos.sql b/sql/updates/0.6/r2073_mangos.sql similarity index 100% rename from sql/updates/r2073_mangos.sql rename to sql/updates/0.6/r2073_mangos.sql diff --git a/sql/updates/r2073_scriptdev2.sql b/sql/updates/0.6/r2073_scriptdev2.sql similarity index 100% rename from sql/updates/r2073_scriptdev2.sql rename to sql/updates/0.6/r2073_scriptdev2.sql diff --git a/sql/updates/r2074_scriptdev2.sql b/sql/updates/0.6/r2074_scriptdev2.sql similarity index 100% rename from sql/updates/r2074_scriptdev2.sql rename to sql/updates/0.6/r2074_scriptdev2.sql diff --git a/sql/updates/r2075_mangos.sql b/sql/updates/0.6/r2075_mangos.sql similarity index 100% rename from sql/updates/r2075_mangos.sql rename to sql/updates/0.6/r2075_mangos.sql diff --git a/sql/updates/r2076_scriptdev2.sql b/sql/updates/0.6/r2076_scriptdev2.sql similarity index 100% rename from sql/updates/r2076_scriptdev2.sql rename to sql/updates/0.6/r2076_scriptdev2.sql diff --git a/sql/updates/r2077_mangos.sql b/sql/updates/0.6/r2077_mangos.sql similarity index 100% rename from sql/updates/r2077_mangos.sql rename to sql/updates/0.6/r2077_mangos.sql diff --git a/sql/updates/r2077_scriptdev2.sql b/sql/updates/0.6/r2077_scriptdev2.sql similarity index 100% rename from sql/updates/r2077_scriptdev2.sql rename to sql/updates/0.6/r2077_scriptdev2.sql diff --git a/sql/updates/r2080_scriptdev2.sql b/sql/updates/0.6/r2080_scriptdev2.sql similarity index 100% rename from sql/updates/r2080_scriptdev2.sql rename to sql/updates/0.6/r2080_scriptdev2.sql diff --git a/sql/updates/r2092_mangos.sql b/sql/updates/0.6/r2092_mangos.sql similarity index 100% rename from sql/updates/r2092_mangos.sql rename to sql/updates/0.6/r2092_mangos.sql diff --git a/sql/updates/r2092_scriptdev2.sql b/sql/updates/0.6/r2092_scriptdev2.sql similarity index 100% rename from sql/updates/r2092_scriptdev2.sql rename to sql/updates/0.6/r2092_scriptdev2.sql diff --git a/sql/updates/r2101_mangos.sql b/sql/updates/0.6/r2101_mangos.sql similarity index 100% rename from sql/updates/r2101_mangos.sql rename to sql/updates/0.6/r2101_mangos.sql diff --git a/sql/updates/r2101_scriptdev2.sql b/sql/updates/0.6/r2101_scriptdev2.sql similarity index 100% rename from sql/updates/r2101_scriptdev2.sql rename to sql/updates/0.6/r2101_scriptdev2.sql diff --git a/sql/updates/r2107_scriptdev2.sql b/sql/updates/0.6/r2107_scriptdev2.sql similarity index 100% rename from sql/updates/r2107_scriptdev2.sql rename to sql/updates/0.6/r2107_scriptdev2.sql diff --git a/sql/updates/r2112_mangos.sql b/sql/updates/0.6/r2112_mangos.sql similarity index 100% rename from sql/updates/r2112_mangos.sql rename to sql/updates/0.6/r2112_mangos.sql diff --git a/sql/updates/r2112_scriptdev2.sql b/sql/updates/0.6/r2112_scriptdev2.sql similarity index 100% rename from sql/updates/r2112_scriptdev2.sql rename to sql/updates/0.6/r2112_scriptdev2.sql diff --git a/sql/updates/r2113_scriptdev2.sql b/sql/updates/0.6/r2113_scriptdev2.sql similarity index 100% rename from sql/updates/r2113_scriptdev2.sql rename to sql/updates/0.6/r2113_scriptdev2.sql diff --git a/sql/updates/r2114_scriptdev2.sql b/sql/updates/0.6/r2114_scriptdev2.sql similarity index 100% rename from sql/updates/r2114_scriptdev2.sql rename to sql/updates/0.6/r2114_scriptdev2.sql diff --git a/sql/updates/r2116_scriptdev2.sql b/sql/updates/0.6/r2116_scriptdev2.sql similarity index 100% rename from sql/updates/r2116_scriptdev2.sql rename to sql/updates/0.6/r2116_scriptdev2.sql diff --git a/sql/updates/r2130_scriptdev2.sql b/sql/updates/0.6/r2130_scriptdev2.sql similarity index 100% rename from sql/updates/r2130_scriptdev2.sql rename to sql/updates/0.6/r2130_scriptdev2.sql diff --git a/sql/updates/r2134_scriptdev2.sql b/sql/updates/0.6/r2134_scriptdev2.sql similarity index 100% rename from sql/updates/r2134_scriptdev2.sql rename to sql/updates/0.6/r2134_scriptdev2.sql diff --git a/sql/updates/r2138_mangos.sql b/sql/updates/0.6/r2138_mangos.sql similarity index 100% rename from sql/updates/r2138_mangos.sql rename to sql/updates/0.6/r2138_mangos.sql diff --git a/sql/updates/r2139_scriptdev2.sql b/sql/updates/0.6/r2139_scriptdev2.sql similarity index 100% rename from sql/updates/r2139_scriptdev2.sql rename to sql/updates/0.6/r2139_scriptdev2.sql diff --git a/sql/updates/r2146_scriptdev2.sql b/sql/updates/0.6/r2146_scriptdev2.sql similarity index 100% rename from sql/updates/r2146_scriptdev2.sql rename to sql/updates/0.6/r2146_scriptdev2.sql diff --git a/sql/updates/r2147_mangos.sql b/sql/updates/0.6/r2147_mangos.sql similarity index 100% rename from sql/updates/r2147_mangos.sql rename to sql/updates/0.6/r2147_mangos.sql diff --git a/sql/updates/r2147_scriptdev2.sql b/sql/updates/0.6/r2147_scriptdev2.sql similarity index 100% rename from sql/updates/r2147_scriptdev2.sql rename to sql/updates/0.6/r2147_scriptdev2.sql diff --git a/sql/updates/r2162_scriptdev2.sql b/sql/updates/0.6/r2162_scriptdev2.sql similarity index 100% rename from sql/updates/r2162_scriptdev2.sql rename to sql/updates/0.6/r2162_scriptdev2.sql diff --git a/sql/updates/r2181_scriptdev2.sql b/sql/updates/0.6/r2181_scriptdev2.sql similarity index 100% rename from sql/updates/r2181_scriptdev2.sql rename to sql/updates/0.6/r2181_scriptdev2.sql diff --git a/sql/updates/r2212_mangos.sql b/sql/updates/0.6/r2212_mangos.sql similarity index 100% rename from sql/updates/r2212_mangos.sql rename to sql/updates/0.6/r2212_mangos.sql diff --git a/sql/updates/r2212_scriptdev2.sql b/sql/updates/0.6/r2212_scriptdev2.sql similarity index 100% rename from sql/updates/r2212_scriptdev2.sql rename to sql/updates/0.6/r2212_scriptdev2.sql diff --git a/sql/updates/r2220_scriptdev2.sql b/sql/updates/0.6/r2220_scriptdev2.sql similarity index 100% rename from sql/updates/r2220_scriptdev2.sql rename to sql/updates/0.6/r2220_scriptdev2.sql diff --git a/sql/updates/r2227_mangos.sql b/sql/updates/0.6/r2227_mangos.sql similarity index 100% rename from sql/updates/r2227_mangos.sql rename to sql/updates/0.6/r2227_mangos.sql diff --git a/sql/updates/r2229_mangos.sql b/sql/updates/0.6/r2229_mangos.sql similarity index 100% rename from sql/updates/r2229_mangos.sql rename to sql/updates/0.6/r2229_mangos.sql diff --git a/sql/updates/r2235_mangos.sql b/sql/updates/0.6/r2235_mangos.sql similarity index 100% rename from sql/updates/r2235_mangos.sql rename to sql/updates/0.6/r2235_mangos.sql diff --git a/sql/updates/r2235_scriptdev2.sql b/sql/updates/0.6/r2235_scriptdev2.sql similarity index 100% rename from sql/updates/r2235_scriptdev2.sql rename to sql/updates/0.6/r2235_scriptdev2.sql diff --git a/sql/updates/r2239_scriptdev2.sql b/sql/updates/0.6/r2239_scriptdev2.sql similarity index 100% rename from sql/updates/r2239_scriptdev2.sql rename to sql/updates/0.6/r2239_scriptdev2.sql diff --git a/sql/updates/r2242_scriptdev2.sql b/sql/updates/0.6/r2242_scriptdev2.sql similarity index 100% rename from sql/updates/r2242_scriptdev2.sql rename to sql/updates/0.6/r2242_scriptdev2.sql diff --git a/sql/updates/r2243_scriptdev2.sql b/sql/updates/0.6/r2243_scriptdev2.sql similarity index 100% rename from sql/updates/r2243_scriptdev2.sql rename to sql/updates/0.6/r2243_scriptdev2.sql diff --git a/sql/updates/r2245_scriptdev2.sql b/sql/updates/0.6/r2245_scriptdev2.sql similarity index 100% rename from sql/updates/r2245_scriptdev2.sql rename to sql/updates/0.6/r2245_scriptdev2.sql diff --git a/sql/updates/r2246_scriptdev2.sql b/sql/updates/0.6/r2246_scriptdev2.sql similarity index 100% rename from sql/updates/r2246_scriptdev2.sql rename to sql/updates/0.6/r2246_scriptdev2.sql diff --git a/sql/updates/r2247_scriptdev2.sql b/sql/updates/0.6/r2247_scriptdev2.sql similarity index 100% rename from sql/updates/r2247_scriptdev2.sql rename to sql/updates/0.6/r2247_scriptdev2.sql diff --git a/sql/updates/r2248_scriptdev2.sql b/sql/updates/0.6/r2248_scriptdev2.sql similarity index 100% rename from sql/updates/r2248_scriptdev2.sql rename to sql/updates/0.6/r2248_scriptdev2.sql diff --git a/sql/updates/r2249_scriptdev2.sql b/sql/updates/0.6/r2249_scriptdev2.sql similarity index 100% rename from sql/updates/r2249_scriptdev2.sql rename to sql/updates/0.6/r2249_scriptdev2.sql diff --git a/sql/updates/r2250_mangos.sql b/sql/updates/0.6/r2250_mangos.sql similarity index 100% rename from sql/updates/r2250_mangos.sql rename to sql/updates/0.6/r2250_mangos.sql diff --git a/sql/updates/r2250_scriptdev2.sql b/sql/updates/0.6/r2250_scriptdev2.sql similarity index 100% rename from sql/updates/r2250_scriptdev2.sql rename to sql/updates/0.6/r2250_scriptdev2.sql diff --git a/sql/updates/r2252_mangos.sql b/sql/updates/0.6/r2252_mangos.sql similarity index 100% rename from sql/updates/r2252_mangos.sql rename to sql/updates/0.6/r2252_mangos.sql diff --git a/sql/updates/r2254_scriptdev2.sql b/sql/updates/0.6/r2254_scriptdev2.sql similarity index 100% rename from sql/updates/r2254_scriptdev2.sql rename to sql/updates/0.6/r2254_scriptdev2.sql diff --git a/sql/updates/r2255_mangos.sql b/sql/updates/0.6/r2255_mangos.sql similarity index 100% rename from sql/updates/r2255_mangos.sql rename to sql/updates/0.6/r2255_mangos.sql diff --git a/sql/updates/r2263_mangos.sql b/sql/updates/0.6/r2263_mangos.sql similarity index 100% rename from sql/updates/r2263_mangos.sql rename to sql/updates/0.6/r2263_mangos.sql diff --git a/sql/updates/r2268_mangos.sql b/sql/updates/0.6/r2268_mangos.sql similarity index 100% rename from sql/updates/r2268_mangos.sql rename to sql/updates/0.6/r2268_mangos.sql diff --git a/sql/updates/r2268_scriptdev2.sql b/sql/updates/0.6/r2268_scriptdev2.sql similarity index 100% rename from sql/updates/r2268_scriptdev2.sql rename to sql/updates/0.6/r2268_scriptdev2.sql diff --git a/sql/updates/r2270_scriptdev2.sql b/sql/updates/0.6/r2270_scriptdev2.sql similarity index 100% rename from sql/updates/r2270_scriptdev2.sql rename to sql/updates/0.6/r2270_scriptdev2.sql diff --git a/sql/updates/r2273_mangos.sql b/sql/updates/0.6/r2273_mangos.sql similarity index 100% rename from sql/updates/r2273_mangos.sql rename to sql/updates/0.6/r2273_mangos.sql diff --git a/sql/updates/r2277_scriptdev2.sql b/sql/updates/0.6/r2277_scriptdev2.sql similarity index 100% rename from sql/updates/r2277_scriptdev2.sql rename to sql/updates/0.6/r2277_scriptdev2.sql diff --git a/sql/updates/r2284_scriptdev2.sql b/sql/updates/0.6/r2284_scriptdev2.sql similarity index 100% rename from sql/updates/r2284_scriptdev2.sql rename to sql/updates/0.6/r2284_scriptdev2.sql diff --git a/sql/updates/r2286_mangos.sql b/sql/updates/0.6/r2286_mangos.sql similarity index 100% rename from sql/updates/r2286_mangos.sql rename to sql/updates/0.6/r2286_mangos.sql diff --git a/sql/updates/r2289_mangos.sql b/sql/updates/0.6/r2289_mangos.sql similarity index 100% rename from sql/updates/r2289_mangos.sql rename to sql/updates/0.6/r2289_mangos.sql diff --git a/sql/updates/r2289_scriptdev2.sql b/sql/updates/0.6/r2289_scriptdev2.sql similarity index 100% rename from sql/updates/r2289_scriptdev2.sql rename to sql/updates/0.6/r2289_scriptdev2.sql diff --git a/sql/updates/r2298_scriptdev2.sql b/sql/updates/0.6/r2298_scriptdev2.sql similarity index 100% rename from sql/updates/r2298_scriptdev2.sql rename to sql/updates/0.6/r2298_scriptdev2.sql diff --git a/sql/updates/r2300_scriptdev2.sql b/sql/updates/0.6/r2300_scriptdev2.sql similarity index 100% rename from sql/updates/r2300_scriptdev2.sql rename to sql/updates/0.6/r2300_scriptdev2.sql diff --git a/sql/updates/r2305_scriptdev2.sql b/sql/updates/0.6/r2305_scriptdev2.sql similarity index 100% rename from sql/updates/r2305_scriptdev2.sql rename to sql/updates/0.6/r2305_scriptdev2.sql diff --git a/sql/updates/r2306_mangos.sql b/sql/updates/0.6/r2306_mangos.sql similarity index 100% rename from sql/updates/r2306_mangos.sql rename to sql/updates/0.6/r2306_mangos.sql diff --git a/sql/updates/r2307_mangos.sql b/sql/updates/0.6/r2307_mangos.sql similarity index 100% rename from sql/updates/r2307_mangos.sql rename to sql/updates/0.6/r2307_mangos.sql diff --git a/sql/updates/r2309_mangos.sql b/sql/updates/0.6/r2309_mangos.sql similarity index 100% rename from sql/updates/r2309_mangos.sql rename to sql/updates/0.6/r2309_mangos.sql diff --git a/sql/updates/r2309_scriptdev2.sql b/sql/updates/0.6/r2309_scriptdev2.sql similarity index 100% rename from sql/updates/r2309_scriptdev2.sql rename to sql/updates/0.6/r2309_scriptdev2.sql diff --git a/sql/updates/r2310_scriptdev2.sql b/sql/updates/0.6/r2310_scriptdev2.sql similarity index 100% rename from sql/updates/r2310_scriptdev2.sql rename to sql/updates/0.6/r2310_scriptdev2.sql diff --git a/sql/updates/r2313_mangos.sql b/sql/updates/0.6/r2313_mangos.sql similarity index 100% rename from sql/updates/r2313_mangos.sql rename to sql/updates/0.6/r2313_mangos.sql diff --git a/sql/updates/r2313_scriptdev2.sql b/sql/updates/0.6/r2313_scriptdev2.sql similarity index 100% rename from sql/updates/r2313_scriptdev2.sql rename to sql/updates/0.6/r2313_scriptdev2.sql diff --git a/sql/updates/r2314_mangos.sql b/sql/updates/0.6/r2314_mangos.sql similarity index 100% rename from sql/updates/r2314_mangos.sql rename to sql/updates/0.6/r2314_mangos.sql diff --git a/sql/updates/r2314_scriptdev2.sql b/sql/updates/0.6/r2314_scriptdev2.sql similarity index 100% rename from sql/updates/r2314_scriptdev2.sql rename to sql/updates/0.6/r2314_scriptdev2.sql diff --git a/sql/updates/r2318_mangos.sql b/sql/updates/0.6/r2318_mangos.sql similarity index 100% rename from sql/updates/r2318_mangos.sql rename to sql/updates/0.6/r2318_mangos.sql diff --git a/sql/updates/r2318_scriptdev2.sql b/sql/updates/0.6/r2318_scriptdev2.sql similarity index 97% rename from sql/updates/r2318_scriptdev2.sql rename to sql/updates/0.6/r2318_scriptdev2.sql index da6ae8ad4..2cc5a85a8 100644 --- a/sql/updates/r2318_scriptdev2.sql +++ b/sql/updates/0.6/r2318_scriptdev2.sql @@ -1,4 +1,4 @@ -DELETE FROM script_texts WHERE entry BETWEEN -1000771 AND -1000780; +DELETE FROM script_texts WHERE entry BETWEEN -1000780 AND -1000771; INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES (-1000771,'Let\'s go $N!',0,0,0,0,'Feero Ironhand SAY_QUEST_START'), (-1000772,'It looks like we\'re in trouble. Look lively, here they come!',0,0,0,0,'Feero Ironhand SAY_FIRST_AMBUSH_START'), diff --git a/sql/updates/r2320_mangos.sql b/sql/updates/0.6/r2320_mangos.sql similarity index 100% rename from sql/updates/r2320_mangos.sql rename to sql/updates/0.6/r2320_mangos.sql diff --git a/sql/updates/r2321_scriptdev2.sql b/sql/updates/0.6/r2321_scriptdev2.sql similarity index 100% rename from sql/updates/r2321_scriptdev2.sql rename to sql/updates/0.6/r2321_scriptdev2.sql diff --git a/sql/updates/r2323_mangos.sql b/sql/updates/0.6/r2323_mangos.sql similarity index 100% rename from sql/updates/r2323_mangos.sql rename to sql/updates/0.6/r2323_mangos.sql diff --git a/sql/updates/r2324_mangos.sql b/sql/updates/0.6/r2324_mangos.sql similarity index 100% rename from sql/updates/r2324_mangos.sql rename to sql/updates/0.6/r2324_mangos.sql diff --git a/sql/updates/r2325_mangos.sql b/sql/updates/0.6/r2325_mangos.sql similarity index 100% rename from sql/updates/r2325_mangos.sql rename to sql/updates/0.6/r2325_mangos.sql diff --git a/sql/updates/r2325_scriptdev2.sql b/sql/updates/0.6/r2325_scriptdev2.sql similarity index 100% rename from sql/updates/r2325_scriptdev2.sql rename to sql/updates/0.6/r2325_scriptdev2.sql diff --git a/sql/updates/r2326_mangos.sql b/sql/updates/0.6/r2326_mangos.sql similarity index 100% rename from sql/updates/r2326_mangos.sql rename to sql/updates/0.6/r2326_mangos.sql diff --git a/sql/updates/r2328_mangos.sql b/sql/updates/0.6/r2328_mangos.sql similarity index 100% rename from sql/updates/r2328_mangos.sql rename to sql/updates/0.6/r2328_mangos.sql diff --git a/sql/updates/r2345_mangos.sql b/sql/updates/0.6/r2345_mangos.sql similarity index 100% rename from sql/updates/r2345_mangos.sql rename to sql/updates/0.6/r2345_mangos.sql diff --git a/sql/updates/r2347_mangos.sql b/sql/updates/0.6/r2347_mangos.sql similarity index 100% rename from sql/updates/r2347_mangos.sql rename to sql/updates/0.6/r2347_mangos.sql diff --git a/sql/updates/r2348_scriptdev2.sql b/sql/updates/0.6/r2348_scriptdev2.sql similarity index 100% rename from sql/updates/r2348_scriptdev2.sql rename to sql/updates/0.6/r2348_scriptdev2.sql diff --git a/sql/updates/r2355_mangos.sql b/sql/updates/0.6/r2355_mangos.sql similarity index 100% rename from sql/updates/r2355_mangos.sql rename to sql/updates/0.6/r2355_mangos.sql diff --git a/sql/updates/r2357_mangos.sql b/sql/updates/0.6/r2357_mangos.sql similarity index 100% rename from sql/updates/r2357_mangos.sql rename to sql/updates/0.6/r2357_mangos.sql diff --git a/sql/updates/r2359_mangos.sql b/sql/updates/0.6/r2359_mangos.sql similarity index 100% rename from sql/updates/r2359_mangos.sql rename to sql/updates/0.6/r2359_mangos.sql diff --git a/sql/updates/r2359_scriptdev2.sql b/sql/updates/0.6/r2359_scriptdev2.sql similarity index 100% rename from sql/updates/r2359_scriptdev2.sql rename to sql/updates/0.6/r2359_scriptdev2.sql diff --git a/sql/updates/r2360_scriptdev2.sql b/sql/updates/0.6/r2360_scriptdev2.sql similarity index 100% rename from sql/updates/r2360_scriptdev2.sql rename to sql/updates/0.6/r2360_scriptdev2.sql diff --git a/sql/updates/r2361_mangos.sql b/sql/updates/0.6/r2361_mangos.sql similarity index 100% rename from sql/updates/r2361_mangos.sql rename to sql/updates/0.6/r2361_mangos.sql diff --git a/sql/updates/r2364_scriptdev2.sql b/sql/updates/0.6/r2364_scriptdev2.sql similarity index 100% rename from sql/updates/r2364_scriptdev2.sql rename to sql/updates/0.6/r2364_scriptdev2.sql diff --git a/sql/updates/r2369_mangos.sql b/sql/updates/0.6/r2369_mangos.sql similarity index 100% rename from sql/updates/r2369_mangos.sql rename to sql/updates/0.6/r2369_mangos.sql diff --git a/sql/updates/r2370_mangos.sql b/sql/updates/0.6/r2370_mangos.sql similarity index 100% rename from sql/updates/r2370_mangos.sql rename to sql/updates/0.6/r2370_mangos.sql diff --git a/sql/updates/r2371_mangos.sql b/sql/updates/0.6/r2371_mangos.sql similarity index 100% rename from sql/updates/r2371_mangos.sql rename to sql/updates/0.6/r2371_mangos.sql diff --git a/sql/updates/r2372_mangos.sql b/sql/updates/0.6/r2372_mangos.sql similarity index 100% rename from sql/updates/r2372_mangos.sql rename to sql/updates/0.6/r2372_mangos.sql diff --git a/sql/updates/r2373_mangos.sql b/sql/updates/0.6/r2373_mangos.sql similarity index 100% rename from sql/updates/r2373_mangos.sql rename to sql/updates/0.6/r2373_mangos.sql diff --git a/sql/updates/r2374_mangos.sql b/sql/updates/0.6/r2374_mangos.sql similarity index 100% rename from sql/updates/r2374_mangos.sql rename to sql/updates/0.6/r2374_mangos.sql diff --git a/sql/updates/r2374_scriptdev2.sql b/sql/updates/0.6/r2374_scriptdev2.sql similarity index 100% rename from sql/updates/r2374_scriptdev2.sql rename to sql/updates/0.6/r2374_scriptdev2.sql diff --git a/sql/updates/r2375_mangos.sql b/sql/updates/0.6/r2375_mangos.sql similarity index 100% rename from sql/updates/r2375_mangos.sql rename to sql/updates/0.6/r2375_mangos.sql diff --git a/sql/updates/r2383_scriptdev2.sql b/sql/updates/0.6/r2383_scriptdev2.sql similarity index 100% rename from sql/updates/r2383_scriptdev2.sql rename to sql/updates/0.6/r2383_scriptdev2.sql diff --git a/sql/updates/r2385_mangos.sql b/sql/updates/0.6/r2385_mangos.sql similarity index 100% rename from sql/updates/r2385_mangos.sql rename to sql/updates/0.6/r2385_mangos.sql diff --git a/sql/updates/r2385_scriptdev2.sql b/sql/updates/0.6/r2385_scriptdev2.sql similarity index 100% rename from sql/updates/r2385_scriptdev2.sql rename to sql/updates/0.6/r2385_scriptdev2.sql diff --git a/sql/updates/r2387_mangos.sql b/sql/updates/0.6/r2387_mangos.sql similarity index 100% rename from sql/updates/r2387_mangos.sql rename to sql/updates/0.6/r2387_mangos.sql diff --git a/sql/updates/r2397_scriptdev2.sql b/sql/updates/0.6/r2397_scriptdev2.sql similarity index 100% rename from sql/updates/r2397_scriptdev2.sql rename to sql/updates/0.6/r2397_scriptdev2.sql diff --git a/sql/updates/r2399_scriptdev2.sql b/sql/updates/0.6/r2399_scriptdev2.sql similarity index 100% rename from sql/updates/r2399_scriptdev2.sql rename to sql/updates/0.6/r2399_scriptdev2.sql diff --git a/sql/updates/r2400_scriptdev2.sql b/sql/updates/0.6/r2400_scriptdev2.sql similarity index 100% rename from sql/updates/r2400_scriptdev2.sql rename to sql/updates/0.6/r2400_scriptdev2.sql diff --git a/sql/updates/r2409_mangos.sql b/sql/updates/0.6/r2409_mangos.sql similarity index 100% rename from sql/updates/r2409_mangos.sql rename to sql/updates/0.6/r2409_mangos.sql diff --git a/sql/updates/r2409_scriptdev2.sql b/sql/updates/0.6/r2409_scriptdev2.sql similarity index 100% rename from sql/updates/r2409_scriptdev2.sql rename to sql/updates/0.6/r2409_scriptdev2.sql diff --git a/sql/updates/r2416_mangos.sql b/sql/updates/0.6/r2416_mangos.sql similarity index 100% rename from sql/updates/r2416_mangos.sql rename to sql/updates/0.6/r2416_mangos.sql diff --git a/sql/updates/r2422_mangos.sql b/sql/updates/0.6/r2422_mangos.sql similarity index 100% rename from sql/updates/r2422_mangos.sql rename to sql/updates/0.6/r2422_mangos.sql diff --git a/sql/updates/r2445_mangos.sql b/sql/updates/0.6/r2445_mangos.sql similarity index 100% rename from sql/updates/r2445_mangos.sql rename to sql/updates/0.6/r2445_mangos.sql diff --git a/sql/updates/r2446_mangos.sql b/sql/updates/0.6/r2446_mangos.sql similarity index 100% rename from sql/updates/r2446_mangos.sql rename to sql/updates/0.6/r2446_mangos.sql diff --git a/sql/updates/r2447_mangos.sql b/sql/updates/0.6/r2447_mangos.sql similarity index 100% rename from sql/updates/r2447_mangos.sql rename to sql/updates/0.6/r2447_mangos.sql diff --git a/sql/updates/r2447_scriptdev2.sql b/sql/updates/0.6/r2447_scriptdev2.sql similarity index 100% rename from sql/updates/r2447_scriptdev2.sql rename to sql/updates/0.6/r2447_scriptdev2.sql diff --git a/sql/updates/r2448_scriptdev2.sql b/sql/updates/0.6/r2448_scriptdev2.sql similarity index 100% rename from sql/updates/r2448_scriptdev2.sql rename to sql/updates/0.6/r2448_scriptdev2.sql diff --git a/sql/updates/r2450_mangos.sql b/sql/updates/0.6/r2450_mangos.sql similarity index 100% rename from sql/updates/r2450_mangos.sql rename to sql/updates/0.6/r2450_mangos.sql diff --git a/sql/updates/r2450_scriptdev2.sql b/sql/updates/0.6/r2450_scriptdev2.sql similarity index 100% rename from sql/updates/r2450_scriptdev2.sql rename to sql/updates/0.6/r2450_scriptdev2.sql diff --git a/sql/updates/r2459_mangos.sql b/sql/updates/0.6/r2459_mangos.sql similarity index 100% rename from sql/updates/r2459_mangos.sql rename to sql/updates/0.6/r2459_mangos.sql diff --git a/sql/updates/r2461_scriptdev2.sql b/sql/updates/0.6/r2461_scriptdev2.sql similarity index 100% rename from sql/updates/r2461_scriptdev2.sql rename to sql/updates/0.6/r2461_scriptdev2.sql diff --git a/sql/updates/r2462_mangos.sql b/sql/updates/0.6/r2462_mangos.sql similarity index 100% rename from sql/updates/r2462_mangos.sql rename to sql/updates/0.6/r2462_mangos.sql diff --git a/sql/updates/r2462_scriptdev2.sql b/sql/updates/0.6/r2462_scriptdev2.sql similarity index 100% rename from sql/updates/r2462_scriptdev2.sql rename to sql/updates/0.6/r2462_scriptdev2.sql diff --git a/sql/updates/r2463_mangos.sql b/sql/updates/0.6/r2463_mangos.sql similarity index 100% rename from sql/updates/r2463_mangos.sql rename to sql/updates/0.6/r2463_mangos.sql diff --git a/sql/updates/r2472_scriptdev2.sql b/sql/updates/0.6/r2472_scriptdev2.sql similarity index 100% rename from sql/updates/r2472_scriptdev2.sql rename to sql/updates/0.6/r2472_scriptdev2.sql diff --git a/sql/updates/r2479_mangos.sql b/sql/updates/0.6/r2479_mangos.sql similarity index 100% rename from sql/updates/r2479_mangos.sql rename to sql/updates/0.6/r2479_mangos.sql diff --git a/sql/updates/r2480_mangos.sql b/sql/updates/0.6/r2480_mangos.sql similarity index 100% rename from sql/updates/r2480_mangos.sql rename to sql/updates/0.6/r2480_mangos.sql diff --git a/sql/updates/r2481_mangos.sql b/sql/updates/0.6/r2481_mangos.sql similarity index 100% rename from sql/updates/r2481_mangos.sql rename to sql/updates/0.6/r2481_mangos.sql diff --git a/sql/updates/r2482_mangos.sql b/sql/updates/0.6/r2482_mangos.sql similarity index 100% rename from sql/updates/r2482_mangos.sql rename to sql/updates/0.6/r2482_mangos.sql diff --git a/sql/updates/r2484_mangos.sql b/sql/updates/0.6/r2484_mangos.sql similarity index 100% rename from sql/updates/r2484_mangos.sql rename to sql/updates/0.6/r2484_mangos.sql diff --git a/sql/updates/r2484_scriptdev2.sql b/sql/updates/0.6/r2484_scriptdev2.sql similarity index 100% rename from sql/updates/r2484_scriptdev2.sql rename to sql/updates/0.6/r2484_scriptdev2.sql diff --git a/sql/updates/r2488_scriptdev2.sql b/sql/updates/0.6/r2488_scriptdev2.sql similarity index 100% rename from sql/updates/r2488_scriptdev2.sql rename to sql/updates/0.6/r2488_scriptdev2.sql diff --git a/sql/updates/r2490_mangos.sql b/sql/updates/0.6/r2490_mangos.sql similarity index 100% rename from sql/updates/r2490_mangos.sql rename to sql/updates/0.6/r2490_mangos.sql diff --git a/sql/updates/r2490_scriptdev2.sql b/sql/updates/0.6/r2490_scriptdev2.sql similarity index 100% rename from sql/updates/r2490_scriptdev2.sql rename to sql/updates/0.6/r2490_scriptdev2.sql diff --git a/sql/updates/r2491_mangos.sql b/sql/updates/0.6/r2491_mangos.sql similarity index 100% rename from sql/updates/r2491_mangos.sql rename to sql/updates/0.6/r2491_mangos.sql diff --git a/sql/updates/r2491_scriptdev2.sql b/sql/updates/0.6/r2491_scriptdev2.sql similarity index 100% rename from sql/updates/r2491_scriptdev2.sql rename to sql/updates/0.6/r2491_scriptdev2.sql diff --git a/sql/updates/r2492_mangos.sql b/sql/updates/0.6/r2492_mangos.sql similarity index 100% rename from sql/updates/r2492_mangos.sql rename to sql/updates/0.6/r2492_mangos.sql diff --git a/sql/updates/r2493_mangos.sql b/sql/updates/0.6/r2493_mangos.sql similarity index 100% rename from sql/updates/r2493_mangos.sql rename to sql/updates/0.6/r2493_mangos.sql diff --git a/sql/updates/r2494_mangos.sql b/sql/updates/0.6/r2494_mangos.sql similarity index 100% rename from sql/updates/r2494_mangos.sql rename to sql/updates/0.6/r2494_mangos.sql diff --git a/sql/updates/r2495_mangos.sql b/sql/updates/0.6/r2495_mangos.sql similarity index 100% rename from sql/updates/r2495_mangos.sql rename to sql/updates/0.6/r2495_mangos.sql diff --git a/sql/updates/r2496_mangos.sql b/sql/updates/0.6/r2496_mangos.sql similarity index 100% rename from sql/updates/r2496_mangos.sql rename to sql/updates/0.6/r2496_mangos.sql diff --git a/sql/updates/r2497_mangos.sql b/sql/updates/0.6/r2497_mangos.sql similarity index 100% rename from sql/updates/r2497_mangos.sql rename to sql/updates/0.6/r2497_mangos.sql diff --git a/sql/updates/r2498_mangos.sql b/sql/updates/0.6/r2498_mangos.sql similarity index 100% rename from sql/updates/r2498_mangos.sql rename to sql/updates/0.6/r2498_mangos.sql diff --git a/sql/updates/r2499_mangos.sql b/sql/updates/0.6/r2499_mangos.sql similarity index 100% rename from sql/updates/r2499_mangos.sql rename to sql/updates/0.6/r2499_mangos.sql diff --git a/sql/updates/r2501_mangos.sql b/sql/updates/0.6/r2501_mangos.sql similarity index 100% rename from sql/updates/r2501_mangos.sql rename to sql/updates/0.6/r2501_mangos.sql diff --git a/sql/updates/r2502_mangos.sql b/sql/updates/0.6/r2502_mangos.sql similarity index 100% rename from sql/updates/r2502_mangos.sql rename to sql/updates/0.6/r2502_mangos.sql diff --git a/sql/updates/r2503_scriptdev2.sql b/sql/updates/0.6/r2503_scriptdev2.sql similarity index 100% rename from sql/updates/r2503_scriptdev2.sql rename to sql/updates/0.6/r2503_scriptdev2.sql diff --git a/sql/updates/r2504_mangos.sql b/sql/updates/0.6/r2504_mangos.sql similarity index 100% rename from sql/updates/r2504_mangos.sql rename to sql/updates/0.6/r2504_mangos.sql diff --git a/sql/updates/r2509_mangos.sql b/sql/updates/0.6/r2509_mangos.sql similarity index 100% rename from sql/updates/r2509_mangos.sql rename to sql/updates/0.6/r2509_mangos.sql diff --git a/sql/updates/r2510_mangos.sql b/sql/updates/0.6/r2510_mangos.sql similarity index 100% rename from sql/updates/r2510_mangos.sql rename to sql/updates/0.6/r2510_mangos.sql diff --git a/sql/updates/r2511_mangos.sql b/sql/updates/0.6/r2511_mangos.sql similarity index 100% rename from sql/updates/r2511_mangos.sql rename to sql/updates/0.6/r2511_mangos.sql diff --git a/sql/updates/r2512_mangos.sql b/sql/updates/0.6/r2512_mangos.sql similarity index 100% rename from sql/updates/r2512_mangos.sql rename to sql/updates/0.6/r2512_mangos.sql diff --git a/sql/updates/r2514_mangos.sql b/sql/updates/0.6/r2514_mangos.sql similarity index 100% rename from sql/updates/r2514_mangos.sql rename to sql/updates/0.6/r2514_mangos.sql diff --git a/sql/updates/r2516_mangos.sql b/sql/updates/0.6/r2516_mangos.sql similarity index 100% rename from sql/updates/r2516_mangos.sql rename to sql/updates/0.6/r2516_mangos.sql diff --git a/sql/updates/r2518_mangos.sql b/sql/updates/0.6/r2518_mangos.sql similarity index 100% rename from sql/updates/r2518_mangos.sql rename to sql/updates/0.6/r2518_mangos.sql diff --git a/sql/updates/r2519_scriptdev2.sql b/sql/updates/0.6/r2519_scriptdev2.sql similarity index 100% rename from sql/updates/r2519_scriptdev2.sql rename to sql/updates/0.6/r2519_scriptdev2.sql diff --git a/sql/updates/r2525_mangos.sql b/sql/updates/0.6/r2525_mangos.sql similarity index 100% rename from sql/updates/r2525_mangos.sql rename to sql/updates/0.6/r2525_mangos.sql diff --git a/sql/updates/r2528_scriptdev2.sql b/sql/updates/0.6/r2528_scriptdev2.sql similarity index 100% rename from sql/updates/r2528_scriptdev2.sql rename to sql/updates/0.6/r2528_scriptdev2.sql diff --git a/sql/updates/0.6/r2532_mangos.sql b/sql/updates/0.6/r2532_mangos.sql new file mode 100644 index 000000000..30389eda6 --- /dev/null +++ b/sql/updates/0.6/r2532_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_redemption_target' WHERE entry IN (6172,6177,17542,17768); diff --git a/sql/updates/0.6/r2534_scriptdev2.sql b/sql/updates/0.6/r2534_scriptdev2.sql new file mode 100644 index 000000000..252155b51 --- /dev/null +++ b/sql/updates/0.6/r2534_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry=-1000193; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000193,'REUSE ME',0,0,0,0,'REUSE ME'); +UPDATE script_texts SET language=0, comment='npc_redemption_target SAY_HEAL' WHERE entry IN (-1000187); diff --git a/sql/updates/0.6/r2537_scriptdev2.sql b/sql/updates/0.6/r2537_scriptdev2.sql new file mode 100644 index 000000000..6c58d1938 --- /dev/null +++ b/sql/updates/0.6/r2537_scriptdev2.sql @@ -0,0 +1,29 @@ +DELETE FROM script_texts WHERE entry=-1000195; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000195,'Thank you again, $N. I\'ll make my way to the road now. When you can, find Terenthis and let him know we escaped.',0,0,0,1,'volcor SAY_ESCAPE'); +DELETE FROM script_waypoint WHERE entry=3692; +INSERT INTO script_waypoint VALUES +(3692, 1, 4608.43, -6.32, 69.74, 1000, 'stand up'), +(3692, 2, 4608.43, -6.32, 69.74, 4000, 'SAY_START'), +(3692, 3, 4604.54, -5.17, 69.51, 0, ''), +(3692, 4, 4604.26, -2.02, 69.42, 0, ''), +(3692, 5, 4607.75, 3.79, 70.13, 1000, 'first ambush'), +(3692, 6, 4607.75, 3.79, 70.13, 0, 'SAY_FIRST_AMBUSH'), +(3692, 7, 4619.77, 27.47, 70.40, 0, ''), +(3692, 8, 4626.28, 42.46, 68.75, 0, ''), +(3692, 9, 4633.13, 51.17, 67.40, 0, ''), +(3692, 10, 4639.67, 79.03, 61.74, 0, ''), +(3692, 11, 4647.54, 94.25, 59.92, 0, 'second ambush'), +(3692, 12, 4682.08, 113.47, 54.83, 0, ''), +(3692, 13, 4705.28, 137.81, 53.36, 0, 'last ambush'), +(3692, 14, 4730.30, 158.76, 52.33, 0, ''), +(3692, 15, 4756.47, 195.65, 53.61, 10000, 'SAY_END'), +(3692, 16, 4608.43, -6.32, 69.74, 1000, 'bow'), +(3692, 17, 4608.43, -6.32, 69.74, 4000, 'SAY_ESCAPE'), +(3692, 18, 4608.43, -6.32, 69.74, 4000, 'SPELL_MOONSTALKER_FORM'), +(3692, 19, 4604.54, -5.17, 69.51, 0, ''), +(3692, 20, 4604.26, -2.02, 69.42, 0, ''), +(3692, 21, 4607.75, 3.79, 70.13, 0, ''), +(3692, 22, 4607.75, 3.79, 70.13, 0, ''), +(3692, 23, 4619.77, 27.47, 70.40, 0, ''), +(3692, 24, 4640.33, 33.74, 68.22, 0, 'quest complete'); diff --git a/sql/updates/0.6/r2538_mangos.sql b/sql/updates/0.6/r2538_mangos.sql new file mode 100644 index 000000000..bfddcec62 --- /dev/null +++ b/sql/updates/0.6/r2538_mangos.sql @@ -0,0 +1,5 @@ +UPDATE instance_template SET ScriptName='instance_icecrown_citadel' WHERE map=631; +DELETE FROM scripted_event_id WHERE id IN (23426,23438); +INSERT INTO scripted_event_id VALUES +(23426,'event_gameobject_citadel_valve'), +(23438,'event_gameobject_citadel_valve'); diff --git a/sql/updates/0.6/r2539_mangos.sql b/sql/updates/0.6/r2539_mangos.sql new file mode 100644 index 000000000..b9c066073 --- /dev/null +++ b/sql/updates/0.6/r2539_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='boss_lord_marrowgar' WHERE entry=36612; +UPDATE creature_template SET ScriptName='boss_lady_deathwhisper' WHERE entry=36855; +UPDATE creature_template SET ScriptName='boss_deathbringer_saurfang' WHERE entry=37813; diff --git a/sql/updates/0.6/r2541_mangos.sql b/sql/updates/0.6/r2541_mangos.sql new file mode 100644 index 000000000..0d093b0e2 --- /dev/null +++ b/sql/updates/0.6/r2541_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=14965; +UPDATE creature_template SET ScriptName='npc_gurubashi_bat_rider' WHERE entry=14750; diff --git a/sql/updates/0.6/r2541_scriptdev2.sql b/sql/updates/0.6/r2541_scriptdev2.sql new file mode 100644 index 000000000..91b4800ea --- /dev/null +++ b/sql/updates/0.6/r2541_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1309025,-1309026,-1309027); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1309025,'The brood shall not fall!',0,1,0,0,'marli SAY_TRANSFORM_BACK'), +(-1309026,'%s emits a deafening shriek',0,2,0,0,'jeklik SAY_SHRIEK'), +(-1309027,'%s begins to cast a Great Heal!',0,2,0,0,'jeklik SAY_HEAL'); diff --git a/sql/updates/0.6/r2542_mangos.sql b/sql/updates/0.6/r2542_mangos.sql new file mode 100644 index 000000000..29549be4b --- /dev/null +++ b/sql/updates/0.6/r2542_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (5732); +INSERT INTO scripted_areatrigger VALUES +(5732,'at_icecrown_citadel'); diff --git a/sql/updates/0.6/r2543_mangos.sql b/sql/updates/0.6/r2543_mangos.sql new file mode 100644 index 000000000..79fe6bce6 --- /dev/null +++ b/sql/updates/0.6/r2543_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (5709); +INSERT INTO scripted_areatrigger VALUES +(5709,'at_icecrown_citadel'); diff --git a/sql/updates/0.6/r2544_mangos.sql b/sql/updates/0.6/r2544_mangos.sql new file mode 100644 index 000000000..422155843 --- /dev/null +++ b/sql/updates/0.6/r2544_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=15041; diff --git a/sql/updates/0.6/r2547_mangos.sql b/sql/updates/0.6/r2547_mangos.sql new file mode 100644 index 000000000..a0a0922fb --- /dev/null +++ b/sql/updates/0.6/r2547_mangos.sql @@ -0,0 +1,6 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18725; +UPDATE creature_template SET ScriptName='' WHERE entry=26443; +UPDATE creature_template SET ScriptName='' WHERE entry=26949; +UPDATE creature_template SET ScriptName='' WHERE entry=27575; +UPDATE creature_template SET ScriptName='' WHERE entry=20903; +UPDATE creature_template SET ScriptName='' WHERE entry=22112; diff --git a/sql/updates/0.6/r2548_scriptdev2.sql b/sql/updates/0.6/r2548_scriptdev2.sql new file mode 100644 index 000000000..415fe1380 --- /dev/null +++ b/sql/updates/0.6/r2548_scriptdev2.sql @@ -0,0 +1 @@ +DELETE FROM gossip_texts WHERE entry=-3560000; diff --git a/sql/updates/0.6/r2552_mangos.sql b/sql/updates/0.6/r2552_mangos.sql new file mode 100644 index 000000000..e89bb224a --- /dev/null +++ b/sql/updates/0.6/r2552_mangos.sql @@ -0,0 +1,4 @@ +UPDATE instance_template SET ScriptName='instance_ruby_sanctum' WHERE map=724; +UPDATE creature_template SET ScriptName='boss_baltharus' WHERE entry=39751; +UPDATE creature_template SET ScriptName='boss_saviana' WHERE entry=39747; +UPDATE creature_template SET ScriptName='boss_zarithrian' WHERE entry=39746; diff --git a/sql/updates/0.6/r2553_mangos.sql b/sql/updates/0.6/r2553_mangos.sql new file mode 100644 index 000000000..4e0713274 --- /dev/null +++ b/sql/updates/0.6/r2553_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=23998; +UPDATE creature_template SET ScriptName='' WHERE entry=23778; +UPDATE creature_template SET ScriptName='' WHERE entry=23859; diff --git a/sql/updates/0.6/r2553_scriptdev2.sql b/sql/updates/0.6/r2553_scriptdev2.sql new file mode 100644 index 000000000..a1d04e707 --- /dev/null +++ b/sql/updates/0.6/r2553_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM gossip_texts WHERE entry IN (-3000106,-3000107,-3000108,-3560000); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000106,'REUSE ME','REUSE ME'), +(-3000107,'REUSE ME','REUSE ME'), +(-3000108,'REUSE ME','REUSE ME'), +(-3560000,'REUSE ME','REUSE ME'); diff --git a/sql/updates/0.6/r2556_mangos.sql b/sql/updates/0.6/r2556_mangos.sql new file mode 100644 index 000000000..fa9a05fc3 --- /dev/null +++ b/sql/updates/0.6/r2556_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_viscidus' WHERE entry=15299; diff --git a/sql/updates/0.6/r2557_mangos.sql b/sql/updates/0.6/r2557_mangos.sql new file mode 100644 index 000000000..1de67a0e5 --- /dev/null +++ b/sql/updates/0.6/r2557_mangos.sql @@ -0,0 +1,6 @@ +DELETE FROM scripted_areatrigger WHERE entry in (4288,4485); +INSERT INTO scripted_areatrigger VALUES +(4288,'at_dark_portal'), +(4485,'at_dark_portal'); +UPDATE creature_template SET ScriptName='npc_medivh_black_morass' WHERE entry=15608; +UPDATE creature_template SET ScriptName='npc_time_rift_channeler' WHERE entry IN (21104,17839,21697,21698); diff --git a/sql/updates/0.6/r2559_scriptdev2.sql b/sql/updates/0.6/r2559_scriptdev2.sql new file mode 100644 index 000000000..1e11253c1 --- /dev/null +++ b/sql/updates/0.6/r2559_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1554028; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1554028,'I have been waiting for you!',0,1,0,0,'pathaleon SAY_INTRO'); diff --git a/sql/updates/0.6/r2561_mangos.sql b/sql/updates/0.6/r2561_mangos.sql new file mode 100644 index 000000000..a2d40acc0 --- /dev/null +++ b/sql/updates/0.6/r2561_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (24848); +DELETE FROM scripted_event_id WHERE id=16547; +INSERT INTO scripted_event_id VALUES +(16547,'event_go_scrying_orb'); diff --git a/sql/updates/0.6/r2562_mangos.sql b/sql/updates/0.6/r2562_mangos.sql new file mode 100644 index 000000000..a520c4342 --- /dev/null +++ b/sql/updates/0.6/r2562_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (21466,21467); diff --git a/sql/updates/0.6/r2563_mangos.sql b/sql/updates/0.6/r2563_mangos.sql new file mode 100644 index 000000000..102260379 --- /dev/null +++ b/sql/updates/0.6/r2563_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=23489; +UPDATE creature_template SET ScriptName='' WHERE entry IN (23483,23484); diff --git a/sql/updates/0.6/r2566_scriptdev2.sql b/sql/updates/0.6/r2566_scriptdev2.sql new file mode 100644 index 000000000..0266f5783 --- /dev/null +++ b/sql/updates/0.6/r2566_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1631193,-1631194); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1631193,'%s goes into a frenzy!',0,3,0,0,'saurfang EMOTE_FRENZY'), +(-1631194,'%s\'s Blood Beasts gain the scent of blood!',0,3,0,0,'saurfang EMOTE_SCENT'); diff --git a/sql/updates/0.6/r2567_mangos.sql b/sql/updates/0.6/r2567_mangos.sql new file mode 100644 index 000000000..1d0fbafe1 --- /dev/null +++ b/sql/updates/0.6/r2567_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (17900,17901); +UPDATE creature_template SET ScriptName='' WHERE entry=34885; diff --git a/sql/updates/0.6/r2567_scriptdev2.sql b/sql/updates/0.6/r2567_scriptdev2.sql new file mode 100644 index 000000000..8cc415215 --- /dev/null +++ b/sql/updates/0.6/r2567_scriptdev2.sql @@ -0,0 +1,2 @@ +DELETE FROM script_texts WHERE entry IN (-1000207); +INSERT INTO script_texts (entry,content_default,comment) VALUES (-1000207,'REUSE ME','REUSE ME'); diff --git a/sql/updates/0.6/r2568_mangos.sql b/sql/updates/0.6/r2568_mangos.sql new file mode 100644 index 000000000..9707d0274 --- /dev/null +++ b/sql/updates/0.6/r2568_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_event_id WHERE id=20651; +INSERT INTO scripted_event_id VALUES +(20651,'event_achiev_kings_bane'); diff --git a/sql/updates/0.6/r2571_mangos.sql b/sql/updates/0.6/r2571_mangos.sql new file mode 100644 index 000000000..81c929143 --- /dev/null +++ b/sql/updates/0.6/r2571_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='npc_gortok_subboss' WHERE entry IN (26683,26684,26685,26686); +DELETE FROM scripted_event_id WHERE id IN (17728); +INSERT INTO scripted_event_id VALUES +(17728,'event_spell_gortok_event'); diff --git a/sql/updates/0.6/r2573_mangos.sql b/sql/updates/0.6/r2573_mangos.sql new file mode 100644 index 000000000..836dd3d38 --- /dev/null +++ b/sql/updates/0.6/r2573_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='boss_drakkari_colossus' WHERE entry=29307; +UPDATE creature_template SET ScriptName='boss_drakkari_elemental' WHERE entry=29573; +UPDATE creature_template SET ScriptName='npc_living_mojo' WHERE entry=29830; diff --git a/sql/updates/0.6/r2574_scriptdev2.sql b/sql/updates/0.6/r2574_scriptdev2.sql new file mode 100644 index 000000000..a3aac9996 --- /dev/null +++ b/sql/updates/0.6/r2574_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1578022,-1578023); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578022,'The trickster Mage-Lord Urom protects the third ring. He will appear alone and defenseless, but do not be fooled by appearances! Urom is a powerful conjurer who commands a menagerie of Phantasmal creatures. Seek him out above.',0,0,0,1,'belgaristrasz SAY_BELGARISTRASZ_UROM'), +(-1578023,'Your greatest challenge lies ahead. Ley-Guardian Eregos is a Blue dragon of immense power. You will find him flying above the uppermost ring.',0,0,0,1,'belgaristrasz SAY_BELGARISTRASZ_EREGOS'); diff --git a/sql/updates/0.6/r2575_scriptdev2.sql b/sql/updates/0.6/r2575_scriptdev2.sql new file mode 100644 index 000000000..d76b80625 --- /dev/null +++ b/sql/updates/0.6/r2575_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1578024; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578024,'Anomalies form as %s shifts into the Astral Plane!',0,3,0,0,'eregos EMOTE_ASTRAL_PLANE'); diff --git a/sql/updates/0.6/r2576_scriptdev2.sql b/sql/updates/0.6/r2576_scriptdev2.sql new file mode 100644 index 000000000..244fd9cf9 --- /dev/null +++ b/sql/updates/0.6/r2576_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1578025; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578025,'%s begins to cast Empowered Arcane Explosion!',0,3,0,0,'urom EMOTE_EXPLOSION'); diff --git a/sql/updates/0.6/r2578_mangos.sql b/sql/updates/0.6/r2578_mangos.sql new file mode 100644 index 000000000..20ec0ac80 --- /dev/null +++ b/sql/updates/0.6/r2578_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_amanitar' WHERE entry=30258; +UPDATE creature_template SET ScriptName='npc_amanitar_mushroom' WHERE entry IN (30391,30435); diff --git a/sql/updates/0.6/r2580_mangos.sql b/sql/updates/0.6/r2580_mangos.sql new file mode 100644 index 000000000..cb2069445 --- /dev/null +++ b/sql/updates/0.6/r2580_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=8879; +UPDATE creature_template SET ScriptName='' WHERE entry=1855; diff --git a/sql/updates/0.6/r2581_mangos.sql b/sql/updates/0.6/r2581_mangos.sql new file mode 100644 index 000000000..c5ca2ac71 --- /dev/null +++ b/sql/updates/0.6/r2581_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_twilight_volunteer' WHERE entry=30385; diff --git a/sql/updates/0.6/r2582_mangos.sql b/sql/updates/0.6/r2582_mangos.sql new file mode 100644 index 000000000..e3d5fb5e3 --- /dev/null +++ b/sql/updates/0.6/r2582_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (21104,17839,21697,21698); diff --git a/sql/updates/0.6/r2584_mangos.sql b/sql/updates/0.6/r2584_mangos.sql new file mode 100644 index 000000000..e0655415d --- /dev/null +++ b/sql/updates/0.6/r2584_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_prison_event_controller' WHERE entry=30883; diff --git a/sql/updates/0.6/r2584_scriptdev2.sql b/sql/updates/0.6/r2584_scriptdev2.sql new file mode 100644 index 000000000..0a96c906e --- /dev/null +++ b/sql/updates/0.6/r2584_scriptdev2.sql @@ -0,0 +1,16 @@ +DELETE FROM script_texts WHERE entry IN (-1608000,-1608001,-1608027); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1608000,'Prison guards, we are leaving! These adventurers are taking over! Go, go, go!',0,1,0,0,'sinclari SAY_BEGIN'), +(-1608001,'I\'m locking the door. Good luck, and thank you for doing this.',0,0,0,1,'sinclari SAY_LOCK_DOOR'), +(-1608027,'You did it! You held the Blue Dragonflight back and defeated their commander. Amazing work!',0,0,0,1,'sinclari SAY_VICTORY'); +DELETE FROM gossip_texts WHERE entry IN (-3608002); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3608002,'I\'m not fighting, so send me in now!','sinclari GOSSIP_ITEM_TELEPORT'); +DELETE FROM script_waypoint WHERE entry=30658; +INSERT INTO script_waypoint VALUES +(30658, 0, 1830.504517, 799.356506, 44.341801, 5000, 'use activation'), +(30658, 1, 1832.461792, 800.431396, 44.311745, 10000, 'SAY_BEGIN call back guards'), +(30658, 2, 1824.786987, 803.828369, 44.363434, 3000, 'SAY_LOCK_DOOR'), +(30658, 3, 1824.786987, 803.828369, 44.363434, 0, 'close door'), +(30658, 4, 1817.315674, 804.060608, 44.363998, 0, 'escort paused - allow teleport inside'), +(30658, 5, 1826.889648, 803.929993, 44.363239, 30000, 'SAY_VICTORY'); diff --git a/sql/updates/0.6/r2585_mangos.sql b/sql/updates/0.6/r2585_mangos.sql new file mode 100644 index 000000000..b1140712e --- /dev/null +++ b/sql/updates/0.6/r2585_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_erekem_guard' WHERE entry=29395; diff --git a/sql/updates/0.6/r2586_scriptdev2.sql b/sql/updates/0.6/r2586_scriptdev2.sql new file mode 100644 index 000000000..0a53a4dc9 --- /dev/null +++ b/sql/updates/0.6/r2586_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1608028); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1608028,'%s\'s Protective Bubble shatters!',0,3,0,0,'ichoron EMOTE_BUBBLE'); diff --git a/sql/updates/0.6/r2590_scriptdev2.sql b/sql/updates/0.6/r2590_scriptdev2.sql new file mode 100644 index 000000000..f4592d2d7 --- /dev/null +++ b/sql/updates/0.6/r2590_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1533045,-1533046,-1533047,-1533052,-1533053,-1533054,-1533059,-1533060,-1533061,-1533071,-1533072,-1533073); diff --git a/sql/updates/0.6/r2591_mangos.sql b/sql/updates/0.6/r2591_mangos.sql new file mode 100644 index 000000000..f6c9e9fa1 --- /dev/null +++ b/sql/updates/0.6/r2591_mangos.sql @@ -0,0 +1,6 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=10918; +UPDATE creature_template SET ScriptName='' WHERE entry=7775; +UPDATE creature_template SET ScriptName='' WHERE entry=8612; +UPDATE creature_template SET ScriptName='' WHERE entry=3052; +UPDATE creature_template SET ScriptName='' WHERE entry=19679; +UPDATE creature_template SET ScriptName='' WHERE entry=18266; diff --git a/sql/updates/0.6/r2595_mangos.sql b/sql/updates/0.6/r2595_mangos.sql new file mode 100644 index 000000000..a44ff675e --- /dev/null +++ b/sql/updates/0.6/r2595_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='boss_anzu' WHERE entry=23035; +DELETE FROM scripted_event_id WHERE id=14797; +INSERT INTO scripted_event_id VALUES +(14797,'event_spell_summon_raven_god'); diff --git a/sql/updates/0.6/r2597_mangos.sql b/sql/updates/0.6/r2597_mangos.sql new file mode 100644 index 000000000..cc3043bb4 --- /dev/null +++ b/sql/updates/0.6/r2597_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_eris_havenfire' WHERE entry=14494; diff --git a/sql/updates/0.6/r2597_scriptdev2.sql b/sql/updates/0.6/r2597_scriptdev2.sql new file mode 100644 index 000000000..11bae9151 --- /dev/null +++ b/sql/updates/0.6/r2597_scriptdev2.sql @@ -0,0 +1,9 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000821 AND -1000815; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000815,'Be healed!',0,1,0,0,'Eris Havenfire SAY_PHASE_HEAL'), +(-1000816,'We are saved! The peasants have escaped the Scourge!',0,1,0,0,'Eris Havenfire SAY_EVENT_END'), +(-1000817,'I have failed once more...',0,1,0,0,'Eris Havenfire SAY_EVENT_FAIL_1'), +(-1000818,'I now return to whence I came, only to find myself here once more to relive the same epic tragedy.',0,0,0,0,'Eris Havenfire SAY_EVENT_FAIL_2'), +(-1000819,'The Scourge are upon us! Run! Run for your lives!',0,1,0,0,'Peasant SAY_PEASANT_APPEAR_1'), +(-1000820,'Please help us! The Prince has gone mad!',0,1,0,0,'Peasant SAY_PEASANT_APPEAR_2'), +(-1000821,'Seek sanctuary in Hearthglen! It is our only hope!',0,1,0,0,'Peasant SAY_PEASANT_APPEAR_3'); diff --git a/sql/updates/0.6/r2598_scriptdev2.sql b/sql/updates/0.6/r2598_scriptdev2.sql new file mode 100644 index 000000000..19bdd36cc --- /dev/null +++ b/sql/updates/0.6/r2598_scriptdev2.sql @@ -0,0 +1,7 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1556020 AND -1556016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1556016,'No! How can this be?',0,1,0,0,'anzu SAY_INTRO_1'), +(-1556017,'Pain will be the price for your insolence! You cannot stop me from claiming the Emerald Dream as my own!',0,1,0,0,'anzu SAY_INTRO_2'), +(-1556018,'Awaken, my children and assist your master!',0,1,0,0,'anzu SAY_BANISH'), +(-1556019,'Your magics shall be your undoing... ak-a-ak...',0,4,0,0,'anzu SAY_WHISPER_MAGIC'), +(-1556020,'%s returns to stone.',0,2,0,0,'anzu EMOTE_BIRD_STONE'); diff --git a/sql/updates/0.6/r2601_mangos.sql b/sql/updates/0.6/r2601_mangos.sql new file mode 100644 index 000000000..f6f99233e --- /dev/null +++ b/sql/updates/0.6/r2601_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_squire_rowe' WHERE entry=17804; diff --git a/sql/updates/0.6/r2601_scriptdev2.sql b/sql/updates/0.6/r2601_scriptdev2.sql new file mode 100644 index 000000000..ab8d87891 --- /dev/null +++ b/sql/updates/0.6/r2601_scriptdev2.sql @@ -0,0 +1,17 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000824 AND -1000822; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000822,'The signal has been sent. He should be arriving shortly.',0,0,0,1,'squire rowe SAY_SIGNAL_SENT'), +(-1000823,'Yawww!',0,0,0,35,'reginald windsor SAY_DISMOUNT'), +(-1000824,'I knew you would come, $N. It is good to see you again, friend.',0,0,0,1,'reginald windsor SAY_WELCOME'); +DELETE FROM gossip_texts WHERE entry=-3000106; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000106,'Let Marshal Windsor know that I am ready.','squire rowe GOSSIP_ITEM_WINDSOR'); +DELETE FROM script_waypoint WHERE entry=17804; +INSERT INTO script_waypoint VALUES +(17804, 0, -9054.86, 443.58, 93.05, 0, ''), +(17804, 1, -9079.33, 424.49, 92.52, 0, ''), +(17804, 2, -9086.21, 419.02, 92.32, 3000, ''), +(17804, 3, -9086.21, 419.02, 92.32, 1000, ''), +(17804, 4, -9079.33, 424.49, 92.52, 0, ''), +(17804, 5, -9054.38, 436.30, 93.05, 0, ''), +(17804, 6, -9042.23, 434.24, 93.37, 5000, 'SAY_SIGNAL_SENT'); diff --git a/sql/updates/0.6/r2603_mangos.sql b/sql/updates/0.6/r2603_mangos.sql new file mode 100644 index 000000000..8aa1f5b89 --- /dev/null +++ b/sql/updates/0.6/r2603_mangos.sql @@ -0,0 +1,2 @@ +DELETE FROM scripted_areatrigger WHERE entry=1966; +INSERT INTO scripted_areatrigger VALUES (1966,'at_murkdeep'); diff --git a/sql/updates/0.6/r2604_mangos.sql b/sql/updates/0.6/r2604_mangos.sql new file mode 100644 index 000000000..8a830c20d --- /dev/null +++ b/sql/updates/0.6/r2604_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_reginald_windsor' WHERE entry =12580; diff --git a/sql/updates/0.6/r2604_scriptdev2.sql b/sql/updates/0.6/r2604_scriptdev2.sql new file mode 100644 index 000000000..396b8d435 --- /dev/null +++ b/sql/updates/0.6/r2604_scriptdev2.sql @@ -0,0 +1,82 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000872 AND -1000825; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000825,'On guard, friend. The lady dragon will not give in without a fight.',0,0,0,1,'reginald windsor SAY_QUEST_ACCEPT'), +(-1000826,'As was fated a lifetime ago in Karazhan, monster - I come - and with me I bring justice.',0,6,0,22,'reginald windsor SAY_GET_READY'), +(-1000827,'Seize him! Seize the worthless criminal and his allies!',0,6,0,0,'prestor SAY_GONNA_DIE'), +(-1000828,'Reginald, you know that I cannot let you pass.',0,0,0,1,'jonathan SAY_DIALOG_1'), +(-1000829,'You must do what you think is right, Marcus. We served together under Turalyon. He made us both the men that we are today. Did he err with me? Do you truly believe my intent is to cause harm to our alliance? Would I shame our heroes?',0,0,0,1,'reginald windsor SAY_DIALOG_2'), +(-1000830,'Holding me here is not the right decision, Marcus.',0,0,0,1,'reginald windsor SAY_DIALOG_3'), +(-1000831,'%s appears lost in contemplation.',0,2,0,0,'jonathan EMOTE_CONTEMPLATION'), +(-1000832,'I am ashamed, old friend. I know not what I do anymore. It is not you that would dare bring shame to the heroes of legend - it is I. It is I and the rest of these corrupt politicians. They fill our lives with empty promises, unending lies.',0,0,0,1,'jonathan SAY_DIALOG_4'), +(-1000833,'We shame our ancestors. We shame those lost to us... forgive me, Reginald.',0,0,0,1,'jonathan SAY_DIALOG_5'), +(-1000834,'Dear friend, you honor them with your vigilant watch. You are steadfast in your allegiance. I do not doubt for a moment that you would not give as great a sacrifice for your people as any of the heroes you stand under.',0,0,0,1,'reginald windsor SAY_DIALOG_6'), +(-1000835,'Now, it is time to bring her reign to an end, Marcus. Stand down, friend.',0,0,0,1,'reginald windsor SAY_DIALOG_7'), +(-1000836,'Stand down! Can you not see that heroes walk among us?',0,0,0,5,'jonathan SAY_DIALOG_8'), +(-1000837,'Move aside! Let them pass!',0,0,0,5,'jonathan SAY_DIALOG_9'), +(-1000838,'Reginald Windsor is not to be harmed! He shall pass through untouched!',0,1,0,22,'jonathan SAY_DIALOG_10'), +(-1000839,'Go, Reginald. May the light guide your hand.',0,0,0,1,'jonathan SAY_DIALOG_11'), +(-1000840,'Thank you, old friend. You have done the right thing.',0,0,0,1,'reginald windsor SAY_DIALOG_12'), +(-1000841,'Follow me, friends. To Stormwind Keep!',0,0,0,0,'reginald windsor SAY_DIALOG_13'), +(-1000842,'Light be with you, sir.',0,0,0,66,'guard SAY_1'), +(-1000843,'We are but dirt beneath your feet, sir.',0,0,0,66,'guard SAY_2'), +(-1000844,'...nerves of thorium.',0,0,0,66,'guard SAY_3'), +(-1000845,'Make way!',0,0,0,66,'guard SAY_4'), +(-1000846,'A living legend...',0,0,0,66,'guard SAY_5'), +(-1000847,'A moment I shall remember for always.',0,0,0,66,'guard SAY_6'), +(-1000848,'You are an inspiration to us all, sir.',0,0,0,66,'guard SAY_7'), +(-1000849,'Be brave, friends. The reptile will thrash wildly. It is an act of desperation. When you are ready, give me the word.',0,0,0,25,'reginald windsor SAY_BEFORE_KEEP'), +(-1000850,'Onward!',0,0,0,5,'reginald windsor SAY_GO_TO_KEEP'), +(-1000851,'Majesty, run while you still can. She is not what you think her to be...',0,0,0,1,'reginald windsor SAY_IN_KEEP_1'), +(-1000852,'To the safe hall, your majesty.',0,0,0,1,'bolvar SAY_IN_KEEP_2'), +(-1000853,'The masquerade is over, Lady Prestor. Or should I call you by your true name... Onyxia...',0,0,0,25,'reginald windsor SAY_IN_KEEP_3'), +(-1000854,'%s laughs.',0,2,0,11,'prestor EMOTE_IN_KEEP_LAUGH'), +(-1000855,'You will be incarcerated and tried for treason, Windsor. I shall watch with glee as they hand down a guilty verdict and sentence you to death by hanging...',0,0,0,1,'prestor SAY_IN_KEEP_4'), +(-1000856,'And as your limp body dangles from the rafters, I shall take pleasure in knowing that a mad man has been put to death. After all, what proof do you have? Did you expect to come in here and point your fingers at royalty and leave unscathed?',0,0,0,6,'prestor SAY_IN_KEEP_5'), +(-1000857,'You will not escape your fate, Onyxia. It has been prophesied - a vision resonating from the great halls of Karazhan. It ends now...',0,0,0,1,'reginald windsor SAY_IN_KEEP_6'), +(-1000858,'%s reaches into his pack and pulls out the encoded tablets...',0,2,0,0,'reginald windsor EMOTE_IN_KEEP_REACH'), +(-1000859,'The Dark Irons thought these tablets to be encoded. This is not any form of coding, it is the tongue of ancient dragon.',0,0,0,1,'reginald windsor SAY_IN_KEEP_7'), +(-1000860,'Listen, dragon. Let the truth resonate throughout these halls.',0,0,0,1,'reginald windsor SAY_IN_KEEP_8'), +(-1000861,'%s reads from the tablets. Unknown, unheard sounds flow through your consciousness',0,2,0,0,'reginald windsor EMOTE_IN_KEEP_READ'), +(-1000862,'%s gasps.',0,2,0,0,'bolvar EMOTE_IN_KEEP_GASP'), +(-1000863,'Curious... Windsor, in this vision, did you survive? I only ask because one thing that I can and will assure is your death. Here and now.',0,0,0,1,'onyxia SAY_IN_KEEP_9'), +(-1000864,'Dragon filth! Guards! Guards! Seize this monster!',0,1,0,22,'bolvar SAY_IN_KEEP_1'), +(-1000865,'Yesss... Guards, come to your lord\'s aid!',0,0,0,1,'onyxia SAY_IN_KEEP_10'), +(-1000866,'DO NOT LET HER ESCAPE!',0,0,0,1,'reginald windsor SAY_IN_KEEP_11'), +(-1000867,'Was this fabled, Windsor? If it was death that you came for then the prophecy has been fulfilled. May your consciousness rot in the Twisting Nether. Finish the rest of these meddlesome insects, children. Bolvar, you have been a pleasureable puppet.',0,0,0,0,'onyxia SAY_IN_KEEP_12'), +(-1000868,'You have failed him, mortalsss... Farewell!',0,1,0,0,'onyxia SAY_IN_KEEP_12'), +(-1000869,'Reginald... I... I am sorry.',0,0,0,0,'bolvar SAY_IN_KEEP_13'), +(-1000870,'Bol... Bolvar... the medallion... use...',0,0,0,0,'reginald windsor SAY_IN_KEEP_14'), +(-1000871,'%s dies.',0,2,0,0,'reginald windsor EMOTE_IN_KEEP_DIE'), +(-1000872,'%s hisses',0,2,0,0,'reginald windsor EMOTE_GUARD_TRANSFORM'); +DELETE FROM gossip_texts WHERE entry=-3000107; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000107,'I am ready, as are my forces. Let us end this masquerade!','reginald windsor GOSSIP_ITEM_START'); +DELETE FROM script_waypoint WHERE entry=12580; +INSERT INTO script_waypoint VALUES +(12580, 0, -8997.63, 486.402, 96.622, 0, ''), +(12580, 1, -8971.08, 507.541, 96.349, 0, 'SAY_DIALOG_1'), +(12580, 2, -8953.17, 518.537, 96.355, 0, ''), +(12580, 3, -8936.33, 501.777, 94.066, 0, ''), +(12580, 4, -8922.52, 498.45, 93.869, 0, ''), +(12580, 5, -8907.64, 509.941, 93.840, 0, ''), +(12580, 6, -8925.26, 542.51, 94.274, 0, ''), +(12580, 7, -8832.28, 622.285, 93.686, 0, ''), +(12580, 8, -8824.8, 621.713, 94.084, 0, ''), +(12580, 9, -8796.46, 590.922, 97.466, 0, ''), +(12580, 10, -8769.85, 607.883, 97.118, 0, ''), +(12580, 11, -8737.14, 574.741, 97.398, 0, 'reset jonathan'), +(12580, 12, -8746.27, 563.446, 97.399, 0, ''), +(12580, 13, -8745.5, 557.877, 97.704, 0, ''), +(12580, 14, -8730.95, 541.477, 101.12, 0, ''), +(12580, 15, -8713.16, 520.692, 97.227, 0, ''), +(12580, 16, -8677.09, 549.614, 97.438, 0, ''), +(12580, 17, -8655.72, 552.732, 96.941, 0, ''), +(12580, 18, -8641.68, 540.516, 98.972, 0, ''), +(12580, 19, -8620.08, 520.120, 102.812, 0, ''), +(12580, 20, -8591.09, 492.553, 104.032, 0, ''), +(12580, 21, -8562.45, 463.583, 104.517, 0, ''), +(12580, 22, -8548.63, 467.38, 104.517, 0, 'SAY_WINDSOR_BEFORE_KEEP'), +(12580, 23, -8487.77, 391.44, 108.386, 0, ''), +(12580, 24, -8455.95, 351.225, 120.88, 0, ''), +(12580, 25, -8446.87, 339.904, 121.33, 0, 'SAY_WINDSOR_KEEP_1'), +(12580, 26, -8446.87, 339.904, 121.33, 10000, ''); diff --git a/sql/updates/0.6/r2606_mangos.sql b/sql/updates/0.6/r2606_mangos.sql new file mode 100644 index 000000000..5e5c9baab --- /dev/null +++ b/sql/updates/0.6/r2606_mangos.sql @@ -0,0 +1,2 @@ +DELETE FROM scripted_areatrigger WHERE entry=4047; +INSERT INTO scripted_areatrigger VALUES (4047,'at_temple_ahnqiraj'); diff --git a/sql/updates/0.6/r2606_scriptdev2.sql b/sql/updates/0.6/r2606_scriptdev2.sql new file mode 100644 index 000000000..df879be3e --- /dev/null +++ b/sql/updates/0.6/r2606_scriptdev2.sql @@ -0,0 +1,25 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1531032 AND -1531012; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1531012,'The massive floating eyeball in the center of the chamber turns its gaze upon you. You stand before a god.',0,2,0,0,'eye cthun EMOTE_INTRO'), +(-1531013,'Only flesh and bone. Mortals are such easy prey...',0,1,0,0,'veklor SAY_INTRO_1'), +(-1531014,'Where are your manners, brother. Let us properly welcome our guests.',0,1,0,0,'veknilash SAY_INTRO_2'), +(-1531015,'There will be pain...',0,1,0,0,'veklor SAY_INTRO_3'), +(-1531016,'Oh so much pain...',0,1,0,0,'veknilash SAY_INTRO_4'), +(-1531017,'Come, little ones.',0,1,0,0,'veklor SAY_INTRO_5'), +(-1531018,'The feast of souls begin now...',0,1,0,0,'veknilash SAY_INTRO_6'), + +(-1531019,'It\'s too late to turn away.',8623,1,0,0,'veklor SAY_AGGRO_1'), +(-1531020,'Prepare to embrace oblivion!',8626,1,0,0,'veklor SAY_AGGRO_2'), +(-1531021,'Like a fly in a web.',8624,1,0,0,'veklor SAY_AGGRO_3'), +(-1531022,'Your brash arrogance!',8628,1,0,0,'veklor SAY_AGGRO_4'), +(-1531023,'You will not escape death!',8629,1,0,0,'veklor SAY_SLAY'), +(-1531024,'My brother...NO!',8625,1,0,0,'veklor SAY_DEATH'), +(-1531025,'To decorate our halls!',8627,1,0,0,'veklor SAY_SPECIAL'), + +(-1531026,'Ah, lambs to the slaughter!',8630,1,0,0,'veknilash SAY_AGGRO_1'), +(-1531027,'Let none survive!',8632,1,0,0,'veknilash SAY_AGGRO_2'), +(-1531028,'Join me brother, there is blood to be shed!',8631,1,0,0,'veknilash SAY_AGGRO_3'), +(-1531029,'Look brother, fresh blood!',8633,1,0,0,'veknilash SAY_AGGRO_4'), +(-1531030,'Your fate is sealed!',8635,1,0,0,'veknilash SAY_SLAY'), +(-1531031,'Vek\'lor, I feel your pain!',8636,1,0,0,'veknilash SAY_DEATH'), +(-1531032,'Shall be your undoing!',8634,1,0,0,'veknilash SAY_SPECIAL'); diff --git a/sql/updates/0.6/r2608_mangos.sql b/sql/updates/0.6/r2608_mangos.sql new file mode 100644 index 000000000..36b8701f2 --- /dev/null +++ b/sql/updates/0.6/r2608_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=21628; diff --git a/sql/updates/0.6/r2608_scriptdev2.sql b/sql/updates/0.6/r2608_scriptdev2.sql new file mode 100644 index 000000000..c510c9cff --- /dev/null +++ b/sql/updates/0.6/r2608_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry=-1000193; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000193,'%s looks down at the discarded necklace. In her sadness, the lady incants a glamour, which beckons forth Highborne spirits. The chamber resonates with their ancient song about the Sin\'dorei...',10896,2,1,0,'lady_sylvanas EMOTE_LAMENT_START'); +UPDATE script_texts SET emote=16 WHERE entry=-1000197; diff --git a/sql/updates/0.6/r2610_scriptdev2.sql b/sql/updates/0.6/r2610_scriptdev2.sql new file mode 100644 index 000000000..a80fcadc0 --- /dev/null +++ b/sql/updates/0.6/r2610_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for MaNGOS 12026+) '; diff --git a/sql/updates/0.6/r2611_mangos.sql b/sql/updates/0.6/r2611_mangos.sql new file mode 100644 index 000000000..8cc4e5ba4 --- /dev/null +++ b/sql/updates/0.6/r2611_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_blood_queen_lanathel' WHERE entry=37955; diff --git a/sql/updates/0.6/r2611_scriptdev2.sql b/sql/updates/0.6/r2611_scriptdev2.sql new file mode 100644 index 000000000..03f565b36 --- /dev/null +++ b/sql/updates/0.6/r2611_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1631195,-1631196); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1631195,'Really... Is that all you got?',16791,1,0,0,'blood_queen SAY_SLAY_1'), +(-1631196,'Such a pity...',16792,1,0,0,'blood_queen SAY_SLAY_2'); diff --git a/sql/updates/0.6/r2612_scriptdev2.sql b/sql/updates/0.6/r2612_scriptdev2.sql new file mode 100644 index 000000000..dacfd326c --- /dev/null +++ b/sql/updates/0.6/r2612_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1556019,-1556021,-1556022); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1556019,'Your magics shall be your undoing... ak-a-ak...',0,5,0,0,'anzu SAY_WHISPER_MAGIC_1'), +(-1556021,'Your powers... ak-ak... turn against you...',0,5,0,0,'anzu SAY_WHISPER_MAGIC_2'), +(-1556022,'Your spells... ke-kaw... are weak magics... easy to turn against you...',0,5,0,0,'anzu SAY_WHISPER_MAGIC_3'); diff --git a/sql/updates/0.6/r2615_scriptdev2.sql b/sql/updates/0.6/r2615_scriptdev2.sql new file mode 100644 index 000000000..8d23b1e67 --- /dev/null +++ b/sql/updates/0.6/r2615_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET sound=14161 WHERE entry=-1602020; diff --git a/sql/updates/0.6/r2616_mangos.sql b/sql/updates/0.6/r2616_mangos.sql new file mode 100644 index 000000000..0d63cfd75 --- /dev/null +++ b/sql/updates/0.6/r2616_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_general_andorov' WHERE entry=15471; +UPDATE creature_template SET ScriptName='npc_kaldorei_elite' WHERE entry=15473; diff --git a/sql/updates/0.6/r2616_scriptdev2.sql b/sql/updates/0.6/r2616_scriptdev2.sql new file mode 100644 index 000000000..a72318fd8 --- /dev/null +++ b/sql/updates/0.6/r2616_scriptdev2.sql @@ -0,0 +1,11 @@ +DELETE FROM script_texts WHERE entry IN (-1509003,-1509004,-1509031,-1509029,-1509030); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1509003,'They come now. Try not to get yourself killed, young blood.',0,1,0,22,'andorov SAY_ANDOROV_INTRO_3'), +(-1509004,'Remember, Rajaxx, when I said I\'d kill you last?',0,1,0,0,'andorov SAY_ANDOROV_INTRO_1'), +(-1509031,'I lied...',0,1,0,0,'andorov SAY_ANDOROV_INTRO_2'), +(-1509029,'Come get some!',0,0,0,0,'andorov SAY_ANDOROV_INTRO_4'), +(-1509030,'Kill first, ask questions later... Incoming!',0,1,0,0,'andorov SAY_ANDOROV_ATTACK_START'); +DELETE FROM gossip_texts WHERE entry IN (-3509000,-3509001); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3509000,'Let\'s find out.','andorov GOSSIP_ITEM_START'), +(-3509001,'Let\'s see what you have.','andorov GOSSIP_ITEM_TRADE'); diff --git a/sql/updates/0.6/r2618_scriptdev2.sql b/sql/updates/0.6/r2618_scriptdev2.sql new file mode 100644 index 000000000..5e9113a06 --- /dev/null +++ b/sql/updates/0.6/r2618_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1509028,-1509031); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1509028,'%s drains your mana and turns to stone.',0,2,0,0,'moam EMOTE_ENERGIZING'), +(-1509031,'I lied...',0,1,0,0,'andorov SAY_ANDOROV_INTRO_2'); diff --git a/sql/updates/0.6/r2619_scriptdev2.sql b/sql/updates/0.6/r2619_scriptdev2.sql new file mode 100644 index 000000000..a48f87a80 --- /dev/null +++ b/sql/updates/0.6/r2619_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1550044); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1550044,'%s begins to cast Pyroblast!',0,3,0,0,'kaelthas EMOTE_PYROBLAST'); diff --git a/sql/updates/0.6/r2620_scriptdev2.sql b/sql/updates/0.6/r2620_scriptdev2.sql new file mode 100644 index 000000000..37bfc7b0d --- /dev/null +++ b/sql/updates/0.6/r2620_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1585023,-1585030); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1585023,'Don\'t look so smug! I know what you\'re thinking, but Tempest Keep was merely a set back. Did you honestly believe I would trust the future to some blind, half-night elf mongrel?',12413,1,0,0,'kaelthas MT SAY_INTRO_1'), +(-1585030,'Oh no, he was merely an instrument, a stepping stone to a much larger plan! It has all led to this, and this time, you will not interfere!',0,1,0,0,'kaelthas MT SAY_INTRO_2'); diff --git a/sql/updates/0.6/r2623_mangos.sql b/sql/updates/0.6/r2623_mangos.sql new file mode 100644 index 000000000..1cce2b13a --- /dev/null +++ b/sql/updates/0.6/r2623_mangos.sql @@ -0,0 +1,8 @@ +UPDATE creature_template SET ScriptName='npc_kagani_nightstrike' WHERE entry=24557; +UPDATE creature_template SET ScriptName='npc_ellris_duskhallow' WHERE entry=24558; +UPDATE creature_template SET ScriptName='npc_eramas_brightblaze' WHERE entry=24554; +UPDATE creature_template SET ScriptName='npc_yazzai' WHERE entry=24561; +UPDATE creature_template SET ScriptName='npc_warlord_salaris' WHERE entry=24559; +UPDATE creature_template SET ScriptName='npc_garaxxas' WHERE entry=24555; +UPDATE creature_template SET ScriptName='npc_apoko' WHERE entry=24553; +UPDATE creature_template SET ScriptName='npc_zelfan' WHERE entry=24556; diff --git a/sql/updates/0.6/r2625_mangos.sql b/sql/updates/0.6/r2625_mangos.sql new file mode 100644 index 000000000..af9da4698 --- /dev/null +++ b/sql/updates/0.6/r2625_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_queen_lanathel_intro' WHERE entry=38004; diff --git a/sql/updates/0.6/r2625_scriptdev2.sql b/sql/updates/0.6/r2625_scriptdev2.sql new file mode 100644 index 000000000..db84b7f6d --- /dev/null +++ b/sql/updates/0.6/r2625_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=1 WHERE entry=-1631101; diff --git a/sql/updates/0.6/r2626_mangos.sql b/sql/updates/0.6/r2626_mangos.sql new file mode 100644 index 000000000..dd493a266 --- /dev/null +++ b/sql/updates/0.6/r2626_mangos.sql @@ -0,0 +1,7 @@ +UPDATE creature_template SET ScriptName='npc_blood_orb_control' WHERE entry=38008; +UPDATE creature_template SET ScriptName='npc_ball_of_flame' WHERE entry IN (38332,38451); +UPDATE creature_template SET ScriptName='npc_kinetic_bomb' WHERE entry=38454; +UPDATE creature_template SET ScriptName='npc_dark_nucleus' WHERE entry=38369; +UPDATE creature_template SET ScriptName='boss_taldaram_icc' WHERE entry=37973; +UPDATE creature_template SET ScriptName='boss_keleseth_icc' WHERE entry=37972; +UPDATE creature_template SET ScriptName='boss_valanar_icc' WHERE entry=37970; diff --git a/sql/updates/0.6/r2626_scriptdev2.sql b/sql/updates/0.6/r2626_scriptdev2.sql new file mode 100644 index 000000000..57f6f9372 --- /dev/null +++ b/sql/updates/0.6/r2626_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1631197,-1631198,-1631199); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1631197,'Invocation of Blood jumps to %s!',0,3,0,0,'blood_princes EMOTE_INVOCATION'), +(-1631198,'%s begins casting Empowered Shock Vortex!',0,3,0,0,'valanar EMOTE_SHOCK_VORTEX'), +(-1631199,'%s speed toward $N!',0,3,0,0,'taldaram EMOTE_FLAMES'); diff --git a/sql/updates/0.6/r2630_mangos.sql b/sql/updates/0.6/r2630_mangos.sql new file mode 100644 index 000000000..74e59c5ea --- /dev/null +++ b/sql/updates/0.6/r2630_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_anubarak_spike' WHERE entry=34660; +UPDATE creature_template SET ScriptName='npc_frost_sphere' WHERE entry=34606; +UPDATE creature_template SET ScriptName='npc_nerubian_borrow' WHERE entry=34862; diff --git a/sql/updates/0.6/r2630_scriptdev2.sql b/sql/updates/0.6/r2630_scriptdev2.sql new file mode 100644 index 000000000..055f148fe --- /dev/null +++ b/sql/updates/0.6/r2630_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry IN (-1649071,-1649072,-1649073,-1649074); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1649071,'%s burrows into the ground!',0,3,0,0,'anubarak EMOTE_BURROW'), +(-1649072,'%s spikes pursue $N!',0,3,0,0,'anubarak EMOTE_PURSUE'), +(-1649073,'%s emerges from the ground!',0,3,0,0,'anubarak EMOTE_EMERGE'), +(-1649074,'%s unleashes a Leeching Swarm to heal himself!',0,3,0,0,'anubarak EMOTE_SWARM'); diff --git a/sql/updates/0.6/r2632_mangos.sql b/sql/updates/0.6/r2632_mangos.sql new file mode 100644 index 000000000..5e7ef3e72 --- /dev/null +++ b/sql/updates/0.6/r2632_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='boss_sindragosa' WHERE entry=36853; +UPDATE creature_template SET ScriptName='npc_rimefang_icc' WHERE entry=37533; +UPDATE creature_template SET ScriptName='npc_spinestalker_icc' WHERE entry=37534; diff --git a/sql/updates/0.6/r2635_mangos.sql b/sql/updates/0.6/r2635_mangos.sql new file mode 100644 index 000000000..e3b431692 --- /dev/null +++ b/sql/updates/0.6/r2635_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18095; +UPDATE creature_template SET ScriptName='npc_doomfire_spirit' WHERE entry=18104; diff --git a/sql/updates/0.6/r2635_scriptdev2.sql b/sql/updates/0.6/r2635_scriptdev2.sql new file mode 100644 index 000000000..40ef4eb79 --- /dev/null +++ b/sql/updates/0.6/r2635_scriptdev2.sql @@ -0,0 +1,10 @@ +UPDATE script_texts SET type=6 WHERE entry=-1534018; +DELETE FROM gossip_texts WHERE entry IN (-3534000,-3534001,-3534002,-3534003,-3534004,-3534005,-3534006); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3534000,'My companions and I are with you, Lady Proudmoore.','jaina GOSSIP_ITEM_JAIN_START'), +(-3534001,'We are ready for whatever Archimonde might send our way, Lady Proudmoore.','jaina GOSSIP_ITEM_ANATHERON'), +(-3534002,'Until we meet again, Lady Proudmoore.','jaina GOSSIP_ITEM_SUCCESS'), +(-3534003,'I am with you, Thrall.','thrall GOSSIP_ITEM_THRALL_START'), +(-3534004,'We have nothing to fear.','thrall GOSSIP_ITEM_AZGALOR'), +(-3534005,'Until we meet again, Thrall.','thrall GOSSIP_ITEM_SUCCESS'), +(-3534006,'I would be grateful for any aid you can provide, Priestess.','tyrande GOSSIP_ITEM_AID'); diff --git a/sql/updates/0.6/r2637_mangos.sql b/sql/updates/0.6/r2637_mangos.sql new file mode 100644 index 000000000..a1c62ed28 --- /dev/null +++ b/sql/updates/0.6/r2637_mangos.sql @@ -0,0 +1,5 @@ +UPDATE instance_template SET ScriptName='instance_eye_of_eternity' WHERE map=616; +UPDATE creature_template SET ScriptName='boss_malygos' WHERE entry=28859; +DELETE FROM scripted_event_id WHERE id IN (20711); +INSERT INTO scripted_event_id VALUES +(20711,'event_go_focusing_iris'); diff --git a/sql/updates/0.6/r2638_scriptdev2.sql b/sql/updates/0.6/r2638_scriptdev2.sql new file mode 100644 index 000000000..9360af0c8 --- /dev/null +++ b/sql/updates/0.6/r2638_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1649075); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1649075,'Champions, you\'re alive! Not only have you defeated every challenge of the Trial of the Crusader, but also thwarted Arthas\' plans! Your skill and cunning will prove to be a powerful weapon against the Scourge. Well done! Allow one of the Crusade\'s mages to transport you to the surface!',0,0,0,1,'tirion SAY_EPILOGUE'); diff --git a/sql/updates/0.6/r2641_mangos.sql b/sql/updates/0.6/r2641_mangos.sql new file mode 100644 index 000000000..3763238ac --- /dev/null +++ b/sql/updates/0.6/r2641_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_power_spark' WHERE entry=30084; diff --git a/sql/updates/0.6/r2641_scriptdev2.sql b/sql/updates/0.6/r2641_scriptdev2.sql new file mode 100644 index 000000000..08285c826 --- /dev/null +++ b/sql/updates/0.6/r2641_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1616013); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1616013,'You will not succeed while I draw breath!',14518,1,0,0,'malygos SAY_DEEP_BREATH'); diff --git a/sql/updates/0.6/r2647_mangos.sql b/sql/updates/0.6/r2647_mangos.sql new file mode 100644 index 000000000..262da6df8 --- /dev/null +++ b/sql/updates/0.6/r2647_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_festergut' WHERE entry=36626; diff --git a/sql/updates/0.6/r2648_mangos.sql b/sql/updates/0.6/r2648_mangos.sql new file mode 100644 index 000000000..e84c430de --- /dev/null +++ b/sql/updates/0.6/r2648_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_attumen' WHERE entry IN (16152); diff --git a/sql/updates/0.6/r2649_mangos.sql b/sql/updates/0.6/r2649_mangos.sql new file mode 100644 index 000000000..59692026d --- /dev/null +++ b/sql/updates/0.6/r2649_mangos.sql @@ -0,0 +1,6 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry=13873; +UPDATE gameobject_template SET ScriptName='' WHERE entry=181956; +UPDATE gameobject_template SET ScriptName='' WHERE entry=178145; +UPDATE gameobject_template SET ScriptName='' WHERE entry=175944; +UPDATE gameobject_template SET ScriptName='' WHERE entry=182024; +UPDATE gameobject_template SET ScriptName='' WHERE entry=176581; diff --git a/sql/updates/0.6/r2649_scriptdev2.sql b/sql/updates/0.6/r2649_scriptdev2.sql new file mode 100644 index 000000000..de06faf83 --- /dev/null +++ b/sql/updates/0.6/r2649_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1000579); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000579,'REUSE ME',0,0,0,0,'REUSE ME'); diff --git a/sql/updates/0.6/r2650_scriptdev2.sql b/sql/updates/0.6/r2650_scriptdev2.sql new file mode 100644 index 000000000..4280ee218 --- /dev/null +++ b/sql/updates/0.6/r2650_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM gossip_texts WHERE entry IN (-3000108,-3000110); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000108,'I need a moment of your time, sir.','prospector anvilward GOSSIP_ITEM_MOMENT'), +(-3000110,'Why... yes, of course. I\'ve something to show you right inside this building, Mr. Anvilward.','prospector anvilward GOSSIP_ITEM_SHOW'); diff --git a/sql/updates/0.6/r2651_mangos.sql b/sql/updates/0.6/r2651_mangos.sql new file mode 100644 index 000000000..7271f68e7 --- /dev/null +++ b/sql/updates/0.6/r2651_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_grark_lorkrub' WHERE entry=9520; diff --git a/sql/updates/0.6/r2651_scriptdev2.sql b/sql/updates/0.6/r2651_scriptdev2.sql new file mode 100644 index 000000000..d8777c4ac --- /dev/null +++ b/sql/updates/0.6/r2651_scriptdev2.sql @@ -0,0 +1,66 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000888 AND -1000873; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000873,'I know the way, insect. There is no need to prod me as if I were cattle.',0,0,0,1,'grark SAY_START'), +(-1000874,'Surely you do not think that you will get away with this incursion. They will come for me and you shall pay for your insolence.',0,0,0,1,'grark SAY_PAY'), +(-1000875,'RUN THEM THROUGH BROTHERS!',0,0,0,5,'grark SAY_FIRST_AMBUSH_START'), +(-1000876,'I doubt you will be so lucky the next time you encounter my brethren.',0,0,0,1,'grark SAY_FIRST_AMBUSH_END'), +(-1000877,'They come for you, fool!',0,0,0,5,'grark SAY_SEC_AMBUSH_START'), +(-1000878,'What do you think you accomplish from this, fool? Even now, the Blackrock armies make preparations to destroy your world.',0,0,0,1,'grark SAY_SEC_AMBUSH_END'), +(-1000879,'On darkest wing they fly. Prepare to meet your end!',0,0,0,5,'grark SAY_THIRD_AMBUSH_START'), +(-1000880,'The worst is yet to come!',0,0,0,1,'grark SAY_THIRD_AMBUSH_END'), +(-1000881,'%s laughs.',0,2,0,11,'grark EMOTE_LAUGH'), +(-1000882,'Time to make your final stand, Insect.',0,0,0,0,'grark SAY_LAST_STAND'), +(-1000883,'Kneel, Grark',0,0,0,1,'lexlort SAY_LEXLORT_1'), +(-1000884,'Grark Lorkrub, you have been charged and found guilty of treason against Horde. How you plead is unimportant. High Executioner Nuzrak, step forward.',0,0,0,1,'lexlort SAY_LEXLORT_2'), +(-1000885,'%s raises his massive axe over Grark.',0,2,0,27,'nuzark EMOTE_RAISE_AXE'), +(-1000886,'%s raises his hand and then lowers it.',0,2,0,0,'lexlort EMOTE_LOWER_HAND'), +(-1000887,'End him...',0,0,0,0,'lexlort SAY_LEXLORT_3'), +(-1000888,'You, soldier, report back to Kargath at once!',0,0,0,1,'lexlort SAY_LEXLORT_4'); + +DELETE FROM script_waypoint WHERE entry=9520; +INSERT INTO script_waypoint VALUES +(9520, 1, -7699.62, -1444.29, 139.87, 4000, 'SAY_START'), +(9520, 2, -7670.67, -1458.25, 140.74, 0, ''), +(9520, 3, -7675.26, -1465.58, 140.74, 0, ''), +(9520, 4, -7685.84, -1472.66, 140.75, 0, ''), +(9520, 5, -7700.08, -1473.41, 140.79, 0, ''), +(9520, 6, -7712.55, -1470.19, 140.79, 0, ''), +(9520, 7, -7717.27, -1481.70, 140.72, 5000, 'SAY_PAY'), +(9520, 8, -7726.23, -1500.78, 132.99, 0, ''), +(9520, 9, -7744.61, -1531.61, 132.69, 0, ''), +(9520, 10, -7763.08, -1536.22, 131.93, 0, ''), +(9520, 11, -7815.32, -1522.61, 134.16, 0, ''), +(9520, 12, -7850.26, -1516.87, 138.17, 0, 'SAY_FIRST_AMBUSH_START'), +(9520, 13, -7850.26, -1516.87, 138.17, 3000, 'SAY_FIRST_AMBUSH_END'), +(9520, 14, -7881.01, -1508.49, 142.37, 0, ''), +(9520, 15, -7888.91, -1458.09, 144.79, 0, ''), +(9520, 16, -7889.18, -1430.21, 145.31, 0, ''), +(9520, 17, -7900.53, -1427.01, 150.26, 0, ''), +(9520, 18, -7904.15, -1429.91, 150.27, 0, ''), +(9520, 19, -7921.48, -1425.47, 140.54, 0, ''), +(9520, 20, -7941.43, -1413.10, 134.35, 0, ''), +(9520, 21, -7964.85, -1367.45, 132.99, 0, ''), +(9520, 22, -7989.95, -1319.121, 133.71, 0, ''), +(9520, 23, -8010.43, -1270.23, 133.42, 0, ''), +(9520, 24, -8025.62, -1243.78, 133.91, 0, 'SAY_SEC_AMBUSH_START'), +(9520, 25, -8025.62, -1243.78, 133.91, 3000, 'SAY_SEC_AMBUSH_END'), +(9520, 26, -8015.22, -1196.98, 146.76, 0, ''), +(9520, 27, -7994.68, -1151.38, 160.70, 0, ''), +(9520, 28, -7970.91, -1132.81, 170.16, 0, 'summon Searscale Drakes'), +(9520, 29, -7927.59, -1122.79, 185.86, 0, ''), +(9520, 30, -7897.67, -1126.67, 194.32, 0, 'SAY_THIRD_AMBUSH_START'), +(9520, 31, -7897.67, -1126.67, 194.32, 3000, 'SAY_THIRD_AMBUSH_END'), +(9520, 32, -7864.11, -1135.98, 203.29, 0, ''), +(9520, 33, -7837.31, -1137.73, 209.63, 0, ''), +(9520, 34, -7808.72, -1134.90, 214.84, 0, ''), +(9520, 35, -7786.85, -1127.24, 214.84, 0, ''), +(9520, 36, -7746.58, -1125.16, 215.08, 5000, 'EMOTE_LAUGH'), +(9520, 37, -7746.41, -1103.62, 215.62, 0, ''), +(9520, 38, -7740.25, -1090.51, 216.69, 0, ''), +(9520, 39, -7730.97, -1085.55, 217.12, 0, ''), +(9520, 40, -7697.89, -1089.43, 217.62, 0, ''), +(9520, 41, -7679.30, -1059.15, 220.09, 0, ''), +(9520, 42, -7661.39, -1038.24, 226.24, 0, ''), +(9520, 43, -7634.49, -1020.96, 234.30, 0, ''), +(9520, 44, -7596.22, -1013.16, 244.03, 0, ''), +(9520, 45, -7556.53, -1021.74, 253.21, 0, 'SAY_LAST_STAND'); diff --git a/sql/updates/0.6/r2652_mangos.sql b/sql/updates/0.6/r2652_mangos.sql new file mode 100644 index 000000000..8fa66e566 --- /dev/null +++ b/sql/updates/0.6/r2652_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName ='npc_marshal_windsor' WHERE entry=9023; +UPDATE creature_template SET ScriptName ='npc_dughal_stormwing' WHERE entry=9022; +UPDATE creature_template SET ScriptName ='npc_tobias_seecher' WHERE entry=9679; diff --git a/sql/updates/0.6/r2652_scriptdev2.sql b/sql/updates/0.6/r2652_scriptdev2.sql new file mode 100644 index 000000000..bf693d239 --- /dev/null +++ b/sql/updates/0.6/r2652_scriptdev2.sql @@ -0,0 +1,92 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1230033 AND -1230010; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1230010,'Thank you, $N! I\'m free!!!',0,0,0,0,'dughal SAY_FREE'), +(-1230011,'You locked up the wrong Marshal, $N. Prepare to be destroyed!',0,0,0,0,'windsor SAY_AGGRO_1'), +(-1230012,'I bet you\'re sorry now, aren\'t you?',0,0,0,0,'windsor SAY_AGGRO_2'), +(-1230013,'You better hold me back or $N is going to feel some prison house beatings.',0,0,0,0,'windsor SAY_AGGRO_3'), +(-1230014,'Let\'s get a move on. My gear should be in the storage area up this way...',0,0,0,0,'windsor SAY_START'), +(-1230015,'Check that cell, $N. If someone is alive in there, we need to get them out.',0,0,0,25,'windsor SAY_CELL_DUGHAL_1'), +(-1230016,'Good work! We\'re almost there, $N. This way.',0,0,0,0,'windsor SAY_CELL_DUGHAL_3'), +(-1230017,'This is it, $N. My stuff should be in that room. Cover me, I\'m going in!',0,0,0,0,'windsor SAY_EQUIPMENT_1'), +(-1230018,'Ah, there it is!',0,0,0,0,'windsor SAY_EQUIPMENT_2'), +(-1230019,'Can you feel the power, $N??? It\'s time to ROCK!',0,0,0,0,'reginald_windsor SAY__EQUIPMENT_3'), +(-1230020,'Now we just have to free Tobias and we can get out of here. This way!',0,0,0,0,'reginald_windsor SAY__EQUIPMENT_4'), +(-1230021,'Open it.',0,0,0,25,'reginald_windsor SAY_CELL_JAZ_1'), +(-1230022,'I never did like those two. Let\'s get moving.',0,0,0,0,'reginald_windsor SAY_CELL_JAZ_2'), +(-1230023,'Open it and be careful this time!',0,0,0,25,'reginald_windsor SAY_CELL_SHILL_1'), +(-1230024,'That intolerant dirtbag finally got what was coming to him. Good riddance!',0,0,0,66,'reginald_windsor SAY_CELL_SHILL_2'), +(-1230025,'Alright, let\'s go.',0,0,0,0,'reginald_windsor SAY_CELL_SHILL_3'), +(-1230026,'Open it. We need to hurry up. I can smell those Dark Irons coming a mile away and I can tell you one thing, they\'re COMING!',0,0,0,25,'reginald_windsor SAY_CELL_CREST_1'), +(-1230027,'He has to be in the last cell. Unless... they killed him.',0,0,0,0,'reginald_windsor SAY_CELL_CREST_2'), +(-1230028,'Get him out of there!',0,0,0,25,'reginald_windsor SAY_CELL_TOBIAS_1'), +(-1230029,'Excellent work, $N. Let\'s find the exit. I think I know the way. Follow me!',0,0,0,0,'reginald_windsor SAY_CELL_TOBIAS_2'), +(-1230030,'We made it!',0,0,0,4,'reginald_windsor SAY_FREE_1'), +(-1230031,'Meet me at Maxwell\'s encampment. We\'ll go over the next stages of the plan there and figure out a way to decode my tablets without the decryption ring.',0,0,0,1,'reginald_windsor SAY_FREE_2'), +(-1230032,'Thank you! I will run for safety immediately!',0,0,0,0,'tobias SAY_TOBIAS_FREE_1'), +(-1230033,'Finally!! I can leave this dump.',0,0,0,0,'tobias SAY_TOBIAS_FREE_2'); + +DELETE FROM gossip_texts WHERE entry IN (-3230000, -3230001); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3230000,'You\'re free, Dughal! Get out of here!','dughal GOSSIP_ITEM'), +(-3230001,'Get out of here, Tobias, you\'re free!','tobias GOSSIP_ITEM'); + +DELETE FROM script_waypoint WHERE entry=9023; +INSERT INTO script_waypoint VALUES +(9023, 1, 316.336, -225.528, -77.7258, 2000, 'SAY_WINDSOR_START'), +(9023, 2, 322.96, -207.13, -77.87, 0, ''), +(9023, 3, 281.05, -172.16, -75.12, 0, ''), +(9023, 4, 272.19, -139.14, -70.61, 0, ''), +(9023, 5, 283.62, -116.09, -70.21, 0, ''), +(9023, 6, 296.18, -94.30, -74.08, 0, ''), +(9023, 7, 294.57, -93.11, -74.08, 0, 'escort paused - SAY_WINDSOR_CELL_DUGHAL_1'), +(9023, 8, 294.57, -93.11, -74.08, 10000, ''), +(9023, 9, 294.57, -93.11, -74.08, 3000, 'SAY_WINDSOR_CELL_DUGHAL_3'), +(9023, 10, 314.31, -74.31, -76.09, 0, ''), +(9023, 11, 360.22, -62.93, -66.77, 0, ''), +(9023, 12, 383.38, -69.40, -63.25, 0, ''), +(9023, 13, 389.99, -67.86, -62.57, 0, ''), +(9023, 14, 400.98, -72.01, -62.31, 0, 'SAY_WINDSOR_EQUIPMENT_1'), +(9023, 15, 404.22, -62.30, -63.50, 2000, ''), +(9023, 16, 404.22, -62.30, -63.50, 1500, 'open supply door'), +(9023, 17, 407.65, -51.86, -63.96, 0, ''), +(9023, 18, 403.61, -51.71, -63.92, 1000, 'SAY_WINDSOR_EQUIPMENT_2'), +(9023, 19, 403.61, -51.71, -63.92, 2000, ''), +(9023, 20, 403.61, -51.71, -63.92, 1000, 'open supply crate'), +(9023, 21, 403.61, -51.71, -63.92, 1000, 'update entry to Reginald Windsor'), +(9023, 22, 403.61, -52.71, -63.92, 4000, 'SAY_WINDSOR_EQUIPMENT_3'), +(9023, 23, 403.61, -52.71, -63.92, 4000, 'SAY_WINDSOR_EQUIPMENT_4'), +(9023, 24, 406.33, -54.87, -63.95, 0, ''), +(9023, 25, 403.86, -73.88, -62.02, 0, ''), +(9023, 26, 428.80, -81.34, -64.91, 0, ''), +(9023, 27, 557.03, -119.71, -61.83, 0, ''), +(9023, 28, 573.40, -124.39, -65.07, 0, ''), +(9023, 29, 593.91, -130.29, -69.25, 0, ''), +(9023, 30, 593.21, -132.16, -69.25, 0, 'escort paused - SAY_WINDSOR_CELL_JAZ_1'), +(9023, 31, 593.21, -132.16, -69.25, 1000, ''), +(9023, 32, 593.21, -132.16, -69.25, 3000, 'SAY_WINDSOR_CELL_JAZ_2'), +(9023, 33, 622.81, -135.55, -71.92, 0, ''), +(9023, 34, 634.68, -151.29, -70.32, 0, ''), +(9023, 35, 635.06, -153.25, -70.32, 0, 'escort paused - SAY_WINDSOR_CELL_SHILL_1'), +(9023, 36, 635.06, -153.25, -70.32, 3000, ''), +(9023, 37, 635.06, -153.25, -70.32, 5000, 'SAY_WINDSOR_CELL_SHILL_2'), +(9023, 38, 635.06, -153.25, -70.32, 2000, 'SAY_WINDSOR_CELL_SHILL_3'), +(9023, 39, 655.25, -172.39, -73.72, 0, ''), +(9023, 40, 654.79, -226.30, -83.06, 0, ''), +(9023, 41, 622.85, -268.85, -83.96, 0, ''), +(9023, 42, 579.45, -275.56, -80.44, 0, ''), +(9023, 43, 561.19, -266.85, -75.59, 0, ''), +(9023, 44, 547.91, -253.92, -70.34, 0, ''), +(9023, 45, 549.20, -252.40, -70.34, 0, 'escort paused - SAY_WINDSOR_CELL_CREST_1'), +(9023, 46, 549.20, -252.40, -70.34, 1000, ''), +(9023, 47, 549.20, -252.40, -70.34, 4000, 'SAY_WINDSOR_CELL_CREST_2'), +(9023, 48, 555.33, -269.16, -74.40, 0, ''), +(9023, 49, 554.31, -270.88, -74.40, 0, 'escort paused - SAY_WINDSOR_CELL_TOBIAS_1'), +(9023, 50, 554.31, -270.88, -74.40, 10000, ''), +(9023, 51, 554.31, -270.88, -74.40, 4000, 'SAY_WINDSOR_CELL_TOBIAS_2'), +(9023, 52, 536.10, -249.60, -67.47, 0, ''), +(9023, 53, 520.94, -216.65, -59.28, 0, ''), +(9023, 54, 505.99, -148.74, -62.17, 0, ''), +(9023, 55, 484.21, -56.24, -62.43, 0, ''), +(9023, 56, 470.39, -6.01, -70.10, 0, ''), +(9023, 57, 452.45, 29.85, -70.37, 1500, 'SAY_WINDSOR_FREE_1'), +(9023, 58, 452.45, 29.85, -70.37, 15000, 'SAY_WINDSOR_FREE_2'); diff --git a/sql/updates/0.6/r2653_mangos.sql b/sql/updates/0.6/r2653_mangos.sql new file mode 100644 index 000000000..0d615c21e --- /dev/null +++ b/sql/updates/0.6/r2653_mangos.sql @@ -0,0 +1,7 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=11956; +UPDATE creature_template SET ScriptName='' WHERE entry=11798; +UPDATE creature_template SET ScriptName='' WHERE entry=11800; +UPDATE creature_template SET ScriptName='' WHERE entry=4489; +UPDATE creature_template SET ScriptName='' WHERE entry IN (9528,9529); +UPDATE creature_template SET ScriptName='' WHERE entry=12944; +UPDATE creature_template SET ScriptName='' WHERE entry=11872; diff --git a/sql/updates/0.6/r2655_mangos.sql b/sql/updates/0.6/r2655_mangos.sql new file mode 100644 index 000000000..dde13c3e1 --- /dev/null +++ b/sql/updates/0.6/r2655_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_ouro_spawner' WHERE entry=15957; diff --git a/sql/updates/0.6/r2656_scriptdev2.sql b/sql/updates/0.6/r2656_scriptdev2.sql new file mode 100644 index 000000000..39d451607 --- /dev/null +++ b/sql/updates/0.6/r2656_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1000889, -1000890); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000889,'%s submits.',0,2,0,0,'grark EMOTE_SUBMIT'), +(-1000890,'You have come to play? Then let us play!',0,0,0,0,'grark SAY_AGGRO'); diff --git a/sql/updates/0.6/r2657_mangos.sql b/sql/updates/0.6/r2657_mangos.sql new file mode 100644 index 000000000..673919bdf --- /dev/null +++ b/sql/updates/0.6/r2657_mangos.sql @@ -0,0 +1,4 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (4033,4034); +INSERT INTO scripted_areatrigger VALUES +(4033,'at_stomach_cthun'), +(4034,'at_stomach_cthun'); diff --git a/sql/updates/0.6/r2657_scriptdev2.sql b/sql/updates/0.6/r2657_scriptdev2.sql new file mode 100644 index 000000000..9322a60ed --- /dev/null +++ b/sql/updates/0.6/r2657_scriptdev2.sql @@ -0,0 +1,10 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1531040 AND -1531033; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1531033,'Death is close...',8580,4,0,0,'cthun SAY_WHISPER_1'), +(-1531034,'You are already dead.',8581,4,0,0,'cthun SAY_WHISPER_2'), +(-1531035,'Your courage will fail.',8582,4,0,0,'cthun SAY_WHISPER_3'), +(-1531036,'Your friends will abandon you.',8583,4,0,0,'cthun SAY_WHISPER_4'), +(-1531037,'You will betray your friends.',8584,4,0,0,'cthun SAY_WHISPER_5'), +(-1531038,'You will die.',8585,4,0,0,'cthun SAY_WHISPER_6'), +(-1531039,'You are weak.',8586,4,0,0,'cthun SAY_WHISPER_7'), +(-1531040,'Your heart will explode.',8587,4,0,0,'cthun SAY_WHISPER_8'); diff --git a/sql/updates/0.6/r2658_mangos.sql b/sql/updates/0.6/r2658_mangos.sql new file mode 100644 index 000000000..faffc5d77 --- /dev/null +++ b/sql/updates/0.6/r2658_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=9037; diff --git a/sql/updates/0.6/r2658_scriptdev2.sql b/sql/updates/0.6/r2658_scriptdev2.sql new file mode 100644 index 000000000..02fac67e5 --- /dev/null +++ b/sql/updates/0.6/r2658_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM gossip_texts WHERE entry=-3230002; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3230002,'Your bondage is at an end, Doom\'rel. I challenge you!','doomrel GOSSIP_ITEM_CHALLENGE'); diff --git a/sql/updates/0.6/r2659_scriptdev2.sql b/sql/updates/0.6/r2659_scriptdev2.sql new file mode 100644 index 000000000..c5d3d8cf8 --- /dev/null +++ b/sql/updates/0.6/r2659_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=53 WHERE entry=-1554028; diff --git a/sql/updates/0.6/r2661_mangos.sql b/sql/updates/0.6/r2661_mangos.sql new file mode 100644 index 000000000..def81fae2 --- /dev/null +++ b/sql/updates/0.6/r2661_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_dalliah' WHERE entry=20885; +UPDATE creature_template SET ScriptName='boss_soccothrates' WHERE entry=20886; diff --git a/sql/updates/0.6/r2661_scriptdev2.sql b/sql/updates/0.6/r2661_scriptdev2.sql new file mode 100644 index 000000000..3088ed78a --- /dev/null +++ b/sql/updates/0.6/r2661_scriptdev2.sql @@ -0,0 +1,29 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1552055 AND -1552031; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1552031,'It is unwise to anger me.',11086,1,0,0,'dalliah SAY_AGGRO'), +(-1552032,'Ahh... That is much better.',11091,1,0,0,'dalliah SAY_HEAL_1'), +(-1552033,'Ahh... Just what I needed.',11092,1,0,0,'dalliah SAY_HEAL_2'), +(-1552034,'Completely ineffective. Just like someone else I know.',11087,1,0,0,'dalliah SAY_KILL_1'), +(-1552035,'You chose the wrong opponent.',11088,1,0,0,'dalliah SAY_KILL_2'), +(-1552036,'I\'ll cut you to pieces!',11090,1,0,0,'dalliah SAY_WHIRLWIND_1'), +(-1552037,'Reap the Whirlwind!',11089,1,0,0,'dalliah SAY_WHIRLWIND_2'), +(-1552038,'Now I\'m really... angry...',11093,1,0,0,'dalliah SAY_DEATH'), + +(-1552039,'Have you come to kill Dalliah? Can I watch?',11237,1,0,1,'soccothrates SAY_DALLIAH_AGGRO_1'), +(-1552040,'This may be the end for you, Dalliah. What a shame that would be.',11245,1,0,1,'soccothrates SAY_DALLIAH_TAUNT_1'), +(-1552041,'Facing difficulties, Dalliah? How nice.',11244,1,0,1,'soccothrates SAY_DALLIAH_TAUNT_2'), +(-1552042,'I suggest a new strategy, you draw the attackers while I gather reinforcements. Hahaha!',11246,1,0,1,'soccothrates SAY_DALLIAH_TAUNT_3'), +(-1552043,'Finally! Well done!',11247,1,0,66,'soccothrates SAY_DALLIAH_DEAD'), +(-1552044,'On guard!',11241,1,0,0,'soccothrates SAY_CHARGE_1'), +(-1552045,'Defend yourself, for all the good it will do...',11242,1,0,0,'soccothrates SAY_CHARGE_2'), +(-1552046,'Knew this was... the only way out',11243,1,0,0,'soccothrates SAY_DEATH'), +(-1552047,'Yes, that was quite satisfying',11239,1,0,0,'soccothrates SAY_KILL'), +(-1552048,'At last, a target for my frustrations!',11238,1,0,0,'soccothrates SAY_AGGRO'), + +(-1552049,'Did you call on me?',11236,1,0,397,'soccothrates SAY_INTRO_1'), +(-1552050,'Why would I call on you?',0,1,0,396,'dalliah SAY_INTRO_2'), +(-1552051,'To do your heavy lifting, most likely.',0,1,0,396,'soccothrates SAY_INTRO_3'), +(-1552052,'When I need someone to prance around like an overstuffed peacock, I''ll call on you.',0,1,0,396,'dalliah SAY_INTRO_4'), +(-1552053,'Then I\'ll commit myself to ignoring you.',0,1,0,396,'soccothrates SAY_INTRO_5'), +(-1552054,'What would you know about commitment, sheet-sah?',0,1,0,396,'dalliah SAY_INTRO_6'), +(-1552055,'You\'re the one who should be-- Wait, we have company...',0,1,0,396,'soccothrates SAY_INTRO_7'); diff --git a/sql/updates/0.6/r2668_mangos.sql b/sql/updates/0.6/r2668_mangos.sql new file mode 100644 index 000000000..2d4199f69 --- /dev/null +++ b/sql/updates/0.6/r2668_mangos.sql @@ -0,0 +1,2 @@ +DELETE FROM `scripted_areatrigger` WHERE `entry` = 5604; +INSERT INTO `scripted_areatrigger` VALUES (5604, 'at_icecrown_citadel'); diff --git a/sql/updates/0.6/r2669_mangos.sql b/sql/updates/0.6/r2669_mangos.sql new file mode 100644 index 000000000..a270ba884 --- /dev/null +++ b/sql/updates/0.6/r2669_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18417; +UPDATE creature_template SET ScriptName='' WHERE entry=18141; diff --git a/sql/updates/0.6/r2670_mangos.sql b/sql/updates/0.6/r2670_mangos.sql new file mode 100644 index 000000000..032ea5e4d --- /dev/null +++ b/sql/updates/0.6/r2670_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='mob_frost_bomb' WHERE entry=37186; diff --git a/sql/updates/0.6/r2671_mangos.sql b/sql/updates/0.6/r2671_mangos.sql new file mode 100644 index 000000000..0dad5e263 --- /dev/null +++ b/sql/updates/0.6/r2671_mangos.sql @@ -0,0 +1,18 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18478; +UPDATE creature_template SET ScriptName='' WHERE entry=18431; +UPDATE creature_template SET ScriptName='' WHERE entry=19203; +UPDATE creature_template SET ScriptName='' WHERE entry=19205; +UPDATE creature_template SET ScriptName='' WHERE entry=19204; +UPDATE creature_template SET ScriptName='' WHERE entry=19206; +UPDATE creature_template SET ScriptName='' WHERE entry=17917; +UPDATE creature_template SET ScriptName='' WHERE entry=21101; +UPDATE creature_template SET ScriptName='' WHERE entry=20040; +UPDATE creature_template SET ScriptName='' WHERE entry=19710; +UPDATE creature_template SET ScriptName='' WHERE entry=20481; +UPDATE creature_template SET ScriptName='' WHERE entry=22140; +UPDATE creature_template SET ScriptName='' WHERE entry=21875; +UPDATE creature_template SET ScriptName='' WHERE entry=23469; +UPDATE creature_template SET ScriptName='' WHERE entry=23123; +UPDATE creature_template SET ScriptName='' WHERE entry=18588; +UPDATE creature_template SET ScriptName='' WHERE entry=22095; +UPDATE creature_template SET ScriptName='' WHERE entry=22307; diff --git a/sql/updates/0.6/r2671_scriptdev2.sql b/sql/updates/0.6/r2671_scriptdev2.sql new file mode 100644 index 000000000..525d67855 --- /dev/null +++ b/sql/updates/0.6/r2671_scriptdev2.sql @@ -0,0 +1,9 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1554012 AND -1554006; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1554006,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554007,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554008,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554009,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554010,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554011,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1554012,'REUSE_ME',0,0,0,0,'REUSE_ME'); diff --git a/sql/updates/0.6/r2673_mangos.sql b/sql/updates/0.6/r2673_mangos.sql new file mode 100644 index 000000000..84e04bf49 --- /dev/null +++ b/sql/updates/0.6/r2673_mangos.sql @@ -0,0 +1,13 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=12225; +UPDATE creature_template SET ScriptName='' WHERE entry=12203; +UPDATE creature_template SET ScriptName='' WHERE entry=12201; +UPDATE creature_template SET ScriptName='' WHERE entry=7358; +UPDATE creature_template SET ScriptName='' WHERE entry=15802; +UPDATE creature_template SET ScriptName='' WHERE entry=15334; +UPDATE creature_template SET ScriptName='' WHERE entry=15725; +UPDATE creature_template SET ScriptName='' WHERE entry=15726; +UPDATE creature_template SET ScriptName='' WHERE entry=17946; +UPDATE creature_template SET ScriptName='' WHERE entry=3057; +UPDATE creature_template SET ScriptName='' WHERE entry=17848; +UPDATE creature_template SET ScriptName='' WHERE entry=18096; +UPDATE creature_template SET ScriptName='' WHERE entry=17862; diff --git a/sql/updates/0.6/r2673_scriptdev2.sql b/sql/updates/0.6/r2673_scriptdev2.sql new file mode 100644 index 000000000..4d0461bcd --- /dev/null +++ b/sql/updates/0.6/r2673_scriptdev2.sql @@ -0,0 +1,32 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1129004 AND -1129000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1129000,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129001,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129002,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129003,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1129004,'REUSE_ME',0,0,0,0,'REUSE_ME'); +DELETE FROM script_texts WHERE entry BETWEEN -1560012 AND -1560006; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1560006,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560007,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560008,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560009,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560010,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560011,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560012,'REUSE_ME',0,0,0,0,'REUSE_ME'); +DELETE FROM script_texts WHERE entry BETWEEN -1560022 AND -1560016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1560016,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560017,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560018,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560019,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560020,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560021,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560022,'REUSE_ME',0,0,0,0,'REUSE_ME'); +DELETE FROM script_texts WHERE entry BETWEEN -1560005 AND -1560001; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1560001,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560002,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560003,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560004,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1560005,'REUSE_ME',0,0,0,0,'REUSE_ME'); diff --git a/sql/updates/0.6/r2674_mangos.sql b/sql/updates/0.6/r2674_mangos.sql new file mode 100644 index 000000000..bcaf00f30 --- /dev/null +++ b/sql/updates/0.6/r2674_mangos.sql @@ -0,0 +1,51 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18338; +UPDATE creature_template SET ScriptName='' WHERE entry IN (8530,8531,8532); +UPDATE creature_template SET ScriptName='' WHERE entry=15085; +UPDATE creature_template SET ScriptName='' WHERE entry=15082; +UPDATE creature_template SET ScriptName='' WHERE entry=15114; +UPDATE creature_template SET ScriptName='' WHERE entry=14986; +UPDATE creature_template SET ScriptName='' WHERE entry=10440; +UPDATE creature_template SET ScriptName='' WHERE entry=10435; +UPDATE creature_template SET ScriptName='' WHERE entry=10437; +UPDATE creature_template SET ScriptName='' WHERE entry=11143; +UPDATE creature_template SET ScriptName='' WHERE entry=11136; +UPDATE creature_template SET ScriptName='' WHERE entry=10439; +UPDATE creature_template SET ScriptName='' WHERE entry=10808; +UPDATE creature_template SET ScriptName='' WHERE entry=11439; +UPDATE creature_template SET ScriptName='' WHERE entry=16118; +UPDATE creature_template SET ScriptName='' WHERE entry=14516; +UPDATE creature_template SET ScriptName='' WHERE entry=14693; +UPDATE creature_template SET ScriptName='' WHERE entry=3974; +UPDATE creature_template SET ScriptName='' WHERE entry=3983; +UPDATE creature_template SET ScriptName='' WHERE entry=4543; +UPDATE creature_template SET ScriptName='' WHERE entry=6490; +UPDATE creature_template SET ScriptName='' WHERE entry=4542; +UPDATE creature_template SET ScriptName='' WHERE entry=17167; +UPDATE creature_template SET ScriptName='' WHERE entry=19875; +UPDATE creature_template SET ScriptName='' WHERE entry=19874; +UPDATE creature_template SET ScriptName='' WHERE entry=19872; +UPDATE creature_template SET ScriptName='' WHERE entry=17007; +UPDATE creature_template SET ScriptName='' WHERE entry=19876; +UPDATE creature_template SET ScriptName='' WHERE entry=19873; +UPDATE creature_template SET ScriptName='' WHERE entry=24240; +UPDATE creature_template SET ScriptName='' WHERE entry=24241; +UPDATE creature_template SET ScriptName='' WHERE entry=24242; +UPDATE creature_template SET ScriptName='' WHERE entry=24243; +UPDATE creature_template SET ScriptName='' WHERE entry=24244; +UPDATE creature_template SET ScriptName='' WHERE entry=24245; +UPDATE creature_template SET ScriptName='' WHERE entry=24246; +UPDATE creature_template SET ScriptName='' WHERE entry=24247; +UPDATE creature_template SET ScriptName='' WHERE entry=10363; +UPDATE creature_template SET ScriptName='' WHERE entry=10220; +UPDATE creature_template SET ScriptName='' WHERE entry=9196; +UPDATE creature_template SET ScriptName='' WHERE entry=10596; +UPDATE creature_template SET ScriptName='' WHERE entry=9736; +UPDATE creature_template SET ScriptName='' WHERE entry=10429; +UPDATE creature_template SET ScriptName='' WHERE entry=9236; +UPDATE creature_template SET ScriptName='' WHERE entry=10430; +UPDATE creature_template SET ScriptName='' WHERE entry=9237; +UPDATE creature_template SET ScriptName='' WHERE entry=9031; +UPDATE creature_template SET ScriptName='' WHERE entry=9502; +UPDATE creature_template SET ScriptName='' WHERE entry=9027; +UPDATE creature_template SET ScriptName='' WHERE entry=9028; +UPDATE creature_template SET ScriptName='' WHERE entry=9938; diff --git a/sql/updates/0.6/r2674_scriptdev2.sql b/sql/updates/0.6/r2674_scriptdev2.sql new file mode 100644 index 000000000..5f457a20d --- /dev/null +++ b/sql/updates/0.6/r2674_scriptdev2.sql @@ -0,0 +1,14 @@ +DELETE FROM script_texts WHERE entry=-1189021; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1189021,'REUSE_ME',0,0,0,0,'REUSE_ME'); +DELETE FROM script_texts WHERE entry BETWEEN -1189014 AND -1189011; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1189011,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189012,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189013,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189014,'REUSE_ME',0,0,0,0,'REUSE_ME'); +DELETE FROM script_texts WHERE entry BETWEEN -1189018 AND -1189016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1189016,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189017,'REUSE_ME',0,0,0,0,'REUSE_ME'), +(-1189018,'REUSE_ME',0,0,0,0,'REUSE_ME'); diff --git a/sql/updates/0.6/r2679_mangos.sql b/sql/updates/0.6/r2679_mangos.sql new file mode 100644 index 000000000..beb28edd7 --- /dev/null +++ b/sql/updates/0.6/r2679_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=14347; diff --git a/sql/updates/0.6/r2683_mangos.sql b/sql/updates/0.6/r2683_mangos.sql new file mode 100644 index 000000000..d4e726dd8 --- /dev/null +++ b/sql/updates/0.6/r2683_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='boss_rotface' WHERE entry=36627; +UPDATE creature_template SET ScriptName='mob_little_ooze' WHERE entry=36897; +UPDATE creature_template SET ScriptName='mob_big_ooze' WHERE entry=36899; diff --git a/sql/updates/0.6/r2685_mangos.sql b/sql/updates/0.6/r2685_mangos.sql new file mode 100644 index 000000000..971d0bb88 --- /dev/null +++ b/sql/updates/0.6/r2685_mangos.sql @@ -0,0 +1,6 @@ +UPDATE creature_template SET ScriptName='boss_valithria_dreamwalker' WHERE entry=36789; +UPDATE creature_template SET ScriptName='mob_gluttonous_abomination' WHERE entry=37886; +UPDATE creature_template SET ScriptName='mob_blistering_zombie' WHERE entry=37934; +UPDATE creature_template SET ScriptName='mob_risen_archmage' WHERE entry=37868; +UPDATE creature_template SET ScriptName='mob_blazing_skeleton' WHERE entry=36791; +UPDATE creature_template SET ScriptName='mob_suppresser' WHERE entry=37863; diff --git a/sql/updates/0.6/r2687_mangos.sql b/sql/updates/0.6/r2687_mangos.sql new file mode 100644 index 000000000..b588bef55 --- /dev/null +++ b/sql/updates/0.6/r2687_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (15170,15171); diff --git a/sql/updates/0.6/r2688_mangos.sql b/sql/updates/0.6/r2688_mangos.sql new file mode 100644 index 000000000..fba8074de --- /dev/null +++ b/sql/updates/0.6/r2688_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=11064; diff --git a/sql/updates/0.6/r2689_mangos.sql b/sql/updates/0.6/r2689_mangos.sql new file mode 100644 index 000000000..dc9cf5160 --- /dev/null +++ b/sql/updates/0.6/r2689_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=3442; +UPDATE creature_template SET ScriptName='' WHERE entry=7564; diff --git a/sql/updates/0.6/r2690_mangos.sql b/sql/updates/0.6/r2690_mangos.sql new file mode 100644 index 000000000..55a8fe3be --- /dev/null +++ b/sql/updates/0.6/r2690_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_professor_putricide' WHERE entry=36678; diff --git a/sql/updates/0.6/r2692_mangos.sql b/sql/updates/0.6/r2692_mangos.sql new file mode 100644 index 000000000..f3f99148f --- /dev/null +++ b/sql/updates/0.6/r2692_mangos.sql @@ -0,0 +1,5 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=37886; +UPDATE creature_template SET ScriptName='' WHERE entry=37934; +UPDATE creature_template SET ScriptName='' WHERE entry=37868; +UPDATE creature_template SET ScriptName='' WHERE entry=36791; +UPDATE creature_template SET ScriptName='' WHERE entry=37863; diff --git a/sql/updates/0.6/r2693_mangos.sql b/sql/updates/0.6/r2693_mangos.sql new file mode 100644 index 000000000..b0d17ba4e --- /dev/null +++ b/sql/updates/0.6/r2693_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_the_lich_king_icc' WHERE entry=36597; diff --git a/sql/updates/0.6/r2695_mangos.sql b/sql/updates/0.6/r2695_mangos.sql new file mode 100644 index 000000000..039ed20e3 --- /dev/null +++ b/sql/updates/0.6/r2695_mangos.sql @@ -0,0 +1,4 @@ +DELETE FROM scripted_event_id WHERE id=11111; +INSERT INTO scripted_event_id VALUES +(11111,'event_go_barrel_old_hillsbrad'); +UPDATE gameobject_template SET ScriptName='' WHERE entry=182589; diff --git a/sql/updates/0.6/r2695_scriptdev2.sql b/sql/updates/0.6/r2695_scriptdev2.sql new file mode 100644 index 000000000..a70d28341 --- /dev/null +++ b/sql/updates/0.6/r2695_scriptdev2.sql @@ -0,0 +1,167 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1560012 AND -1560000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1560000,'Thrall! You didn\'t really think you would escape did you? You and your allies shall answer to Blackmoore - after I\'ve had my fun!',10406,0,0,1,'skarloc SAY_ENTER'), +(-1560001,'My magical power can turn back time to before Thrall\'s death, but be careful. My power to manipulate time is limited.',0,0,0,0,'image of eronzion SAY_RESET_THRALL'), +(-1560002,'I have set back the flow of time just once more. If you fail to prevent Thrall\'s death, then all is lost.',0,0,0,0,'image of eronzion SAY_RESET_THRALL_LAST'), +(-1560003,'What\'s the meaning of this? GUARDS!',0,0,0,0,'armorer SAY_CALL_GUARDS'), +(-1560004,'All that you know... will be undone.',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_1'), +(-1560005,'Let\'s go.',0,0,0,0,'thrall hillsbrad SAY_TH_ARMORY2'), +(-1560006,'%s startles the horse with a fierce yell!',0,2,0,0,'thrall hillsbrad EMOTE_TH_STARTLE_HORSE'), +(-1560007,'I thought I saw something go into the barn.',0,0,0,0,'tarren mill lookout SAY_LOOKOUT_BARN_1'), +(-1560008,'I didn\'t see anything.',0,0,0,0,'tarren mill lookout SAY_PROTECTOR_BARN_2'), +(-1560009,'%s tries to calm the horse down.',0,2,0,0,'thrall EMOTE_TH_CALM_HORSE'), +(-1560010,'Something riled that horse. Let\'s go!',0,0,0,0,'tarren mill lookout SAY_PROTECTOR_BARN_3'), +(-1560011,'Taretha isn\'t here. Let\'s head into town.',0,0,0,0,'thrall hillsbrad SAY_TH_HEAD_TOWN'), +(-1560012,'She\'s not here.',0,0,0,0,'thrall hillsbrad SAY_TH_CHURCH'); +DELETE FROM script_texts WHERE entry BETWEEN -1560020 AND -1560016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1560016,'Thrall\'s trapped himself in the chapel. He can\'t escape now.',0,0,0,0,'tarren mill lookout SAY_LOOKOUT_CHURCH'), +(-1560017,'He\'s here, stop him!',0,0,0,0,'tarren mill lookout SAY_LOOKOUT_INN'), +(-1560018,'We have all the time in the world....',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_2'), +(-1560019,'You cannot escape us!',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_3'), +(-1560020,'Do not think you can win!',0,0,0,0,'infinite dragon SAY_INFINITE_AGGRO_4'); + +UPDATE script_texts SET type=0 WHERE entry=-1560027; +DELETE FROM gossip_texts WHERE entry IN (-3560000,-3560007); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3560000,'We are ready to get you out of here, Thrall. Let\'s go!','thrall GOSSIP_ITEM_START'), +(-3560007,'Tarren Mill.','thrall GOSSIP_ITEM_TARREN_1'); + +DELETE FROM script_waypoint WHERE entry=17876; +INSERT INTO script_waypoint VALUES +(17876, 0, 2230.91, 118.765, 82.2947, 2000, 'open the prison door'), +(17876, 1, 2230.33, 114.980, 82.2946, 0, ''), +(17876, 2, 2233.36, 111.057, 82.2996, 0, ''), +(17876, 3, 2231.17, 108.486, 82.6624, 0, ''), +(17876, 4, 2220.22, 114.605, 89.4264, 0, ''), +(17876, 5, 2215.23, 115.990, 89.4549, 0, ''), +(17876, 6, 2210.00, 106.849, 89.4549, 0, ''), +(17876, 7, 2205.66, 105.234, 89.4549, 0, ''), +(17876, 8, 2192.26, 112.618, 89.4549, 2000, 'SAY_ARMORER_CALL_GUARDS'), +(17876, 9, 2185.32, 116.593, 89.4548, 2000, 'SAY_TH_ARMORER_HIT'), +(17876, 10, 2182.11, 120.328, 89.4548, 3000, 'SAY_TH_ARMORY_1'), +(17876, 11, 2182.11, 120.328, 89.4548, 5000, ''), +(17876, 12, 2182.11, 120.328, 89.4548, 3000, 'SAY_TH_ARMORY_2'), +(17876, 13, 2189.44, 113.922, 89.4549, 0, ''), +(17876, 14, 2195.63, 110.584, 89.4549, 0, ''), +(17876, 15, 2201.09, 115.115, 89.4549, 0, ''), +(17876, 16, 2204.34, 121.036, 89.4355, 0, ''), +(17876, 17, 2208.66, 129.127, 87.9560, 0, 'first ambush'), +(17876, 18, 2193.09, 137.940, 88.2164, 0, ''), +(17876, 19, 2173.39, 149.064, 87.9227, 0, ''), +(17876, 20, 2164.25, 137.965, 85.0595, 0, 'second ambush'), +(17876, 21, 2149.31, 125.645, 77.0858, 0, ''), +(17876, 22, 2142.78, 127.173, 75.5954, 0, ''), +(17876, 23, 2139.28, 133.952, 73.6386, 0, 'third ambush'), +(17876, 24, 2139.54, 155.235, 67.1269, 0, ''), +(17876, 25, 2145.38, 167.551, 64.8974, 0, 'fourth ambush'), +(17876, 26, 2134.28, 175.304, 67.9446, 0, ''), +(17876, 27, 2118.08, 187.387, 68.8141, 0, ''), +(17876, 28, 2105.88, 195.461, 65.1854, 0, ''), +(17876, 29, 2096.77, 196.939, 65.2117, 0, ''), +(17876, 30, 2083.90, 209.395, 64.8736, 0, ''), +(17876, 31, 2063.40, 229.509, 64.4883, 0, 'summon Skarloc'), +(17876, 32, 2063.40, 229.509, 64.4883, 10000, 'SAY_SKARLOC_ENTER'), +(17876, 33, 2063.40, 229.509, 64.4883, 5000, 'attack Skarloc'), +(17876, 34, 2063.40, 229.509, 64.4883, 0, 'gossip after skarloc'), +(17876, 35, 2046.70, 251.941, 62.7851, 4000, 'mount up'), +(17876, 36, 2046.70, 251.941, 62.7851, 3000, 'SAY_TH_MOUNTS_UP'), +(17876, 37, 2011.77, 278.478, 65.3388, 0, ''), +(17876, 38, 2005.08, 289.676, 66.1179, 0, ''), +(17876, 39, 2033.11, 337.450, 66.0948, 0, ''), +(17876, 40, 2070.30, 416.208, 66.0893, 0, ''), +(17876, 41, 2086.76, 469.768, 65.9182, 0, ''), +(17876, 42, 2101.70, 497.955, 61.7881, 0, ''), +(17876, 43, 2133.39, 530.933, 55.3700, 0, ''), +(17876, 44, 2157.91, 559.635, 48.5157, 0, ''), +(17876, 45, 2167.34, 586.191, 42.4394, 0, ''), +(17876, 46, 2174.17, 637.643, 33.9002, 0, ''), +(17876, 47, 2179.31, 656.053, 34.723, 0, ''), +(17876, 48, 2183.65, 670.941, 34.0318, 0, ''), +(17876, 49, 2201.50, 668.616, 36.1236, 0, ''), +(17876, 50, 2221.56, 652.747, 36.6153, 0, ''), +(17876, 51, 2238.97, 640.125, 37.2214, 0, ''), +(17876, 52, 2251.17, 620.574, 40.1473, 0, ''), +(17876, 53, 2261.98, 595.303, 41.4117, 0, ''), +(17876, 54, 2278.67, 560.172, 38.9090, 0, ''), +(17876, 55, 2336.72, 528.327, 40.9369, 0, ''), +(17876, 56, 2381.04, 519.612, 37.7312, 0, ''), +(17876, 57, 2412.20, 515.425, 39.2068, 0, ''), +(17876, 58, 2452.39, 516.174, 42.9387, 0, ''), +(17876, 59, 2467.38, 539.389, 47.4992, 0, ''), +(17876, 60, 2470.70, 554.333, 46.6668, 0, ''), +(17876, 61, 2478.07, 575.321, 55.4549, 0, ''), +(17876, 62, 2480.00, 585.408, 56.6921, 0, ''), +(17876, 63, 2482.67, 608.817, 55.6643, 0, ''), +(17876, 64, 2485.62, 626.061, 58.0132, 2000, 'dismount'), +(17876, 65, 2486.91, 626.356, 58.0761, 2000, 'EMOTE_TH_STARTLE_HORSE'), +(17876, 66, 2486.91, 626.356, 58.0761, 0, 'gossip before barn'), +(17876, 67, 2488.58, 660.940, 57.3913, 0, ''), +(17876, 68, 2502.56, 686.059, 55.6252, 0, ''), +(17876, 69, 2502.08, 694.360, 55.5083, 0, ''), +(17876, 70, 2491.46, 694.321, 55.7163, 0, 'enter barn'), +(17876, 71, 2491.10, 703.300, 55.7630, 0, ''), +(17876, 72, 2485.64, 702.992, 55.7917, 0, ''), +(17876, 73, 2479.63, 696.521, 55.7901, 0, 'spawn mobs'), +(17876, 74, 2476.24, 696.204, 55.8093, 0, 'start dialogue'), +(17876, 75, 2475.39, 695.983, 55.8146, 0, ''), +(17876, 76, 2477.75, 694.473, 55.7945, 0, ''), +(17876, 77, 2481.27, 697.747, 55.7910, 0, ''), +(17876, 78, 2486.31, 703.131, 55.7861, 0, ''), +(17876, 79, 2490.76, 703.511, 55.7662, 0, ''), +(17876, 80, 2491.30, 694.792, 55.7195, 0, 'exit barn'), +(17876, 81, 2502.08, 694.360, 55.5083, 0, ''), +(17876, 82, 2507.99, 679.298, 56.3760, 0, ''), +(17876, 83, 2524.79, 669.919, 54.9258, 0, ''), +(17876, 84, 2543.19, 665.289, 56.2957, 0, ''), +(17876, 85, 2566.49, 664.354, 54.5034, 0, ''), +(17876, 86, 2592.00, 664.611, 56.4394, 0, ''), +(17876, 87, 2614.43, 663.806, 55.3921, 2000, ''), +(17876, 88, 2616.14, 665.499, 55.1610, 0, ''), +(17876, 89, 2623.56, 666.965, 54.3983, 0, ''), +(17876, 90, 2629.99, 661.059, 54.2738, 0, ''), +(17876, 91, 2629.00, 656.982, 56.0651, 0, 'enter the church'), +(17876, 92, 2620.84, 633.007, 56.0300, 3000, 'SAY_TH_CHURCH_ENTER'), +(17876, 93, 2620.84, 633.007, 56.0300, 5000, 'church ambush'), +(17876, 94, 2620.84, 633.007, 56.0300, 0, 'SAY_TH_CHURCH_END'), +(17876, 95, 2622.99, 639.178, 56.0300, 0, ''), +(17876, 96, 2628.73, 656.693, 56.0610, 0, ''), +(17876, 97, 2630.34, 661.135, 54.2738, 0, ''), +(17876, 98, 2635.38, 672.243, 54.4508, 0, ''), +(17876, 99, 2644.13, 668.158, 55.3797, 0, ''), +(17876, 100, 2646.82, 666.740, 56.9898, 0, ''), +(17876, 101, 2658.22, 665.432, 57.1725, 0, ''), +(17876, 102, 2661.88, 674.849, 57.1725, 0, ''), +(17876, 103, 2656.23, 677.208, 57.1725, 0, ''), +(17876, 104, 2652.28, 670.270, 61.9353, 0, ''), +(17876, 105, 2650.79, 664.290, 61.9302, 0, 'inn ambush'), +(17876, 106, 2660.48, 659.409, 61.9370, 5000, 'SAY_TA_ESCAPED'), +(17876, 107, 2660.48, 659.409, 61.9370, 0, 'SAY_TH_MEET_TARETHA - gossip before epoch'), +(17876, 108, 2660.48, 659.409, 61.9370, 0, 'SAY_EPOCH_ENTER1'), +(17876, 109, 2650.62, 666.643, 61.9305, 0, ''), +(17876, 110, 2652.37, 670.561, 61.9368, 0, ''), +(17876, 111, 2656.05, 676.761, 57.1727, 0, ''), +(17876, 112, 2658.49, 677.166, 57.1727, 0, ''), +(17876, 113, 2659.28, 667.117, 57.1727, 0, ''), +(17876, 114, 2649.71, 665.387, 57.1727, 0, ''), +(17876, 115, 2634.79, 672.964, 54.4577, 0, 'outside inn'), +(17876, 116, 2635.06, 673.892, 54.4713, 18000, 'SAY_EPOCH_ENTER3'), +(17876, 117, 2635.06, 673.892, 54.4713, 0, 'fight begins'), +(17876, 118, 2635.06, 673.892, 54.4713, 0, 'fight ends'), +(17876, 119, 2634.30, 661.698, 54.4147, 0, 'run off'), +(17876, 120, 2652.21, 644.396, 56.1906, 0, ''); + +DELETE FROM script_waypoint WHERE entry=18887; +INSERT INTO script_waypoint VALUES +(18887, 0, 2650.06, 665.473, 61.9305, 0, ''), +(18887, 1, 2652.44, 670.761, 61.9370, 0, ''), +(18887, 2, 2655.96, 676.913, 57.1725, 0, ''), +(18887, 3, 2659.40, 677.317, 57.1725, 0, ''), +(18887, 4, 2651.75, 664.482, 57.1725, 0, ''), +(18887, 5, 2647.49, 666.595, 57.0824, 0, ''), +(18887, 6, 2644.37, 668.167, 55.4182, 0, ''), +(18887, 7, 2638.57, 671.231, 54.5200, 0, 'start dialogue - escort paused'), +(18887, 8, 2636.56, 679.894, 54.6595, 0, ''), +(18887, 9, 2640.79, 689.647, 55.3215, 0, ''), +(18887, 10, 2639.35, 706.777, 56.0667, 0, ''), +(18887, 11, 2617.70, 731.884, 55.5571, 0, ''); diff --git a/sql/updates/0.6/r2696_scriptdev2.sql b/sql/updates/0.6/r2696_scriptdev2.sql new file mode 100644 index 000000000..04c79f953 --- /dev/null +++ b/sql/updates/0.6/r2696_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry=-1532115; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1532115,'Splendid, I\'m going to get the audience ready. Break a leg!',0,0,0,0,'barnes SAY_EVENT_START'); +DELETE FROM gossip_texts WHERE entry IN (-3532000,-3532001,-3532002); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3532000,'Teleport me to the Guardian\'s Library','berthold GOSSIP_ITEM_TELEPORT'), +(-3532001,'I\'m not an actor.','barnes GOSSIP_ITEM_OPERA_1'), +(-3532002,'Ok, I\'ll give it a try, then.','barnes GOSSIP_ITEM_OPERA_2'); diff --git a/sql/updates/0.6/r2697_scriptdev2.sql b/sql/updates/0.6/r2697_scriptdev2.sql new file mode 100644 index 000000000..ddafeaeac --- /dev/null +++ b/sql/updates/0.6/r2697_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM gossip_texts WHERE entry IN (-3532003,-3532004,-3532005); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3532003,'I\'ve never been more ready.','barnes GOSSIP_ITEM_OPERA_JULIANNE_WIPE'), +(-3532004,'The wolf\'s going down.','barnes GOSSIP_ITEM_OPERA_WOLF_WIPE'), +(-3532005,'What phat lewtz you have grandmother?','grandma GOSSIP_ITEM_GRANDMA'); diff --git a/sql/updates/0.6/r2700_mangos.sql b/sql/updates/0.6/r2700_mangos.sql new file mode 100644 index 000000000..1acb18d33 --- /dev/null +++ b/sql/updates/0.6/r2700_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=10432; diff --git a/sql/updates/0.6/r2701_mangos.sql b/sql/updates/0.6/r2701_mangos.sql new file mode 100644 index 000000000..fdaf5b752 --- /dev/null +++ b/sql/updates/0.6/r2701_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=18412; diff --git a/sql/updates/0.6/r2702_mangos.sql b/sql/updates/0.6/r2702_mangos.sql new file mode 100644 index 000000000..ad92fdf84 --- /dev/null +++ b/sql/updates/0.6/r2702_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='npc_image_of_medivh' WHERE entry=17651; +DELETE FROM scripted_event_id WHERE id=10951; +INSERT INTO scripted_event_id VALUES +(10951,'event_spell_medivh_journal'); diff --git a/sql/updates/0.6/r2702_scriptdev2.sql b/sql/updates/0.6/r2702_scriptdev2.sql new file mode 100644 index 000000000..efc5127fe --- /dev/null +++ b/sql/updates/0.6/r2702_scriptdev2.sql @@ -0,0 +1,11 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1532124 AND -1532116; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1532116,'You\'ve got my attention, dragon. You\'ll find I\'m not as easily scared as the villagers below.',0,1,0,0,'image of medivh SAY_MEDIVH_1'), +(-1532117,'Your dabbling in the arcane has gone too far, Medivh. You\'ve attracted the attention of powers beyond your understanding. You must leave Karazhan at once!',0,1,0,0,'arcanagos SAY_ARCANAGOS_2'), +(-1532118,'You dare challenge me at my own dwelling? Your arrogance is astounding, even for a dragon.',0,1,0,0,'image of medivh SAY_MEDIVH_3'), +(-1532119,'A dark power seeks to use you, Medivh! If you stay, dire days will follow. You must hurry, we don\'t have much time!',0,1,0,0,'arcanagos SAY_ARCANAGOS_4'), +(-1532120,'I do not know what you speak of, dragon... but I will not be bullied by this display of insolence. I\'ll leave Karazhan when it suits me!',0,1,0,0,'image of medivh SAY_MEDIVH_5'), +(-1532121,'You leave me no alternative. I will stop you by force if you wont listen to reason.',0,1,0,0,'arcanagos SAY_ARCANAGOS_6'), +(-1532122,'%s begins to cast a spell of great power, weaving his own essence into the magic.',0,2,0,0,'image of medivh EMOTE_CAST_SPELL'), +(-1532123,'What have you done, wizard? This cannot be! I\'m burning from... within!',0,1,0,0,'arcanagos SAY_ARCANAGOS_7'), +(-1532124,'He should not have angered me. I must go... recover my strength now...',0,0,0,0,'image of medivh SAY_MEDIVH_8'); diff --git a/sql/updates/0.6/r2703_mangos.sql b/sql/updates/0.6/r2703_mangos.sql new file mode 100644 index 000000000..980044589 --- /dev/null +++ b/sql/updates/0.6/r2703_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_image_arcanagos' WHERE entry=17652; diff --git a/sql/updates/0.6/r2704_mangos.sql b/sql/updates/0.6/r2704_mangos.sql new file mode 100644 index 000000000..18a79d165 --- /dev/null +++ b/sql/updates/0.6/r2704_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='boss_nightbane' WHERE entry=17225; +DELETE FROM scripted_event_id WHERE id in (10591); +INSERT INTO scripted_event_id VALUES +(10591,'event_spell_summon_nightbane'); diff --git a/sql/updates/0.6/r2704_scriptdev2.sql b/sql/updates/0.6/r2704_scriptdev2.sql new file mode 100644 index 000000000..5a50904fe --- /dev/null +++ b/sql/updates/0.6/r2704_scriptdev2.sql @@ -0,0 +1,42 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1532130 AND -1532125; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1532125,'An ancient being awakens in the distance...',0,2,0,0,'nightbane EMOTE_AWAKEN'), +(-1532126,'What fools! I shall bring a quick end to your suffering!',0,1,0,0,'nightbane SAY_AGGRO'), +(-1532127,'Miserable vermin. I shall exterminate you from the air!',0,1,0,0,'nightbane SAY_AIR_PHASE'), +(-1532128,'Enough! I shall land and crush you myself!',0,1,0,0,'nightbane SAY_LAND_PHASE_1'), +(-1532129,'Insects! Let me show you my strength up close!',0,1,0,0,'nightbane SAY_LAND_PHASE_2'), +(-1532130,'%s takes a deep breath.',0,3,0,0,'nightbane EMOTE_DEEP_BREATH'); +DELETE FROM script_waypoint WHERE entry=17225; +INSERT INTO script_waypoint VALUES +(17225, 0, -11033.51, -1784.65, 182.284, 3000, ''), +(17225, 1, -11107.57, -1873.36, 136.878, 0, ''), +(17225, 2, -11118.71, -1883.65, 132.441, 0, ''), +(17225, 3, -11132.92, -1888.12, 128.969, 0, ''), +(17225, 4, -11150.31, -1890.54, 126.557, 0, ''), +(17225, 5, -11160.64, -1891.63, 124.793, 0, ''), +(17225, 6, -11171.52, -1889.45, 123.417, 0, ''), +(17225, 7, -11183.46, -1884.09, 119.754, 0, ''), +(17225, 8, -11196.25, -1874.01, 115.227, 0, ''), +(17225, 9, -11205.59, -1859.66, 110.216, 0, ''), +(17225, 10, -11236.53, -1818.03, 97.3972, 0, ''), +(17225, 11, -11253.11, -1794.48, 93.3101, 0, ''), +(17225, 12, -11254.86, -1787.13, 92.5174, 0, ''), +(17225, 13, -11253.32, -1777.08, 91.7739, 0, ''), +(17225, 14, -11247.48, -1770.27, 92.4183, 0, ''), +(17225, 15, -11238.61, -1766.51, 94.6417, 0, ''), +(17225, 16, -11227.56, -1767.22, 100.256, 0, ''), +(17225, 17, -11218.41, -1770.55, 107.859, 0, ''), +(17225, 18, -11204.81, -1781.77, 110.383, 0, ''), +(17225, 19, -11195.77, -1801.07, 110.833, 0, ''), +(17225, 20, -11195.81, -1824.66, 113.936, 0, ''), +(17225, 21, -11197.11, -1860.01, 117.945, 0, ''), +(17225, 22, -11194.60, -1884.23, 121.401, 0, ''), +(17225, 23, -11184.21, -1894.78, 120.326, 0, ''), +(17225, 24, -11176.91, -1899.84, 119.844, 0, ''), +(17225, 25, -11168.13, -1901.77, 118.958, 0, ''), +(17225, 26, -11154.91, -1901.66, 117.218, 0, ''), +(17225, 27, -11143.15, -1901.22, 115.885, 0, ''), +(17225, 28, -11131.19, -1897.59, 113.722, 0, ''), +(17225, 29, -11121.31, -1890.25, 111.643, 0, ''), +(17225, 30, -11118.22, -1883.83, 110.595, 3000, ''), +(17225, 31, -11118.45, -1883.68, 91.473, 0, 'start combat'); diff --git a/sql/updates/0.6/r2706_mangos.sql b/sql/updates/0.6/r2706_mangos.sql new file mode 100644 index 000000000..494bd50cf --- /dev/null +++ b/sql/updates/0.6/r2706_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=17646; +UPDATE creature_template SET ScriptName='npc_infernal_target' WHERE entry=17644; diff --git a/sql/updates/0.6/r2707_mangos.sql b/sql/updates/0.6/r2707_mangos.sql new file mode 100644 index 000000000..68cb2dbb8 --- /dev/null +++ b/sql/updates/0.6/r2707_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_shade_of_aran_blizzard' WHERE entry=17161; diff --git a/sql/updates/0.6/r2708_mangos.sql b/sql/updates/0.6/r2708_mangos.sql new file mode 100644 index 000000000..de3461ca5 --- /dev/null +++ b/sql/updates/0.6/r2708_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=17548; diff --git a/sql/updates/0.6/r2710_scriptdev2.sql b/sql/updates/0.6/r2710_scriptdev2.sql new file mode 100644 index 000000000..84f796272 --- /dev/null +++ b/sql/updates/0.6/r2710_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=3 WHERE entry IN (-1532089,-1532090); diff --git a/sql/updates/0.6/r2712_mangos.sql b/sql/updates/0.6/r2712_mangos.sql new file mode 100644 index 000000000..8f4f1e5b7 --- /dev/null +++ b/sql/updates/0.6/r2712_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_dragonhawk_egg' WHERE entry=23817; diff --git a/sql/updates/0.6/r2718_scriptdev2.sql b/sql/updates/0.6/r2718_scriptdev2.sql new file mode 100644 index 000000000..d8822639d --- /dev/null +++ b/sql/updates/0.6/r2718_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1548056; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1548056,'%s takes a deep breath!',0,3,0,0,'lurker below EMOTE_DEEP_BREATH'); diff --git a/sql/updates/0.6/r2720_mangos.sql b/sql/updates/0.6/r2720_mangos.sql new file mode 100644 index 000000000..c9314865b --- /dev/null +++ b/sql/updates/0.6/r2720_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=23598; diff --git a/sql/updates/0.6/r2721_scriptdev2.sql b/sql/updates/0.6/r2721_scriptdev2.sql new file mode 100644 index 000000000..cb49c6ef0 --- /dev/null +++ b/sql/updates/0.6/r2721_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=3 WHERE entry IN (-1548039, -1548041); diff --git a/sql/updates/0.6/r2722_mangos.sql b/sql/updates/0.6/r2722_mangos.sql new file mode 100644 index 000000000..b0d861869 --- /dev/null +++ b/sql/updates/0.6/r2722_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_coren_direbrew' WHERE entry=23872; diff --git a/sql/updates/0.6/r2722_scriptdev2.sql b/sql/updates/0.6/r2722_scriptdev2.sql new file mode 100644 index 000000000..1a336d9c1 --- /dev/null +++ b/sql/updates/0.6/r2722_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1230034; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1230034,'You\'ll pay for this insult, $c!',0,0,0,15,'coren direbrew SAY_AGGRO'); diff --git a/sql/updates/0.6/r2730_mangos.sql b/sql/updates/0.6/r2730_mangos.sql new file mode 100644 index 000000000..4d16e708a --- /dev/null +++ b/sql/updates/0.6/r2730_mangos.sql @@ -0,0 +1,4 @@ +UPDATE item_template SET ScriptName='' WHERE entry=31088; +UPDATE creature_template SET ScriptName='' WHERE entry=19870; +UPDATE creature_template SET ScriptName='' WHERE entry=22009; +UPDATE gameobject_template SET ScriptName='go_shield_generator' WHERE entry IN (185051,185052,185053,185054); diff --git a/sql/updates/0.6/r2731_mangos.sql b/sql/updates/0.6/r2731_mangos.sql new file mode 100644 index 000000000..e80d82254 --- /dev/null +++ b/sql/updates/0.6/r2731_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_target_trigger' WHERE entry=17474; diff --git a/sql/updates/0.6/r2731_scriptdev2.sql b/sql/updates/0.6/r2731_scriptdev2.sql new file mode 100644 index 000000000..c6c2e38d0 --- /dev/null +++ b/sql/updates/0.6/r2731_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry=-1544016; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1544016,'%s is nearly free of his bonds!',0,2,0,0,'magtheridon EMOTE_NEARLY_FREE'); +UPDATE script_texts SET type=6 WHERE entry IN (-1544000, -1544001, -1544002, -1544003, -1544004, -1544005); diff --git a/sql/updates/0.6/r2734_mangos.sql b/sql/updates/0.6/r2734_mangos.sql new file mode 100644 index 000000000..60804b924 --- /dev/null +++ b/sql/updates/0.6/r2734_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_shield_orb' WHERE entry=25502; diff --git a/sql/updates/0.6/r2734_scriptdev2.sql b/sql/updates/0.6/r2734_scriptdev2.sql new file mode 100644 index 000000000..2fce2de05 --- /dev/null +++ b/sql/updates/0.6/r2734_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1580064, -1580065, -1580066, -1580067, -1580068); diff --git a/sql/updates/0.6/r2737_mangos.sql b/sql/updates/0.6/r2737_mangos.sql new file mode 100644 index 000000000..ca7403767 --- /dev/null +++ b/sql/updates/0.6/r2737_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_enslaved_soul' WHERE entry=23469; +UPDATE creature_template SET ScriptName='' WHERE entry=23111; diff --git a/sql/updates/0.6/r2740_scriptdev2.sql b/sql/updates/0.6/r2740_scriptdev2.sql new file mode 100644 index 000000000..6819ca841 --- /dev/null +++ b/sql/updates/0.6/r2740_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry=-1564130; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1564130,'Broken of the Ashtongue tribe, your leader speaks!',0,1,0,0,'akama shade SAY_FREE_1'); +UPDATE script_texts SET sound=11386 WHERE entry=-1564013; +UPDATE script_texts SET sound=11385 WHERE entry=-1564014; +DELETE FROM gossip_texts WHERE entry=-3564000; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3564000,'I\'m with you, Akama.','akama(shade) GOSSIP_ITEM_START_ENCOUNTER'); diff --git a/sql/updates/0.6/r2742_mangos.sql b/sql/updates/0.6/r2742_mangos.sql new file mode 100644 index 000000000..1b3927857 --- /dev/null +++ b/sql/updates/0.6/r2742_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_protectorate_demolitionist' WHERE entry=20802; diff --git a/sql/updates/0.6/r2742_scriptdev2.sql b/sql/updates/0.6/r2742_scriptdev2.sql new file mode 100644 index 000000000..a916d8e6b --- /dev/null +++ b/sql/updates/0.6/r2742_scriptdev2.sql @@ -0,0 +1,29 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000900 AND -1000891; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000891,'Let\'s do this... Just keep me covered and I\'ll deliver the package.',0,0,0,0,'demolitionist SAY_INTRO'), +(-1000892,'I\'m under attack! I repeat, I am under attack!',0,0,0,0,'demolitionist SAY_ATTACK_1'), +(-1000893,'I need to find a new line of work.',0,0,0,0,'demolitionist SAY_ATTACK_2'), +(-1000894,'By the second sun of K\'aresh, look at this place! I can only imagine what Salhadaar is planning. Come on, let\'s keep going.',0,0,0,1,'demolitionist SAY_STAGING_GROUNDS'), +(-1000895,'With this much void waste and run off, a toxic void horror can\'t be too far behind.',0,0,0,0,'demolitionist SAY_TOXIC_HORROR'), +(-1000896,'Look there, fleshling! Salhadaar\'s conduits! He\'s keeping well fed...',0,0,0,1,'demolitionist SAY_SALHADAAR'), +(-1000897,'Alright, keep me protected while I plant this disruptor. This shouldn\'t take very long...',0,0,0,0,'demolitionist SAY_DISRUPTOR'), +(-1000898,'Protect the conduit! Stop the intruders!',0,0,0,0,'nexus stalkers SAY_PROTECT'), +(-1000899,'Done! Back up! Back up!',0,0,0,0,'demolitionist SAY_FINISH_1'), +(-1000900,'Looks like my work here is done. Report to the holo-image of Ameer over at the transporter.',0,0,0,1,'demolitionist SAY_FINISH_2'); + +DELETE FROM script_waypoint WHERE entry=20802; +INSERT INTO script_waypoint VALUES +(20802, 0, 4017.864, 2325.038, 114.029, 3000, 'SAY_INTRO'), +(20802, 1, 4006.373, 2324.593, 111.455, 0, ''), +(20802, 2, 3998.391, 2326.364, 113.164, 0, ''), +(20802, 3, 3982.309, 2330.261, 113.846, 7000, 'SAY_STAGING_GROUNDS'), +(20802, 4, 3950.646, 2329.249, 113.924, 0, 'SAY_TOXIC_HORROR'), +(20802, 5, 3939.229, 2330.994, 112.197, 0, ''), +(20802, 6, 3927.858, 2333.644, 111.330, 0, ''), +(20802, 7, 3917.851, 2337.696, 113.493, 0, ''), +(20802, 8, 3907.743, 2343.336, 114.062, 0, ''), +(20802, 9, 3878.760, 2378.611, 114.037, 8000, 'SAY_SALHADAAR'), +(20802, 10, 3863.153, 2355.876, 114.987, 0, ''), +(20802, 11, 3861.241, 2344.893, 115.201, 0, ''), +(20802, 12, 3872.463, 2323.114, 114.671, 0, 'escort paused - SAY_DISRUPTOR'), +(20802, 13, 3863.740, 2349.790, 115.382, 0, 'SAY_FINISH_2'); diff --git a/sql/updates/0.6/r2743_mangos.sql b/sql/updates/0.6/r2743_mangos.sql new file mode 100644 index 000000000..c5b3652d4 --- /dev/null +++ b/sql/updates/0.6/r2743_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_captured_vanguard' WHERE entry=20763; diff --git a/sql/updates/0.6/r2743_scriptdev2.sql b/sql/updates/0.6/r2743_scriptdev2.sql new file mode 100644 index 000000000..07444dbc8 --- /dev/null +++ b/sql/updates/0.6/r2743_scriptdev2.sql @@ -0,0 +1,28 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000904 AND -1000901; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000901,'Thanks, friend. Will you help me get out of here?',0,0,0,1,'vanguard SAY_VANGUARD_INTRO'), +(-1000902,'We\'re not too far from the Protectorate Watch Post, $N. This way!',0,0,0,1,'vanguard SAY_VANGUARD_START'), +(-1000903,'Commander! This fleshling rescued me!',0,0,0,0,'vanguard SAY_VANGUARD_FINISH'), +(-1000904,'%s salutes $N.',0,2,0,0,'vanguard EMOTE_VANGUARD_FINISH'); + +DELETE FROM script_waypoint WHERE entry=20763; +INSERT INTO script_waypoint VALUES +(20763, 0, 4084.092, 2297.254, 110.277, 0, ''), +(20763, 1, 4107.174, 2294.916, 106.625, 0, ''), +(20763, 2, 4154.129, 2296.789, 102.331, 0, ''), +(20763, 3, 4166.021, 2302.819, 103.422, 0, ''), +(20763, 4, 4195.039, 2301.094, 113.786, 0, ''), +(20763, 5, 4205.246, 2297.116, 117.992, 0, ''), +(20763, 6, 4230.429, 2294.642, 127.307, 0, ''), +(20763, 7, 4238.981, 2293.579, 129.332, 0, ''), +(20763, 8, 4250.184, 2293.272, 129.009, 0, ''), +(20763, 9, 4262.810, 2290.768, 126.485, 0, ''), +(20763, 10, 4265.845, 2278.562, 128.235, 0, ''), +(20763, 11, 4265.609, 2265.734, 128.452, 0, ''), +(20763, 12, 4258.838, 2245.354, 132.804, 0, ''), +(20763, 13, 4247.976, 2221.211, 137.668, 0, ''), +(20763, 14, 4247.973, 2213.876, 137.721, 0, ''), +(20763, 15, 4249.876, 2204.265, 137.121, 4000, ''), +(20763, 16, 4249.876, 2204.265, 137.121, 0, 'SAY_VANGUARD_FINISH'), +(20763, 17, 4252.455, 2170.885, 137.677, 3000, 'EMOTE_VANGUARD_FINISH'), +(20763, 18, 4252.455, 2170.885, 137.677, 5000, ''); diff --git a/sql/updates/0.6/r2745_mangos.sql b/sql/updates/0.6/r2745_mangos.sql new file mode 100644 index 000000000..c3e1078cf --- /dev/null +++ b/sql/updates/0.6/r2745_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=23336; +UPDATE creature_template SET ScriptName='' WHERE entry=23069; +UPDATE creature_template SET ScriptName='' WHERE entry=23259; +UPDATE gameobject_template SET ScriptName='' WHERE entry=185916; diff --git a/sql/updates/0.6/r2745_scriptdev2.sql b/sql/updates/0.6/r2745_scriptdev2.sql new file mode 100644 index 000000000..97f51a36c --- /dev/null +++ b/sql/updates/0.6/r2745_scriptdev2.sql @@ -0,0 +1,74 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1564134 AND -1564131; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1564131,'This door is all that stands between us and the Betrayer. Stand aside, friends.',0,0,0,1,'akama illidan SAY_OPEN_DOOR_1'), +(-1564132,'I cannot do this alone...',0,0,0,0,'akama illidan SAY_OPEN_DOOR_2'), +(-1564133,'You are not alone, Akama.',0,0,0,0,'spirit Udalo SAY_OPEN_DOOR_3'), +(-1564134,'Your people will always be with you!',0,0,0,0,'spirit Olum SAY_OPEN_DOOR_4'); + +DELETE FROM script_texts WHERE entry BETWEEN -1564122 AND -1564097; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1564097,'Akama. Your duplicity is hardly surprising. I should have slaughtered you and your malformed brethren long ago.',11463,1,0,0,'illidan SAY_ILLIDAN_SPEECH_1'), +(-1564098,'We\'ve come to end your reign, Illidan. My people and all of Outland shall be free!',11389,1,0,25,'akama(illidan) SAY_AKAMA_SPEECH_2'), +(-1564099,'Boldly said. But I remain unconvinced.',11464,1,0,6,'illidan SAY_ILLIDAN_SPEECH_3'), +(-1564100,'The time has come! The moment is at hand!',11380,1,0,22,'akama(illidan) SAY_AKAMA_SPEECH_4'), +(-1564101,'You are not prepared!',11466,1,0,406,'illidan SAY_ILLIDAN_SPEECH_5'), +(-1564102,'Is this it, mortals? Is this all the fury you can muster?',11476,1,0,0,'illidan SAY_ILLIDAN_SPEECH_6'), +(-1564103,'Their fury pales before mine, Illidan. We have some unsettled business between us.',11491,1,0,6,'maiev SAY_MAIEV_SPEECH_7'), +(-1564104,'Maiev... How is this even possible?',11477,1,0,1,'illidan SAY_ILLIDAN_SPEECH_8'), +(-1564105,'My long hunt is finally over. Today, Justice will be done!',11492,1,0,5,'maiev SAY_MAIEV_SPEECH_9'), +(-1564106,'Feel the hatred of ten thousand years!',11470,1,0,0,'illidan SAY_FRENZY'), +(-1564107,'It is finished. You are beaten.',11496,1,0,0,'maiev SAY_MAIEV_EPILOGUE_1'), +(-1564108,'You have won... Maiev. But the huntress... is nothing without the hunt. You... are nothing... without me.',11478,1,0,0,'illidan SAY_ILLIDAN_EPILOGUE_2'), +(-1564109,'He\'s right. I feel nothing... I am... nothing.',11497,1,0,0,'maiev SAY_MAIEV_EPILOGUE_3'), +(-1564110,'Farewell, champions.',11498,1,0,0,'maiev SAY_MAIEV_EPILOGUE_4'), +(-1564111,'The Light will fill these dismal halls once again. I swear it.',11387,1,0,0,'akama(illidan) SAY_AKAMA_EPILOGUE_5'), +(-1564112,'I can feel your hatred.',11467,1,0,0,'illidan SAY_TAUNT_1'), +(-1564113,'Give in to your fear!',11468,1,0,0,'illidan SAY_TAUNT_2'), +(-1564114,'You know nothing of power!',11469,1,0,0,'illidan SAY_TAUNT_3'), +(-1564115,'Such... arrogance!',11471,1,0,0,'illidan SAY_TAUNT_4'), +(-1564116,'That is for Naisha!',11493,1,0,0,'maiev SAY_MAIEV_TAUNT_1'), +(-1564117,'Bleed as I have bled!',11494,1,0,0,'maiev SAY_MAIEV_TAUNT_2'), +(-1564118,'There shall be no prison for you this time!',11495,1,0,0,'maiev SAY_MAIEV_TRAP'), +(-1564119,'Meet your end, demon!',11500,1,0,0,'maiev SAY_MAIEV_TAUNT_4'), +(-1564120,'Be wary friends, The Betrayer meditates in the court just beyond.',11388,1,0,0,'akama(illidan) SAY_AKAMA_BEWARE'), +(-1564121,'Come, my minions. Deal with this traitor as he deserves!',11465,1,0,0,'illidan SAY_AKAMA_MINION'), +(-1564122,'I\'ll deal with these mongrels. Strike now, friends! Strike at the betrayer!',11390,1,0,22,'akama(illidan) SAY_AKAMA_LEAVE'); + +DELETE FROM gossip_texts WHERE entry IN (-3564001,-3564002); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3564001,'I\'m ready, Akama.','akama(illidan) GOSSIP_ITEM_PREPARE'), +(-3564002,'We\'re ready to face Illidan.','akama(illidan) GOSSIP_ITEM_START_EVENT'); + +DELETE FROM script_waypoint WHERE entry=23089; +INSERT INTO script_waypoint VALUES +(23089, 0, 660.22, 305.74, 271.688, 0, 'escort paused - GOSSIP_ITEM_PREPARE'), +(23089, 1, 675.10, 343.30, 271.688, 0, ''), +(23089, 2, 694.01, 374.84, 271.687, 0, ''), +(23089, 3, 706.22, 375.75, 274.888, 0, ''), +(23089, 4, 720.48, 370.38, 281.300, 0, ''), +(23089, 5, 733.30, 357.66, 292.477, 0, ''), +(23089, 6, 740.40, 344.39, 300.920, 0, ''), +(23089, 7, 747.54, 329.03, 308.509, 0, ''), +(23089, 8, 748.24, 318.78, 311.781, 0, ''), +(23089, 9, 752.41, 304.31, 312.077, 0, 'escort paused - SAY_AKAMA_OPEN_DOOR_1'), +(23089, 10, 770.27, 304.89, 312.35, 0, ''), +(23089, 11, 780.18, 305.26, 319.71 , 0, ''), +(23089, 12, 791.45, 289.27, 319.80, 0, ''), +(23089, 13, 790.41, 262.70, 341.42, 0, ''), +(23089, 14, 782.88, 250.20, 341.60, 0, ''), +(23089, 15, 765.35, 241.40, 353.62, 0, ''), +(23089, 16, 750.61, 235.63, 353.02, 0, 'escort paused - GOSSIP_ITEM_START_EVENT'), +(23089, 17, 748.87, 304.93, 352.99, 0, 'escort paused - SAY_ILLIDAN_SPEECH_1'), +(23089, 18, 737.92, 368.15, 352.99, 0, ''), +(23089, 19, 749.64, 378.69, 352.99, 0, ''), +(23089, 20, 766.49, 371.79, 353.63, 0, ''), +(23089, 21, 784.98, 361.89, 341.41, 0, ''), +(23089, 22, 791.44, 347.10, 341.41, 0, ''), +(23089, 23, 794.80, 319.47, 319.75, 0, ''), +(23089, 24, 794.34, 304.34, 319.75, 0, 'escort paused - fight illidari elites'), +(23089, 25, 794.80, 319.47, 319.75, 0, ''), +(23089, 26, 791.44, 347.10, 341.41, 0, ''), +(23089, 27, 784.98, 361.89, 341.41, 0, ''), +(23089, 28, 766.49, 371.79, 353.63, 0, ''), +(23089, 29, 749.64, 378.69, 352.99, 0, ''), +(23089, 30, 737.92, 368.15, 352.99, 0, 'escort paused'); diff --git a/sql/updates/0.6/r2749_mangos.sql b/sql/updates/0.6/r2749_mangos.sql new file mode 100644 index 000000000..6ded09da2 --- /dev/null +++ b/sql/updates/0.6/r2749_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_fel_guard_hound' WHERE entry=21847; diff --git a/sql/updates/0.6/r2752_mangos.sql b/sql/updates/0.6/r2752_mangos.sql new file mode 100644 index 000000000..7c5fb4b8a --- /dev/null +++ b/sql/updates/0.6/r2752_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=24922; diff --git a/sql/updates/0.7/r2756_mangos.sql b/sql/updates/0.7/r2756_mangos.sql new file mode 100644 index 000000000..0d7642068 --- /dev/null +++ b/sql/updates/0.7/r2756_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_eye_of_acherus' WHERE entry=28511; diff --git a/sql/updates/0.7/r2756_scriptdev2.sql b/sql/updates/0.7/r2756_scriptdev2.sql new file mode 100644 index 000000000..8c65e1fac --- /dev/null +++ b/sql/updates/0.7/r2756_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1609089, -1609090); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609089,'The Eye of Acherus launches towards its destination',0,3,0,0,'eye of acherus EMOTE_DESTIANTION'), +(-1609090,'The Eye of Acherus is in your control',0,3,0,0,'eye of acherus EMOTE_CONTROL'); diff --git a/sql/updates/0.7/r2757_mangos.sql b/sql/updates/0.7/r2757_mangos.sql new file mode 100644 index 000000000..8ce5af829 --- /dev/null +++ b/sql/updates/0.7/r2757_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM world_template WHERE map=609; +INSERT INTO world_template VALUES +(609, 'world_map_ebon_hold'); diff --git a/sql/updates/0.7/r2758_mangos.sql b/sql/updates/0.7/r2758_mangos.sql new file mode 100644 index 000000000..ee8d476d1 --- /dev/null +++ b/sql/updates/0.7/r2758_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_scarlet_ghoul' WHERE entry=28845; diff --git a/sql/updates/0.7/r2758_scriptdev2.sql b/sql/updates/0.7/r2758_scriptdev2.sql new file mode 100644 index 000000000..b6e3b42af --- /dev/null +++ b/sql/updates/0.7/r2758_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1609096 AND -1609091; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609091,'Mommy?',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_1'), +(-1609092,'GIVE ME BRAINS!',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_2'), +(-1609093,'Must feed...',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_3'), +(-1609094,'So hungry...',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_4'), +(-1609095,'$gPoppy:Mama;!',0,0,0,434,'scarlet ghoul SAY_GHUL_SPAWN_5'), +(-1609096,'It puts the ghoul in the pit or else it gets the lash!',0,0,0,25,'gothik the harvester SAY_GOTHIK_THROW_IN_PIT'); diff --git a/sql/updates/0.7/r2761_mangos.sql b/sql/updates/0.7/r2761_mangos.sql new file mode 100644 index 000000000..abb49c1c0 --- /dev/null +++ b/sql/updates/0.7/r2761_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_highlord_darion_mograine' WHERE entry=29173; +UPDATE creature_template SET ScriptName='npc_fellow_death_knight' WHERE entry IN (29199, 29204, 29200); diff --git a/sql/updates/0.7/r2761_scriptdev2.sql b/sql/updates/0.7/r2761_scriptdev2.sql new file mode 100644 index 000000000..64d4632ce --- /dev/null +++ b/sql/updates/0.7/r2761_scriptdev2.sql @@ -0,0 +1,97 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1609286 AND -1609201; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609201, 'Soldiers of the Scourge, stand ready! Prepare to unleash your fury upon the Argent Dawn!',14677,1,0,0,'Highlord Darion Mograine'), +(-1609202, 'The sky weeps at the devastation of these lands! Soon, Azeroth\'s futile tears will rain down upon us!',14678,1,0,0,'Highlord Darion Mograine'), +(-1609203, 'Death knights of Acherus, the death march begins!',14681,1,0,0,'Highlord Darion Mograine'), +(-1609204, 'Soldiers of the Scourge, death knights of Acherus, minions of the darkness: hear the call of the Highlord!',14679,1,0,22,'Highlord Darion Mograine'), +(-1609205, 'RISE!',14680,1,0,15,'Highlord Darion Mograine'), +(-1609206, 'The skies turn red with the blood of the fallen! The Lich King watches over us, minions! Leave only ashes and misery in your destructive wake!',14682,1,0,25,'Highlord Darion Mograine'), +(-1609207, 'Scourge armies approach!',0,1,0,0,'Korfax, Champion of the Light'), +(-1609208, 'Stand fast, brothers and sisters! The Light will prevail!',14487,1,0,0,'Lord Maxwell Tyrosus'), +(-1609209, 'Kneel before the Highlord!',14683,0,0,0,'Highlord Darion Mograine'), +(-1609210, 'You stand no chance!',14684,0,0,0,'Highlord Darion Mograine'), +(-1609211, 'The Scourge will destroy this place!',14685,0,0,0,'Highlord Darion Mograine'), +(-1609212, 'Your life is forfeit.',14686,0,0,0,'Highlord Darion Mograine'), +(-1609213, 'Life is meaningless without suffering.',14687,0,0,0,'Highlord Darion Mograine'), +(-1609214, 'How much longer will your forces hold out?',14688,0,0,0,'Highlord Darion Mograine'), +(-1609215, 'The Argent Dawn is finished!"',14689,0,0,0,'Highlord Darion Mograine'), +(-1609216, 'Spare no one!',14690,0,0,0,'Highlord Darion Mograine'), +(-1609217, 'What is this?! My... I cannot strike...',14691,0,0,0,'Highlord Darion Mograine'), +(-1609218, 'Obey me, blade!',14692,1,0,0,'Highlord Darion Mograine'), +(-1609219, 'You will do as I command! I am in control here!',14693,0,0,0,'Highlord Darion Mograine'), +(-1609220, 'I can not... the blade fights me.',14694,0,0,0,'Highlord Darion Mograine'), +(-1609221, 'What is happening to me?',14695,0,0,0,'Highlord Darion Mograine'), +(-1609222, 'Power...wanes...',14696,0,0,0,'Highlord Darion Mograine'), +(-1609223, 'Ashbringer defies me...',14697,0,0,0,'Highlord Darion Mograine'), +(-1609224, 'Minions, come to my aid!',14698,0,0,0,'Highlord Darion Mograine'), +(-1609225, 'You cannot win, Darion!',14584,1,0,0,'Highlord Tirion Fordring'), +(-1609226, 'Bring them before the chapel!',14585,1,0,0,'Highlord Tirion Fordring'), +(-1609227, 'Stand down, death knights. We have lost... The Light... This place... No hope...',14699,0,0,68,'Highlord Darion Mograine'), +(-1609228, 'Have you learned nothing, boy? You have become all that your father fought against! Like that coward, Arthas, you allowed yourself to be consumed by the darkness...the hate... Feeding upon the misery of those you tortured and killed!',14586,0,0,1,'Highlord Tirion Fordring'), +(-1609229, 'Your master knows what lies beneath the chapel. It is why he dares not show his face! He\'s sent you and your death knights to meet their doom, Darion.',14587,0,0,25,'Highlord Tirion Fordring'), +(-1609230, 'What you are feeling right now is the anguish of a thousand lost souls! Souls that you and your master brought here! The Light will tear you apart, Darion!',14588,0,0,1,'Highlord Tirion Fordring'), +(-1609231, 'Save your breath, old man. It might be the last you ever draw.',14700,0,0,25,'Highlord Darion Mograine'), +(-1609232, 'My son! My dear, beautiful boy!',14493,0,0,0,'Highlord Alexandros Mograine'), +(-1609233, 'Father!',14701,0,0,5,'Highlord Darion Mograine'), +(-1609234, 'Argh...what...is...',14702,0,0,68,'Highlord Darion Mograine'), +(-1609235, 'Father, you have returned!',14703,0,0,0,'Darion Mograine'), +(-1609236, 'You have been gone a long time, father. I thought...',14704,0,0,0,'Darion Mograine'), +(-1609237, 'Nothing could have kept me away from here, Darion. Not from my home and family.',14494,0,0,1,'Highlord Alexandros Mograine'), +(-1609238, 'Father, I wish to join you in the war against the undead. I want to fight! I can sit idle no longer!',14705,0,0,6,'Darion Mograine'), +(-1609239, 'Darion Mograine, you are barely of age to hold a sword, let alone battle the undead hordes of Lordaeron! I couldn\'t bear losing you. Even the thought...',14495,0,0,1,'Highlord Alexandros Mograine'), +(-1609240, 'If I die, father, I would rather it be on my feet, standing in defiance against the undead legions! If I die, father, I die with you!',14706,0,0,6,'Darion Mograine'), +(-1609241, 'My son, there will come a day when you will command the Ashbringer and, with it, mete justice across this land. I have no doubt that when that day finally comes, you will bring pride to our people and that Lordaeron will be a better place because of you. But, my son, that day is not today.',14496,0,0,1,'Highlord Alexandros Mograine'), +(-1609242, 'Do not forget...',14497,0,0,6,'Highlord Alexandros Mograine'), +(-1609243, 'Touching...',14803,1,0,0,'The Lich King'), +(-1609244, 'You have\'ve betrayed me! You betrayed us all you monster! Face the might of Mograine!',14707,1,0,0,'Highlord Darion Mograine'), +(-1609245, 'He\'s mine now...',14805,0,0,0,'The Lich King'), +(-1609246, 'Pathetic...',14804,0,0,0,'The Lich King'), +(-1609247, 'You\'re a damned monster, Arthas!',14589,0,0,25,'Highlord Tirion Fordring'), +(-1609248, 'You were right, Fordring. I did send them in to die. Their lives are meaningless, but yours...',14806,0,0,1,'The Lich King'), +(-1609249, 'How simple it was to draw the great Tirion Fordring out of hiding. You\'ve left yourself exposed, paladin. Nothing will save you...',14807,0,0,1,'The Lich King'), +(-1609250, 'ATTACK!!!',14488,1,0,0,'Lord Maxwell Tyrosus'), +(-1609251, 'APOCALYPSE!',14808,1,0,0,'The Lich King'), +(-1609252, 'That day is not today...',14708,0,0,0,'Highlord Darion Mograine'), +(-1609253, 'Tirion!',14709,1,0,0,'Highlord Darion Mograine'), +(-1609254, 'ARTHAS!!!!',14591,1,0,0,'Highlord Tirion Fordring'), +(-1609255, 'What is this?',14809,1,0,0,'The Lich King'), +(-1609256, 'Your end.',14592,1,0,0,'Highlord Tirion Fordring'), +(-1609257, 'Impossible...',14810,1,0,0,'The Lich King'), +(-1609258, 'This... isn\'t... over...',14811,1,0,25,'The Lich King'), +(-1609259, 'When next we meet it won\'t be on holy ground, paladin.',14812,1,0,1,'The Lich King'), +(-1609260, 'Rise, Darion, and listen...',14593,0,0,0,'Highlord Tirion Fordring'), +(-1609261, 'We have all been witness to a terrible tragedy. The blood of good men has been shed upon this soil! Honorable knights, slain defending their lives - our lives!',14594,0,0,0,'Highlord Tirion Fordring'), +(-1609262, 'And while such things can never be forgotten, we must remain vigilant in our cause!',14595,0,0,0,'Highlord Tirion Fordring'), +(-1609263, 'The Lich King must answer for what he has done and must not be allowed to cause further destruction to our world.',14596,0,0,0,'Highlord Tirion Fordring'), +(-1609264, 'I make a promise to you now, brothers and sisters: The Lich King will be defeated! On this day, I call for a union.',14597,0,0,0,'Highlord Tirion Fordring'), +(-1609265, 'The Argent Dawn and the Order of the Silver Hand will come together as one! We will succeed where so many before us have failed!',14598,0,0,0,'Highlord Tirion Fordring'), +(-1609266, 'We will take the fight to Arthas and tear down the walls of Icecrown!',14599,0,0,15,'Highlord Tirion Fordring'), +(-1609267, 'The Argent Crusade comes for you, Arthas!',14600,1,0,15,'Highlord Tirion Fordring'), +(-1609268, 'So too do the Knights of the Ebon Blade... While our kind has no place in your world, we will fight to bring an end to the Lich King. This I vow!',14710,0,0,1,'Highlord Darion Mograine'), +(-1609269, 'Thousands of Scourge rise up at the Highlord\'s command.',0,3,0,0,''), +(-1609270, 'The army marches towards Light\'s Hope Chapel.',0,3,0,0,''), +(-1609271, 'After over a hundred Defenders of the Light fall, Highlord Tirion Fordring arrives.',0,3,0,0,''), +(-1609272, '%s flee',0,2,0,0,'Orbaz'), +(-1609273, '%s kneels in defeat before Tirion Fordring.',0,3,0,0,'Highlord Darion Mograine'), +(-1609274, '%s arrives.',0,2,0,0,'Highlord Alexandros Mograine'), +(-1609275, '%s becomes a shade of his past, and walks up to his father.',0,2,0,0,'Highlord Darion Mograine'), +(-1609276, '%s hugs his father.',0,2,0,0,'Darion Mograine'), +(-1609277, '%s disappears, and the Lich King appears.',0,2,0,0,'Alexandros'), +(-1609278, '%s becomes himself again...and is now angry.',0,2,0,0,'Highlord Darion Mograine'), +(-1609279, '%s casts a spell on Tirion.',0,2,0,0,'The Lich King'), +(-1609280, '%s gasps for air.',0,2,0,0,'Highlord Tirion Fordring'), +(-1609281, '%s casts a powerful spell, killing the Defenders and knocking back the others.',0,2,0,0,'The Lich King'), +(-1609282, '%s throws the Corrupted Ashbringer to Tirion, who catches it. Tirion becomes awash with Light, and the Ashbringer is cleansed.',0,2,0,0,'Highlord Darion Mograine'), +(-1609283, '%s collapses.',0,2,0,0,'Highlord Darion Mograine'), +(-1609284, '%s charges towards the Lich King, Ashbringer in hand and strikes the Lich King.',0,2,0,0,'Highlord Tirion Fordring'), +(-1609285, '%s disappears. Tirion walks over to where Darion lay',0,2,0,0,'The Lich King'), +(-1609286, 'Light washes over the chapel -- the Light of Dawn is uncovered.',0,2,0,0,''); + +DELETE FROM `script_waypoint` WHERE entry=29173; +INSERT INTO `script_waypoint` VALUES +(29173, 0, 2411.322, -5152.227, 83.777, 0,''), +(29173, 1, 2386.443, -5177.385, 74.049, 0,''), +(29173, 2, 2357.140, -5209.571, 79.642, 0,'SAY_LIGHT_OF_DAWN_STAND_1'), +(29173, 3, 2342.683, -5232.791, 85.259, 0,'SAY_LIGHT_OF_DAWN_STAND_2'), +(29173, 4, 2281.354, -5278.533, 82.227, 0,'Start battle'), +(29173, 5, 2280.302, -5284.489, 82.657, 600000,'Go in front of the chapel for outro'); diff --git a/sql/updates/0.7/r2762_scriptdev2.sql b/sql/updates/0.7/r2762_scriptdev2.sql new file mode 100644 index 000000000..2af19e71d --- /dev/null +++ b/sql/updates/0.7/r2762_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12280+) '; diff --git a/sql/updates/0.7/r2763_mangos.sql b/sql/updates/0.7/r2763_mangos.sql new file mode 100644 index 000000000..1cb445c9e --- /dev/null +++ b/sql/updates/0.7/r2763_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_acherus_deathcharger' WHERE entry=28782; diff --git a/sql/updates/0.7/r2763_scriptdev2.sql b/sql/updates/0.7/r2763_scriptdev2.sql new file mode 100644 index 000000000..e4a117066 --- /dev/null +++ b/sql/updates/0.7/r2763_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1609287,-1609288); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609287,'%s rears up, beckoning you to ride it.',0,2,0,0,'Acherus Deathcharger EMOTE_HORSE_READY'), +(-1609288,'Impressive, death knight. Return to me in the world of the living for your reward.',0,0,0,2,'Salanar the Horseman SAY_RACE_FINISHED'); diff --git a/sql/updates/0.7/r2764_scriptdev2.sql b/sql/updates/0.7/r2764_scriptdev2.sql new file mode 100644 index 000000000..46a52b00e --- /dev/null +++ b/sql/updates/0.7/r2764_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1609287,-1609288); +DELETE FROM script_texts WHERE entry IN (-1609097,-1609098); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609097,'%s rears up, beckoning you to ride it.',0,2,0,0,'Acherus Deathcharger EMOTE_HORSE_READY'), +(-1609098,'Impressive, death knight. Return to me in the world of the living for your reward.',0,0,0,2,'Salanar the Horseman SAY_RACE_FINISHED'); diff --git a/sql/updates/0.7/r2765_scriptdev2.sql b/sql/updates/0.7/r2765_scriptdev2.sql new file mode 100644 index 000000000..8482a5a32 --- /dev/null +++ b/sql/updates/0.7/r2765_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM gossip_texts WHERE entry IN (-3609000, -3609001); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3609000,'I challenge you, death knight!','Death Knight Initiate GOSSIP_ITEM_ACCEPT_DUEL'), +(-3609001,'I am ready, Highlord. Let the siege of Light\'s Hope begin!','Highlord Darion Mograine GOSSIP_ITEM_READY'); diff --git a/sql/updates/0.7/r2766_mangos.sql b/sql/updates/0.7/r2766_mangos.sql new file mode 100644 index 000000000..4fb6f9969 --- /dev/null +++ b/sql/updates/0.7/r2766_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_lich_king_light_dawn' WHERE entry=29183; diff --git a/sql/updates/0.7/r2768_scriptdev2.sql b/sql/updates/0.7/r2768_scriptdev2.sql new file mode 100644 index 000000000..4ea4d2ae3 --- /dev/null +++ b/sql/updates/0.7/r2768_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12292+) '; diff --git a/sql/updates/0.7/r2773_scriptdev2.sql b/sql/updates/0.7/r2773_scriptdev2.sql new file mode 100644 index 000000000..813405d90 --- /dev/null +++ b/sql/updates/0.7/r2773_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12308+) '; diff --git a/sql/updates/0.7/r2776_scriptdev2.sql b/sql/updates/0.7/r2776_scriptdev2.sql new file mode 100644 index 000000000..d674617b7 --- /dev/null +++ b/sql/updates/0.7/r2776_scriptdev2.sql @@ -0,0 +1,2 @@ +UPDATE script_texts SET content_default='Thank you, Highlord. Now, challengers, I will begin the ritual of summoning. When I am done a fearsome doomguard will appear!', emote=2 WHERE entry=-1649010; +UPDATE script_texts SET emote=11 WHERE entry=-1649036; diff --git a/sql/updates/0.7/r2779_scriptdev2.sql b/sql/updates/0.7/r2779_scriptdev2.sql new file mode 100644 index 000000000..6f32983b1 --- /dev/null +++ b/sql/updates/0.7/r2779_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12316+) '; diff --git a/sql/updates/0.7/r2783_scriptdev2.sql b/sql/updates/0.7/r2783_scriptdev2.sql new file mode 100644 index 000000000..d5495df52 --- /dev/null +++ b/sql/updates/0.7/r2783_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12328+) '; diff --git a/sql/updates/0.7/r2785_scriptdev2.sql b/sql/updates/0.7/r2785_scriptdev2.sql new file mode 100644 index 000000000..fca8408f0 --- /dev/null +++ b/sql/updates/0.7/r2785_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12361+) '; diff --git a/sql/updates/0.7/r2790_mangos.sql b/sql/updates/0.7/r2790_mangos.sql new file mode 100644 index 000000000..bb68773d4 --- /dev/null +++ b/sql/updates/0.7/r2790_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_baltharus_clone' WHERE entry=39899; diff --git a/sql/updates/0.7/r2799_mangos.sql b/sql/updates/0.7/r2799_mangos.sql new file mode 100644 index 000000000..4de80fe5a --- /dev/null +++ b/sql/updates/0.7/r2799_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_halion_real' WHERE entry=39863; +UPDATE creature_template SET ScriptName='boss_halion_twilight' WHERE entry=40142; diff --git a/sql/updates/0.7/r2801_mangos.sql b/sql/updates/0.7/r2801_mangos.sql new file mode 100644 index 000000000..ca24aa2c4 --- /dev/null +++ b/sql/updates/0.7/r2801_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_dark_matter' WHERE entry=28235; +UPDATE creature_template SET ScriptName='npc_searing_gaze' WHERE entry=28265; diff --git a/sql/updates/0.7/r2801_scriptdev2.sql b/sql/updates/0.7/r2801_scriptdev2.sql new file mode 100644 index 000000000..8de4f70ce --- /dev/null +++ b/sql/updates/0.7/r2801_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM gossip_texts WHERE entry IN (-3599000, -3599001); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3599000,'Brann, it would be our honor!','brann GOSSIP_ITEM_ID_START'), +(-3599001,'Let\'s move Brann, enough of the history lessons!','brann GOSSIP_ITEM_ID_PROGRESS'); diff --git a/sql/updates/0.7/r2802_mangos.sql b/sql/updates/0.7/r2802_mangos.sql new file mode 100644 index 000000000..a78ab7677 --- /dev/null +++ b/sql/updates/0.7/r2802_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=29682; diff --git a/sql/updates/0.7/r2806_mangos.sql b/sql/updates/0.7/r2806_mangos.sql new file mode 100644 index 000000000..0224a7a34 --- /dev/null +++ b/sql/updates/0.7/r2806_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=21729; diff --git a/sql/updates/0.7/r2808_mangos.sql b/sql/updates/0.7/r2808_mangos.sql new file mode 100644 index 000000000..ce4997a34 --- /dev/null +++ b/sql/updates/0.7/r2808_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_varos' WHERE entry=27447; diff --git a/sql/updates/0.7/r2808_scriptdev2.sql b/sql/updates/0.7/r2808_scriptdev2.sql new file mode 100644 index 000000000..ecc5ea47a --- /dev/null +++ b/sql/updates/0.7/r2808_scriptdev2.sql @@ -0,0 +1,12 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1578023 AND -1578020; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578020,'There will be no mercy!',13649,1,0,0,'varos SAY_AGGRO'), +(-1578021,'Blast them! Destroy them!',13650,1,0,0,'varos SAY_CALL_CAPTAIN_1'), +(-1578022,'Take no prisoners! Attack!',13651,1,0,0,'varos SAY_CALL_CAPTAIN_2'), +(-1578023,'Strike now! Obliterate them!',13652,1,0,0,'varos SAY_CALL_CAPTAIN_3'); +DELETE FROM script_texts WHERE entry BETWEEN -1578029 AND -1578026; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578026,'You were warned!',13653,1,0,0,'varos SAY_KILL_1'), +(-1578027,'The Oculus is ours!',13654,1,0,0,'varos SAY_KILL_2'), +(-1578028,'They are... too strong! Underestimated their... fortitude.',13655,1,0,0,'varos SAY_DEATH'), +(-1578029,'%s calls an Azure Ring Captain!',0,3,0,0,'varos EMOTE_CAPTAIN'); diff --git a/sql/updates/0.7/r2809_mangos.sql b/sql/updates/0.7/r2809_mangos.sql new file mode 100644 index 000000000..e55dae7d1 --- /dev/null +++ b/sql/updates/0.7/r2809_mangos.sql @@ -0,0 +1,9 @@ +UPDATE creature_template SET ScriptName='npc_azure_ring_captain' WHERE entry=28236; +UPDATE creature_template SET ScriptName='npc_arcane_beam' WHERE entry=28239; +UPDATE creature_template SET ScriptName='npc_centrifuge_core' WHERE entry=28183; +DELETE FROM scripted_event_id WHERE id IN (10665,12229,18454,18455); +INSERT INTO scripted_event_id VALUES +(10665,'event_spell_call_captain'), +(12229,'event_spell_call_captain'), +(18454,'event_spell_call_captain'), +(18455,'event_spell_call_captain'); diff --git a/sql/updates/0.7/r2810_mangos.sql b/sql/updates/0.7/r2810_mangos.sql new file mode 100644 index 000000000..d39d93c2f --- /dev/null +++ b/sql/updates/0.7/r2810_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_planar_anomaly' WHERE entry=30879; diff --git a/sql/updates/0.7/r2815_mangos.sql b/sql/updates/0.7/r2815_mangos.sql new file mode 100644 index 000000000..8c70a8e80 --- /dev/null +++ b/sql/updates/0.7/r2815_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_oculus_drake' WHERE entry IN (27756, 27692, 27755); diff --git a/sql/updates/0.7/r2815_scriptdev2.sql b/sql/updates/0.7/r2815_scriptdev2.sql new file mode 100644 index 000000000..2ca1d3c5d --- /dev/null +++ b/sql/updates/0.7/r2815_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1578030; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1578030,'%s flies away.',0,2,0,0,'drakes EMOTE_FLY_AWAY'); diff --git a/sql/updates/0.7/r2816_mangos.sql b/sql/updates/0.7/r2816_mangos.sql new file mode 100644 index 000000000..aadc5f7ca --- /dev/null +++ b/sql/updates/0.7/r2816_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_crystal_spike_trigger' WHERE entry IN (27101, 27079); diff --git a/sql/updates/0.7/r2817_mangos.sql b/sql/updates/0.7/r2817_mangos.sql new file mode 100644 index 000000000..a7f4ab3f8 --- /dev/null +++ b/sql/updates/0.7/r2817_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_grauf' WHERE entry=26893; diff --git a/sql/updates/0.7/r2817_scriptdev2.sql b/sql/updates/0.7/r2817_scriptdev2.sql new file mode 100644 index 000000000..0dcab50cd --- /dev/null +++ b/sql/updates/0.7/r2817_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=22 WHERE entry=-1575019; diff --git a/sql/updates/0.7/r2818_scriptdev2.sql b/sql/updates/0.7/r2818_scriptdev2.sql new file mode 100644 index 000000000..788f31030 --- /dev/null +++ b/sql/updates/0.7/r2818_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1575041,-1616034); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1575041,'%s takes a deep breath.',0,3,0,0,'grauf EMOTE_DEEP_BREATH'), +(-1616034,'%s takes a deep breath.',0,3,0,0,'malygos SAY_EMOTE_BREATH'); diff --git a/sql/updates/0.7/r2820_scriptdev2.sql b/sql/updates/0.7/r2820_scriptdev2.sql new file mode 100644 index 000000000..0d2e702c4 --- /dev/null +++ b/sql/updates/0.7/r2820_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12409+) '; diff --git a/sql/updates/0.7/r2821_mangos.sql b/sql/updates/0.7/r2821_mangos.sql new file mode 100644 index 000000000..872467ffd --- /dev/null +++ b/sql/updates/0.7/r2821_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry=13016; diff --git a/sql/updates/0.7/r2822_scriptdev2.sql b/sql/updates/0.7/r2822_scriptdev2.sql new file mode 100644 index 000000000..06bfa1c74 --- /dev/null +++ b/sql/updates/0.7/r2822_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM gossip_texts WHERE entry=-3568000; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3568000,'Thanks for the concern, but we intend to explore Zul\'Aman.','harrison jones GOSSIP_ITEM_BEGIN'); diff --git a/sql/updates/0.7/r2823_mangos.sql b/sql/updates/0.7/r2823_mangos.sql new file mode 100644 index 000000000..e471353d1 --- /dev/null +++ b/sql/updates/0.7/r2823_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_impale_target' WHERE entry=29184; diff --git a/sql/updates/0.7/r2824_scriptdev2.sql b/sql/updates/0.7/r2824_scriptdev2.sql new file mode 100644 index 000000000..d44a9e24d --- /dev/null +++ b/sql/updates/0.7/r2824_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1601013, -1601025, -1601026); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1601013,'%s moves up the tunnel!',0,3,0,0,'hadronox EMOTE_MOVE_TUNNEL'), +(-1601025,'The gate has been breached! Quickly, divert forces to deal with these invaders!',0,1,0,0,'anub\'ar crusher SAY_AGGRO'), +(-1601026,'There\'s no time left! All remaining forces, attack the invaders!',0,1,0,0,'anub\'ar crusher SAY_SPECIAL'); diff --git a/sql/updates/0.7/r2826_mangos.sql b/sql/updates/0.7/r2826_mangos.sql new file mode 100644 index 000000000..0501c556e --- /dev/null +++ b/sql/updates/0.7/r2826_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_wyrmrest_skytalon' WHERE entry=30161; diff --git a/sql/updates/0.7/r2831_mangos.sql b/sql/updates/0.7/r2831_mangos.sql new file mode 100644 index 000000000..52f05db68 --- /dev/null +++ b/sql/updates/0.7/r2831_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_father_flame' WHERE entry=175245; diff --git a/sql/updates/0.7/r2831_scriptdev2.sql b/sql/updates/0.7/r2831_scriptdev2.sql new file mode 100644 index 000000000..bc20cb368 --- /dev/null +++ b/sql/updates/0.7/r2831_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1229020; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1229020,'Intruders are destroying our eggs! Stop!!',0,1,0,0,'rookery hatcher - SAY_ROOKERY_EVENT_START'); diff --git a/sql/updates/0.7/r2832_mangos.sql b/sql/updates/0.7/r2832_mangos.sql new file mode 100644 index 000000000..7fe65fe97 --- /dev/null +++ b/sql/updates/0.7/r2832_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='boss_krick' WHERE entry=36477; +UPDATE creature_template SET ScriptName='boss_ick' WHERE entry=36476; +UPDATE creature_template SET ScriptName='npc_exploding_orb' WHERE entry=36610; diff --git a/sql/updates/0.7/r2832_scriptdev2.sql b/sql/updates/0.7/r2832_scriptdev2.sql new file mode 100644 index 000000000..25534c1fa --- /dev/null +++ b/sql/updates/0.7/r2832_scriptdev2.sql @@ -0,0 +1,3 @@ +UPDATE script_texts SET emote=396 WHERE entry IN (-1658037, -1658046); +UPDATE script_texts SET emote=15 WHERE entry IN (-1658040); +UPDATE script_texts SET emote=431 WHERE entry IN (-1658035); diff --git a/sql/updates/0.7/r2835_scriptdev2.sql b/sql/updates/0.7/r2835_scriptdev2.sql new file mode 100644 index 000000000..f82b94b60 --- /dev/null +++ b/sql/updates/0.7/r2835_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=1 WHERE entry IN (-1658007,-1658010,-1658011); diff --git a/sql/updates/0.7/r2836_scriptdev2.sql b/sql/updates/0.7/r2836_scriptdev2.sql new file mode 100644 index 000000000..cf40248ef --- /dev/null +++ b/sql/updates/0.7/r2836_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1658020,-1658047); diff --git a/sql/updates/0.7/r2837_mangos.sql b/sql/updates/0.7/r2837_mangos.sql new file mode 100644 index 000000000..727ebf74c --- /dev/null +++ b/sql/updates/0.7/r2837_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_ymirjar_deathbringer' WHERE entry=36892; +DELETE FROM scripted_areatrigger WHERE entry=5578; +INSERT INTO scripted_areatrigger VALUES (5578,'at_pit_of_saron'); diff --git a/sql/updates/0.7/r2837_scriptdev2.sql b/sql/updates/0.7/r2837_scriptdev2.sql new file mode 100644 index 000000000..4487e190e --- /dev/null +++ b/sql/updates/0.7/r2837_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=6 WHERE entry IN (-1658048,-1658049); diff --git a/sql/updates/0.7/r2838_mangos.sql b/sql/updates/0.7/r2838_mangos.sql new file mode 100644 index 000000000..529040375 --- /dev/null +++ b/sql/updates/0.7/r2838_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_collapsing_icicle' WHERE entry=36847; diff --git a/sql/updates/0.7/r2840_mangos.sql b/sql/updates/0.7/r2840_mangos.sql new file mode 100644 index 000000000..053198064 --- /dev/null +++ b/sql/updates/0.7/r2840_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_tyrannus' WHERE entry=36658; +UPDATE creature_template SET ScriptName='boss_rimefang_pos' WHERE entry=36661; diff --git a/sql/updates/0.7/r2840_scriptdev2.sql b/sql/updates/0.7/r2840_scriptdev2.sql new file mode 100644 index 000000000..bf1fbaa47 --- /dev/null +++ b/sql/updates/0.7/r2840_scriptdev2.sql @@ -0,0 +1,8 @@ +UPDATE script_texts SET emote=5 WHERE entry IN (-1658063,-1658064); +UPDATE script_texts SET emote=396 WHERE entry IN (-1658067); +DELETE FROM script_texts WHERE entry IN (-1658051,-1658061,-1658068,-1658069); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1658051,'Heroes! We will hold off the undead as long as we can, even to our dying breath. Deal with the Scourgelord!',17148,1,0,0,'victus SAY_VICTUS_TRASH'), +(-1658061,'Brave champions, we owe you our lives, our freedom... Though it be a tiny gesture in the face of this enormous debt, I pledge that from this day forth, all will know of your deeds, and the blazing path of light you cut through the shadow of this dark citadel.',17149,1,0,0,'victus SAY_VICTUS_OUTRO_1'), +(-1658068,'Heroes! We will hold off the undead as long as we can, even to our dying breath. Deal with the Scourgelord!',17150,1,0,0,'ironskull SAY_IRONSKULL_TRASH'), +(-1658069,'Brave champions, we owe you our lives, our freedom... Though it be a tiny gesture in the face of this enormous debt, I pledge that from this day forth, all will know of your deeds, and the blazing path of light you cut through the shadow of this dark citadel.',17151,1,0,0,'ironskull SAY_IRONSKULL_OUTRO_1'); diff --git a/sql/updates/0.7/r2842_mangos.sql b/sql/updates/0.7/r2842_mangos.sql new file mode 100644 index 000000000..cce22fbdc --- /dev/null +++ b/sql/updates/0.7/r2842_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (5581); +INSERT INTO scripted_areatrigger VALUES +(5581,'at_pit_of_saron'); diff --git a/sql/updates/0.7/r2846_mangos.sql b/sql/updates/0.7/r2846_mangos.sql new file mode 100644 index 000000000..d9b0e057a --- /dev/null +++ b/sql/updates/0.7/r2846_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=15302; +UPDATE creature_template SET ScriptName='' WHERE entry=15260; diff --git a/sql/updates/0.7/r2847_mangos.sql b/sql/updates/0.7/r2847_mangos.sql new file mode 100644 index 000000000..e1bfffe9e --- /dev/null +++ b/sql/updates/0.7/r2847_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_erekem_guard' WHERE entry=32228; diff --git a/sql/updates/0.7/r2853_scriptdev2.sql b/sql/updates/0.7/r2853_scriptdev2.sql new file mode 100644 index 000000000..ad9b962cc --- /dev/null +++ b/sql/updates/0.7/r2853_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry = -1070005; +INSERT INTO script_texts (entry, content_default, sound, type, language, emote, comment) VALUES +(-1070005,'%s breaks free from his stone slumber!', 0, 2, 0, 0, 'archaedas EMOTE_BREAK_FREE'); diff --git a/sql/updates/0.7/r2856_mangos.sql b/sql/updates/0.7/r2856_mangos.sql new file mode 100644 index 000000000..96fbc5a5d --- /dev/null +++ b/sql/updates/0.7/r2856_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_black_dragon_egg' WHERE entry=177807; diff --git a/sql/updates/0.7/r2856_scriptdev2.sql b/sql/updates/0.7/r2856_scriptdev2.sql new file mode 100644 index 000000000..bac419735 --- /dev/null +++ b/sql/updates/0.7/r2856_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry = -1469035; +INSERT INTO script_texts (entry, content_default, sound, type, language, emote, comment) VALUES +(-1469035,'Orb of Domination loses power and shuts off!',0,2,0,0,'razorgore EMOTE_ORB_SHUT_OFF'); diff --git a/sql/updates/0.7/r2858_scriptdev2.sql b/sql/updates/0.7/r2858_scriptdev2.sql new file mode 100644 index 000000000..2eb1d8bf0 --- /dev/null +++ b/sql/updates/0.7/r2858_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for C-MaNGOS 12451+) '; diff --git a/sql/updates/0.7/r2861_mangos.sql b/sql/updates/0.7/r2861_mangos.sql new file mode 100644 index 000000000..3a1beed9b --- /dev/null +++ b/sql/updates/0.7/r2861_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (17909,19052,22427); +UPDATE creature_template SET ScriptName='' WHERE entry=14822; +UPDATE creature_template SET ScriptName='' WHERE entry IN (384,1261,1460,2357,3362,3685,4730,4731,4885,7952,7955,16264,17584); +UPDATE creature_template SET ScriptName='' WHERE entry=28776; diff --git a/sql/updates/0.7/r2863_mangos.sql b/sql/updates/0.7/r2863_mangos.sql new file mode 100644 index 000000000..e6049ab7b --- /dev/null +++ b/sql/updates/0.7/r2863_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_feather_vortex' WHERE entry=24136; diff --git a/sql/updates/0.7/r2870_scriptdev2.sql b/sql/updates/0.7/r2870_scriptdev2.sql new file mode 100644 index 000000000..417b0d053 --- /dev/null +++ b/sql/updates/0.7/r2870_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12458+) '; diff --git a/sql/updates/0.7/r2873_mangos.sql b/sql/updates/0.7/r2873_mangos.sql new file mode 100644 index 000000000..607c1a0fd --- /dev/null +++ b/sql/updates/0.7/r2873_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_power_blue_flight' WHERE entry=25653; diff --git a/sql/updates/0.7/r2874_mangos.sql b/sql/updates/0.7/r2874_mangos.sql new file mode 100644 index 000000000..d1dd899e8 --- /dev/null +++ b/sql/updates/0.7/r2874_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_snufflenose_gopher' WHERE entry=4781; diff --git a/sql/updates/0.7/r2875_mangos.sql b/sql/updates/0.7/r2875_mangos.sql new file mode 100644 index 000000000..f245baded --- /dev/null +++ b/sql/updates/0.7/r2875_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_therylune' WHERE entry=3584; diff --git a/sql/updates/0.7/r2875_scriptdev2.sql b/sql/updates/0.7/r2875_scriptdev2.sql new file mode 100644 index 000000000..f398bd3cc --- /dev/null +++ b/sql/updates/0.7/r2875_scriptdev2.sql @@ -0,0 +1,28 @@ +DELETE FROM script_texts WHERE entry IN (-1000905, -1000906); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000905,'Ok, let\'s go!!',0,0,0,1,'therylune SAY_THERYLUNE_START'), +(-1000906,'I can make it the rest of the way. $N. THANKS!',0,0,0,1,'therylune SAY_THERYLUNE_START'); + +DELETE FROM script_waypoint WHERE entry=3584; +INSERT INTO script_waypoint VALUES +(3584, 0, 4520.4, 420.235, 33.5284, 2000, ''), +(3584, 1, 4512.26, 408.881, 32.9308, 0, ''), +(3584, 2, 4507.94, 396.47, 32.9476, 0, ''), +(3584, 3, 4507.53, 383.781, 32.995, 0, ''), +(3584, 4, 4512.1, 374.02, 33.166, 0, ''), +(3584, 5, 4519.75, 373.241, 33.1574, 0, ''), +(3584, 6, 4592.41, 369.127, 31.4893, 0, ''), +(3584, 7, 4598.55, 364.801, 31.4947, 0, ''), +(3584, 8, 4602.76, 357.649, 32.9265, 0, ''), +(3584, 9, 4597.88, 352.629, 34.0317, 0, ''), +(3584, 10, 4590.23, 350.9, 36.2977, 0, ''), +(3584, 11, 4581.5, 348.254, 38.3878, 0, ''), +(3584, 12, 4572.05, 348.059, 42.3539, 0, ''), +(3584, 13, 4564.75, 344.041, 44.2463, 0, ''), +(3584, 14, 4556.63, 341.003, 47.6755, 0, ''), +(3584, 15, 4554.38, 334.968, 48.8003, 0, ''), +(3584, 16, 4557.63, 329.783, 49.9532, 0, ''), +(3584, 17, 4563.32, 316.829, 53.2409, 0, ''), +(3584, 18, 4566.09, 303.127, 55.0396, 0, ''), +(3584, 19, 4561.65, 295.456, 57.0984, 4000, 'SAY_THERYLUNE_FINISH'), +(3584, 20, 4551.03, 293.333, 57.1534, 2000, ''); diff --git a/sql/updates/0.7/r2878_mangos.sql b/sql/updates/0.7/r2878_mangos.sql new file mode 100644 index 000000000..d315c2023 --- /dev/null +++ b/sql/updates/0.7/r2878_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=31218; +UPDATE creature_template SET ScriptName='' WHERE entry=31219; +UPDATE creature_template SET ScriptName='npc_flame_tsunami' WHERE entry=30616; diff --git a/sql/updates/0.7/r2879_mangos.sql b/sql/updates/0.7/r2879_mangos.sql new file mode 100644 index 000000000..dcb9c2dcf --- /dev/null +++ b/sql/updates/0.7/r2879_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_fire_cyclone' WHERE entry=30648; diff --git a/sql/updates/0.7/r2880_mangos.sql b/sql/updates/0.7/r2880_mangos.sql new file mode 100644 index 000000000..85324d697 --- /dev/null +++ b/sql/updates/0.7/r2880_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_sapphiron_birth' WHERE entry=181356; diff --git a/sql/updates/0.7/r2885_mangos.sql b/sql/updates/0.7/r2885_mangos.sql new file mode 100644 index 000000000..1ca53c899 --- /dev/null +++ b/sql/updates/0.7/r2885_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_zumrah' WHERE entry=7271; diff --git a/sql/updates/0.7/r2885_scriptdev2.sql b/sql/updates/0.7/r2885_scriptdev2.sql new file mode 100644 index 000000000..70aef751d --- /dev/null +++ b/sql/updates/0.7/r2885_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry IN (-1209000, -1209001, -1209002, -1209003); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1209000,'How dare you enter my sanctum!',0,0,0,0,'zumrah SAY_INTRO'), +(-1209001,'Sands consume you!',5872,1,14,0,'zumrah SAY_AGGRO'), +(-1209002,'Fall!',5873,1,14,0,'zumrah SAY_KILL'), +(-1209003,'Come to me, my children!',0,0,8,0,'zumrah SAY_SUMMON'); diff --git a/sql/updates/0.7/r2887_scriptdev2.sql b/sql/updates/0.7/r2887_scriptdev2.sql new file mode 100644 index 000000000..efcfe7145 --- /dev/null +++ b/sql/updates/0.7/r2887_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12471+) '; diff --git a/sql/updates/0.7/r2889_scriptdev2.sql b/sql/updates/0.7/r2889_scriptdev2.sql new file mode 100644 index 000000000..827841176 --- /dev/null +++ b/sql/updates/0.7/r2889_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12491+) '; diff --git a/sql/updates/0.7/r2891_mangos.sql b/sql/updates/0.7/r2891_mangos.sql new file mode 100644 index 000000000..1de3cdfbd --- /dev/null +++ b/sql/updates/0.7/r2891_mangos.sql @@ -0,0 +1,5 @@ +DELETE FROM scripted_event_id WHERE id IN (2609); +INSERT INTO scripted_event_id VALUES +(2609,'event_spell_unlocking'); +UPDATE creature_template SET ScriptName='' WHERE entry=7604; +UPDATE creature_template SET ScriptName='' WHERE entry=7607; diff --git a/sql/updates/0.7/r2893_mangos.sql b/sql/updates/0.7/r2893_mangos.sql new file mode 100644 index 000000000..60f56b8db --- /dev/null +++ b/sql/updates/0.7/r2893_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (27263,27264,27265); +UPDATE gameobject_template SET ScriptName='' WHERE entry IN (185547,185553,185551); diff --git a/sql/updates/0.7/r2894_mangos.sql b/sql/updates/0.7/r2894_mangos.sql new file mode 100644 index 000000000..91e3fa25f --- /dev/null +++ b/sql/updates/0.7/r2894_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_domesticated_felboar' WHERE entry=21195; +UPDATE creature_template SET ScriptName='npc_shadowmoon_tuber_node' WHERE entry=21347; diff --git a/sql/updates/0.7/r2894_scriptdev2.sql b/sql/updates/0.7/r2894_scriptdev2.sql new file mode 100644 index 000000000..65f4d3e9d --- /dev/null +++ b/sql/updates/0.7/r2894_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1000907, -1000908, -1000909); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000907,'%s sniffs at the air. A tuber is near!',0,2,0,0,'domesticated felboar EMOTE_SNIFF_AIR'), +(-1000908,'%s starts to dig.',0,2,0,0,'domesticated felboar EMOTE_START_DIG'), +(-1000909,'%s squeals with glee at its discovery.',0,2,0,0,'domesticated felboar EMOTE_SQUEAL'); diff --git a/sql/updates/0.7/r2896_mangos.sql b/sql/updates/0.7/r2896_mangos.sql new file mode 100644 index 000000000..b23ef47b7 --- /dev/null +++ b/sql/updates/0.7/r2896_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='boss_ahune' WHERE entry=25740; +UPDATE creature_template SET ScriptName='npc_frozen_core' WHERE entry=25865; +UPDATE creature_template SET ScriptName='npc_ice_spear_bunny' WHERE entry=25985; diff --git a/sql/updates/0.7/r2897_mangos.sql b/sql/updates/0.7/r2897_mangos.sql new file mode 100644 index 000000000..dd8d03be3 --- /dev/null +++ b/sql/updates/0.7/r2897_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_veneratus_spawn_node' WHERE entry=21334; diff --git a/sql/updates/0.7/r2897_scriptdev2.sql b/sql/updates/0.7/r2897_scriptdev2.sql new file mode 100644 index 000000000..064ea9970 --- /dev/null +++ b/sql/updates/0.7/r2897_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1000579); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000579,'There! Destroy him! The Cipher must be recovered!',0,0,0,25,'spirit hunter - SAY_VENERATUS_SPAWN'); diff --git a/sql/updates/0.7/r2898_mangos.sql b/sql/updates/0.7/r2898_mangos.sql new file mode 100644 index 000000000..78684f24a --- /dev/null +++ b/sql/updates/0.7/r2898_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (19998,20334,21296,21975); +UPDATE creature_template SET ScriptName='npc_bloodmaul_stout_trigger' WHERE entry=21241; diff --git a/sql/updates/0.7/r2898_scriptdev2.sql b/sql/updates/0.7/r2898_scriptdev2.sql new file mode 100644 index 000000000..078ea407d --- /dev/null +++ b/sql/updates/0.7/r2898_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1000156, -1000207, -1000208); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000156,'Bloodmaul Brew? Me favorite!',0,0,0,0,'bladespire ogre SAY_BREW_1'), +(-1000207,'Mmm. Me thirsty!',0,0,0,0,'bladespire ogre SAY_BREW_2'), +(-1000208,'Ohh, look! Bloodmaul Brew! Mmmm...',0,0,0,0,'bladespire ogre SAY_BREW_3'); diff --git a/sql/updates/0.7/r2899_mangos.sql b/sql/updates/0.7/r2899_mangos.sql new file mode 100644 index 000000000..833a29491 --- /dev/null +++ b/sql/updates/0.7/r2899_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_demonic_vapor' WHERE entry=25265; diff --git a/sql/updates/0.7/r2899_scriptdev2.sql b/sql/updates/0.7/r2899_scriptdev2.sql new file mode 100644 index 000000000..6524bbfe3 --- /dev/null +++ b/sql/updates/0.7/r2899_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry IN (-1580107); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1580107,'%s takes a deep breath.',0,3,0,0,'felmyst EMOTE_DEEP_BREATH'); diff --git a/sql/updates/0.7/r2901_scriptdev2.sql b/sql/updates/0.7/r2901_scriptdev2.sql new file mode 100644 index 000000000..6b922423c --- /dev/null +++ b/sql/updates/0.7/r2901_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12514+) '; diff --git a/sql/updates/0.7/r2902_mangos.sql b/sql/updates/0.7/r2902_mangos.sql new file mode 100644 index 000000000..7650acd4b --- /dev/null +++ b/sql/updates/0.7/r2902_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_simon_game_bunny' WHERE entry=22923; diff --git a/sql/updates/0.7/r2903_scriptdev2.sql b/sql/updates/0.7/r2903_scriptdev2.sql new file mode 100644 index 000000000..5426b0915 --- /dev/null +++ b/sql/updates/0.7/r2903_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12524+) '; diff --git a/sql/updates/0.7/r2904_mangos.sql b/sql/updates/0.7/r2904_mangos.sql new file mode 100644 index 000000000..a96298513 --- /dev/null +++ b/sql/updates/0.7/r2904_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_anchorite_truuen' WHERE entry=17238; diff --git a/sql/updates/0.7/r2904_scriptdev2.sql b/sql/updates/0.7/r2904_scriptdev2.sql new file mode 100644 index 000000000..bed35b3a3 --- /dev/null +++ b/sql/updates/0.7/r2904_scriptdev2.sql @@ -0,0 +1,57 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000919 AND -1000910; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000910,'Shall we begin, my friend?',0,0,0,0,'anchorite truuen SAY_BEGIN'), +(-1000911,'This area is known to be full of foul Scourge. You may want to take a moment to prepare any defenses at your disposal.',0,0,0,0,'anchorite truuen SAY_FIRST_STOP'), +(-1000912,'Very well, let us continue.',0,0,0,0,'anchorite truuen SAY_CONTINUE'), +(-1000913,'Beware! We are attacked!',0,0,0,0,'anchorite truuen SAY_FIRST_ATTACK'), +(-1000914,'It must be the purity of the Mark of the Lightbringer that is drawing forth the Scourge to us. We must proceed with caution lest we overwhelmed!',0,0,0,0,'anchorite truuen SAY_PURITY'), +(-1000915,'We are beset upon again! Defend yourself!',0,0,0,0,'anchorite truuen SAY_SECOND_ATTACK'), +(-1000916,'The land truly needs to be cleansed by the Light! Let us continue on the tomb. It isn\'t far now.',0,0,0,0,'anchorite truuen SAY_CLEANSE'), +(-1000917,'Be welcome, friends!',0,0,0,0,'high priest thel\'danis SAY_WELCOME'), +(-1000918,'Thank you for coming in remembrance of me. Your efforts in recovering that symbol, while unnecessary, are certainly touching to an old man\'s heart.',0,0,0,0,'ghost of uther SAY_EPILOGUE_1'), +(-1000919,'Please, rise my friend. Keep the Blessing as a symbol of the strength of the Light and how heroes long gone might once again rise in each of us to inspire.',0,0,0,0,'ghost of uther SAY_EPILOGUE_2'); + +DELETE FROM script_waypoint WHERE entry=17238; +INSERT INTO script_waypoint VALUES +(17238, 0, 954.21, -1433.72, 63.00, 0, ''), +(17238, 1, 972.70, -1438.85, 65.56, 0, ''), +(17238, 2, 984.79, -1444.15, 64.13, 0, ''), +(17238, 3, 999.00, -1451.74, 61.20, 0, ''), +(17238, 4, 1030.94, -1470.39, 63.49, 25000, 'SAY_FIRST_STOP'), +(17238, 5, 1030.94, -1470.39, 63.49, 3000, 'SAY_CONTINUE'), +(17238, 6, 1036.50, -1484.25, 64.60, 0, ''), +(17238, 7, 1039.11, -1501.22, 65.32, 0, ''), +(17238, 8, 1038.44, -1522.18, 64.55, 0, ''), +(17238, 9, 1037.19, -1543.15, 62.33, 0, ''), +(17238, 10, 1036.79, -1563.88, 61.93, 5000, 'SAY_FIRST_ATTACK'), +(17238, 11, 1036.79, -1563.88, 61.93, 5000, 'SAY_PURITY'), +(17238, 12, 1035.61, -1587.64, 61.66, 0, ''), +(17238, 13, 1035.43, -1612.97, 61.54, 0, ''), +(17238, 14, 1035.36, -1630.66, 61.53, 0, ''), +(17238, 15, 1038.85, -1653.02, 60.35, 0, ''), +(17238, 16, 1042.27, -1669.36, 60.75, 0, ''), +(17238, 17, 1050.41, -1687.22, 60.52, 0, ''), +(17238, 18, 1061.15, -1704.45, 60.59, 0, ''), +(17238, 19, 1073.51, -1716.99, 60.65, 0, ''), +(17238, 20, 1084.20, -1727.24, 60.95, 0, ''), +(17238, 21, 1100.71, -1739.89, 60.64, 5000, 'SAY_SECOND_ATTACK'), +(17238, 22, 1100.71, -1739.89, 60.64, 0, 'SAY_CLEANSE'), +(17238, 23, 1117.03, -1749.01, 60.87, 0, ''), +(17238, 24, 1123.58, -1762.29, 62.40, 0, ''), +(17238, 25, 1123.36, -1769.29, 62.83, 0, ''), +(17238, 26, 1115.78, -1779.59, 62.09, 0, ''), +(17238, 27, 1109.56, -1789.78, 61.03, 0, ''), +(17238, 28, 1094.81, -1797.62, 61.22, 0, ''), +(17238, 29, 1079.30, -1801.58, 64.95, 0, ''), +(17238, 30, 1060.24, -1803.40, 70.36, 0, ''), +(17238, 31, 1047.69, -1804.49, 73.92, 0, ''), +(17238, 32, 1032.59, -1805.99, 76.13, 0, ''), +(17238, 33, 1013.60, -1812.36, 77.32, 0, ''), +(17238, 34, 1007.01, -1814.38, 80.48, 0, ''), +(17238, 35, 999.93, -1816.39, 80.48, 2000, 'SAY_WELCOME'), +(17238, 36, 984.72, -1822.05, 80.48, 0, ''), +(17238, 37, 977.77, -1824.80, 80.79, 0, ''), +(17238, 38, 975.33, -1824.91, 81.24, 12000, 'event complete'), +(17238, 39, 975.33, -1824.91, 81.24, 10000, 'SAY_EPILOGUE_1'), +(17238, 40, 975.33, -1824.91, 81.24, 8000, 'SAY_EPILOGUE_2'), +(17238, 41, 975.33, -1824.91, 81.24, 30000, ''); diff --git a/sql/updates/0.7/r2905_mangos.sql b/sql/updates/0.7/r2905_mangos.sql new file mode 100644 index 000000000..f39be10b2 --- /dev/null +++ b/sql/updates/0.7/r2905_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_lich_king_village' WHERE entry=24248; diff --git a/sql/updates/0.7/r2905_scriptdev2.sql b/sql/updates/0.7/r2905_scriptdev2.sql new file mode 100644 index 000000000..9432c3af4 --- /dev/null +++ b/sql/updates/0.7/r2905_scriptdev2.sql @@ -0,0 +1,10 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000927 AND -1000920; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000920,'%s turns to face you.',0,2,0,0,'lich_king_wyrmskull EMOTE_LICH_KING_FACE'), +(-1000921,'Shamanism has brought you here... Its scent permeates the air. *The Lich King laughs* I was once a shaman.',14742,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_1'), +(-1000922,'Shall we prepare it for you, my lord?',0,0,0,0,'valkyr_soulclaimer SAY_PREPARE'), +(-1000923,'No, minion. This one is not ready.',14743,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_2'), +(-1000924,'Do you feel it, mortal? Death seeps through me, enveloping all that I touch. With just a snap of my finger your soul will languish in damnation for all eternity.',14744,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_3'), +(-1000925,'But... It is not yet your time to serve the Lich King. Yes, a greater destiny awaits you. Power... You must become more powerful before you are to serve me.',14745,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_4'), +(-1000926,'Now watch, val\'kyr. Observe as I apply pressure. Can you see that it is not yet ripe? Watch as it pops and falls lifeless to the floor.',14746,0,0,0,'lich_king_wyrmskull SAY_LICH_KING_5'), +(-1000927,'Persistence or stupidity? It matters not. Let this be a lesson learned, mortal!',14747,0,0,0,'lich_king_wyrmskull SAY_PERSISTANCE'); diff --git a/sql/updates/0.7/r2907_mangos.sql b/sql/updates/0.7/r2907_mangos.sql new file mode 100644 index 000000000..6a99f0880 --- /dev/null +++ b/sql/updates/0.7/r2907_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_king_ymiron' WHERE entry=24321; +DELETE FROM scripted_areatrigger WHERE entry IN (4779); +INSERT INTO scripted_areatrigger VALUES (4779,'at_nifflevar'); diff --git a/sql/updates/0.7/r2907_scriptdev2.sql b/sql/updates/0.7/r2907_scriptdev2.sql new file mode 100644 index 000000000..1417614ec --- /dev/null +++ b/sql/updates/0.7/r2907_scriptdev2.sql @@ -0,0 +1,22 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000947 AND -1000928; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000928,'%s motions for silence.',0,3,0,25,'king_ymiron EMOTE_KING_SILENCE'), +(-1000929,'Vrykul, your king implores you listen!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_1'), +(-1000930,'The Gods have abandonned us!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_2'), +(-1000931,'The crowd gasps in horror.',0,2,0,0,'king_ymiron EMOTE_YMIRON_CROWD_1'), +(-1000932,'Even now, in our darkest hour, they mock us!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_3'), +(-1000933,'Where are the titans in out time of greatest need? Our women birth abberations - disfigured runts unable to even stand on their own! Weak and ugly... Useless...',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_4'), +(-1000934,'Ymiron has toiled. Long have I sat upon my throne and thought hard of our plight. There is only one answer... One reason...',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_5'), +(-1000935,'For who but the titans themselves could bestow such a curse? What could have such power?',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_6'), +(-1000936,'And the answer is nothing... For it is the titans who have cursed us!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_7'), +(-1000937,'The crowd clamours.',0,2,0,0,'king_ymiron EMOTE_YMIRON_CROWD_2'), +(-1000938,'On this day all Vrykul will shed their old beliefs! We denounce our old gods! All Vrykul will pledge their allegiance to Ymiron! Ymiron will protect our noble race!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_8'), +(-1000939,'The crowd cheers.',0,2,0,0,'king_ymiron EMOTE_YMIRON_CROWD_3'), +(-1000940,'And now my first decree upon the Vrykul! All malformed infants born of Vrykul mother and father are to be destroyed upon birth! Our blood must remain pure always! Those found in violation of Ymiron\'s decree will be taken to Gjalerbron for execution!',0,1,0,22,'king_ymiron SAY_KING_YMIRON_SPEECH_9'), +(-1000941,'Vrykul must remain pure!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_1'), +(-1000942,'Show the aberrations no mercy, Ymiron!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_2'), +(-1000943,'Show them mercy, my king! They are of our flesh and blood!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_3'), +(-1000944,'They weaken us! Our strength is dilluted by their very existence! Destroy them all!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_4'), +(-1000945,'All hail our glorious king, Ymiron!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_5'), +(-1000946,'The King is going to speak!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_6'), +(-1000947,'Let him speak! Be silent!',0,0,0,0,'king_ymiron_crowd SAY_YMIRON_CROWD_7'); diff --git a/sql/updates/0.7/r2908_mangos.sql b/sql/updates/0.7/r2908_mangos.sql new file mode 100644 index 000000000..c6a3885b5 --- /dev/null +++ b/sql/updates/0.7/r2908_mangos.sql @@ -0,0 +1,13 @@ +UPDATE creature_template SET ScriptName='npc_echo_of_medivh' WHERE entry=16816; +UPDATE creature_template SET ScriptName='npc_king_llane' WHERE entry=21684; +UPDATE creature_template SET ScriptName='npc_warchief_blackhand' WHERE entry=21752; +UPDATE creature_template SET ScriptName='npc_human_conjurer' WHERE entry=21683; +UPDATE creature_template SET ScriptName='npc_orc_warlock' WHERE entry=21750; +UPDATE creature_template SET ScriptName='npc_human_footman' WHERE entry=17211; +UPDATE creature_template SET ScriptName='npc_orc_grunt' WHERE entry=17469; +UPDATE creature_template SET ScriptName='npc_water_elemental' WHERE entry=21160; +UPDATE creature_template SET ScriptName='npc_summoned_daemon' WHERE entry=21726; +UPDATE creature_template SET ScriptName='npc_human_charger' WHERE entry=21664; +UPDATE creature_template SET ScriptName='npc_orc_wolf' WHERE entry=21748; +UPDATE creature_template SET ScriptName='npc_human_cleric' WHERE entry=21682; +UPDATE creature_template SET ScriptName='npc_orc_necrolyte' WHERE entry=21747; diff --git a/sql/updates/0.7/r2908_scriptdev2.sql b/sql/updates/0.7/r2908_scriptdev2.sql new file mode 100644 index 000000000..604f95da1 --- /dev/null +++ b/sql/updates/0.7/r2908_scriptdev2.sql @@ -0,0 +1,19 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1532132 AND -1532131; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1532131,'The halls of Karazhan shake, as the curse binding the doors of the Gamemaster\'s Hall is lifted.',0,2,0,0,'echo_of_medivh EMOTE_LIFT_CURSE'), +(-1532132,'%s cheats!',0,3,0,0,'echo_of_medivh EMOTE_CHEAT'); + +DELETE FROM gossip_texts WHERE entry BETWEEN -3532017 AND -3532006; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3532006,'Control Orc Grunt','orc grunt GOSSIP_ITEM_ORC_GRUNT'), +(-3532007,'Control Orc Wolf','orc wolf GOSSIP_ITEM_ORC_WOLF'), +(-3532008,'Control Summoned Daemon','summoned deamon GOSSIP_ITEM_SUMMONED_DEAMON'), +(-3532009,'Control Orc Warlock','orc warlock GOSSIP_ITEM_ORC_WARLOCK'), +(-3532010,'Control Orc Necrolyte','orc necrolyte GOSSIP_ITEM_ORC_NECROLYTE'), +(-3532011,'Control Warchief Blackhand','warchief blackhand GOSSIP_ITEM_WARCHIEF_BLACKHAND'), +(-3532012,'Control Human Footman','human footman GOSSIP_ITEM_HUMAN_FOOTMAN'), +(-3532013,'Control Human Charger','human charger GOSSIP_ITEM_HUMAN_CHARGER'), +(-3532014,'Control Conjured Water Elemental','conjured water elemental GOSSIP_ITEM_WATER_ELEMENTAL'), +(-3532015,'Control Human Conjurer','human conjurer GOSSIP_ITEM_HUMAN_CONJURER'), +(-3532016,'Control Human Cleric','human cleric GOSSIP_ITEM_HUMAN_CLERIC'), +(-3532017,'Control King Llane','king llane GOSSIP_ITEM_KING_LLANE'); diff --git a/sql/updates/0.7/r2912_mangos.sql b/sql/updates/0.7/r2912_mangos.sql new file mode 100644 index 000000000..4ec9d9357 --- /dev/null +++ b/sql/updates/0.7/r2912_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='' WHERE entry IN (187982,187995,187996,187997,187998,187999,188000,188001,188002,188003,188004,188005,188006,188007,188008); diff --git a/sql/updates/0.7/r2913_scriptdev2.sql b/sql/updates/0.7/r2913_scriptdev2.sql new file mode 100644 index 000000000..1075c4ac5 --- /dev/null +++ b/sql/updates/0.7/r2913_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET emote=293 WHERE entry=-1580032; diff --git a/sql/updates/0.7/r2914_scriptdev2.sql b/sql/updates/0.7/r2914_scriptdev2.sql new file mode 100644 index 000000000..bdc36b3a4 --- /dev/null +++ b/sql/updates/0.7/r2914_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM gossip_texts WHERE entry=-3532018; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3532018,'Please reset the chess board, we would like to play again.','medivh GOSSIP_ITEM_RESET_BOARD'); diff --git a/sql/updates/0.7/r2915_mangos.sql b/sql/updates/0.7/r2915_mangos.sql new file mode 100644 index 000000000..ee844e62f --- /dev/null +++ b/sql/updates/0.7/r2915_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_kinelory' WHERE entry=2713; diff --git a/sql/updates/0.7/r2915_scriptdev2.sql b/sql/updates/0.7/r2915_scriptdev2.sql new file mode 100644 index 000000000..ebc0528d8 --- /dev/null +++ b/sql/updates/0.7/r2915_scriptdev2.sql @@ -0,0 +1,50 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000957 AND -1000948; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000948,'Well then, let\'s get this started. The longer we\'re here, the more damage the undead could be doing back in Hilsbrad.',0,0,0,0,'kinelory SAY_START'), +(-1000949,'All right, this is where we really have to be on our paws. Be ready!',0,0,0,0,'kinelory SAY_REACH_BOTTOM'), +(-1000950,'Attack me if you will, but you won\'t stop me from getting back to Quae.',0,0,0,0,'kinelory SAY_AGGRO_KINELORY'), +(-1000951,'You have my word that I shall find a use for your body after I\'ve killed you, Kinelory.',0,0,0,0,'jorell SAY_AGGRO_JORELL'), +(-1000952,'Watch my rear! I\'ll see what I can find in all this junk...',0,0,0,0,'kinelory SAY_WATCH_BACK'), +(-1000953,'%s begins rummaging through the apothecary\'s belongings.',0,2,0,0,'kinelory EMOTE_BELONGINGS'), +(-1000954,'I bet Quae\'ll think this is important. She\'s pretty knowledgeable about these things--no expert, but knowledgable.',0,0,0,0,'kinelory SAY_DATA_FOUND'), +(-1000955,'Okay, let\'s get out of here quick quick! Try and keep up. I\'m going to make a break for it.',0,0,0,0,'kinelory SAY_ESCAPE'), +(-1000956,'We made it! Quae, we made it!',0,0,0,0,'kinelory SAY_FINISH'), +(-1000957,'%s hands her pack to Quae.',0,2,0,0,'kinelory EMOTE_HAND_PACK'); + +DELETE FROM script_waypoint WHERE entry=2713; +INSERT INTO script_waypoint VALUES +(2713, 0, -1416.91, -3044.12, 36.21, 0, ''), +(2713, 1, -1408.43, -3051.35, 37.79, 0, ''), +(2713, 2, -1399.45, -3069.20, 31.25, 0, ''), +(2713, 3, -1400.28, -3083.14, 27.06, 0, ''), +(2713, 4, -1405.30, -3096.72, 26.36, 0, ''), +(2713, 5, -1406.12, -3105.95, 24.82, 0, ''), +(2713, 6, -1417.41, -3106.80, 16.61, 0, ''), +(2713, 7, -1433.06, -3101.55, 12.56, 0, ''), +(2713, 8, -1439.86, -3086.36, 12.29, 0, ''), +(2713, 9, -1450.48, -3065.16, 12.58, 5000, 'SAY_REACH_BOTTOM'), +(2713, 10, -1456.15, -3055.53, 12.54, 0, ''), +(2713, 11, -1459.41, -3035.16, 12.11, 0, ''), +(2713, 12, -1472.47, -3034.18, 12.44, 0, ''), +(2713, 13, -1495.57, -3034.48, 12.55, 0, ''), +(2713, 14, -1524.91, -3035.47, 13.15, 0, ''), +(2713, 15, -1549.05, -3037.77, 12.98, 0, ''), +(2713, 16, -1555.69, -3028.02, 13.64, 3000, 'SAY_WATCH_BACK'), +(2713, 17, -1555.69, -3028.02, 13.64, 5000, 'SAY_DATA_FOUND'), +(2713, 18, -1555.69, -3028.02, 13.64, 2000, 'SAY_ESCAPE'), +(2713, 19, -1551.19, -3037.78, 12.96, 0, ''), +(2713, 20, -1584.60, -3048.77, 13.67, 0, ''), +(2713, 21, -1602.14, -3042.82, 15.12, 0, ''), +(2713, 22, -1610.68, -3027.42, 17.22, 0, ''), +(2713, 23, -1601.65, -3007.97, 24.65, 0, ''), +(2713, 24, -1581.05, -2992.32, 30.85, 0, ''), +(2713, 25, -1559.95, -2979.51, 34.30, 0, ''), +(2713, 26, -1536.51, -2969.78, 32.64, 0, ''), +(2713, 27, -1511.81, -2961.09, 29.12, 0, ''), +(2713, 28, -1484.83, -2960.87, 32.54, 0, ''), +(2713, 29, -1458.23, -2966.80, 40.52 , 0, ''), +(2713, 30, -1440.20, -2971.20, 43.15, 0, ''), +(2713, 31, -1427.85, -2989.15, 38.09, 0, ''), +(2713, 32, -1420.27, -3008.91, 35.01, 0, ''), +(2713, 33, -1427.58, -3032.53, 32.31, 5000, 'SAY_FINISH'), +(2713, 34, -1427.40, -3035.17, 32.26, 0, ''); diff --git a/sql/updates/0.7/r2916_mangos.sql b/sql/updates/0.7/r2916_mangos.sql new file mode 100644 index 000000000..2b44a6e3c --- /dev/null +++ b/sql/updates/0.7/r2916_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_stinky_ignatz' WHERE entry=4880; diff --git a/sql/updates/0.7/r2916_scriptdev2.sql b/sql/updates/0.7/r2916_scriptdev2.sql new file mode 100644 index 000000000..05044e053 --- /dev/null +++ b/sql/updates/0.7/r2916_scriptdev2.sql @@ -0,0 +1,35 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000962 AND -1000958; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000958,'You must protect me from monsters, who are living in this forest!',0,0,0,0,'stinky ignatz SAY_STINKY_BEGIN'), +(-1000959,'This part of forest are very danger for us. We must be a careful!',0,0,0,0,'stinky ignatz SAY_STINKY_FIRST_STOP'), +(-1000960,'Kill two monsters, who stay near Bogbean plant and then I gather a bogbean.',0,0,0,0,'stinky ignatz SAY_STINKY_2_MONSTERS'), +(-1000961,'I am gathering a bogbean. It takes some time.',0,0,0,69,'stinky ignatz SAY_STINKY_GATHERING'), +(-1000962,'Thanks you for help.',0,0,0,0,'stinky ignatz SAY_STINKY_END'); + +DELETE FROM script_waypoint WHERE entry=4880; +INSERT INTO script_waypoint VALUES +(4880, 0, -2674.53, -3440.48, 33.686, 0, ''), +(4880, 1, -2711.17, -3435.06, 33.1926, 0, ''), +(4880, 2, -2734.04, -3456.12, 33.2254, 0, ''), +(4880, 3, -2749.64, -3457.26, 32.8249, 0, ''), +(4880, 4, -2762.25, -3457.77, 30.6813, 0, ''), +(4880, 5, -2777.0, -3456.12, 30.2484, 0, ''), +(4880, 6, -2805.49, -3450.27, 29.0624, 0, ''), +(4880, 7, -2809.77, -3447.14, 30.0948, 0, ''), +(4880, 8, -2824, -3440.62, 33.405, 0, ''), +(4880, 9, -2840.2, -3439.02, 34.1008, 0, ''), +(4880, 10, -2878.49, -3482.81, 34.362, 0, ''), +(4880, 11, -2878.35, -3511.51, 34.4826, 0, 'SAY_STINKY_FIRST_STOP'), +(4880, 12, -2873.99, -3514.84, 34.5298, 0, ''), +(4880, 13, -2866.71, -3519.06, 36.3674, 0, ''), +(4880, 14, -2850.75, -3539.38, 36.4573, 0, ''), +(4880, 15, -2844.49, -3557.7, 35.5588, 0, ''), +(4880, 16, -2841.36, -3574.59, 35.5056, 0, ''), +(4880, 17, -2841.13, -3596.95, 36.7699, 30000, 'SAY_STINKY_2_MONSTERS'), +(4880, 18, -2828.83, -3597.3, 31.2891, 0, ''), +(4880, 19, -2822.13, -3596.33, 31.2684, 5000, 'SAY_STINKY_GATHERING'), +(4880, 20, -2829.08, -3597.82, 31.307, 0, ''), +(4880, 21, -2859.28, -3602.33, 42.298, 0, ''), +(4880, 22, -2881.64, -3601.28, 42.2111, 0, ''), +(4880, 23, -2904.04, -3601.35, 34.969, 0, ''), +(4880, 24, -2907.6, -3612.73, 34.2434, 10000, 'SAY_STINKY_END'); diff --git a/sql/updates/0.7/r2917_mangos.sql b/sql/updates/0.7/r2917_mangos.sql new file mode 100644 index 000000000..eabbbf8a7 --- /dev/null +++ b/sql/updates/0.7/r2917_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_rabid_bear' WHERE entry=2164; diff --git a/sql/updates/0.7/r2918_mangos.sql b/sql/updates/0.7/r2918_mangos.sql new file mode 100644 index 000000000..847cd57cb --- /dev/null +++ b/sql/updates/0.7/r2918_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_kernobee' WHERE entry=7850; diff --git a/sql/updates/0.7/r2920_mangos.sql b/sql/updates/0.7/r2920_mangos.sql new file mode 100644 index 000000000..5797c6aca --- /dev/null +++ b/sql/updates/0.7/r2920_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (30890, 31214); +UPDATE creature_template SET ScriptName='mob_twilight_eggs' WHERE entry IN (31204); +UPDATE creature_template SET ScriptName='npc_tenebron_egg_controller' WHERE entry=31138; diff --git a/sql/updates/0.7/r2920_scriptdev2.sql b/sql/updates/0.7/r2920_scriptdev2.sql new file mode 100644 index 000000000..496eff467 --- /dev/null +++ b/sql/updates/0.7/r2920_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE script_texts SET type=3 WHERE entry IN (-1615008,-1615017,-1615032,-1615041,-1615042); diff --git a/sql/updates/0.7/r2921_mangos.sql b/sql/updates/0.7/r2921_mangos.sql new file mode 100644 index 000000000..76872f107 --- /dev/null +++ b/sql/updates/0.7/r2921_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_netherspite_portal' WHERE entry IN (17367,17368,17369); diff --git a/sql/updates/0.8/r2923_mangos.sql b/sql/updates/0.8/r2923_mangos.sql new file mode 100644 index 000000000..74d53aa18 --- /dev/null +++ b/sql/updates/0.8/r2923_mangos.sql @@ -0,0 +1,6 @@ +UPDATE creature_template SET ScriptName='boss_ignis' WHERE entry=33118; +UPDATE creature_template SET ScriptName='npc_iron_construct' WHERE entry=33121; +UPDATE creature_template SET ScriptName='npc_scorch' WHERE entry=33221; +DELETE FROM scripted_event_id WHERE id IN (21620); +INSERT INTO scripted_event_id VALUES +(21620,'event_ulduar'); diff --git a/sql/updates/0.8/r2925_mangos.sql b/sql/updates/0.8/r2925_mangos.sql new file mode 100644 index 000000000..4951c7237 --- /dev/null +++ b/sql/updates/0.8/r2925_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_xt_002' WHERE entry=33293; diff --git a/sql/updates/0.8/r2926_mangos.sql b/sql/updates/0.8/r2926_mangos.sql new file mode 100644 index 000000000..168446c51 --- /dev/null +++ b/sql/updates/0.8/r2926_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_heart_deconstructor' WHERE entry=33329; +UPDATE creature_template SET ScriptName='npc_xt_toy_pile' WHERE entry=33337; diff --git a/sql/updates/0.8/r2926_scriptdev2.sql b/sql/updates/0.8/r2926_scriptdev2.sql new file mode 100644 index 000000000..c95c8f07c --- /dev/null +++ b/sql/updates/0.8/r2926_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry IN (-1603054,-1603055,-1603236,-1603237); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603054,'%s\'s heart is exposed and leaking energy.',0,3,0,0,'xt-002 EMOTE_EXPOSE_HEART'), +(-1603055,'%s consumes a scrapbot to repair himself!',0,3,0,0,'xt-002 EMOTE_REPAIR'), +(-1603236,'%s\'s heart is severed from his body.',0,3,0,0,'xt-002 EMOTE_KILL_HEART'), +(-1603237,'%s begins to cause the earth to quake.',0,3,0,0,'xt-002 EMOTE_EARTH_QUAKE'); diff --git a/sql/updates/0.8/r2927_mangos.sql b/sql/updates/0.8/r2927_mangos.sql new file mode 100644 index 000000000..f710e07bd --- /dev/null +++ b/sql/updates/0.8/r2927_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_razorscale' WHERE entry=33186; +UPDATE creature_template SET ScriptName='npc_expedition_commander' WHERE entry=33210; diff --git a/sql/updates/0.8/r2927_scriptdev2.sql b/sql/updates/0.8/r2927_scriptdev2.sql new file mode 100644 index 000000000..a88f528ab --- /dev/null +++ b/sql/updates/0.8/r2927_scriptdev2.sql @@ -0,0 +1,7 @@ +DELETE FROM script_texts WHERE entry IN (-1603040,-1603238); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603040,'Move quickly! She won\'t remain grounded for long!',15648,1,0,0,'razorscale SAY_GROUNDED'), +(-1603238,'%s is extinguished by the water!',0,2,0,0,'ignis EMOTE_EXTINGUISH_SCORCH'); +DELETE FROM gossip_texts WHERE entry=-3603009; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3603009,'We are ready to help!','Expedition Commander GOSSIP_ITEM_START_RAZORSCALE'); diff --git a/sql/updates/0.8/r2929_mangos.sql b/sql/updates/0.8/r2929_mangos.sql new file mode 100644 index 000000000..8e7590a65 --- /dev/null +++ b/sql/updates/0.8/r2929_mangos.sql @@ -0,0 +1,5 @@ +UPDATE creature_template SET ScriptName='npc_razorscale_spawner' WHERE entry=33245; +UPDATE creature_template SET ScriptName='npc_harpoon_fire_state' WHERE entry=33282; +DELETE FROM scripted_event_id WHERE id IN (20964); +INSERT INTO scripted_event_id VALUES +(20964,'event_spell_harpoon_shot'); diff --git a/sql/updates/0.8/r2930_mangos.sql b/sql/updates/0.8/r2930_mangos.sql new file mode 100644 index 000000000..e41914438 --- /dev/null +++ b/sql/updates/0.8/r2930_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_flame_leviathan' WHERE entry=33113; diff --git a/sql/updates/0.8/r2930_scriptdev2.sql b/sql/updates/0.8/r2930_scriptdev2.sql new file mode 100644 index 000000000..cf42274c3 --- /dev/null +++ b/sql/updates/0.8/r2930_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1603239,-1603240,-1603241); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603239,'You\'ve done it! You\'ve broken the defenses of Ulduar. In a few moments, we will be dropping in to...',15804,0,0,0,'bronzebeard radio SAY_PRE_LEVIATHAN_1'), +(-1603240,'What is that? Be careful! Something\'s headed your way!',15805,0,0,0,'bronzebeard radio SAY_PRE_LEVIATHAN_2'), +(-1603241,'Quickly! Evasive action! Evasive act--',15806,0,0,0,'bronzebeard radio SAY_PRE_LEVIATHAN_3'); diff --git a/sql/updates/0.8/r2932_mangos.sql b/sql/updates/0.8/r2932_mangos.sql new file mode 100644 index 000000000..15b69e4a5 --- /dev/null +++ b/sql/updates/0.8/r2932_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_ulduar_teleporter' WHERE entry=194569; diff --git a/sql/updates/0.8/r2933_mangos.sql b/sql/updates/0.8/r2933_mangos.sql new file mode 100644 index 000000000..ad1baac8f --- /dev/null +++ b/sql/updates/0.8/r2933_mangos.sql @@ -0,0 +1,8 @@ +UPDATE creature_template SET ScriptName='npc_keeper_norgannon' WHERE entry=33686; +UPDATE creature_template SET ScriptName='npc_brann_ulduar' WHERE entry=33579; +DELETE FROM scripted_event_id WHERE id IN (21030,21031,21032,21033); +INSERT INTO scripted_event_id VALUES +(21030,'event_go_ulduar_tower'), -- Tower of Life destroyed event +(21031,'event_go_ulduar_tower'), -- Tower of Storms destroyed event +(21032,'event_go_ulduar_tower'), -- Tower of Frost destroyed event +(21033,'event_go_ulduar_tower'); -- Tower of Flame destroyed event diff --git a/sql/updates/0.8/r2933_scriptdev2.sql b/sql/updates/0.8/r2933_scriptdev2.sql new file mode 100644 index 000000000..ec592860c --- /dev/null +++ b/sql/updates/0.8/r2933_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM gossip_texts WHERE entry IN (-3603010,-3603011,-3603012); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3603010,'Activate secondary defensive systems.','Lore Keeper of Norgannon GOSSIP_ITEM_ACTIVATE_SYSTEMS'), +(-3603011,'Confirmed.','Lore Keeper of Norgannon GOSSIP_ITEM_CONFIRMED'), +(-3603012,'We\'re ready. Begin the assault!','Brann Bronzebeard GOSSIP_ITEM_BEGIN_ASSAULT'); diff --git a/sql/updates/0.8/r2935_mangos.sql b/sql/updates/0.8/r2935_mangos.sql new file mode 100644 index 000000000..ab7ca2f49 --- /dev/null +++ b/sql/updates/0.8/r2935_mangos.sql @@ -0,0 +1,7 @@ +UPDATE creature_template SET ScriptName='npc_hodir_fury_reticle' WHERE entry=33108; +UPDATE creature_template SET ScriptName='npc_hodir_fury' WHERE entry=33212; +UPDATE creature_template SET ScriptName='npc_freya_ward' WHERE entry=33367; +UPDATE creature_template SET ScriptName='npc_mimiron_inferno' WHERE entry=33370; +DELETE FROM scripted_event_id WHERE id IN (21605); +INSERT INTO scripted_event_id VALUES +(21605,'event_ulduar'); diff --git a/sql/updates/0.8/r2935_scriptdev2.sql b/sql/updates/0.8/r2935_scriptdev2.sql new file mode 100644 index 000000000..a460636ab --- /dev/null +++ b/sql/updates/0.8/r2935_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry IN (-1603242,-1603243,-1603244,-1603245); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603242,'%s activates Hodir\'s Fury.',0,3,0,0,'leviathan EMOTE_HODIR_FURY'), +(-1603243,'%s activates Freya\'s Ward.',0,3,0,0,'leviathan EMOTE_FREYA_WARD'), +(-1603244,'%s activates Mimiron\'s Inferno.',0,3,0,0,'leviathan EMOTE_MIMIRON_INFERNO'), +(-1603245,'%s activates Thorim\'s Hammer.',0,3,0,0,'leviathan EMOTE_THORIM_HAMMER'); diff --git a/sql/updates/0.8/r2936_scriptdev2.sql b/sql/updates/0.8/r2936_scriptdev2.sql new file mode 100644 index 000000000..5f89aa8a9 --- /dev/null +++ b/sql/updates/0.8/r2936_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12550+) '; diff --git a/sql/updates/0.8/r2938_mangos.sql b/sql/updates/0.8/r2938_mangos.sql new file mode 100644 index 000000000..a2cb49e14 --- /dev/null +++ b/sql/updates/0.8/r2938_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='npc_scrapbot' WHERE entry=33343; +DELETE FROM scripted_event_id WHERE id IN (21606); +INSERT INTO scripted_event_id VALUES +(21606,'event_ulduar'); diff --git a/sql/updates/0.8/r2939_mangos.sql b/sql/updates/0.8/r2939_mangos.sql new file mode 100644 index 000000000..8656cefd2 --- /dev/null +++ b/sql/updates/0.8/r2939_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_kologarn' WHERE entry=32930; diff --git a/sql/updates/0.8/r2940_mangos.sql b/sql/updates/0.8/r2940_mangos.sql new file mode 100644 index 000000000..fc319ea10 --- /dev/null +++ b/sql/updates/0.8/r2940_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_focused_eyebeam' WHERE entry IN (33802,33632); diff --git a/sql/updates/0.8/r2942_mangos.sql b/sql/updates/0.8/r2942_mangos.sql new file mode 100644 index 000000000..4f9c8e076 --- /dev/null +++ b/sql/updates/0.8/r2942_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_rubble_stalker' WHERE entry=33809; diff --git a/sql/updates/0.8/r2944_mangos.sql b/sql/updates/0.8/r2944_mangos.sql new file mode 100644 index 000000000..3f39482a0 --- /dev/null +++ b/sql/updates/0.8/r2944_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_storm_tempered_keeper' WHERE entry IN (33699,33722); +UPDATE creature_template SET ScriptName='npc_charged_sphere' WHERE entry=33715; diff --git a/sql/updates/0.8/r2946_mangos.sql b/sql/updates/0.8/r2946_mangos.sql new file mode 100644 index 000000000..326a4ffa8 --- /dev/null +++ b/sql/updates/0.8/r2946_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_algalon' WHERE entry=32871; +UPDATE gameobject_template SET ScriptName='go_celestial_access' WHERE entry IN (194628,194752); diff --git a/sql/updates/0.8/r2946_scriptdev2.sql b/sql/updates/0.8/r2946_scriptdev2.sql new file mode 100644 index 000000000..2025d429c --- /dev/null +++ b/sql/updates/0.8/r2946_scriptdev2.sql @@ -0,0 +1,10 @@ +DELETE FROM script_texts WHERE entry IN (-1603106,-1603107,-1603121,-1603122,-1603123,-1603124,-1603125,-1603246); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603106,'Translocation complete. Commencing planetary analysis of Azeroth.',15405,1,0,0,'algalon SAY_INTRO_1'), +(-1603107,'Stand back, mortals. I\'m not here to fight you.',15406,1,0,0,'algalon SAY_INTRO_2'), +(-1603121,'I have seen worlds bathed in the Makers\' flames, their denizens fading without as much as a whimper. Entire planetary systems born and razed in the time that it takes your mortal hearts to beat once. Yet all throughout, my own heart devoid of emotion... of empathy. I. Have. Felt. Nothing. A million-million lives wasted. Had they all held within them your tenacity? Had they all loved life as you do?',15393,1,0,0,'algalon SAY_OUTRO_1'), +(-1603122,'Perhaps it is your imperfections... that which grants you free will... that allows you to persevere against all cosmically calculated odds. You prevail where the Titan\'s own perfect creations have failed.',15401,1,0,0,'algalon SAY_OUTRO_2'), +(-1603123,'I\'ve rearranged the reply code - your planet will be spared. I cannot be certain of my own calculations anymore.',15402,1,0,0,'algalon SAY_OUTRO_3'), +(-1603124,'I lack the strength to transmit the signal. You must... hurry... find a place of power... close to the skies.',15403,1,0,0,'algalon SAY_OUTRO_4'), +(-1603125,'Do not worry about my fate, Bronzen. If the signal is not transmitted in time, re-origination will proceed regardless. Save... your world...',15404,1,0,0,'algalon SAY_OUTRO_5'), +(-1603246,'I know just the place. Will you be all right?',15823,1,0,0,'brann SAY_BRANN_OUTRO'); diff --git a/sql/updates/0.8/r2947_mangos.sql b/sql/updates/0.8/r2947_mangos.sql new file mode 100644 index 000000000..9078db728 --- /dev/null +++ b/sql/updates/0.8/r2947_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='npc_living_constellation' WHERE entry=33052; +UPDATE creature_template SET ScriptName='npc_worm_hole' WHERE entry=34099; +UPDATE creature_template SET ScriptName='npc_black_hole' WHERE entry=32953; +UPDATE creature_template SET ScriptName='npc_collapsing_star' WHERE entry=32955; diff --git a/sql/updates/0.8/r2948_mangos.sql b/sql/updates/0.8/r2948_mangos.sql new file mode 100644 index 000000000..ec14d4560 --- /dev/null +++ b/sql/updates/0.8/r2948_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_hodir' WHERE entry=32845; diff --git a/sql/updates/0.8/r2951_mangos.sql b/sql/updates/0.8/r2951_mangos.sql new file mode 100644 index 000000000..0fe67d31a --- /dev/null +++ b/sql/updates/0.8/r2951_mangos.sql @@ -0,0 +1,6 @@ +UPDATE creature_template SET ScriptName='npc_flash_freeze' WHERE entry IN (32926,32938); +UPDATE creature_template SET ScriptName='npc_icicle_target' WHERE entry=33174; +DELETE FROM scripted_event_id WHERE id IN (20907,21045); +INSERT INTO scripted_event_id VALUES +(20907,'event_boss_hodir'), +(21045,'event_boss_hodir'); diff --git a/sql/updates/0.8/r2954_mangos.sql b/sql/updates/0.8/r2954_mangos.sql new file mode 100644 index 000000000..be7d44dcb --- /dev/null +++ b/sql/updates/0.8/r2954_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_thorim' WHERE entry=32865; diff --git a/sql/updates/0.8/r2955_mangos.sql b/sql/updates/0.8/r2955_mangos.sql new file mode 100644 index 000000000..0fcef2fb9 --- /dev/null +++ b/sql/updates/0.8/r2955_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName="npc_cenarion_sparrowhawk" WHERE entry=22972; diff --git a/sql/updates/0.8/r2955_scriptdev2.sql b/sql/updates/0.8/r2955_scriptdev2.sql new file mode 100644 index 000000000..a7664bc4e --- /dev/null +++ b/sql/updates/0.8/r2955_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM script_texts WHERE entry IN (-1000963,-1000964,-1000965); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000963,'%s looks at you for a moment, then motions for you to follow.',0,2,0,0,'cenarion sparrowhawk EMOTE_FOLLOW'), +(-1000964,'%s surveys the ground for the buried raven stones.',0,2,0,0,'cenarion sparrowhawk EMOTE_SURVEY'), +(-1000965,'%s locates a buried raven stone.',0,2,0,0,'cenarion sparrowhawk EMOTE_LOCATE'); diff --git a/sql/updates/0.8/r2958_mangos.sql b/sql/updates/0.8/r2958_mangos.sql new file mode 100644 index 000000000..e411978fc --- /dev/null +++ b/sql/updates/0.8/r2958_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_sif' WHERE entry=33196; +UPDATE creature_template SET ScriptName='npc_thunder_orb' WHERE entry=33378; diff --git a/sql/updates/0.8/r2959_mangos.sql b/sql/updates/0.8/r2959_mangos.sql new file mode 100644 index 000000000..491b9a25c --- /dev/null +++ b/sql/updates/0.8/r2959_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_runic_colossus' WHERE entry=32872; diff --git a/sql/updates/0.8/r2959_scriptdev2.sql b/sql/updates/0.8/r2959_scriptdev2.sql new file mode 100644 index 000000000..989d720f0 --- /dev/null +++ b/sql/updates/0.8/r2959_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1603247; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603247,'%s surrounds itself with a crackling Runic Barrier!',0,3,0,0,'thorim EMOTE_RUNIC_BARRIER'); diff --git a/sql/updates/0.8/r2962_mangos.sql b/sql/updates/0.8/r2962_mangos.sql new file mode 100644 index 000000000..82ae2b5f7 --- /dev/null +++ b/sql/updates/0.8/r2962_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_freya' WHERE entry=32906; diff --git a/sql/updates/0.8/r2963_mangos.sql b/sql/updates/0.8/r2963_mangos.sql new file mode 100644 index 000000000..4f9a6afb6 --- /dev/null +++ b/sql/updates/0.8/r2963_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_eonars_gift' WHERE entry=33228; +UPDATE creature_template SET ScriptName='npc_nature_bomb' WHERE entry=34129; diff --git a/sql/updates/0.8/r2964_mangos.sql b/sql/updates/0.8/r2964_mangos.sql new file mode 100644 index 000000000..fa7b28266 --- /dev/null +++ b/sql/updates/0.8/r2964_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_iron_roots' WHERE entry IN (33088,33168); diff --git a/sql/updates/0.8/r2965_mangos.sql b/sql/updates/0.8/r2965_mangos.sql new file mode 100644 index 000000000..105740e04 --- /dev/null +++ b/sql/updates/0.8/r2965_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='npc_healthy_spore' WHERE entry=33215; +UPDATE creature_template SET ScriptName='npc_water_spirit' WHERE entry=33202; +UPDATE creature_template SET ScriptName='npc_snaplasher' WHERE entry=32916; +UPDATE creature_template SET ScriptName='npc_storm_lasher' WHERE entry=32919; diff --git a/sql/updates/0.8/r2965_scriptdev2.sql b/sql/updates/0.8/r2965_scriptdev2.sql new file mode 100644 index 000000000..7ea823a5f --- /dev/null +++ b/sql/updates/0.8/r2965_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1603011; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603011,'The %s withers into the earth and begins to regenerate.',0,2,0,0,'freya EMOTE_REGEN_ALLIES'); diff --git a/sql/updates/0.8/r2967_mangos.sql b/sql/updates/0.8/r2967_mangos.sql new file mode 100644 index 000000000..cf95b4ed8 --- /dev/null +++ b/sql/updates/0.8/r2967_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_leviathan_mk2' WHERE entry=33432; diff --git a/sql/updates/0.8/r2969_mangos.sql b/sql/updates/0.8/r2969_mangos.sql new file mode 100644 index 000000000..1280a23f4 --- /dev/null +++ b/sql/updates/0.8/r2969_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry IN (22208,22212,22213); diff --git a/sql/updates/0.8/r2970_mangos.sql b/sql/updates/0.8/r2970_mangos.sql new file mode 100644 index 000000000..71a6ae506 --- /dev/null +++ b/sql/updates/0.8/r2970_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='boss_mimiron' WHERE entry=33350; +UPDATE creature_template SET ScriptName='boss_vx001' WHERE entry=33651; +UPDATE creature_template SET ScriptName='boss_aerial_unit' WHERE entry=33670; +UPDATE gameobject_template SET ScriptName='go_big_red_button' WHERE entry=194739; diff --git a/sql/updates/0.8/r2970_scriptdev2.sql b/sql/updates/0.8/r2970_scriptdev2.sql new file mode 100644 index 000000000..c8c7791aa --- /dev/null +++ b/sql/updates/0.8/r2970_scriptdev2.sql @@ -0,0 +1,16 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1603260 AND -1603248; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603248,'Self-destruct sequence initiated.',15413,1,0,0,'mimiron SAY_SELF_DESTRUCT'), +(-1603249,'This area will self-destruct in ten minutes.',15415,1,0,0,'mimiron SAY_DESTRUCT_10_MIN'), +(-1603250,'This area will self-destruct in nine minutes.',15416,1,0,0,'mimiron SAY_DESTRUCT_9_MIN'), +(-1603251,'This area will self-destruct in eight minutes.',15417,1,0,0,'mimiron SAY_DESTRUCT_8_MIN'), +(-1603252,'This area will self-destruct in seven minutes.',15418,1,0,0,'mimiron SAY_DESTRUCT_7_MIN'), +(-1603253,'This area will self-destruct in six minutes.',15419,1,0,0,'mimiron SAY_DESTRUCT_6_MIN'), +(-1603254,'This area will self-destruct in five minutes.',15420,1,0,0,'mimiron SAY_DESTRUCT_5_MIN'), +(-1603255,'This area will self-destruct in four minutes.',15421,1,0,0,'mimiron SAY_DESTRUCT_4_MIN'), +(-1603256,'This area will self-destruct in three minutes.',15422,1,0,0,'mimiron SAY_DESTRUCT_3_MIN'), +(-1603257,'This area will self-destruct in two minutes.',15423,1,0,0,'mimiron SAY_DESTRUCT_2_MIN'), +(-1603258,'This area will self-destruct in one minute.',15424,1,0,0,'mimiron SAY_DESTRUCT_1_MIN'), +(-1603259,'Self-destruct sequence finalized. Have a nice day.',15425,1,0,0,'mimiron SAY_DESTRUCT_0_MIN'), +(-1603260,'Self-destruct sequence terminated. Overide code A905.',15414,1,0,0,'mimiron SAY_SELF_DESTRUCT_END'); +UPDATE script_texts SET emote=1 WHERE entry=-1603194; diff --git a/sql/updates/0.8/r2971_mangos.sql b/sql/updates/0.8/r2971_mangos.sql new file mode 100644 index 000000000..0d0a0dec5 --- /dev/null +++ b/sql/updates/0.8/r2971_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_proximity_mine' WHERE entry=34362; +UPDATE creature_template SET ScriptName='npc_bot_trigger' WHERE entry=33856; +UPDATE creature_template SET ScriptName='boss_leviathan_mk2_turret' WHERE entry=34071; diff --git a/sql/updates/0.8/r2971_scriptdev2.sql b/sql/updates/0.8/r2971_scriptdev2.sql new file mode 100644 index 000000000..615050c20 --- /dev/null +++ b/sql/updates/0.8/r2971_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1603196; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603196,'%s begins to cast Plasma Blast!',0,3,0,0,'mimiron EMOTE_PLASMA_BLAST'); diff --git a/sql/updates/0.8/r2972_mangos.sql b/sql/updates/0.8/r2972_mangos.sql new file mode 100644 index 000000000..c301b03a5 --- /dev/null +++ b/sql/updates/0.8/r2972_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='npc_rocket_strike' WHERE entry=34047; +UPDATE creature_template SET ScriptName='npc_mimiron_flames' WHERE entry IN (34363,34121); +UPDATE creature_template SET ScriptName='npc_computer' WHERE entry=34143; +UPDATE creature_template SET ScriptName='npc_frost_bomb' WHERE entry=34149; diff --git a/sql/updates/0.8/r2973_mangos.sql b/sql/updates/0.8/r2973_mangos.sql new file mode 100644 index 000000000..4dde57b2e --- /dev/null +++ b/sql/updates/0.8/r2973_mangos.sql @@ -0,0 +1,4 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc_crates_bunny' WHERE entry=27827; +DELETE FROM scripted_areatrigger WHERE entry=5291; +INSERT INTO scripted_areatrigger VALUES +(5291,'at_culling_of_stratholme'); diff --git a/sql/updates/0.8/r2973_scriptdev2.sql b/sql/updates/0.8/r2973_scriptdev2.sql new file mode 100644 index 000000000..1a86fb244 --- /dev/null +++ b/sql/updates/0.8/r2973_scriptdev2.sql @@ -0,0 +1,9 @@ +DELETE FROM script_texts WHERE entry IN (-1595000,-1595001); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1595000,'All soldiers of Lordaeron should immediately report to the entrance of Stratholme, and await further orders from Prince Arthas.',0,6,0,0,'lordaeron crier SAY_SOLDIERS_REPORT'), +(-1595001,'Good work with the crates! Come talk to me in front of Stratholme for your next assignment!',0,4,0,0,'chromie WHISPER_CHROMIE_CRATES'); + +DELETE FROM gossip_texts WHERE entry IN (-3595006,-3595007); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3595006,'Chromie, you and I both know what''s going to happen in this time stream. We''ve seen this all before.$B$BCan you just skip us ahead to all the real action?','chromie GOSSIP_ITEM_INN_SKIP'), +(-3595007,'Yes, please!','chromie GOSSIP_ITEM_INN_TELEPORT'); diff --git a/sql/updates/0.8/r2974_mangos.sql b/sql/updates/0.8/r2974_mangos.sql new file mode 100644 index 000000000..fc0787575 --- /dev/null +++ b/sql/updates/0.8/r2974_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_sara' WHERE entry=33134; diff --git a/sql/updates/0.8/r2977_mangos.sql b/sql/updates/0.8/r2977_mangos.sql new file mode 100644 index 000000000..81791a307 --- /dev/null +++ b/sql/updates/0.8/r2977_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_ominous_cloud' WHERE entry=33292; +UPDATE creature_template SET ScriptName='npc_voice_yogg_saron' WHERE entry=33280; diff --git a/sql/updates/0.8/r2977_scriptdev2.sql b/sql/updates/0.8/r2977_scriptdev2.sql new file mode 100644 index 000000000..931d30b6c --- /dev/null +++ b/sql/updates/0.8/r2977_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1603261; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603261,'%s begins to boil upon touching $n!',0,2,0,0,'ominous cloud EMOTE_CLOUD_BOIL'); diff --git a/sql/updates/0.8/r2978_mangos.sql b/sql/updates/0.8/r2978_mangos.sql new file mode 100644 index 000000000..e3e63c8bb --- /dev/null +++ b/sql/updates/0.8/r2978_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_ulduar_keeper' WHERE entry IN (33241,33242,33244,33213); diff --git a/sql/updates/0.8/r2978_scriptdev2.sql b/sql/updates/0.8/r2978_scriptdev2.sql new file mode 100644 index 000000000..66bc7c99d --- /dev/null +++ b/sql/updates/0.8/r2978_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry IN (-1603012,-1603013); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603012,'As you wish, $N.',0,0,0,0,'keeper SAY_KEEPER_ACTIVE'), +(-1603013,'REUSE ME',0,0,0,0,'REUSE ME'); +DELETE FROM gossip_texts WHERE entry IN (-3603013,-3603014); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3603013,'Lend us your aid, keeper. Together we will defeat Yogg-Saron.','Ulduar Keeper GOSSIP_ITEM_LEND_AID'), +(-3603014,'Yes.','Ulduar Keeper GOSSIP_ITEM_KEEPER_CONFIRM'); diff --git a/sql/updates/0.8/r2980_mangos.sql b/sql/updates/0.8/r2980_mangos.sql new file mode 100644 index 000000000..c25fc0082 --- /dev/null +++ b/sql/updates/0.8/r2980_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='spell_dummy_npc' WHERE entry IN (30169); diff --git a/sql/updates/0.8/r2981_mangos.sql b/sql/updates/0.8/r2981_mangos.sql new file mode 100644 index 000000000..739d66e07 --- /dev/null +++ b/sql/updates/0.8/r2981_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_floating_spirit' WHERE entry IN (30141,30143,30145); +UPDATE creature_template SET ScriptName='npc_restless_frostborn' WHERE entry IN (29974,30135,30144); +UPDATE creature_template SET ScriptName='' WHERE entry=30996; diff --git a/sql/updates/0.8/r2982_mangos.sql b/sql/updates/0.8/r2982_mangos.sql new file mode 100644 index 000000000..c558ac502 --- /dev/null +++ b/sql/updates/0.8/r2982_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_beryl_sorcerer' WHERE entry=25316; +UPDATE creature_template SET ScriptName='npc_captured_beryl_sorcerer' WHERE entry=25474; diff --git a/sql/updates/0.8/r2983_scriptdev2.sql b/sql/updates/0.8/r2983_scriptdev2.sql new file mode 100644 index 000000000..98f8c428c --- /dev/null +++ b/sql/updates/0.8/r2983_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12587+) '; diff --git a/sql/updates/0.8/r2984_mangos.sql b/sql/updates/0.8/r2984_mangos.sql new file mode 100644 index 000000000..ec4cf2298 --- /dev/null +++ b/sql/updates/0.8/r2984_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_nexus_drake_hatchling' WHERE entry=26127; diff --git a/sql/updates/0.8/r2985_mangos.sql b/sql/updates/0.8/r2985_mangos.sql new file mode 100644 index 000000000..75259cc54 --- /dev/null +++ b/sql/updates/0.8/r2985_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_rethhedron' WHERE entry=22357; diff --git a/sql/updates/0.8/r2985_scriptdev2.sql b/sql/updates/0.8/r2985_scriptdev2.sql new file mode 100644 index 000000000..94d0e8a85 --- /dev/null +++ b/sql/updates/0.8/r2985_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1000966,-1000967); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000966,'I WILL CRUSH YOU LIKE A GNAT!',0,1,0,0,'reth\'hedron SAY_LOW_HP'), +(-1000967,'You will regret this, mortal! Reth\'hedron will return... I will have my vengeance!',0,1,0,53,'reth\'hedron SAY_EVENT_END'); diff --git a/sql/updates/0.8/r2987_mangos.sql b/sql/updates/0.8/r2987_mangos.sql new file mode 100644 index 000000000..22290edd9 --- /dev/null +++ b/sql/updates/0.8/r2987_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_drijya' WHERE entry=20281; diff --git a/sql/updates/0.8/r2987_scriptdev2.sql b/sql/updates/0.8/r2987_scriptdev2.sql new file mode 100644 index 000000000..e1afb9f53 --- /dev/null +++ b/sql/updates/0.8/r2987_scriptdev2.sql @@ -0,0 +1,42 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000976 AND -1000968; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000968,'Very well. Before we head down there, take a moment to prepare yourself.',0,0,0,1,'drijya SAY_DRIJYA_START'), +(-1000969,'Let\'s proceed at a brisk pace.',0,0,0,0,'drijya SAY_DRIJYA_1'), +(-1000970,'We\'ll start at that first energy pylon, straight ahead. Remember, try to keep them off of me.',0,0,0,1,'drijya SAY_DRIJYA_2'), +(-1000971,'Keep them off me!',0,0,0,0,'drijya SAY_DRIJYA_3'), +(-1000972,'I\'m done with this pylon. On to the next.',0,0,0,1,'drijya SAY_DRIJYA_4'), +(-1000973,'Alright, pylon two down. Now for the heat mainfold.',0,0,0,1,'drijya SAY_DRIJYA_5'), +(-1000974,'That should do it. The teleporter should blow any second now !',0,0,0,5,'drijya SAY_DRIJYA_6'), +(-1000975,'Ok, let\'s get out of here!',0,0,0,1,'drijya SAY_DRIJYA_7'), +(-1000976,'Thank you, $n! I couldn\'t have done it without you. You\'ll let Gahruj know?',0,0,0,1,'drijya SAY_DRIJYA_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=20281; +INSERT INTO script_waypoint VALUES +(20281, 0, 3096.416, 2801.408, 118.149, 7000, 'SAY_DRIJYA_START'), +(20281, 1, 3096.516, 2801.065, 118.128, 0, 'SAY_DRIJYA_1'), +(20281, 2, 3099.995, 2796.665, 118.118, 0, ''), +(20281, 3, 3098.759, 2786.174, 117.125, 0, ''), +(20281, 4, 3087.792, 2754.602, 115.441, 0, ''), +(20281, 5, 3080.718, 2730.793, 115.930, 9000, 'SAY_DRIJYA_2'), +(20281, 6, 3060.235, 2731.306, 115.122, 0, ''), +(20281, 7, 3050.863, 2727.388, 114.054, 0, ''), +(20281, 8, 3050.863, 2727.388, 114.054, 8000, 'SAY_DRIJYA_4'), +(20281, 9, 3055.008, 2724.972, 113.687, 0, ''), +(20281, 10, 3053.777, 2718.427, 113.684, 0, ''), +(20281, 11, 3028.622, 2693.375, 114.670, 0, ''), +(20281, 12, 3022.430, 2695.297, 113.406, 0, ''), +(20281, 13, 3022.430, 2695.297, 113.406, 8000, 'SAY_DRIJYA_5'), +(20281, 14, 3025.463, 2700.755, 113.514, 0, ''), +(20281, 15, 3011.336, 2716.782, 113.691, 0, ''), +(20281, 16, 3010.882, 2726.991, 114.239, 0, ''), +(20281, 17, 3009.178, 2729.083, 114.324, 0, ''), +(20281, 18, 3009.178, 2729.083, 114.324, 15000, 'SAY_DRIJYA_6'), +(20281, 19, 3009.178, 2729.083, 114.324, 6000, 'SPELL_EXPLOSION_VISUAL'), +(20281, 20, 3009.178, 2729.083, 114.324, 8000, 'SAY_DRIJYA_7'), +(20281, 21, 3033.888, 2736.437, 114.369, 0, ''), +(20281, 22, 3071.492, 2741.502, 116.462, 0, ''), +(20281, 23, 3087.792, 2754.602, 115.441, 0, ''), +(20281, 24, 3094.505, 2770.198, 115.744, 0, ''), +(20281, 25, 3103.510, 2784.362, 116.857, 0, ''), +(20281, 26, 3099.995, 2796.665, 118.118, 0, ''), +(20281, 27, 3096.290, 2801.027, 118.096, 0, 'SAY_DRIJYA_COMPLETE'); diff --git a/sql/updates/0.8/r2988_mangos.sql b/sql/updates/0.8/r2988_mangos.sql new file mode 100644 index 000000000..0524736d7 --- /dev/null +++ b/sql/updates/0.8/r2988_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_firecrackers_bunny' WHERE entry=24230; diff --git a/sql/updates/0.8/r2989_mangos.sql b/sql/updates/0.8/r2989_mangos.sql new file mode 100644 index 000000000..f8386f37e --- /dev/null +++ b/sql/updates/0.8/r2989_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_ghoul_feeding_bunny' WHERE entry=28591; +UPDATE creature_template SET ScriptName='npc_decaying_ghoul' WHERE entry=28565; diff --git a/sql/updates/0.8/r2991_scriptdev2.sql b/sql/updates/0.8/r2991_scriptdev2.sql new file mode 100644 index 000000000..5fb3f18ac --- /dev/null +++ b/sql/updates/0.8/r2991_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000980 AND -1000977; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000977,'Oh, it\'s on now! But you thought I\'d be alone too, huh?!',0,0,0,0,'tapoke slim jahn SAY_AGGRO'), +(-1000978,'Okay, okay! No need to get all violent. I\'ll talk. I\'ll talk!',0,0,0,20,'tapoke slim jahn SAY_DEFEAT'), +(-1000979,'Whoa! This is way more than what I bargained for, you\'re on your own, Slim!',0,0,0,0,'slim\'s friend SAY_FRIEND_DEFEAT'), +(-1000980,'I have a few notes from the job back at my place. I\'ll get them and then meet you back in the inn.',0,0,0,1,'tapoke slim jahn SAY_NOTES'); diff --git a/sql/updates/0.8/r2992_mangos.sql b/sql/updates/0.8/r2992_mangos.sql new file mode 100644 index 000000000..927a5e523 --- /dev/null +++ b/sql/updates/0.8/r2992_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_scourged_flamespitter' WHERE entry=25582; diff --git a/sql/updates/0.8/r2993_scriptdev2.sql b/sql/updates/0.8/r2993_scriptdev2.sql new file mode 100644 index 000000000..1dfd37e93 --- /dev/null +++ b/sql/updates/0.8/r2993_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12606+) '; diff --git a/sql/updates/0.8/r2994_mangos.sql b/sql/updates/0.8/r2994_mangos.sql new file mode 100644 index 000000000..2e811e283 --- /dev/null +++ b/sql/updates/0.8/r2994_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_anchorite_barada' WHERE entry=22431; +UPDATE creature_template SET ScriptName='npc_colonel_jules' WHERE entry=22432; diff --git a/sql/updates/0.8/r2994_scriptdev2.sql b/sql/updates/0.8/r2994_scriptdev2.sql new file mode 100644 index 000000000..fda85199e --- /dev/null +++ b/sql/updates/0.8/r2994_scriptdev2.sql @@ -0,0 +1,17 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000992 AND -1000981; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000981,'It is time. The rite of exorcism will now commence...',0,0,0,0,'anchorite barada SAY_EXORCISM_1'), +(-1000982,'Prepare yourself. Do not allow the ritual to be interrupted or we may lose our patient...',0,0,0,1,'anchorite barada SAY_EXORCISM_2'), +(-1000983,'Keep away. The fool is mine.',0,0,0,0,'colonel jules SAY_EXORCISM_3'), +(-1000984,'Back, foul beings of darkness! You have no power here!',0,0,0,0,'anchorite barada SAY_EXORCISM_4'), +(-1000985,'No! Not yet! This soul is ours!',0,0,0,0,'colonel jules SAY_EXORCISM_5'), +(-1000986,'Back! I cast you back... corrupter of faith! Author of pain! Do not return, or suffer the same fate as you did here today!',0,0,0,2,'anchorite barada SAY_EXORCISM_6'), +(-1000987,'I... must not...falter!',0,0,0,0,'anchorite barada SAY_EXORCISM_RANDOM_1'), +(-1000988,'Be cleansed with Light, human! Let not the demonic corruption overwhelm you.',0,0,0,0,'anchorite barada SAY_EXORCISM_RANDOM_2'), +(-1000989,'Back, foul beings of darkness! You have no power here!',0,0,0,0,'anchorite barada SAY_EXORCISM_RANDOM_3'), +(-1000990,'This is fruitless, draenei! You and your little helper cannot wrest control of this pathetic human. He is mine!',0,0,0,0,'colonel jules SAY_EXORCISM_RANDOM_4'), +(-1000991,'I see your ancestors, Anchorite! They writhe and scream in the darkness... they are with us!',0,0,0,0,'colonel jules SAY_EXORCISM_RANDOM_5'), +(-1000992,'I will tear your soul into morsels and slow roast them over demon fire!',0,0,0,0,'colonel jules SAY_EXORCISM_RANDOM_6'); +DELETE FROM gossip_texts WHERE entry=-3000111; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000111,'I am ready, Anchorite. Let us begin the exorcism.','anchorite barada GOSSIP_ITEM_EXORCISM'); diff --git a/sql/updates/0.8/r2995_mangos.sql b/sql/updates/0.8/r2995_mangos.sql new file mode 100644 index 000000000..2a289a578 --- /dev/null +++ b/sql/updates/0.8/r2995_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_dorius_stonetender' WHERE entry=8284; diff --git a/sql/updates/0.8/r2995_scriptdev2.sql b/sql/updates/0.8/r2995_scriptdev2.sql new file mode 100644 index 000000000..b3e8c39e9 --- /dev/null +++ b/sql/updates/0.8/r2995_scriptdev2.sql @@ -0,0 +1,41 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1000995 AND -1000993; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000993,'It\'s on! $N, meet my fists. Fists, say hello to $N.',0,0,0,0,'dorius stonetender SAY_AGGRO_1'), +(-1000994,'I\'m about to open a can on this $N.',0,0,0,0,'dorius stonetender SAY_AGGRO_2'); + +DELETE FROM script_waypoint WHERE entry=8284; +INSERT INTO script_waypoint VALUES +(8284, 0, -7007.209, -1749.160, 234.182, 3000, 'stand up'), +(8284, 1, -7007.324, -1729.849, 234.162, 0, ''), +(8284, 2, -7006.394, -1726.522, 234.099, 0, ''), +(8284, 3, -7003.256, -1726.903, 234.594, 0, ''), +(8284, 4, -6994.778, -1733.571, 238.281, 0, ''), +(8284, 5, -6987.904, -1735.935, 240.727, 0, ''), +(8284, 6, -6978.704, -1736.991, 241.809, 0, ''), +(8284, 7, -6964.261, -1740.251, 241.713, 0, ''), +(8284, 8, -6946.701, -1746.284, 241.667, 0, ''), +(8284, 9, -6938.751, -1749.381, 240.744, 0, ''), +(8284, 10, -6927.004, -1768.782, 240.744, 0, ''), +(8284, 11, -6909.453, -1791.258, 240.744, 0, ''), +(8284, 12, -6898.225, -1804.870, 240.744, 0, ''), +(8284, 13, -6881.280, -1821.788, 240.744, 0, ''), +(8284, 14, -6867.653, -1832.672, 240.706, 0, ''), +(8284, 15, -6850.184, -1839.254, 243.006, 0, ''), +(8284, 16, -6829.381, -1847.635, 244.190, 0, ''), +(8284, 17, -6804.618, -1857.535, 244.209, 0, ''), +(8284, 18, -6776.421, -1868.879, 244.142, 0, ''), +(8284, 19, -6753.471, -1876.906, 244.170, 10000, 'stop'), +(8284, 20, -6753.471, -1876.906, 244.170, 0, 'ambush'), +(8284, 21, -6731.033, -1884.944, 244.144, 0, ''), +(8284, 22, -6705.738, -1896.779, 244.144, 0, ''), +(8284, 23, -6678.956, -1909.607, 244.369, 0, ''), +(8284, 24, -6654.263, -1916.758, 244.145, 0, ''), +(8284, 25, -6620.604, -1917.608, 244.149, 0, ''), +(8284, 26, -6575.958, -1922.408, 244.149, 0, ''), +(8284, 27, -6554.811, -1929.883, 244.162, 0, ''), +(8284, 28, -6521.856, -1947.322, 244.151, 0, ''), +(8284, 29, -6493.320, -1962.654, 244.151, 0, ''), +(8284, 30, -6463.350, -1975.537, 244.213, 0, ''), +(8284, 31, -6435.428, -1983.847, 244.548, 0, ''), +(8284, 32, -6418.380, -1985.778, 246.554, 0, ''), +(8284, 33, -6389.783, -1986.544, 246.771, 30000, 'quest complete'); diff --git a/sql/updates/0.8/r2996_mangos.sql b/sql/updates/0.8/r2996_mangos.sql new file mode 100644 index 000000000..e224d0f63 --- /dev/null +++ b/sql/updates/0.8/r2996_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_fhwoor' WHERE entry=17877; diff --git a/sql/updates/0.8/r2996_scriptdev2.sql b/sql/updates/0.8/r2996_scriptdev2.sql new file mode 100644 index 000000000..a2778120e --- /dev/null +++ b/sql/updates/0.8/r2996_scriptdev2.sql @@ -0,0 +1,105 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001000 AND -1000995; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000995,'Fhwoor go now, $N. Get ark, come back.',0,0,0,0,'fhwoor SAY_ESCORT_START'), +(-1000996,'Take moment... get ready.',0,0,0,0,'fhwoor SAY_PREPARE'), +(-1000997,'We go!',0,0,0,0,'fhwoor SAY_CAMP_ENTER'), +(-1000998,'Uh oh...',0,0,0,0,'fhwoor SAY_AMBUSH'), +(-1000999,'Ha ha, squishy naga!',0,0,0,0,'fhwoor SAY_AMBUSH_CLEARED'), +(-1001000,'Fhwoor do good!',0,0,0,0,'fhwoor SAY_ESCORT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=17877; +INSERT INTO script_waypoint VALUES +(17877, 0, 231.403, 8479.940, 17.928, 3000, ''), +(17877, 1, 214.645, 8469.645, 23.121, 0, ''), +(17877, 2, 208.538, 8463.481, 24.738, 0, ''), +(17877, 3, 196.524, 8446.077, 24.814, 0, ''), +(17877, 4, 188.186, 8431.674, 22.625, 0, ''), +(17877, 5, 181.196, 8420.152, 23.730, 0, ''), +(17877, 6, 171.919, 8406.290, 21.844, 0, ''), +(17877, 7, 166.613, 8396.479, 23.585, 0, ''), +(17877, 8, 167.237, 8386.686, 21.546, 0, ''), +(17877, 9, 169.401, 8372.670, 19.599, 0, ''), +(17877, 10, 174.148, 8342.325, 20.409, 0, ''), +(17877, 11, 173.195, 8324.177, 21.126, 0, ''), +(17877, 12, 172.415, 8310.290, 21.702, 0, ''), +(17877, 13, 173.233, 8298.755, 19.564, 0, ''), +(17877, 14, 173.984, 8287.925, 18.839, 0, ''), +(17877, 15, 189.984, 8266.263, 18.500, 0, ''), +(17877, 16, 204.057, 8256.019, 19.701, 0, ''), +(17877, 17, 212.950, 8248.737, 21.583, 0, ''), +(17877, 18, 223.152, 8240.160, 20.001, 0, ''), +(17877, 19, 230.730, 8232.994, 18.990, 0, ''), +(17877, 20, 238.261, 8223.804, 20.720, 0, ''), +(17877, 21, 247.651, 8214.208, 19.146, 0, ''), +(17877, 22, 259.231, 8207.796, 19.278, 0, ''), +(17877, 23, 272.360, 8204.755, 19.980, 0, ''), +(17877, 24, 282.211, 8202.087, 22.090, 20000, 'SAY_PREPARE'), +(17877, 25, 282.211, 8202.087, 22.090, 0, 'SAY_CAMP_ENTER'), +(17877, 26, 296.006, 8191.644, 21.680, 0, ''), +(17877, 27, 304.472, 8188.048, 20.707, 0, ''), +(17877, 28, 317.574, 8182.044, 18.296, 0, ''), +(17877, 29, 340.046, 8178.776, 17.937, 0, ''), +(17877, 30, 353.799, 8181.222, 18.557, 0, ''), +(17877, 31, 368.231, 8186.324, 22.450, 0, ''), +(17877, 32, 375.737, 8187.030, 23.916, 0, ''), +(17877, 33, 390.067, 8186.638, 21.190, 0, ''), +(17877, 34, 398.699, 8181.824, 18.648, 0, ''), +(17877, 35, 412.325, 8172.612, 17.927, 0, ''), +(17877, 36, 424.541, 8161.957, 19.575, 0, ''), +(17877, 37, 436.900, 8157.407, 22.115, 0, ''), +(17877, 38, 444.548, 8155.414, 23.553, 0, ''), +(17877, 39, 457.201, 8154.233, 23.429, 0, ''), +(17877, 40, 470.989, 8154.142, 21.650, 0, ''), +(17877, 41, 483.435, 8154.151, 20.706, 0, ''), +(17877, 42, 507.558, 8157.515, 21.729, 0, ''), +(17877, 43, 528.036, 8162.028, 22.795, 0, ''), +(17877, 44, 542.402, 8161.099, 22.914, 0, ''), +(17877, 45, 557.286, 8160.273, 23.708, 13000, ''), +(17877, 46, 557.286, 8160.273, 23.708, 0, 'take the Ark'), +(17877, 47, 539.767, 8144.839, 22.217, 0, ''), +(17877, 48, 531.296, 8139.475, 22.146, 0, ''), +(17877, 49, 509.056, 8139.262, 20.705, 0, ''), +(17877, 50, 499.975, 8136.228, 20.408, 0, ''), +(17877, 51, 485.511, 8129.389, 22.010, 0, ''), +(17877, 52, 474.371, 8128.534, 22.657, 0, ''), +(17877, 53, 460.708, 8130.115, 20.946, 0, ''), +(17877, 54, 449.248, 8129.271, 21.033, 0, ''), +(17877, 55, 433.670, 8125.064, 18.440, 0, ''), +(17877, 56, 412.822, 8121.581, 17.603, 0, ''), +(17877, 57, 391.150, 8117.812, 17.736, 0, ''), +(17877, 58, 379.024, 8114.185, 17.889, 0, ''), +(17877, 59, 365.110, 8106.992, 18.220, 0, ''), +(17877, 60, 352.531, 8108.944, 17.932, 0, ''), +(17877, 61, 340.894, 8120.636, 17.374, 0, ''), +(17877, 62, 328.480, 8134.929, 18.112, 0, ''), +(17877, 63, 317.573, 8143.246, 20.604, 0, ''), +(17877, 64, 311.146, 8146.796, 21.097, 0, ''), +(17877, 65, 299.359, 8152.583, 18.676, 0, ''), +(17877, 66, 276.115, 8160.440, 17.735, 0, ''), +(17877, 67, 262.704, 8170.509, 17.478, 0, ''), +(17877, 68, 243.755, 8177.747, 17.744, 0, ''), +(17877, 69, 233.496, 8178.426, 17.528, 0, ''), +(17877, 70, 219.874, 8182.550, 19.637, 0, 'SAY_AMBUSH - escort paused'), +(17877, 71, 219.874, 8182.550, 19.637, 20000, 'SAY_AMBUSH_CLEARED'), +(17877, 72, 210.978, 8193.978, 20.777, 0, ''), +(17877, 73, 203.699, 8213.042, 22.768, 0, ''), +(17877, 74, 199.246, 8225.537, 24.847, 0, ''), +(17877, 75, 195.064, 8239.906, 22.640, 0, ''), +(17877, 76, 193.198, 8253.617, 20.083, 0, ''), +(17877, 77, 189.151, 8264.834, 18.714, 0, ''), +(17877, 78, 178.814, 8281.036, 19.070, 0, ''), +(17877, 79, 173.952, 8293.241, 18.533, 0, ''), +(17877, 80, 174.399, 8305.458, 21.006, 0, ''), +(17877, 81, 175.124, 8319.509, 21.626, 0, ''), +(17877, 82, 175.690, 8339.654, 20.375, 0, ''), +(17877, 83, 172.754, 8362.673, 19.181, 0, ''), +(17877, 84, 176.465, 8379.798, 18.445, 0, ''), +(17877, 85, 186.433, 8393.126, 18.933, 0, ''), +(17877, 86, 199.438, 8407.825, 18.763, 0, ''), +(17877, 87, 211.874, 8422.383, 18.785, 0, ''), +(17877, 88, 219.900, 8436.264, 21.927, 0, ''), +(17877, 89, 225.062, 8450.565, 22.832, 0, ''), +(17877, 90, 226.942, 8464.410, 19.822, 0, ''), +(17877, 91, 231.403, 8479.940, 17.928, 0, ''), +(17877, 92, 247.625, 8483.801, 22.464, 13000, ''), +(17877, 93, 231.403, 8479.940, 17.928, 10000, 'SAY_ESCORT_COMPLETE'); diff --git a/sql/updates/0.8/r2997_mangos.sql b/sql/updates/0.8/r2997_mangos.sql new file mode 100644 index 000000000..69928c88e --- /dev/null +++ b/sql/updates/0.8/r2997_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_nagrand_captive' WHERE entry IN (18209,18210); diff --git a/sql/updates/0.8/r2997_scriptdev2.sql b/sql/updates/0.8/r2997_scriptdev2.sql new file mode 100644 index 000000000..4d36a5055 --- /dev/null +++ b/sql/updates/0.8/r2997_scriptdev2.sql @@ -0,0 +1,30 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001005 AND -1001001; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001001,'We must leave before more are alerted.',0,0,0,0,'kurenai captive SAY_KUR_START'), +(-1001002,'It\'s an ambush! Defend yourself!',0,0,0,0,'kurenai captive SAY_KUR_AMBUSH_1'), +(-1001003,'We are surrounded!',0,0,0,0,'kurenai captive SAY_KUR_AMBUSH_2'), +(-1001004,'Up ahead is the road to Telaar. We will split up when we reach the fork as they will surely send more Murkblood after us. Hopefully one of us makes it back to Telaar alive.',0,0,0,1,'kurenai captive SAY_KUR_COMPLETE_1'), +(-1001005,'Farewell, stranger. Your heroics will be remembered by my people. Now, hurry to Telaar!',0,0,0,1,'kurenai captive SAY_KUR_COMPLETE_2'); + +DELETE FROM script_waypoint WHERE entry=18209; +INSERT INTO script_waypoint VALUES +(18209, 0, -1518.092407, 8465.188477, -4.102, 0, ''), +(18209, 1, -1516.741699, 8472.000977, -4.101, 0, ''), +(18209, 2, -1516.330444, 8473.119141, -4.102, 0, ''), +(18209, 3, -1514.117310, 8476.740234, -4.100, 0, ''), +(18209, 4, -1512.199951, 8481.147461, -4.015, 0, ''), +(18209, 5, -1514.709839, 8488.281250, -3.544, 0, ''), +(18209, 6, -1516.556274, 8495.236328, -2.463, 0, ''), +(18209, 7, -1515.730957, 8506.528320, -0.609, 7000, 'SAY_KUR_AMBUSH'), +(18209, 8, -1505.038940, 8513.247070, 0.672, 0, ''), +(18209, 9, -1476.161133, 8496.066406, 2.157, 0, ''), +(18209, 10, -1464.450684, 8492.601563, 3.529, 0, ''), +(18209, 11, -1457.568359, 8492.183594, 4.449, 0, ''), +(18209, 12, -1444.100342, 8499.031250, 6.177, 0, ''), +(18209, 13, -1426.472168, 8510.116211, 7.686, 0, ''), +(18209, 14, -1403.685303, 8524.146484, 9.680, 0, ''), +(18209, 15, -1384.890503, 8542.014648, 11.180, 0, ''), +(18209, 16, -1385.107422, 8547.194336, 11.297, 5000, 'SAY_KUR_COMPLETE'), +(18209, 17, -1387.814453, 8556.652344, 11.735, 0, ''), +(18209, 18, -1397.817749, 8574.999023, 13.204, 0, ''), +(18209, 19, -1411.961304, 8598.225586, 14.990, 0, ''); diff --git a/sql/updates/0.8/r2998_mangos.sql b/sql/updates/0.8/r2998_mangos.sql new file mode 100644 index 000000000..d2fdb99b8 --- /dev/null +++ b/sql/updates/0.8/r2998_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName="npc_skyguard_prisoner" WHERE entry=23383; diff --git a/sql/updates/0.8/r2998_scriptdev2.sql b/sql/updates/0.8/r2998_scriptdev2.sql new file mode 100644 index 000000000..029cc1417 --- /dev/null +++ b/sql/updates/0.8/r2998_scriptdev2.sql @@ -0,0 +1,32 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001012 AND -1001006; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001006,'Thanks for your help. Let\'s get out of here!',0,0,0,1,'skyguard prisoner SAY_ESCORT_START'), +(-1001007,'Let\'s keep moving. I don\'t like this place.',0,0,0,1,'skyguard prisoner SAY_AMBUSH_END'), +(-1001008,'Thanks again. Sergeant Doryn will be glad to hear he has one less scout to replace this week.',0,0,0,1,'skyguard prisoner SAY_ESCORT_COMPLETE'), +(-1001009,'Death to our enemies!',0,0,0,0,'skettis wing guard SAY_AMBUSH_1'), +(-1001010,'No one escapes Skettis!',0,0,0,0,'skettis wing guard SAY_AMBUSH_2'), +(-1001011,'Skettis prevails!',0,0,0,0,'skettis wing guard SAY_AMBUSH_3'), +(-1001012,'You\'ll go nowhere, Skyguard scum!',0,0,0,0,'skettis wing guard SAY_AMBUSH_4'); + +DELETE FROM script_waypoint WHERE entry=23383; +INSERT INTO script_waypoint VALUES +(23383, 0, -4109.424, 3034.155, 344.168, 5000, 'SAY_ESCORT_START'), +(23383, 1, -4113.265, 3035.989, 344.071, 0, ''), +(23383, 2, -4120.018, 3032.223, 344.074, 0, ''), +(23383, 3, -4124.412, 3026.332, 344.151, 0, ''), +(23383, 4, -4128.823, 3026.645, 344.035, 0, ''), +(23383, 5, -4138.909, 3028.952, 338.920, 0, ''), +(23383, 6, -4152.592, 3031.234, 336.913, 0, ''), +(23383, 7, -4169.812, 3034.305, 342.047, 0, ''), +(23383, 8, -4174.631, 3036.044, 343.457, 0, ''), +(23383, 9, -4174.399, 3044.983, 343.862, 0, ''), +(23383, 10, -4176.635, 3052.014, 344.077, 0, ''), +(23383, 11, -4183.662, 3058.895, 344.150, 0, ''), +(23383, 12, -4182.916, 3065.411, 342.574, 0, ''), +(23383, 13, -4182.055, 3070.558, 337.644, 5000, 'ambush'), +(23383, 14, -4182.055, 3070.558, 337.644, 5000, 'SAY_AMBUSH_END'), +(23383, 15, -4181.256, 3077.131, 331.590, 0, ''), +(23383, 16, -4179.994, 3086.101, 325.571, 0, ''), +(23383, 17, -4178.770, 3090.101, 323.955, 0, ''), +(23383, 18, -4177.965, 3093.867, 323.839, 5000, 'SAY_ESCORT_COMPLETE'), +(23383, 19, -4166.252, 3106.508, 320.961, 0, ''); diff --git a/sql/updates/0.8/r2999_mangos.sql b/sql/updates/0.8/r2999_mangos.sql new file mode 100644 index 000000000..d3ef848c1 --- /dev/null +++ b/sql/updates/0.8/r2999_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_bonker_togglevolt' WHERE entry=25589; diff --git a/sql/updates/0.8/r2999_scriptdev2.sql b/sql/updates/0.8/r2999_scriptdev2.sql new file mode 100644 index 000000000..54b16dbb1 --- /dev/null +++ b/sql/updates/0.8/r2999_scriptdev2.sql @@ -0,0 +1,44 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001017 AND -1001013; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001013,'Right then, no time to waste. Let\'s get outa here!',0,0,0,1,'bonker togglevolt SAY_BONKER_START'), +(-1001014,'Here we go.',0,0,0,0,'bonker togglevolt SAY_BONKER_GO'), +(-1001015,'I AM NOT AN APPETIZER!',0,0,0,0,'bonker togglevolt SAY_BONKER_AGGRO'), +(-1001016,'I think it\'s up this way to the left. Let\'s go!',0,0,0,1,'bonker togglevolt SAY_BONKER_LEFT'), +(-1001017,'Ah, fresh air! I can get myself back to the airstrip from here. Be sure to tell Fizzcrank I\'m back and safe. Thanks so much, $N!',0,0,0,1,'sbonker togglevolt SAY_BONKER_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=25589; +INSERT INTO script_waypoint VALUES +(25589, 0, 4414.220, 5367.299, -15.494, 13000, 'SAY_BONKER_START'), +(25589, 1, 4414.220, 5367.299, -15.494, 0, 'SAY_BONKER_GO'), +(25589, 2, 4429.033, 5366.662, -17.198, 0, ''), +(25589, 3, 4454.772, 5371.562, -16.385, 10000, 'SAY_BONKER_LEFT'), +(25589, 4, 4467.889, 5372.425, -15.236, 0, ''), +(25589, 5, 4481.388, 5378.616, -14.997, 0, ''), +(25589, 6, 4484.985, 5392.241, -15.310, 0, ''), +(25589, 7, 4473.114, 5414.899, -15.272, 0, ''), +(25589, 8, 4461.070, 5427.644, -16.163, 0, ''), +(25589, 9, 4441.339, 5435.530, -15.367, 0, ''), +(25589, 10, 4427.119, 5436.604, -15.149 , 0, ''), +(25589, 11, 4408.939, 5428.320, -14.629, 0, ''), +(25589, 12, 4396.607, 5415.876, -13.552, 0, ''), +(25589, 13, 4392.921, 5405.893, -10.506, 0, ''), +(25589, 14, 4390.492, 5390.298, -5.628, 0, ''), +(25589, 15, 4393.429, 5358.273, 2.967, 0, ''), +(25589, 16, 4400.138, 5345.599, 4.656, 0, ''), +(25589, 17, 4412.080, 5336.678, 7.272, 0, ''), +(25589, 18, 4436.494, 5335.233, 12.415, 0, ''), +(25589, 19, 4454.602, 5341.273, 15.560, 0, ''), +(25589, 20, 4471.045, 5352.314, 18.686, 0, ''), +(25589, 21, 4478.235, 5367.257, 20.225, 0, ''), +(25589, 22, 4481.352, 5387.544, 24.537, 0, ''), +(25589, 23, 4483.067, 5405.131, 27.576, 0, ''), +(25589, 24, 4475.878, 5414.829, 29.965, 0, ''), +(25589, 25, 4466.598, 5423.731, 32.224, 0, ''), +(25589, 26, 4451.211, 5431.026, 36.189, 0, ''), +(25589, 27, 4428.056, 5434.374, 38.946, 0, ''), +(25589, 28, 4398.915, 5443.864, 44.214, 0, ''), +(25589, 29, 4386.822, 5451.893, 48.935, 0, ''), +(25589, 30, 4379.861, 5457.215, 51.371, 0, ''), +(25589, 31, 4372.712, 5461.347, 48.541, 0, ''), +(25589, 32, 4364.523, 5465.798, 48.661, 10000, 'SAY_BONKER_COMPLETE'), +(25589, 33, 4337.198, 5472.948, 46.035, 0, ''); diff --git a/sql/updates/0.8/r3001_scriptdev2.sql b/sql/updates/0.8/r3001_scriptdev2.sql new file mode 100644 index 000000000..fe6af7f85 --- /dev/null +++ b/sql/updates/0.8/r3001_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12661+) '; diff --git a/sql/updates/0.8/r3002_mangos.sql b/sql/updates/0.8/r3002_mangos.sql new file mode 100644 index 000000000..558243cd6 --- /dev/null +++ b/sql/updates/0.8/r3002_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_squad_leader' WHERE entry IN (31737,31833); +UPDATE creature_template SET ScriptName='npc_infantry' WHERE entry IN (31701,31832); diff --git a/sql/updates/0.8/r3002_scriptdev2.sql b/sql/updates/0.8/r3002_scriptdev2.sql new file mode 100644 index 000000000..ef3d1c8a3 --- /dev/null +++ b/sql/updates/0.8/r3002_scriptdev2.sql @@ -0,0 +1,90 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001043 AND -1001018; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001018,'On the move, men!',0,0,0,0,'kor\'kron squad leader SAY_HORDER_RUN'), +(-1001019,'Alright boys, let\'s do this!',0,0,0,0,'skybreaker squad leader SAY_ALLIANCE_RUN'), +(-1001020,'Incoming!',0,1,0,0,'squad leader SAY_AGGRO_1'), +(-1001021,'Ambush!',0,1,0,0,'squad leader SAY_AGGRO_2'), +(-1001022,'For the Horde!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_1'), +(-1001023,'Time for some blood, men!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_2'), +(-1001024,'Vrykul!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_3'), +(-1001025,'Weapons out!',0,1,0,0,'kor\'kron squad leader SAY_HORDE_AGGRO_4'), +(-1001026,'Find some cover!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_1'), +(-1001027,'Group up!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_2'), +(-1001028,'On your feet, boys!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_3'), +(-1001029,'Vrykul attack!',0,1,0,0,'skybreaker squad leader SAY_ALLIANCE_AGGRO_4'), +(-1001030,'Quickly, catch your breaths before we press for the gate!',0,0,0,0,'kor\'kron squad leader SAY_HORDE_BREAK'), +(-1001031,'On your feet, men! Move, move move!',0,0,0,0,'kor\'kron squad leader SAY_HORDE_BREAK_DONE'), +(-1001032,'Nice work! We can only rest a moment.',0,0,0,0,'skybreaker squad leader SAY_ALLIANCE_BREAK'), +(-1001033,'On your feet, boys! Move, move move!',0,0,0,0,'skybreaker squad leader SAY_ALLIANCE_BREAK_DONE'), +(-1001034,'Thanks for keeping us covered back there! We\'ll hold the gate while we wait for reinforcements.',0,0,0,1,'squad leader SAY_EVENT_COMPLETE'), +(-1001035,'Die, maggot!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_1'), +(-1001036,'Haraak foln!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_2'), +(-1001037,'I spit on you!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_3'), +(-1001038,'I will feed you to the dogs!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_4'), +(-1001039,'I will take pleasure in gutting you!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_5'), +(-1001040,'I\'ll eat your heart!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_6'), +(-1001041,'Sniveling pig!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_7'), +(-1001042,'Ugglin oo bjorr!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_8'), +(-1001043,'You come to die!',0,0,0,0,'ymirheim defender SAY_DEFENDER_AGGRO_9'); + +DELETE FROM script_waypoint WHERE entry=31737; +INSERT INTO script_waypoint VALUES +(31737, 0, 7269.769, 1509.434, 320.903, 0, ''), +(31737, 1, 7258.117, 1526.602, 324.304, 0, ''), +(31737, 2, 7260.972, 1549.837, 335.689, 1000, 'SAY_ALLIANCE_RUN'), +(31737, 3, 7264.854, 1564.689, 341.974, 0, ''), +(31737, 4, 7255.504, 1579.524, 351.389, 0, ''), +(31737, 5, 7246.569, 1583.333, 358.133, 0, ''), +(31737, 6, 7232.839, 1581.032, 367.501, 0, 'first attack'), +(31737, 7, 7223.732, 1580.088, 373.346, 0, ''), +(31737, 8, 7218.684, 1586.349, 377.490, 0, ''), +(31737, 9, 7217.367, 1593.943, 379.455, 0, ''), +(31737, 10, 7225.456, 1598.870, 379.647, 0, ''), +(31737, 11, 7237.810, 1601.123, 381.088, 0, ''), +(31737, 12, 7251.413, 1609.023, 383.766, 0, ''), +(31737, 13, 7265.517, 1611.843, 382.620, 0, ''), +(31737, 14, 7277.738, 1609.804, 383.899, 0, ''), +(31737, 15, 7290.876, 1608.956, 390.451, 0, 'second attack'), +(31737, 16, 7310.857, 1615.485, 400.580, 0, ''), +(31737, 17, 7327.588, 1622.280, 411.449, 0, ''), +(31737, 18, 7343.151, 1629.884, 423.033, 0, ''), +(31737, 19, 7347.384, 1636.286, 428.066, 0, ''), +(31737, 20, 7343.727, 1644.666, 430.427, 8000, 'SAY_ALLIANCE_BREAK'), +(31737, 21, 7343.727, 1644.666, 430.427, 1000, 'SAY_ALLIANCE_BREAK_DONE'), +(31737, 22, 7301.614, 1649.022, 434.578, 0, ''), +(31737, 23, 7291.128, 1653.633, 435.176, 0, ''), +(31737, 24, 7278.780, 1657.080, 434.619, 0, ''), +(31737, 25, 7259.066, 1651.533, 433.942, 0, 'gate attack'), +(31737, 26, 7243.214, 1662.610, 438.890, 0, ''), +(31737, 27, 7211.633, 1684.327, 462.316, 0, 'SAY_EVENT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=31833; +INSERT INTO script_waypoint VALUES +(31833, 0, 7504.983, 1806.833, 355.928, 0, ''), +(31833, 1, 7500.186, 1817.217, 355.494, 0, ''), +(31833, 2, 7492.701, 1828.367, 361.420, 1000, 'SAY_HORDER_RUN'), +(31833, 3, 7481.528, 1836.774, 370.704, 0, ''), +(31833, 4, 7463.597, 1840.573, 383.662, 0, 'first attack'), +(31833, 5, 7449.448, 1839.822, 394.694, 0, ''), +(31833, 6, 7432.161, 1847.350, 406.290, 0, ''), +(31833, 7, 7415.067, 1845.623, 419.790, 0, ''), +(31833, 8, 7409.832, 1839.991, 423.997, 0, ''), +(31833, 9, 7403.585, 1822.599, 428.435, 0, 'second attack'), +(31833, 10, 7398.860, 1810.257, 430.373, 0, ''), +(31833, 11, 7396.572, 1789.399, 432.286, 0, ''), +(31833, 12, 7397.816, 1769.238, 432.947, 0, ''), +(31833, 13, 7399.105, 1745.266, 433.108, 8000, 'SAY_HORDE_BREAK'), +(31833, 14, 7399.105, 1745.266, 433.108, 1000, 'SAY_HORDE_BREAK_DONE'), +(31833, 15, 7393.293, 1729.907, 435.058, 0, ''), +(31833, 16, 7385.299, 1720.183, 437.602, 0, ''), +(31833, 17, 7370.189, 1715.580, 442.425, 0, ''), +(31833, 18, 7358.270, 1719.352, 446.378, 0, ''), +(31833, 19, 7348.808, 1723.011, 449.727, 0, ''), +(31833, 20, 7333.273, 1724.842, 453.621, 0, ''), +(31833, 21, 7325.701, 1725.662, 456.896, 0, ''), +(31833, 22, 7319.808, 1725.676, 459.731, 0, 'gate attack'), +(31833, 23, 7308.107, 1726.708, 465.138, 0, ''), +(31833, 24, 7297.754, 1727.792, 467.980, 0, ''), +(31833, 25, 7288.278, 1726.889, 469.816, 0, ''), +(31833, 26, 7278.187, 1722.632, 472.149, 0, ''), +(31833, 27, 7253.084, 1729.579, 474.225, 0, 'SAY_EVENT_COMPLETE'); diff --git a/sql/updates/0.8/r3004_mangos.sql b/sql/updates/0.8/r3004_mangos.sql new file mode 100644 index 000000000..62a13babd --- /dev/null +++ b/sql/updates/0.8/r3004_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_father_kamaros' WHERE entry IN (31279,32800); diff --git a/sql/updates/0.8/r3004_scriptdev2.sql b/sql/updates/0.8/r3004_scriptdev2.sql new file mode 100644 index 000000000..55d89b758 --- /dev/null +++ b/sql/updates/0.8/r3004_scriptdev2.sql @@ -0,0 +1,67 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001050 AND -1001044; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001044,'The Light\'s blessing be upon you for aiding me in my time of need, $N.',0,0,0,0,'father kamaros SAY_ESCORT_START_1'), +(-1001045,'I\'ve had my fill of this place. Let us depart.',0,0,0,1,'father kamaros SAY_ESCORT_START_2'), +(-1001046,'Face your judgment by the Light!',0,0,0,0,'father kamaros SAY_AGGRO_1'), +(-1001047,'The Argent Crusade never surrenders!',0,0,0,0,'father kamaros SAY_AGGRO_2'), +(-1001048,'You will never take me alive!',0,0,0,0,'father kamaros SAY_AGGRO_3'), +(-1001049,'I have you to thank for my life. I will return to my comrades and spread word of your bravery. Fight the Scourge with all the strength you can muster, and we will be by your side.',0,0,0,1,'father kamaros SAY_ESCORT_COMPLETE_2'), +(-1001050,'You must tell my brothers that I live.',0,0,0,1,'father kamaros SAY_ESCORT_COMPLETE_1'); + +DELETE FROM script_waypoint WHERE entry=31279; +INSERT INTO script_waypoint VALUES +(31279, 0, 6717.810, 3451.979, 683.747, 5000, 'SAY_ESCORT_START_1'), +(31279, 1, 6717.810, 3451.979, 683.747, 2000, 'SAY_ESCORT_START_2'), +(31279, 2, 6718.854, 3436.952, 682.197, 0, ''), +(31279, 3, 6725.714, 3432.644, 682.197, 0, ''), +(31279, 4, 6733.117, 3435.033, 682.136, 0, ''), +(31279, 5, 6744.931, 3445.788, 679.032, 0, ''), +(31279, 6, 6760.190, 3459.459, 674.487, 0, ''), +(31279, 7, 6773.156, 3469.683, 673.155, 0, ''), +(31279, 8, 6783.855, 3480.482, 674.481, 0, ''), +(31279, 9, 6790.618, 3484.064, 676.671, 0, ''), +(31279, 10, 6805.924, 3483.840, 682.128, 0, ''), +(31279, 11, 6818.427, 3483.294, 686.889, 0, ''), +(31279, 12, 6832.831, 3480.982, 690.189, 0, ''), +(31279, 13, 6854.910, 3479.888, 693.181, 0, ''), +(31279, 14, 6873.589, 3478.932, 694.618, 0, ''), +(31279, 15, 6895.129, 3478.388, 698.266, 0, ''), +(31279, 16, 6916.835, 3478.487, 702.575, 0, ''), +(31279, 17, 6937.283, 3477.337, 707.257, 0, ''), +(31279, 18, 6959.092, 3472.777, 710.180, 0, ''), +(31279, 19, 6969.530, 3470.091, 710.401, 0, ''), +(31279, 20, 6980.068, 3466.872, 710.831, 0, ''), +(31279, 21, 7008.199, 3457.296, 696.672, 0, ''), +(31279, 22, 7020.182, 3452.484, 696.518, 0, ''), +(31279, 23, 7031.362, 3445.230, 696.108, 3000, 'SAY_KAMAROS_COMPLETE_1'), +(31279, 24, 7031.362, 3445.230, 696.108, 7000, 'SAY_KAMAROS_COMPLETE_2'), +(31279, 25, 7067.656, 3420.741, 694.879, 0, ''); + +DELETE FROM script_waypoint WHERE entry=32800; +INSERT INTO script_waypoint VALUES +(32800, 0, 6736.090, 3422.160, 683.457, 5000, 'SAY_ESCORT_START_1'), +(32800, 1, 6736.090, 3422.160, 683.457, 2000, 'SAY_ESCORT_START_2'), +(32800, 2, 6734.518, 3425.644, 682.517, 0, ''), +(32800, 3, 6733.167, 3430.796, 682.156, 0, ''), +(32800, 4, 6733.117, 3435.033, 682.136, 0, ''), +(32800, 5, 6744.931, 3445.788, 679.032, 0, ''), +(32800, 6, 6760.190, 3459.459, 674.487, 0, ''), +(32800, 7, 6773.156, 3469.683, 673.155, 0, ''), +(32800, 8, 6783.855, 3480.482, 674.481, 0, ''), +(32800, 9, 6790.618, 3484.064, 676.671, 0, ''), +(32800, 10, 6805.924, 3483.840, 682.128, 0, ''), +(32800, 11, 6818.427, 3483.294, 686.889, 0, ''), +(32800, 12, 6832.831, 3480.982, 690.189, 0, ''), +(32800, 13, 6854.910, 3479.888, 693.181, 0, ''), +(32800, 14, 6873.589, 3478.932, 694.618, 0, ''), +(32800, 15, 6895.129, 3478.388, 698.266, 0, ''), +(32800, 16, 6916.835, 3478.487, 702.575, 0, ''), +(32800, 17, 6937.283, 3477.337, 707.257, 0, ''), +(32800, 18, 6959.092, 3472.777, 710.180, 0, ''), +(32800, 19, 6969.530, 3470.091, 710.401, 0, ''), +(32800, 20, 6980.068, 3466.872, 710.831, 0, ''), +(32800, 21, 7008.199, 3457.296, 696.672, 0, ''), +(32800, 22, 7020.182, 3452.484, 696.518, 0, ''), +(32800, 23, 7031.362, 3445.230, 696.108, 3000, 'SAY_KAMAROS_COMPLETE_1'), +(32800, 24, 7031.362, 3445.230, 696.108, 7000, 'SAY_KAMAROS_COMPLETE_2'), +(32800, 25, 7067.656, 3420.741, 694.879, 0, ''); diff --git a/sql/updates/0.8/r3005_mangos.sql b/sql/updates/0.8/r3005_mangos.sql new file mode 100644 index 000000000..c3fab4ebd --- /dev/null +++ b/sql/updates/0.8/r3005_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_injured_miner' WHERE entry=29434; diff --git a/sql/updates/0.8/r3005_scriptdev2.sql b/sql/updates/0.8/r3005_scriptdev2.sql new file mode 100644 index 000000000..2b13b1541 --- /dev/null +++ b/sql/updates/0.8/r3005_scriptdev2.sql @@ -0,0 +1,57 @@ +DELETE FROM script_texts WHERE entry IN (-1001051,-1001052); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001051,'Let me know when you\'re ready. I\'d prefer sooner than later... what with the slowly dying from poison and all.',0,0,0,1,'injured goblin miner SAY_ESCORT_READY'), +(-1001052,'I\'m going to bring the venom sac to Ricket... and then... you know... collapse. Thank you for helping me!',0,0,0,1,'injured goblin miner SAY_ESCORT_COMPLETE'); +DELETE FROM gossip_texts WHERE entry=-3000112; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000112,'I\'m ready - let\'s get out of here.','injured goblin miner GOSSIP_ITEM_ESCORT_READY'); + +DELETE FROM script_waypoint WHERE entry=29434; +INSERT INTO script_waypoint VALUES +(29434, 0, 6643.662, -1258.140, 396.812, 0, 'SAY_ESCORT_READY'), +(29434, 1, 6669.843, -1261.131, 396.362, 0, ''), +(29434, 2, 6672.479, -1244.102, 396.644, 0, ''), +(29434, 3, 6665.353, -1229.893, 399.214, 0, ''), +(29434, 4, 6656.884, -1210.856, 399.819, 0, ''), +(29434, 5, 6658.687, -1187.532, 398.761, 0, ''), +(29434, 6, 6664.340, -1166.372, 398.633, 0, ''), +(29434, 7, 6667.770, -1157.029, 398.136, 0, ''), +(29434, 8, 6670.005, -1145.671, 398.019, 0, ''), +(29434, 9, 6678.494, -1120.105, 397.160, 0, ''), +(29434, 10, 6685.051, -1100.975, 396.287, 0, ''), +(29434, 11, 6682.745, -1087.736, 396.795, 0, ''), +(29434, 12, 6679.602, -1073.343, 404.633, 0, ''), +(29434, 13, 6680.316, -1066.258, 405.499, 0, ''), +(29434, 14, 6689.714, -1053.830, 407.333, 0, ''), +(29434, 15, 6696.244, -1043.514, 411.230, 0, ''), +(29434, 16, 6695.093, -1032.211, 414.625, 0, ''), +(29434, 17, 6690.720, -1016.449, 414.825, 0, ''), +(29434, 18, 6679.976, -1009.805, 414.836, 0, ''), +(29434, 19, 6664.816, -1009.983, 414.840, 0, ''), +(29434, 20, 6647.982, -1010.354, 418.831, 0, ''), +(29434, 21, 6635.366, -1010.637, 423.007, 0, ''), +(29434, 22, 6615.762, -1001.898, 426.584, 0, ''), +(29434, 23, 6597.334, -1002.802, 429.766, 0, ''), +(29434, 24, 6581.178, -1009.971, 433.705, 0, ''), +(29434, 25, 6562.826, -1016.122, 433.558, 0, ''), +(29434, 26, 6535.386, -1024.189, 433.084, 0, ''), +(29434, 27, 6520.094, -1030.279, 433.506, 0, ''), +(29434, 28, 6505.704, -1028.766, 436.897, 0, ''), +(29434, 29, 6496.504, -1027.350, 437.309, 0, ''), +(29434, 30, 6489.653, -1026.457, 434.885, 0, ''), +(29434, 31, 6474.284, -1024.466, 434.650, 0, ''), +(29434, 32, 6456.688, -1022.172, 432.239, 0, ''), +(29434, 33, 6449.764, -1021.355, 431.501, 6000, 'SAY_ESCORT_COMPLETE'), +(29434, 34, 6418.638, -1018.385, 427.910, 0, 'despawn'), +(29434, 35, 6639.769, -1109.591, 427.193, 0, ''), +(29434, 36, 6641.524, -1104.348, 426.970, 0, ''), +(29434, 37, 6659.703, -1106.495, 423.005, 0, ''), +(29434, 38, 6670.649, -1118.345, 424.474, 0, ''), +(29434, 39, 6666.202, -1130.105, 423.113, 0, ''), +(29434, 40, 6642.683, -1129.107, 416.779, 0, ''), +(29434, 41, 6628.478, -1127.415, 414.923, 0, ''), +(29434, 42, 6619.763, -1113.337, 412.185, 0, ''), +(29434, 43, 6622.960, -1101.692, 409.846, 0, ''), +(29434, 44, 6640.454, -1088.525, 403.227, 0, ''), +(29434, 45, 6659.586, -1073.823, 402.945, 0, ''), +(29434, 46, 6671.060, -1064.829, 405.381, 0, 'continue at wp 13'); diff --git a/sql/updates/0.8/r3006_mangos.sql b/sql/updates/0.8/r3006_mangos.sql new file mode 100644 index 000000000..103770c39 --- /dev/null +++ b/sql/updates/0.8/r3006_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_harrison_jones' WHERE entry=26814; diff --git a/sql/updates/0.8/r3006_scriptdev2.sql b/sql/updates/0.8/r3006_scriptdev2.sql new file mode 100644 index 000000000..dbfdcbbfa --- /dev/null +++ b/sql/updates/0.8/r3006_scriptdev2.sql @@ -0,0 +1,71 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001063 AND -1001053; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001053,'Alright, kid. Stay behind me and you\'ll be fine.',0,0,0,36,'harrison jones SAY_ESCORT_START'), +(-1001054,'Their ceremonial chamber, where I was to be sacrificed...',0,0,0,1,'harrison jones SAY_CHAMBER_1'), +(-1001055,'Time to put an end to all this!',0,0,0,1,'harrison jones SAY_CHAMBER_2'), +(-1001056,'You\'re free to go, miss.',0,0,0,1,'harrison jones SAY_CHAMBER_RELEASE'), +(-1001057,'Thank you!',0,0,0,71,'Adarrah SAY_THANK_YOU'), +(-1001058,'Odd. That usually does it.',0,0,0,1,'harrison jones SAY_CHAMBER_3'), +(-1001059,'Just as well, I\'ve had enough of this place.',0,0,0,1,'harrison jones SAY_CHAMBER_4'), +(-1001060,'What\'s this?',0,0,0,0,'harrison jones SAY_CHAMBER_5'), +(-1001061,'Aww, not a snake!',0,0,0,1,'harrison jones SAY_CHAMBER_6'), +(-1001062,'Listen, kid. I can handle this thing. You just watch my back!',0,0,0,1,'harrison jones SAY_CHAMBER_7'), +(-1001063,'See ya \'round, kid!',0,0,0,1,'harrison jones SAY_ESCORT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=26814; +INSERT INTO script_waypoint VALUES +(26814, 0, 4905.259, -4758.709, 27.316, 2000, 'open cage - SAY_ESCORT_START'), +(26814, 1, 4895.403, -4754.880, 27.233, 0, ''), +(26814, 2, 4887.629, -4761.870, 27.233, 0, ''), +(26814, 3, 4881.628, -4768.923, 32.142, 0, ''), +(26814, 4, 4878.448, -4772.853, 32.646, 0, ''), +(26814, 5, 4876.892, -4787.923, 32.531, 0, ''), +(26814, 6, 4877.230, -4792.542, 32.532, 0, ''), +(26814, 7, 4878.416, -4793.893, 32.549, 5000, 'SAY_CHAMBER_1'), +(26814, 8, 4878.416, -4793.893, 32.549, 5000, 'SAY_CHAMBER_2'), +(26814, 9, 4883.791, -4796.650, 32.575, 0, ''), +(26814, 10, 4908.433, -4797.975, 32.514, 4000, 'open cage'), +(26814, 11, 4908.433, -4797.975, 32.514, 3000, 'SAY_CHAMBER_RELEASE'), +(26814, 12, 4908.433, -4797.975, 32.514, 2000, 'SAY_THANK_YOU'), +(26814, 13, 4908.678, -4806.945, 32.283, 0, ''), +(26814, 14, 4911.196, -4817.785, 32.491, 0, ''), +(26814, 15, 4914.571, -4823.823, 32.666, 3000, ''), +(26814, 16, 4914.571, -4823.823, 32.666, 7000, 'bang gong'), +(26814, 17, 4908.558, -4820.374, 32.550, 5000, 'SAY_CHAMBER_3'), +(26814, 18, 4908.558, -4820.374, 32.550, 0, 'SAY_CHAMBER_4'), +(26814, 19, 4899.099, -4816.810, 32.029, 0, ''), +(26814, 20, 4891.287, -4813.185, 32.029, 0, ''), +(26814, 21, 4886.007, -4803.263, 32.029, 0, 'close door'), +(26814, 22, 4883.618, -4799.119, 32.556, 1000, 'SAY_CHAMBER_5 - set run'), +(26814, 23, 4900.580, -4806.635, 32.029, 7000, 'SAY_CHAMBER_6'), +(26814, 24, 4900.580, -4806.635, 32.029, 6000, 'SAY_CHAMBER_7'), +(26814, 25, 4900.580, -4806.635, 32.029, 0, 'snake attack'), +(26814, 26, 4886.463, -4799.330, 32.552, 0, ''), +(26814, 27, 4862.184, -4782.641, 32.605, 0, ''), +(26814, 28, 4843.930, -4771.764, 32.602, 0, ''), +(26814, 29, 4831.872, -4775.357, 32.581, 0, ''), +(26814, 30, 4819.254, -4788.892, 25.473, 0, ''), +(26814, 31, 4814.696, -4798.355, 25.483, 0, ''), +(26814, 32, 4824.520, -4822.539, 25.492, 0, ''), +(26814, 33, 4826.834, -4838.310, 25.511, 0, ''), +(26814, 34, 4822.480, -4846.951, 25.473, 0, ''), +(26814, 35, 4812.121, -4852.343, 25.622, 0, ''), +(26814, 36, 4779.916, -4848.937, 25.442, 0, ''), +(26814, 37, 4770.701, -4848.962, 25.428, 0, ''), +(26814, 38, 4758.476, -4857.186, 25.848, 0, ''), +(26814, 39, 4737.023, -4857.752, 26.292, 0, ''), +(26814, 40, 4722.875, -4857.749, 26.495, 0, ''), +(26814, 41, 4715.862, -4857.869, 24.707, 0, ''), +(26814, 42, 4705.447, -4858.532, 28.910, 0, ''), +(26814, 43, 4691.578, -4858.917, 33.103, 0, ''), +(26814, 44, 4681.879, -4860.041, 35.440, 0, ''), +(26814, 45, 4670.293, -4861.545, 35.480, 0, ''), +(26814, 46, 4667.317, -4878.836, 35.480, 0, ''), +(26814, 47, 4661.148, -4895.541, 35.499, 0, ''), +(26814, 48, 4656.874, -4907.395, 38.980, 0, ''), +(26814, 49, 4656.184, -4916.478, 44.398, 0, ''), +(26814, 50, 4656.566, -4927.874, 47.576, 0, ''), +(26814, 51, 4660.753, -4938.885, 47.992, 0, ''), +(26814, 52, 4667.464, -4954.763, 47.993, 0, ''), +(26814, 53, 4673.411, -4967.304, 47.791, 3000, 'SAY_ESCORT_COMPLETE'), +(26814, 54, 4694.427, -4979.960, 44.715, 0, ''); diff --git a/sql/updates/0.8/r3007_mangos.sql b/sql/updates/0.8/r3007_mangos.sql new file mode 100644 index 000000000..313da0f3f --- /dev/null +++ b/sql/updates/0.8/r3007_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_apothecary_hanes' WHERE entry=23784; diff --git a/sql/updates/0.8/r3007_scriptdev2.sql b/sql/updates/0.8/r3007_scriptdev2.sql new file mode 100644 index 000000000..45e88c4b8 --- /dev/null +++ b/sql/updates/0.8/r3007_scriptdev2.sql @@ -0,0 +1,59 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001071 AND -1001064; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001064,'You couldn\'t have come at a better time! Let\'s get out of here.',0,0,0,0,'apothecary hanes SAY_ESCORT_START'), +(-1001065,'Yes, let us leave... but not before we leave our Alliance hosts something to remember us by!',0,0,0,0,'apothecary hanes SAY_FIRE_1'), +(-1001066,'They have limited supplies in this camp. It would be a real shame if something were to happen to them.',0,0,0,16,'apothecary hanes SAY_FIRE_2'), +(-1001067,'Ah, yes... watch it burn!',0,0,0,0,'apothecary hanes SAY_SUPPLIES_1'), +(-1001068,'We\'re almost done!',0,0,0,0,'apothecary hanes SAY_SUPPLIES_2'), +(-1001069,'Let\'s high-tail it out of here.',0,0,0,0,'apothecary hanes SAY_SUPPLIES_ESCAPE'), +(-1001070,'That\'ll teach you to mess with an apothecary, you motherless Alliance dogs!',0,1,0,22,'apothecary hanes SAY_SUPPLIES_COMPLETE'), +(-1001071,'Don\'t shoot! Apothecary coming through!',0,1,0,0,'apothecary hanes SAY_ARRIVE_BASE'); + +DELETE FROM script_waypoint WHERE entry=23784; +INSERT INTO script_waypoint VALUES +(23784, 0, 1377.875, -6421.482, 1.323, 0, 'SAY_ESCORT_START'), +(23784, 1, 1377.523, -6415.196, 1.515, 0, ''), +(23784, 2, 1379.988, -6401.920, 2.428, 8000, 'SAY_FIRE_1'), +(23784, 3, 1379.988, -6401.920, 2.428, 5000, 'SAY_FIRE_2'), +(23784, 4, 1379.749, -6398.577, 2.829, 0, ''), +(23784, 5, 1383.767, -6392.131, 3.639, 0, ''), +(23784, 6, 1395.301, -6381.135, 4.711, 0, ''), +(23784, 7, 1407.236, -6372.452, 6.434, 0, ''), +(23784, 8, 1421.052, -6363.196, 6.430, 0, ''), +(23784, 9, 1424.191, -6358.807, 6.443, 0, ''), +(23784, 10, 1422.745, -6350.552, 6.138, 0, ''), +(23784, 11, 1419.152, -6342.663, 5.811, 0, ''), +(23784, 12, 1414.308, -6336.418, 5.865, 0, ''), +(23784, 13, 1405.468, -6336.249, 6.210, 0, ''), +(23784, 14, 1400.868, -6340.454, 6.415, 4000, 'set fire'), +(23784, 15, 1400.868, -6340.454, 6.415, 15000, 'SAY_SUPPLIES_1'), +(23784, 16, 1406.004, -6335.554, 6.190, 0, ''), +(23784, 17, 1421.080, -6337.905, 5.517, 0, ''), +(23784, 18, 1436.049, -6341.191, 6.772, 0, ''), +(23784, 19, 1449.407, -6344.460, 8.267, 0, ''), +(23784, 20, 1465.833, -6345.101, 7.695, 2000, 'set fire'), +(23784, 21, 1470.890, -6347.974, 7.576, 3000, 'set fire'), +(23784, 22, 1470.890, -6347.974, 7.576, 4000, 'SAY_SUPPLIES_2'), +(23784, 23, 1464.277, -6345.285, 7.896, 0, ''), +(23784, 24, 1463.023, -6339.777, 7.718, 0, ''), +(23784, 25, 1465.487, -6335.771, 7.332, 0, ''), +(23784, 26, 1479.166, -6325.064, 7.440, 0, ''), +(23784, 27, 1489.401, -6315.133, 8.296, 0, ''), +(23784, 28, 1502.828, -6311.045, 6.770, 0, ''), +(23784, 29, 1506.398, -6317.246, 7.299, 4000, 'set fire'), +(23784, 30, 1506.398, -6317.246, 7.299, 2000, 'laugh'), +(23784, 31, 1506.398, -6317.246, 7.299, 10000, 'SAY_SUPPLIES_COMPLETE'), +(23784, 32, 1506.398, -6317.246, 7.299, 5000, 'SAY_SUPPLIES_ESCAPE'), +(23784, 33, 1511.000, -6295.903, 6.193, 0, ''), +(23784, 34, 1517.061, -6275.862, 5.202, 0, ''), +(23784, 35, 1523.781, -6258.195, 4.561, 0, ''), +(23784, 36, 1529.622, -6244.452, 5.823, 0, ''), +(23784, 37, 1537.658, -6224.802, 6.349, 0, ''), +(23784, 38, 1545.301, -6214.430, 6.917, 0, ''), +(23784, 39, 1556.078, -6203.805, 6.566, 0, ''), +(23784, 40, 1567.203, -6194.417, 7.262, 0, 'SAY_ARRIVE_BASE'), +(23784, 41, 1582.464, -6183.626, 7.145, 0, ''), +(23784, 42, 1593.279, -6173.173, 7.319, 0, ''), +(23784, 43, 1604.470, -6164.387, 8.379, 0, ''), +(23784, 44, 1617.776, -6157.249, 9.323, 2000, 'quest complete'), +(23784, 45, 1644.696, -6149.582, 7.357, 0, ''); diff --git a/sql/updates/0.8/r3008_mangos.sql b/sql/updates/0.8/r3008_mangos.sql new file mode 100644 index 000000000..aa4667cd8 --- /dev/null +++ b/sql/updates/0.8/r3008_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_taelan_fordring' WHERE entry=1842; +UPDATE creature_template SET ScriptName='npc_isillien' WHERE entry=1840; +UPDATE creature_template SET ScriptName='npc_tirion_fordring' WHERE entry=12126; diff --git a/sql/updates/0.8/r3008_scriptdev2.sql b/sql/updates/0.8/r3008_scriptdev2.sql new file mode 100644 index 000000000..ddf70608b --- /dev/null +++ b/sql/updates/0.8/r3008_scriptdev2.sql @@ -0,0 +1,107 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001105 AND -1001072; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001072,'Something is wrong with the Highlord. Do something!',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_1'), +(-1001073,'Hey, what is going on over there? Sir, are you alright?',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_2'), +(-1001074,'What the....',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_3'), +(-1001075,'Sir?',0,0,0,1,'scarlet cavalier SAY_CAVALIER_WORRY_4'), +(-1001076,'NOOOOOOOOOOOOO!',0,1,0,15,'taelan fordring SAY_SCARLET_COMPLETE_1'), +(-1001077,'I will lead us through Hearthglen to the forest\'s edge. From there, you will take me to my father.',0,0,0,1,'taelan fordring SAY_SCARLET_COMPLETE_2'), +(-1001078,'Remove your disguise, lest you feel the bite of my blade when the fury has taken control.',0,0,0,1,'taelan fordring SAY_ESCORT_START'), +(-1001079,'Halt.',0,0,0,0,'taelan fordring SAY_TAELAN_MOUNT'), +(-1001080,'%s calls for his mount.',0,2,0,22,'taelan fordring EMOTE_TAELAN_MOUNT'), +(-1001081,'It\'s not much further. The main road is just up ahead.',0,0,0,1,'taelan fordring SAY_REACH_TOWER'), +(-1001082,'You will not make it to the forest\'s edge, Fordring.',0,0,0,1,'isillien SAY_ISILLIEN_1'), +(-1001083,'Isillien!',0,1,0,25,'taelan fordring SAY_ISILLIEN_2'), +(-1001084,'This is not your fight, stranger. Protect yourself from the attacks of the Crimson Elite. I shall battle the Grand Inquisitor.',0,0,0,1,'taelan fordring SAY_ISILLIEN_3'), +(-1001085,'You disappoint me, Taelan. I had plans for you... grand plans. Alas, it was only a matter of time before your filthy bloodline would catch up with you.',0,0,0,1,'isillien SAY_ISILLIEN_4'), +(-1001086,'It is as they say: Like father, like son. You are as weak of will as Tirion... perhaps more so. I can only hope my assassins finally succeeded in ending his pitiful life.',0,0,0,1,'isillien SAY_ISILLIEN_5'), +(-1001087,'The Grand Crusader has charged me with destroying you and your newfound friends, Taelan, but know this: I do this for pleasure, not of obligation or duty.',0,0,0,1,'isillien SAY_ISILLIEN_6'), +(-1001088,'%s calls for his guardsman.',0,2,0,0,'isillien EMOTE_ISILLIEN_ATTACK'), +(-1001089,'The end is now, Fordring.',0,0,0,1,'isillien SAY_ISILLIEN_ATTACK'), +(-1001090,'Enough!',0,0,0,0,'isillien SAY_KILL_TAELAN_1'), +(-1001091,'%s laughs.',0,2,0,11,'isillien EMOTE_ISILLIEN_LAUGH'), +(-1001092,'Did you really believe that you could defeat me? Your friends are soon to join you, Taelan.',0,0,0,0,'isillien SAY_KILL_TAELAN_2'), +(-1001093,'% turns his attention towards you.',0,2,0,0,'isillien EMOTE_ATTACK_PLAYER'), +(-1001094,'What have you done, Isillien? You once fought with honor, for the good of our people... and now... you have murdered my boy...',0,0,0,0,'tirion fordring SAY_TIRION_1'), +(-1001095,'Tragic. The elder Fordring lives on... You are too late, old man. Retreat back to your cave, hermit, unless you wish to join your son in the Twisting Nether.',0,0,0,0,'isillien SAY_TIRION_2'), +(-1001096,'May your soul burn in anguish, Isillien! Light give me strength to battle this fiend.',0,0,0,0,'tirion fordring SAY_TIRION_3'), +(-1001097,'Face me, coward. Face the faith and strength that you once embodied.',0,0,0,0,'tirion fordring SAY_TIRION_4'), +(-1001098,'Then come, hermit!',0,0,0,0,'isillien SAY_TIRION_5'), +(-1001099,'A thousand more like him exist. Ten thousand. Should one fall, another will rise to take the seat of power.',0,0,0,0,'tirion fordring SAY_EPILOG_1'), +(-1001100,'%s falls to one knee.',0,2,0,16,'tirion fordring EMOTE_FALL_KNEE'), +(-1001101,'Look what they did to my boy.',0,0,0,0,'tirion fordring SAY_EPILOG_2'), +(-1001102,'%s holds the limp body of Taelan Fordring and softly sobs.',0,2,0,0,'tirion fordring EMOTE_HOLD_TAELAN'), +(-1001103,'Too long have I sat idle, gripped in this haze... this malaise, lamenting what could have been... what should have been.',0,0,0,0,'tirion fordring SAY_EPILOG_3'), +(-1001104,'Your death will not have been in vain, Taelan. A new Order is born on this day... an Order which will dedicate itself to extinguising the evil that plagues this world. An evil that cannot hide behind politics and pleasantries.',0,0,0,0,'tirion fordring SAY_EPILOG_4'), +(-1001105,'This I promise... This I vow...',0,0,0,0,'tirion fordring SAY_EPILOG_5'); + +DELETE FROM script_waypoint WHERE entry=1842; +INSERT INTO script_waypoint VALUES +(1842, 0, 2941.748, -1391.816, 167.237, 0, 'SAY_ESCORT_START'), +(1842, 1, 2940.561, -1393.641, 165.943, 0, ''), +(1842, 2, 2932.194, -1410.657, 165.943, 0, ''), +(1842, 3, 2921.808, -1405.087, 165.943, 0, ''), +(1842, 4, 2916.479, -1402.582, 165.943, 0, ''), +(1842, 5, 2918.523, -1398.121, 165.943, 0, ''), +(1842, 6, 2922.801, -1389.494, 160.842, 0, ''), +(1842, 7, 2924.931, -1385.645, 160.842, 0, ''), +(1842, 8, 2930.931, -1388.654, 160.842, 0, ''), +(1842, 9, 2946.701, -1396.646, 160.842, 0, ''), +(1842, 10, 2948.721, -1392.789, 160.842, 0, ''), +(1842, 11, 2951.979, -1386.616, 155.948, 0, ''), +(1842, 12, 2953.836, -1383.326, 155.948, 0, ''), +(1842, 13, 2951.192, -1381.740, 155.948, 0, ''), +(1842, 14, 2946.675, -1379.287, 152.020, 0, ''), +(1842, 15, 2942.795, -1377.661, 152.020, 0, ''), +(1842, 16, 2935.488, -1392.522, 152.020, 0, ''), +(1842, 17, 2921.167, -1384.796, 152.020, 0, ''), +(1842, 18, 2915.331, -1395.354, 152.020, 0, ''), +(1842, 19, 2926.250, -1401.263, 152.028, 0, ''), +(1842, 20, 2930.321, -1403.479, 150.521, 0, ''), +(1842, 21, 2933.936, -1405.357, 150.521, 0, ''), +(1842, 22, 2929.221, -1415.786, 150.504, 0, ''), +(1842, 23, 2921.173, -1431.680, 150.781, 0, ''), +(1842, 24, 2917.470, -1438.781, 150.781, 0, ''), +(1842, 25, 2913.048, -1453.524, 148.098, 0, 'SAY_TAELAN_MOUNT'), +(1842, 26, 2913.832, -1474.930, 146.224, 0, ''), +(1842, 27, 2906.815, -1487.061, 146.224, 0, ''), +(1842, 28, 2900.644, -1496.575, 146.306, 0, ''), +(1842, 29, 2885.249, -1501.585, 146.020, 0, ''), +(1842, 30, 2863.877, -1500.380, 146.681, 0, ''), +(1842, 31, 2846.509, -1487.183, 146.332, 0, ''), +(1842, 32, 2823.752, -1490.987, 145.782, 0, ''), +(1842, 33, 2800.984, -1510.907, 145.049, 0, ''), +(1842, 34, 2789.488, -1525.215, 143.729, 0, ''), +(1842, 35, 2776.964, -1542.305, 139.435, 0, ''), +(1842, 36, 2762.032, -1561.804, 133.763, 0, ''), +(1842, 37, 2758.741, -1569.599, 131.514, 0, ''), +(1842, 38, 2765.488, -1588.793, 129.721, 0, ''), +(1842, 39, 2779.613, -1613.120, 129.132, 0, ''), +(1842, 40, 2757.654, -1638.032, 128.236, 0, ''), +(1842, 41, 2741.308, -1659.790, 126.457, 0, ''), +(1842, 42, 2729.797, -1677.571, 126.499, 0, ''), +(1842, 43, 2716.778, -1694.648, 126.301, 0, ''), +(1842, 44, 2706.658, -1709.474, 123.420, 0, ''), +(1842, 45, 2699.506, -1720.572, 120.265, 0, ''), +(1842, 46, 2691.977, -1738.466, 114.994, 0, ''), +(1842, 47, 2690.514, -1757.045, 108.764, 0, ''), +(1842, 48, 2691.953, -1780.309, 99.890, 0, ''), +(1842, 49, 2689.344, -1803.264, 89.130, 0, ''), +(1842, 50, 2697.849, -1820.550, 80.681, 0, ''), +(1842, 51, 2701.934, -1836.706, 73.700, 0, ''), +(1842, 52, 2698.088, -1853.866, 68.999, 0, ''), +(1842, 53, 2693.657, -1870.237, 66.882, 0, ''), +(1842, 54, 2682.347, -1885.251, 66.009, 0, ''), +(1842, 55, 2668.229, -1900.796, 66.256, 0, 'SAY_REACH_TOWER - escort paused'); + +DELETE FROM script_waypoint WHERE entry=1840; +INSERT INTO script_waypoint VALUES +(1840, 0, 2689.677, -1937.474, 72.14, 0, ''), +(1840, 1, 2683.112, -1926.823, 72.14, 0, ''), +(1840, 2, 2678.725, -1919.416, 68.86, 0, 'escort paused'); + +DELETE FROM script_waypoint WHERE entry=12126; +INSERT INTO script_waypoint VALUES +(12126, 0, 2631.229, -1917.927, 72.59, 0, ''), +(12126, 1, 2643.529, -1914.072, 71.00, 0, ''), +(12126, 2, 2653.827, -1907.536, 69.34, 0, 'escort paused'); diff --git a/sql/updates/0.8/r3010_mangos.sql b/sql/updates/0.8/r3010_mangos.sql new file mode 100644 index 000000000..20aea0386 --- /dev/null +++ b/sql/updates/0.8/r3010_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (4052); +INSERT INTO scripted_areatrigger VALUES +(4052,'at_temple_ahnqiraj'); diff --git a/sql/updates/0.8/r3011_mangos.sql b/sql/updates/0.8/r3011_mangos.sql new file mode 100644 index 000000000..82d573c56 --- /dev/null +++ b/sql/updates/0.8/r3011_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_tethyr' WHERE entry=23899; diff --git a/sql/updates/0.8/r3012_mangos.sql b/sql/updates/0.8/r3012_mangos.sql new file mode 100644 index 000000000..488026be5 --- /dev/null +++ b/sql/updates/0.8/r3012_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_shay_leafrunner' WHERE entry=7774; diff --git a/sql/updates/0.8/r3012_scriptdev2.sql b/sql/updates/0.8/r3012_scriptdev2.sql new file mode 100644 index 000000000..52a221402 --- /dev/null +++ b/sql/updates/0.8/r3012_scriptdev2.sql @@ -0,0 +1,13 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001116 AND -1001106; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001106,'Don\'t forget to get my bell out of the chest here. And remember, if do happen to wander off, just ring it and I\'ll find you again.',0,0,0,1,'shay leafrunner SAY_ESCORT_START'), +(-1001107,'Are we taking the scenic route?',0,0,0,0,'shay leafrunner SAY_WANDER_1'), +(-1001108,'Oh, what a beautiful flower over there...',0,0,0,0,'shay leafrunner SAY_WANDER_2'), +(-1001109,'Are you sure this is the right way? Maybe we should go this way instead...',0,0,0,0,'shay leafrunner SAY_WANDER_3'), +(-1001110,'Hmmm, I wonder what\'s over this way?',0,0,0,0,'shay leafrunner SAY_WANDER_4'), +(-1001111,'This is quite an adventure!',0,0,0,0,'shay leafrunner SAY_WANDER_DONE_1'), +(-1001112,'Oh, I wandered off again. I\'m sorry.',0,0,0,0,'shay leafrunner SAY_WANDER_DONE_2'), +(-1001113,'The bell again, such a sweet sound.',0,0,0,0,'shay leafrunner SAY_WANDER_DONE_3'), +(-1001114,'%s begins to wander off.',0,2,0,0,'shay leafrunner EMOTE_WANDER'), +(-1001115,'Oh, here you are, Rockbiter! I\'m sorry, I know I\'m not supposed to wander off.',0,0,0,1,'shay leafrunner SAY_EVENT_COMPLETE_1'), +(-1001116,'I\'m so glad yer back Shay. Please, don\'t ever run off like that again! What would I tell yer parents if I lost ya?',0,0,0,1,'rockbiter SAY_EVENT_COMPLETE_2'); diff --git a/sql/updates/0.8/r3013_mangos.sql b/sql/updates/0.8/r3013_mangos.sql new file mode 100644 index 000000000..192c5418c --- /dev/null +++ b/sql/updates/0.8/r3013_mangos.sql @@ -0,0 +1,8 @@ +DELETE FROM scripted_areatrigger WHERE entry IN (5710,5711,5712,5714,5715,5716); +INSERT INTO scripted_areatrigger VALUES +(5710, 'at_hot_on_the_trail'), +(5711, 'at_hot_on_the_trail'), +(5712, 'at_hot_on_the_trail'), +(5714, 'at_hot_on_the_trail'), +(5715, 'at_hot_on_the_trail'), +(5716, 'at_hot_on_the_trail'); diff --git a/sql/updates/0.8/r3014_mangos.sql b/sql/updates/0.8/r3014_mangos.sql new file mode 100644 index 000000000..19489ecf7 --- /dev/null +++ b/sql/updates/0.8/r3014_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_saronite_mine_slave' WHERE entry=31397; diff --git a/sql/updates/0.8/r3014_scriptdev2.sql b/sql/updates/0.8/r3014_scriptdev2.sql new file mode 100644 index 000000000..69d115523 --- /dev/null +++ b/sql/updates/0.8/r3014_scriptdev2.sql @@ -0,0 +1,13 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001124 AND -1001117; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001117,'AHAHAHAHA... you\'ll join us soon enough!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_1'), +(-1001118,'I don\'t want to leave! I want to stay here!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_2'), +(-1001119,'I must get further underground to where he is. I must jump!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_3'), +(-1001120,'I won\'t leave!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_4'), +(-1001121,'I\'ll never return. The whole reason for my existence awaits below!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_5'), +(-1001122,'I\'m coming, master!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_6'), +(-1001123,'My life for you!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_7'), +(-1001124,'NO! You\'re wrong! The voices in my head are beautiful!',0,1,0,0,'saronite mine slave SAY_MINER_SUICIDE_8'); +DELETE FROM gossip_texts WHERE entry=-3000113; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000113,'Go on, you\'re free. Get out of here!','saronite mine slave GOSSIP_ITEM_SLAVE_FREE'); diff --git a/sql/updates/0.8/r3015_mangos.sql b/sql/updates/0.8/r3015_mangos.sql new file mode 100644 index 000000000..d9b1a966f --- /dev/null +++ b/sql/updates/0.8/r3015_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_tipsy_mcmanus' WHERE entry=28566; +UPDATE creature_template SET ScriptName='npc_wants_fruit_credit' WHERE entry IN (28535,28536,28537); +UPDATE gameobject_template SET ScriptName='go_quest_still_at_it_credit' WHERE entry IN (190635,190636); diff --git a/sql/updates/0.8/r3015_scriptdev2.sql b/sql/updates/0.8/r3015_scriptdev2.sql new file mode 100644 index 000000000..db8316050 --- /dev/null +++ b/sql/updates/0.8/r3015_scriptdev2.sql @@ -0,0 +1,17 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001136 AND -1001125; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001125,'Beginning the distillation in 5 seconds.',0,0,0,0,'tipsy mcmanus SAY_DISTILLATION_START'), +(-1001126,'Add another orange! Quickly!',0,0,0,25,'tipsy mcmanus SAY_ADD_ORANGE'), +(-1001127,'Add bananas!',0,0,0,25,'tipsy mcmanus SAY_ADD_BANANAS'), +(-1001128,'Put a papaya in the still!',0,0,0,25,'tipsy mcmanus SAY_ADD_PAPAYA'), +(-1001129,'The still needs heat! Light the brazier!',0,0,0,5,'tipsy mcmanus SAY_LIGHT_BRAZIER'), +(-1001130,'Pressure\'s too high! Open the pressure valve!',0,0,0,5,'tipsy mcmanus SAY_OPEN_VALVE'), +(-1001131,'Good job! Keep your eyes open, now.',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_1'), +(-1001132,'Nicely handled! Stay on your toes!',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_2'), +(-1001133,'Well done! Be ready for anything!',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_3'), +(-1001134,'That\'ll do. Never know what it\'ll need next...',0,0,0,4,'tipsy mcmanus SAY_ACTION_COMPLETE_4'), +(-1001135,'It\'s no good! I\'m shutting it down...',0,0,0,0,'tipsy mcmanus SAY_DISTILLATION_FAIL'), +(-1001136,'We\'ve done it! Come get the cask.',0,0,0,0,'tipsy mcmanus SAY_DISTILLATION_COMPLETE'); +DELETE FROM gossip_texts WHERE entry=-3000114; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3000114,'I\'m ready to start the distillation, uh, Tipsy.','tipsy mcmanus GOSSIP_ITEM_START_DISTILLATION'); diff --git a/sql/updates/0.8/r3016_scriptdev2.sql b/sql/updates/0.8/r3016_scriptdev2.sql new file mode 100644 index 000000000..dd04e9c1d --- /dev/null +++ b/sql/updates/0.8/r3016_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001140 AND -1001137; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001137,'The duel will begin in...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN'), +(-1001138,'3...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN_3'), +(-1001139,'2...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN_2'), +(-1001140,'1...',0,5,0,0,'death knight initiate EMOTE_DUEL_BEGIN_1'); diff --git a/sql/updates/0.8/r3017_mangos.sql b/sql/updates/0.8/r3017_mangos.sql new file mode 100644 index 000000000..f778d76cc --- /dev/null +++ b/sql/updates/0.8/r3017_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='boss_head_of_horseman' WHERE entry=23775; diff --git a/sql/updates/0.8/r3018_scriptdev2.sql b/sql/updates/0.8/r3018_scriptdev2.sql new file mode 100644 index 000000000..ea50fe55c --- /dev/null +++ b/sql/updates/0.8/r3018_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12674+) '; diff --git a/sql/updates/0.8/r3019_mangos.sql b/sql/updates/0.8/r3019_mangos.sql new file mode 100644 index 000000000..f83fd315d --- /dev/null +++ b/sql/updates/0.8/r3019_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_scalawag_frog' WHERE entry=26503; +UPDATE creature_template SET ScriptName='npc_crystalline_ice_giant' WHERE entry=26809; diff --git a/sql/updates/0.8/r3021_scriptdev2.sql b/sql/updates/0.8/r3021_scriptdev2.sql new file mode 100644 index 000000000..03e74caad --- /dev/null +++ b/sql/updates/0.8/r3021_scriptdev2.sql @@ -0,0 +1,60 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001147 AND -1001141; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001141,'Nope, not here...',0,0,0,0,'stinky ignatz SAY_SECOND_STOP'), +(-1001142,'There must be one around here somewhere...',0,0,0,0,'stinky ignatz SAY_THIRD_STOP_1'), +(-1001143,'Ah, there\'s one!',0,0,0,0,'stinky ignatz SAY_THIRD_STOP_2'), +(-1001144,'Come, $N! Let\'s go over there and collect it!',0,0,0,0,'stinky ignatz SAY_THIRD_STOP_3'), +(-1001145,'Ok, let\'s get out of here!',0,0,0,0,'stinky ignatz SAY_PLANT_GATHERED'), +(-1001146,'I\'m glad you\'re here! Because I need your help!!',0,0,0,0,'stinky ignatz SAY_AGGRO_3'), +(-1001147,'Look out! The $N attacks!',0,0,0,0,'stinky ignatz SAY_AGGRO_4'); +DELETE FROM script_texts WHERE entry BETWEEN -1000962 AND -1000958; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1000958,'Ok, let\'s get started.',0,0,0,0,'stinky ignatz SAY_STINKY_BEGIN'), +(-1000959,'Now let\'s look for the herb.',0,0,0,0,'stinky ignatz SAY_STINKY_FIRST_STOP'), +(-1000960,'Help! The beast is on me!',0,0,0,0,'stinky ignatz SAY_AGGRO_1'), +(-1000961,'Help! I\'m under attack!',0,0,0,0,'stinky ignatz SAY_AGGRO_2'), +(-1000962,'I can make it from here. Thanks, $N! And talk to my employer about a reward!',0,0,0,0,'stinky ignatz SAY_STINKY_END'); + +DELETE FROM script_waypoint WHERE entry=4880; +INSERT INTO script_waypoint VALUES +(4880, 0, -2670.221, -3446.189, 34.085, 0, ''), +(4880, 1, -2683.958, -3451.094, 34.707, 0, ''), +(4880, 2, -2703.241, -3454.822, 33.395, 0, ''), +(4880, 3, -2721.615, -3457.408, 33.626, 0, ''), +(4880, 4, -2739.977, -3459.843, 33.329, 0, ''), +(4880, 5, -2756.240, -3460.516, 32.037, 5000, 'SAY_STINKY_FIRST_STOP'), +(4880, 6, -2764.517, -3472.714, 33.750, 0, ''), +(4880, 7, -2773.679, -3482.913, 32.840, 0, ''), +(4880, 8, -2781.394, -3490.613, 32.598, 0, ''), +(4880, 9, -2788.308, -3492.904, 30.761, 0, ''), +(4880, 10, -2794.578, -3489.185, 31.119, 5000, 'SAY_SECOND_STOP'), +(4880, 11, -2789.427, -3498.043, 31.050, 0, ''), +(4880, 12, -2786.968, -3508.168, 31.983, 0, ''), +(4880, 13, -2786.770, -3519.953, 31.079, 0, ''), +(4880, 14, -2789.359, -3525.025, 31.831, 0, ''), +(4880, 15, -2797.950, -3523.693, 31.697, 0, ''), +(4880, 16, -2812.971, -3519.838, 29.864, 0, ''), +(4880, 17, -2818.331, -3521.396, 30.563, 0, ''), +(4880, 18, -2824.771, -3528.728, 32.399, 0, ''), +(4880, 19, -2830.697, -3539.875, 32.505, 0, ''), +(4880, 20, -2836.235, -3549.962, 31.180, 0, ''), +(4880, 21, -2837.576, -3561.052, 30.740, 0, ''), +(4880, 22, -2834.445, -3568.264, 30.751, 0, ''), +(4880, 23, -2827.351, -3569.807, 31.316, 0, ''), +(4880, 24, -2817.380, -3566.961, 30.947, 5000, 'SAY_THIRD_STOP_1'), +(4880, 25, -2817.380, -3566.961, 30.947, 2000, 'SAY_THIRD_STOP_2'), +(4880, 26, -2817.380, -3566.961, 30.947, 0, 'SAY_THIRD_STOP_3'), +(4880, 27, -2818.815, -3579.415, 28.525, 0, ''), +(4880, 28, -2820.205, -3590.640, 30.269, 0, ''), +(4880, 29, -2820.849, -3593.938, 31.150, 3000, ''), +(4880, 30, -2820.849, -3593.938, 31.150, 3000, 'SAY_PLANT_GATHERED'), +(4880, 31, -2834.209, -3592.041, 33.790, 0, ''), +(4880, 32, -2840.306, -3586.207, 36.288, 0, ''), +(4880, 33, -2847.491, -3576.416, 37.660, 0, ''), +(4880, 34, -2855.718, -3565.184, 39.390, 0, ''), +(4880, 35, -2861.785, -3552.902, 41.243, 0, ''), +(4880, 36, -2869.542, -3545.579, 40.701, 0, ''), +(4880, 37, -2877.784, -3538.372, 37.274, 0, ''), +(4880, 38, -2882.677, -3534.165, 34.844, 0, ''), +(4880, 39, -2888.567, -3534.117, 34.298, 4000, 'SAY_STINKY_END'), +(4880, 40, -2888.567, -3534.117, 34.298, 0, ''); diff --git a/sql/updates/0.8/r3022_mangos.sql b/sql/updates/0.8/r3022_mangos.sql new file mode 100644 index 000000000..1dea888f5 --- /dev/null +++ b/sql/updates/0.8/r3022_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_guardian_of_yogg' WHERE entry=33136; +UPDATE creature_template SET ScriptName='boss_yogg_saron' WHERE entry=33288; diff --git a/sql/updates/0.8/r3022_scriptdev2.sql b/sql/updates/0.8/r3022_scriptdev2.sql new file mode 100644 index 000000000..c6f8a3fc8 --- /dev/null +++ b/sql/updates/0.8/r3022_scriptdev2.sql @@ -0,0 +1,9 @@ +DELETE FROM script_texts WHERE entry=-1603206; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603206,'I am the lucid dream.',15754,1,0,457,'yogg SAY_PHASE_2_INTRO_1'); +DELETE FROM script_texts WHERE entry BETWEEN -1603265 AND -1603262; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603262,'The monster in your nightmares.',0,1,0,457,'yogg SAY_PHASE_2_INTRO_2'), +(-1603263,'The fiend of a thousand faces.',0,1,0,457,'yogg SAY_PHASE_2_INTRO_3'), +(-1603264,'Cower before my true form.',0,1,0,457,'yogg SAY_PHASE_2_INTRO_4'), +(-1603265,'BOW DOWN BEFORE THE GOD OF DEATH!',0,1,0,0,'yogg SAY_PHASE_2_INTRO_5'); diff --git a/sql/updates/0.8/r3023_mangos.sql b/sql/updates/0.8/r3023_mangos.sql new file mode 100644 index 000000000..892405819 --- /dev/null +++ b/sql/updates/0.8/r3023_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_captured_arkonarin' WHERE entry=11016; diff --git a/sql/updates/0.8/r3023_scriptdev2.sql b/sql/updates/0.8/r3023_scriptdev2.sql new file mode 100644 index 000000000..869977199 --- /dev/null +++ b/sql/updates/0.8/r3023_scriptdev2.sql @@ -0,0 +1,128 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001158 AND -1001148; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001148,'I am ready, $N. Let\'s find my equipment and get out of here. I think I know where it is.',0,0,0,1,'captured arko\'narin SAY_ESCORT_START'), +(-1001149,'Oh my! Look at this... all these candles. I\'m sure they\'re used for some terrible ritual or dark summoning. We best make haste.',0,0,0,18,'captured arko\'narin SAY_FIRST_STOP'), +(-1001150,'There! Over there!',0,0,0,25,'captured arko\'narin SAY_SECOND_STOP'), +(-1001151,'You will not stop me from escaping here, $N!',0,0,0,0,'captured arko\'narin SAY_AGGRO'), +(-1001152,'All I need now is a golden lasso.',0,0,0,0,'captured arko\'narin SAY_EQUIPMENT'), +(-1001153,'DIE DEMON DOGS!',0,0,0,0,'captured arko\'narin SAY_ESCAPE'), +(-1001154,'Ah! Fresh air at last! I never thought I\'d see the day.',0,0,0,4,'captured arko\'narin SAY_FRESH_AIR'), +(-1001155,'BETRAYER!',0,1,0,0,'spirit of trey lightforge SAY_BETRAYER'), +(-1001156,'What was that?! Trey? TREY?',0,0,0,22,'captured arko\'narin SAY_TREY'), +(-1001157,'You kept me in the cell for too long, monster!',0,0,0,0,'captured arko\'narin SAY_ATTACK_TREY'), +(-1001158,'No! My friend... what\'s happened? This is all my fault...',0,0,0,18,'captured arko\'narin SAY_ESCORT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=11016; +INSERT INTO script_waypoint VALUES +(11016, 0, 5004.985, -440.237, 319.059, 4000, 'SAY_ESCORT_START'), +(11016, 1, 4992.224, -449.964, 317.057, 0, ''), +(11016, 2, 4988.549, -457.438, 316.289, 0, ''), +(11016, 3, 4989.978, -464.297, 316.846, 0, ''), +(11016, 4, 4994.038, -467.754, 318.055, 0, ''), +(11016, 5, 5002.307, -466.318, 319.965, 0, ''), +(11016, 6, 5011.801, -462.889, 321.501, 0, ''), +(11016, 7, 5020.533, -460.797, 321.970, 0, ''), +(11016, 8, 5026.836, -463.171, 321.345, 0, ''), +(11016, 9, 5028.663, -476.805, 318.726, 0, ''), +(11016, 10, 5029.503, -487.131, 318.179, 0, ''), +(11016, 11, 5031.178, -497.678, 316.533, 0, ''), +(11016, 12, 5032.720, -504.748, 314.744, 0, ''), +(11016, 13, 5034.997, -513.138, 314.372, 0, ''), +(11016, 14, 5037.493, -521.733, 313.221, 6000, 'SAY_FIRST_STOP'), +(11016, 15, 5049.055, -519.546, 313.221, 0, ''), +(11016, 16, 5059.170, -522.930, 313.221, 0, ''), +(11016, 17, 5062.755, -529.933, 313.221, 0, ''), +(11016, 18, 5063.896, -538.827, 313.221, 0, ''), +(11016, 19, 5062.223, -545.635, 313.221, 0, ''), +(11016, 20, 5061.690, -552.333, 313.101, 0, ''), +(11016, 21, 5060.333, -560.349, 310.873, 0, ''), +(11016, 22, 5055.621, -565.541, 308.737, 0, ''), +(11016, 23, 5049.803, -567.604, 306.537, 0, ''), +(11016, 24, 5043.011, -564.946, 303.682, 0, ''), +(11016, 25, 5038.221, -559.823, 301.463, 0, ''), +(11016, 26, 5039.456, -548.675, 297.824, 0, ''), +(11016, 27, 5043.437, -538.807, 297.801, 0, ''), +(11016, 28, 5056.397, -528.954, 297.801, 0, ''), +(11016, 29, 5064.397, -521.904, 297.801, 0, ''), +(11016, 30, 5067.616, -512.999, 297.196, 0, ''), +(11016, 31, 5065.990, -505.329, 297.214, 0, ''), +(11016, 32, 5062.238, -499.086, 297.448, 0, ''), +(11016, 33, 5065.087, -492.069, 298.054, 0, ''), +(11016, 34, 5071.195, -491.173, 297.666, 5000, 'SAY_SECOND_STOP'), +(11016, 35, 5087.474, -496.478, 296.677, 0, ''), +(11016, 36, 5095.552, -508.639, 296.677, 0, ''), +(11016, 37, 5104.300, -521.014, 296.677, 0, ''), +(11016, 38, 5110.132, -532.123, 296.677, 4000, 'open equipment chest'), +(11016, 39, 5110.132, -532.123, 296.677, 4000, 'cast SPELL_STRENGHT_ARKONARIN'), +(11016, 40, 5110.132, -532.123, 296.677, 4000, 'SAY_EQUIPMENT'), +(11016, 41, 5110.132, -532.123, 296.677, 0, 'SAY_ESCAPE'), +(11016, 42, 5099.748, -510.823, 296.677, 0, ''), +(11016, 43, 5091.944, -497.516, 296.677, 0, ''), +(11016, 44, 5079.375, -486.811, 297.638, 0, ''), +(11016, 45, 5069.212, -488.770, 298.082, 0, ''), +(11016, 46, 5064.242, -496.051, 297.275, 0, ''), +(11016, 47, 5065.084, -505.239, 297.361, 0, ''), +(11016, 48, 5067.818, -515.245, 297.125, 0, ''), +(11016, 49, 5064.617, -521.170, 297.801, 0, ''), +(11016, 50, 5053.221, -530.739, 297.801, 0, ''), +(11016, 51, 5045.725, -538.311, 297.801, 0, ''), +(11016, 52, 5039.695, -548.112, 297.801, 0, ''), +(11016, 53, 5038.778, -557.588, 300.787, 0, ''), +(11016, 54, 5042.014, -566.749, 303.838, 0, ''), +(11016, 55, 5050.555, -568.149, 306.782, 0, ''), +(11016, 56, 5056.979, -564.674, 309.342, 0, ''), +(11016, 57, 5060.791, -556.801, 311.936, 0, ''), +(11016, 58, 5059.581, -551.626, 313.221, 0, ''), +(11016, 59, 5062.826, -541.994, 313.221, 0, ''), +(11016, 60, 5063.554, -531.288, 313.221, 0, ''), +(11016, 61, 5057.934, -523.088, 313.221, 0, ''), +(11016, 62, 5049.471, -519.360, 313.221, 0, ''), +(11016, 63, 5040.789, -519.809, 313.221, 0, ''), +(11016, 64, 5034.299, -515.361, 313.948, 0, ''), +(11016, 65, 5032.001, -505.532, 314.663, 0, ''), +(11016, 66, 5029.915, -495.645, 316.821, 0, ''), +(11016, 67, 5028.871, -487.000, 318.179, 0, ''), +(11016, 68, 5028.109, -475.531, 318.839, 0, ''), +(11016, 69, 5027.759, -465.442, 320.643, 0, ''), +(11016, 70, 5019.955, -460.892, 321.969, 0, ''), +(11016, 71, 5009.426, -464.793, 321.248, 0, ''), +(11016, 72, 4999.567, -468.062, 319.426, 0, ''), +(11016, 73, 4992.034, -468.128, 317.894, 0, ''), +(11016, 74, 4988.168, -461.293, 316.369, 0, ''), +(11016, 75, 4990.624, -447.459, 317.104, 0, ''), +(11016, 76, 4993.475, -438.643, 318.272, 0, ''), +(11016, 77, 4995.451, -430.178, 318.462, 0, ''), +(11016, 78, 4993.564, -422.876, 318.864, 0, ''), +(11016, 79, 4985.401, -420.864, 320.205, 0, ''), +(11016, 80, 4976.515, -426.168, 323.112, 0, ''), +(11016, 81, 4969.832, -429.755, 325.029, 0, ''), +(11016, 82, 4960.702, -425.440, 325.834, 0, ''), +(11016, 83, 4955.447, -418.765, 327.433, 0, ''), +(11016, 84, 4949.702, -408.796, 328.004, 0, ''), +(11016, 85, 4940.017, -403.222, 329.956, 0, ''), +(11016, 86, 4934.982, -401.475, 330.898, 0, ''), +(11016, 87, 4928.693, -399.302, 331.744, 0, ''), +(11016, 88, 4926.935, -398.436, 333.079, 0, ''), +(11016, 89, 4916.163, -393.822, 333.729, 0, ''), +(11016, 90, 4908.393, -396.217, 333.217, 0, ''), +(11016, 91, 4905.610, -396.535, 335.050, 0, ''), +(11016, 92, 4897.876, -395.245, 337.346, 0, ''), +(11016, 93, 4895.206, -388.203, 339.295, 0, ''), +(11016, 94, 4896.945, -382.429, 341.040, 0, ''), +(11016, 95, 4901.885, -378.799, 342.771, 0, ''), +(11016, 96, 4908.087, -380.635, 344.597, 0, ''), +(11016, 97, 4911.910, -385.818, 346.491, 0, ''), +(11016, 98, 4910.104, -393.444, 348.798, 0, ''), +(11016, 99, 4903.500, -396.947, 350.812, 0, ''), +(11016, 100, 4898.083, -394.226, 351.821, 0, ''), +(11016, 101, 4891.333, -393.436, 351.801, 0, ''), +(11016, 102, 4881.203, -395.211, 351.590, 0, ''), +(11016, 103, 4877.843, -395.536, 349.713, 0, ''), +(11016, 104, 4873.972, -394.919, 349.844, 5000, 'SAY_FRESH_AIR'), +(11016, 105, 4873.972, -394.919, 349.844, 3000, 'SAY_BETRAYER'), +(11016, 106, 4873.972, -394.919, 349.844, 2000, 'SAY_TREY'), +(11016, 107, 4873.972, -394.919, 349.844, 0, 'SAY_ATTACK_TREY'), +(11016, 108, 4873.972, -394.919, 349.844, 5000, 'SAY_ESCORT_COMPLETE'), +(11016, 109, 4873.972, -394.919, 349.844, 1000, ''), +(11016, 110, 4863.016, -394.521, 350.650, 0, ''), +(11016, 111, 4848.696, -397.612, 351.215, 0, ''); diff --git a/sql/updates/0.8/r3024_mangos.sql b/sql/updates/0.8/r3024_mangos.sql new file mode 100644 index 000000000..fa66c0988 --- /dev/null +++ b/sql/updates/0.8/r3024_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_arei' WHERE entry=9598; diff --git a/sql/updates/0.8/r3024_scriptdev2.sql b/sql/updates/0.8/r3024_scriptdev2.sql new file mode 100644 index 000000000..dfe9c20d7 --- /dev/null +++ b/sql/updates/0.8/r3024_scriptdev2.sql @@ -0,0 +1,51 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001167 AND -1001159; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001159,'Please, help me to get through this cursed forest, $r.',0,0,0,0,'arei SAY_ESCORT_START'), +(-1001160,'This creature suffers from the effect of the fel... We must end its misery.',0,0,0,0,'arei SAY_ATTACK_IRONTREE'), +(-1001161,'The corruption of the fel has not left any of the creatures of Felwood untouched, $N. Please, be on your guard.',0,0,0,0,'arei SAY_ATTACK_TOXIC_HORROR'), +(-1001162,'I sense the taint of corruption upon this $N. Help me detroy it.',0,0,0,0,'arei SAY_EXIT_WOODS'), +(-1001163,'That I must fight against my own kind deeply saddens me.',0,0,0,0,'arei SAY_CLEAR_PATH'), +(-1001164,'I can sens it now, $N. Ashenvale lies down this path.',0,0,0,0,'arei SAY_ASHENVALE'), +(-1001165,'I feel... something strange...',0,0,0,0,'arei SAY_TRANSFORM'), +(-1001166,'$N my form has now changed! The true strength of my spirit is returing to me now... The cursed grasp of the forest is leaving me.',0,0,0,0,'arei SAY_LIFT_CURSE'), +(-1001167,'Thank you, $N. Now my spirit will finally be at peace.',0,0,0,0,'arei SAY_ESCORT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=9598; +INSERT INTO script_waypoint VALUES +(9598, 0, 6004.265, -1180.494, 376.377, 0, 'SAY_ESCORT_START'), +(9598, 1, 6002.512, -1157.294, 381.407, 0, ''), +(9598, 2, 6029.228, -1139.720, 383.127, 0, ''), +(9598, 3, 6042.479, -1128.963, 386.582, 0, ''), +(9598, 4, 6062.820, -1115.522, 386.850, 0, ''), +(9598, 5, 6089.188, -1111.907, 383.105, 0, ''), +(9598, 6, 6104.390, -1114.561, 380.490, 0, ''), +(9598, 7, 6115.080, -1128.572, 375.779, 0, ''), +(9598, 8, 6119.352, -1147.314, 372.518, 0, ''), +(9598, 9, 6119.003, -1176.082, 371.072, 0, ''), +(9598, 10, 6120.982, -1198.408, 373.432, 0, ''), +(9598, 11, 6123.521, -1226.636, 374.119, 0, ''), +(9598, 12, 6127.737, -1246.035, 373.574, 0, ''), +(9598, 13, 6133.433, -1253.642, 369.100, 0, ''), +(9598, 14, 6150.787, -1269.151, 369.240, 0, ''), +(9598, 15, 6155.805, -1275.029, 373.627, 0, ''), +(9598, 16, 6163.544, -1307.130, 376.234, 0, ''), +(9598, 17, 6174.800, -1340.885, 379.039, 0, ''), +(9598, 18, 6191.144, -1371.260, 378.453, 0, ''), +(9598, 19, 6215.652, -1397.517, 376.012, 0, ''), +(9598, 20, 6243.784, -1407.675, 371.594, 0, ''), +(9598, 21, 6280.775, -1408.259, 370.554, 0, ''), +(9598, 22, 6325.360, -1406.688, 370.082, 0, ''), +(9598, 23, 6355.000, -1404.337, 370.646, 0, ''), +(9598, 24, 6374.679, -1399.176, 372.105, 0, ''), +(9598, 25, 6395.803, -1367.057, 374.910, 0, ''), +(9598, 26, 6408.569, -1333.487, 376.616, 0, ''), +(9598, 27, 6409.075, -1312.168, 379.598, 0, ''), +(9598, 28, 6418.689, -1277.697, 381.638, 0, ''), +(9598, 29, 6441.689, -1247.316, 387.246, 0, ''), +(9598, 30, 6462.136, -1226.316, 397.610, 0, ''), +(9598, 31, 6478.021, -1216.260, 408.284, 0, ''), +(9598, 32, 6499.632, -1217.087, 419.461, 0, ''), +(9598, 33, 6523.165, -1220.780, 430.549, 0, ''), +(9598, 34, 6542.716, -1216.997, 437.788, 0, ''), +(9598, 35, 6557.279, -1211.125, 441.452, 0, ''), +(9598, 36, 6574.568, -1204.589, 443.216, 0, 'SAY_EXIT_IRONTREE'); diff --git a/sql/updates/0.8/r3025_scriptdev2.sql b/sql/updates/0.8/r3025_scriptdev2.sql new file mode 100644 index 000000000..1aa4d2fb1 --- /dev/null +++ b/sql/updates/0.8/r3025_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12682+) '; diff --git a/sql/updates/0.8/r3028_mangos.sql b/sql/updates/0.8/r3028_mangos.sql new file mode 100644 index 000000000..5c92ef815 --- /dev/null +++ b/sql/updates/0.8/r3028_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_death_ray' WHERE entry=33881; +UPDATE creature_template SET ScriptName='npc_immortal_guardian' WHERE entry=33988; +UPDATE creature_template SET ScriptName='npc_constrictor_tentacle' WHERE entry=33983; diff --git a/sql/updates/0.8/r3028_scriptdev2.sql b/sql/updates/0.8/r3028_scriptdev2.sql new file mode 100644 index 000000000..6eb0469f2 --- /dev/null +++ b/sql/updates/0.8/r3028_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1603266; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603266,'%s opens his mouth wide!',0,3,0,0,'yogg EMOTE_DEAFENING_ROAR'); diff --git a/sql/updates/0.8/r3029_mangos.sql b/sql/updates/0.8/r3029_mangos.sql new file mode 100644 index 000000000..1b3c03c5a --- /dev/null +++ b/sql/updates/0.8/r3029_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_brain_yogg_saron' WHERE entry=33890; +UPDATE creature_template SET ScriptName='npc_descent_madness' WHERE entry=34072; +UPDATE creature_template SET ScriptName='npc_laughing_skull' WHERE entry=33990; diff --git a/sql/updates/0.8/r3031_mangos.sql b/sql/updates/0.8/r3031_mangos.sql new file mode 100644 index 000000000..7c8383710 --- /dev/null +++ b/sql/updates/0.8/r3031_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_keeper_mimiron' WHERE entry=33412; +UPDATE creature_template SET ScriptName='npc_keeper_thorim' WHERE entry=33413; diff --git a/sql/updates/0.8/r3031_scriptdev2.sql b/sql/updates/0.8/r3031_scriptdev2.sql new file mode 100644 index 000000000..8a0344059 --- /dev/null +++ b/sql/updates/0.8/r3031_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1603211; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603211,'%s prepares to unleash Empowering Shadows!',0,3,0,0,'yogg EMOTE_EMPOWERING_SHADOWS'); diff --git a/sql/updates/0.8/r3034_scriptdev2.sql b/sql/updates/0.8/r3034_scriptdev2.sql new file mode 100644 index 000000000..3bd09be2d --- /dev/null +++ b/sql/updates/0.8/r3034_scriptdev2.sql @@ -0,0 +1,7 @@ +DELETE FROM script_texts WHERE entry IN (-1603227,-1603228,-1603231,-1603267); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1603227,'Bad news sire.',15538,0,0,1,'yogg SAY_GARONA_1'), +(-1603228,'Gul\'dan is bringing up his warlocks by nightfall. Until then, the Blackrock clan will be trying to take the Eastern Wall.',15540,0,0,1,'yogg SAY_GARONA_3'), +(-1603231,'We will hold until the reinforcements come. As long as men with stout hearts are manning the walls and throne Stormwind will hold.',15585,0,0,1,'yogg SAY_KING_LLANE'), +(-1603267,'The clans are united under Blackhand in this assault. They will stand together until Stormwind has fallen.',15539,0,0,0,'yogg SAY_GARONA_2'); +UPDATE script_texts SET emote=1 WHERE entry IN (-1603222,-1603223,-1603224,-1603225); diff --git a/sql/updates/0.8/r3046_mangos.sql b/sql/updates/0.8/r3046_mangos.sql new file mode 100644 index 000000000..318276c2a --- /dev/null +++ b/sql/updates/0.8/r3046_mangos.sql @@ -0,0 +1,3 @@ +UPDATE creature_template SET ScriptName='npc_darkness' WHERE entry=25879; +UPDATE creature_template SET ScriptName='npc_singularity' WHERE entry=25855; +UPDATE creature_template SET ScriptName='' WHERE entry=25782; diff --git a/sql/updates/0.8/r3048_mangos.sql b/sql/updates/0.8/r3048_mangos.sql new file mode 100644 index 000000000..1acc2e7c5 --- /dev/null +++ b/sql/updates/0.8/r3048_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_flame_breath_trigger' WHERE entry=28351; diff --git a/sql/updates/0.8/r3049_scriptdev2.sql b/sql/updates/0.8/r3049_scriptdev2.sql new file mode 100644 index 000000000..909e87a0a --- /dev/null +++ b/sql/updates/0.8/r3049_scriptdev2.sql @@ -0,0 +1,62 @@ +DELETE FROM script_texts WHERE entry IN (-1001168,-1001169); +INSERT INTO script_texts (entry,content_default,sound,type,LANGUAGE,emote,comment) VALUES +(-1001168,'The naga torture the spirits of water. They invoke chaos and destruction!',0,0,0,0,'wilda SAY_WIL_PROGRESS_4'), +(-1001169,'The naga do not respect nature. They twist and corrupt it to meet their needs. They live to agitate the spirits.',0,0,0,0,'wilda SAY_WIL_PROGRESS_5'); +UPDATE script_texts SET emote=1 WHERE entry=-1000389; +UPDATE script_texts SET emote=3 WHERE entry=-1000390; + +DELETE FROM script_waypoint WHERE entry=21027; +INSERT INTO script_waypoint VALUES +(21027, 0, -2714.697266, 1326.879395, 34.306953, 0, ''), +(21027, 1, -2666.364990, 1348.222656, 34.445557, 0, ''), +(21027, 2, -2693.789307, 1336.964966, 34.445557, 0, ''), +(21027, 3, -2715.495361, 1328.054443, 34.106014, 0, ''), +(21027, 4, -2742.530762, 1314.138550, 33.606144, 0, ''), +(21027, 5, -2745.077148, 1311.108765, 33.630898, 0, ''), +(21027, 6, -2749.855225, 1302.737915, 33.475632, 0, ''), +(21027, 7, -2753.639648, 1294.059448, 33.314930, 0, ''), +(21027, 8, -2756.796387, 1285.122192, 33.391262, 0, 'spawn assassin'), +(21027, 9, -2750.042969, 1273.661987, 33.188259, 0, ''), +(21027, 10, -2740.378418, 1258.846680, 33.212521, 0, ''), +(21027, 11, -2733.629395, 1248.259766, 33.640598, 0, ''), +(21027, 12, -2727.212646, 1238.606445, 33.520847, 0, ''), +(21027, 13, -2726.377197, 1237.264526, 33.461823, 4000, 'SAY_WIL_PROGRESS1'), +(21027, 14, -2726.377197, 1237.264526, 33.461823, 4000, 'SAY_WIL_FIND_EXIT'), +(21027, 15, -2746.383301, 1266.390625, 33.191952, 0, 'spawn assassin'), +(21027, 16, -2746.383301, 1266.390625, 33.191952, 0, ''), +(21027, 17, -2758.927734, 1285.134155, 33.341728, 0, ''), +(21027, 18, -2761.845703, 1292.313599, 33.209042, 0, ''), +(21027, 19, -2758.871826, 1300.677612, 33.285332, 0, ''), +(21027, 20, -2753.928955, 1307.755859, 33.452457, 0, ''), +(21027, 21, -2738.612061, 1316.191284, 33.482975, 0, ''), +(21027, 22, -2727.897461, 1320.013916, 33.381111, 0, ''), +(21027, 23, -2709.458740, 1315.739990, 33.301838, 0, ''), +(21027, 24, -2704.658936, 1301.620361, 32.463303, 0, ''), +(21027, 25, -2704.120117, 1298.922607, 32.768162, 0, ''), +(21027, 26, -2691.798340, 1292.846436, 33.852642, 0, 'spawn assassin'), +(21027, 27, -2682.879639, 1288.853882, 32.995399, 0, ''), +(21027, 28, -2661.869141, 1279.682495, 26.686783, 0, ''), +(21027, 29, -2648.943604, 1270.272827, 24.147522, 0, ''), +(21027, 30, -2642.506836, 1262.938721, 23.512444, 0, 'spawn assassin'), +(21027, 31, -2636.984863, 1252.429077, 20.418257, 0, ''), +(21027, 32, -2648.113037, 1224.984863, 8.691818, 0, 'spawn assassin'), +(21027, 33, -2658.393311, 1200.136719, 5.492243, 0, ''), +(21027, 34, -2668.504395, 1190.450562, 3.127407, 0, ''), +(21027, 35, -2685.930420, 1174.360840, 5.163924, 0, ''), +(21027, 36, -2701.613770, 1160.026367, 5.611311, 0, ''), +(21027, 37, -2714.659668, 1149.980347, 4.342373, 0, ''), +(21027, 38, -2721.443359, 1145.002808, 1.913474, 0, ''), +(21027, 39, -2733.962158, 1143.436279, 2.620415, 0, 'spawn assassin'), +(21027, 40, -2757.876709, 1146.937500, 6.184002, 2000, 'SAY_WIL_JUST_AHEAD'), +(21027, 41, -2772.300537, 1166.052734, 6.331811, 0, ''), +(21027, 42, -2790.265381, 1189.941650, 5.207958, 0, ''), +(21027, 43, -2805.448975, 1208.663940, 5.557623, 0, 'spawn assassin'), +(21027, 44, -2820.617676, 1225.870239, 6.266103, 0, ''), +(21027, 45, -2831.926758, 1237.725830, 5.808506, 0, ''), +(21027, 46, -2842.578369, 1252.869629, 6.807481, 0, ''), +(21027, 47, -2846.344971, 1258.727295, 7.386168, 0, ''), +(21027, 48, -2847.556396, 1266.771729, 8.208790, 0, ''), +(21027, 49, -2841.654541, 1285.809204, 7.933223, 0, ''), +(21027, 50, -2841.754883, 1289.832520, 6.990304, 0, ''), +(21027, 51, -2861.973145, 1298.774536, 6.807335, 0, 'spawn assassin'), +(21027, 52, -2871.398438, 1302.348145, 6.807335, 7500, 'SAY_WIL_END'); diff --git a/sql/updates/0.8/r3050_mangos.sql b/sql/updates/0.8/r3050_mangos.sql new file mode 100644 index 000000000..5ba05a0a0 --- /dev/null +++ b/sql/updates/0.8/r3050_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_dimensius' WHERE entry=19554; diff --git a/sql/updates/0.8/r3050_scriptdev2.sql b/sql/updates/0.8/r3050_scriptdev2.sql new file mode 100644 index 000000000..910652720 --- /dev/null +++ b/sql/updates/0.8/r3050_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1001170,-1001171); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001170,'Time only has meaning to mortals, insect. Dimensius is infinite!',0,1,0,0,'dimensius SAY_AGGRO'), +(-1001171,'I hunger! Feed me the power of this forge, my children!',0,1,0,0,'dimensius SAY_SUMMON'); diff --git a/sql/updates/0.8/r3051_mangos.sql b/sql/updates/0.8/r3051_mangos.sql new file mode 100644 index 000000000..6377e017c --- /dev/null +++ b/sql/updates/0.8/r3051_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_glob_of_viscidus' WHERE entry=15667; diff --git a/sql/updates/0.8/r3051_scriptdev2.sql b/sql/updates/0.8/r3051_scriptdev2.sql new file mode 100644 index 000000000..e2f87fd31 --- /dev/null +++ b/sql/updates/0.8/r3051_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1531046 AND -1531041; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1531041,'%s begins to slow!',0,2,0,0,'viscidus EMOTE_SLOW'), +(-1531042,'%s is freezing up!',0,2,0,0,'viscidus EMOTE_FREEZE'), +(-1531043,'%s is frozen solid!',0,2,0,0,'viscidus EMOTE_FROZEN'), +(-1531044,'%s begins to crack!',0,2,0,0,'viscidus EMOTE_CRACK'), +(-1531045,'%s looks ready to shatter!',0,2,0,0,'viscidus EMOTE_SHATTER'), +(-1531046,'%s explodes!',0,2,0,0,'viscidus EMOTE_EXPLODE'); diff --git a/sql/updates/0.8/r3054_mangos.sql b/sql/updates/0.8/r3054_mangos.sql new file mode 100644 index 000000000..bb762afe5 --- /dev/null +++ b/sql/updates/0.8/r3054_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_magister_aledis' WHERE entry=20159; diff --git a/sql/updates/0.8/r3054_scriptdev2.sql b/sql/updates/0.8/r3054_scriptdev2.sql new file mode 100644 index 000000000..2f7b0d2e6 --- /dev/null +++ b/sql/updates/0.8/r3054_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1001172; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001172,'Spare my life! I will tell you about Arelion\'s secret.',0,0,0,0,'magister_aledis SAY_ALEDIS_DEFEAT'); diff --git a/sql/updates/0.8/r3055_mangos.sql b/sql/updates/0.8/r3055_mangos.sql new file mode 100644 index 000000000..48d810ba5 --- /dev/null +++ b/sql/updates/0.8/r3055_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_emily' WHERE entry=26588; diff --git a/sql/updates/0.8/r3055_scriptdev2.sql b/sql/updates/0.8/r3055_scriptdev2.sql new file mode 100644 index 000000000..fc6005b0d --- /dev/null +++ b/sql/updates/0.8/r3055_scriptdev2.sql @@ -0,0 +1,44 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001183 AND -1001173; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001173,'Are you ready, Mr. Floppy? Stay close to me and watch out for those wolves!',0,0,0,0,'emily SAY_ESCORT_START'), +(-1001174,'Um... I think one of those wolves is back...',0,0,0,0,'emily SAY_FIRST_WOLF'), +(-1001175,'He\'s going for Mr. Floppy!',0,0,0,0,'emily SAY_WOLF_ATTACK'), +(-1001176,'There\'s a big meanie attacking Mr. Floppy! Help!',0,0,0,0,'emily SAY_HELP_FLOPPY_1'), +(-1001177,'Let\'s get out of here before more wolves find us!',0,0,0,0,'emily SAY_FIRST_WOLF_DEFEAT'), +(-1001178,'Oh, no! Look, it\'s another wolf, and it\'s a biiiiiiig one!',0,0,0,0,'emily SAY_SECOND_WOLF'), +(-1001179,'He\'s gonna eat Mr. Floppy! You gotta help Mr. Floppy! You just gotta!',0,0,0,0,'emily SAY_HELP_FLOPPY_2'), +(-1001180,'Don\'t go toward the light, Mr. Floppy!',0,0,0,0,'emily SAY_FLOPPY_ALMOST_DEAD'), +(-1001181,'Mr. Floppy, you\'re ok! Thank you so much for saving Mr. Floppy!',0,0,0,0,'emily SAY_SECOND_WOLF_DEFEAT'), +(-1001182,'I think I see the camp! We\'re almost home, Mr. Floppy! Let\'s go!',0,0,0,0,'emily SAY_RESUME_ESCORT'), +(-1001183,'Thank you for helping me to get back to the camp. Go tell Walter that I\'m safe now!',0,0,0,0,'emily SAY_ESCORT_COMPLETE'); + +DELETE FROM script_waypoint WHERE entry=26588; +INSERT INTO script_waypoint VALUES +(26588, 0, 4322.890, -3693.610, 263.910, 4000, 'SAY_ESCORT_START'), +(26588, 1, 4330.509, -3689.442, 263.627, 0, ''), +(26588, 2, 4341.477, -3684.207, 257.441, 0, ''), +(26588, 3, 4346.749, -3685.898, 256.866, 0, ''), +(26588, 4, 4347.176, -3694.563, 256.560, 0, ''), +(26588, 5, 4335.924, -3704.452, 258.113, 0, ''), +(26588, 6, 4317.913, -3722.990, 256.835, 0, ''), +(26588, 7, 4309.215, -3736.347, 257.451, 0, ''), +(26588, 8, 4301.650, -3751.553, 257.810, 0, ''), +(26588, 9, 4296.501, -3769.056, 251.977, 0, ''), +(26588, 10, 4291.985, -3785.022, 245.880, 2000, 'SAY_FIRST_WOLF'), +(26588, 11, 4291.985, -3785.022, 245.880, 0, 'SAY_WOLF_ATTACK'), +(26588, 12, 4291.985, -3785.022, 245.880, 3000, ''), +(26588, 13, 4299.542, -3807.021, 237.238, 0, ''), +(26588, 14, 4308.171, -3835.070, 226.317, 0, ''), +(26588, 15, 4312.530, -3847.574, 222.333, 0, ''), +(26588, 16, 4317.506, -3861.733, 214.915, 0, ''), +(26588, 17, 4325.013, -3882.172, 208.888, 0, ''), +(26588, 18, 4332.627, -3893.466, 203.584, 0, ''), +(26588, 19, 4338.521, -3899.447, 199.843, 0, ''), +(26588, 20, 4344.693, -3911.864, 197.886, 0, ''), +(26588, 21, 4349.635, -3922.679, 195.293, 0, ''), +(26588, 22, 4351.970, -3934.677, 191.418, 0, 'SAY_SECOND_WOLF'), +(26588, 23, 4351.970, -3934.677, 191.418, 3000, ''), +(26588, 24, 4351.970, -3934.677, 191.418, 2000, 'SAY_RESUME_ESCORT'), +(26588, 25, 4350.807, -3944.965, 190.528, 0, 'SAY_ESCORT_COMPLETE'), +(26588, 26, 4347.947, -3958.875, 193.360, 0, ''), +(26588, 27, 4345.956, -3988.083, 187.320, 0, ''); diff --git a/sql/updates/0.8/r3059_mangos.sql b/sql/updates/0.8/r3059_mangos.sql new file mode 100644 index 000000000..1950d7aae --- /dev/null +++ b/sql/updates/0.8/r3059_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_saronite_vapor' WHERE entry=33488; diff --git a/sql/updates/0.8/r3060_mangos.sql b/sql/updates/0.8/r3060_mangos.sql new file mode 100644 index 000000000..3a97730bd --- /dev/null +++ b/sql/updates/0.8/r3060_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_arthas' WHERE entry=26499; diff --git a/sql/updates/0.8/r3060_scriptdev2.sql b/sql/updates/0.8/r3060_scriptdev2.sql new file mode 100644 index 000000000..22b207f73 --- /dev/null +++ b/sql/updates/0.8/r3060_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM gossip_texts WHERE entry IN (-3595006,-3595008); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3595006,'Chromie, you and I both know what\'s going to happen in this time stream. We\'ve seen this all before. Can you just skip us ahead to all the real action?','chromie GOSSIP_ITEM_INN_SKIP'), +(-3595008,'Yes, my Prince. We are ready.','arthas GOSSIP_ITEM_CITY_GATES'); diff --git a/sql/updates/0.8/r3061_scriptdev2.sql b/sql/updates/0.8/r3061_scriptdev2.sql new file mode 100644 index 000000000..efc33caa5 --- /dev/null +++ b/sql/updates/0.8/r3061_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1595002; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1595002,'Oh, no! Adventurers, something awful has happened! A colleague of mine has been captured by the Infinite Dragonflight, and they\'re doing something horrible to him! Keeping Arthas is still your highest priority, but if you act fast you could help save a Guardian of Time!',0,4,0,0,'chromie WHISPER_CHROMIE_GUARDIAN'); diff --git a/sql/updates/0.8/r3062_scriptdev2.sql b/sql/updates/0.8/r3062_scriptdev2.sql new file mode 100644 index 000000000..9c5a5170e --- /dev/null +++ b/sql/updates/0.8/r3062_scriptdev2.sql @@ -0,0 +1,11 @@ +DELETE FROM script_texts WHERE entry IN (-1595003,-1595004,-1595005,-1595006,-1595007,-1595008); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1595003,'Scourge forces have been spotted near the Festival Lane Gate!',0,6,0,0,'lordaeron crier SAY_SCOURGE_FESTIVAL_LANE'), +(-1595004,'Scourge forces have been spotted near the King\'s Square fountain!',0,6,0,0,'lordaeron crier SAY_SCOURGE_KINGS_SQUARE'), +(-1595005,'Scourge forces have been spotted near the Market Row Gate!',0,6,0,0,'lordaeron crier SAY_SCOURGE_MARKET_ROW'), +(-1595006,'Scourge forces have been spotted near the Town Hall!',0,6,0,0,'lordaeron crier SAY_SCOURGE_TOWN_HALL'), +(-1595007,'Scourge forces have been spotted near the Elder\'s Square Gate!',0,6,0,0,'lordaeron crier SAY_SCOURGE_ELDERS_SQUARE'), +(-1595008,'Champions, meet me at the Town Hall at once. We must take the fight to Mal\'Ganis.',14297,6,0,0,'arthas SAY_MEET_TOWN_HALL'); +DELETE FROM gossip_texts WHERE entry=-3595009; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3595009,'We\'re only doing what is best for Lordaeron, your Highness.','arthas GOSSIP_ITEM_TOWN_HALL'); diff --git a/sql/updates/0.8/r3064_mangos.sql b/sql/updates/0.8/r3064_mangos.sql new file mode 100644 index 000000000..2363b8f6d --- /dev/null +++ b/sql/updates/0.8/r3064_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_spell_dummy_crusader_strike' WHERE entry IN (28167,28169); diff --git a/sql/updates/0.8/r3064_scriptdev2.sql b/sql/updates/0.8/r3064_scriptdev2.sql new file mode 100644 index 000000000..feab65637 --- /dev/null +++ b/sql/updates/0.8/r3064_scriptdev2.sql @@ -0,0 +1,125 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1595041 AND -1595009; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1595009,'Follow me, I know the way through.',14298,0,0,1,'arthas SAY_FOLLOW'), +(-1595010,'Ah, you\'ve finally arrived Prince Arthas. You\'re here just in the nick of time.',0,0,0,1,'citizen SAY_ARRIVED'), +(-1595011,'Yes, I\'m glad I could get to you before the plague.',14299,0,0,0,'arthas SAY_GET_BEFORE_PLAGUE'), +(-1595012,'What is this sorcery?',14300,0,0,0,'arthas SAY_SORCERY'), +(-1595013,'There\'s no need for you to understand, Arthas. All you need to do is die.',0,0,0,1,'citizen SAY_NO_UNDERSTAND'), +(-1595014,'Mal\'Ganis appears to have more than Scourge in his arsenal. We should make haste.',14301,0,0,1,'arthas SAY_MORE_THAN_SCOURGE'), +(-1595015,'More vile sorcery! Be ready for anything!',14302,0,0,0,'arthas SAY_MORE_SORCERY'), +(-1595016,'Let\'s move on.',14303,0,0,396,'arthas SAY_MOVE_ON'), +(-1595017,'Watch your backs: they have us surrounded in this hall.',14304,0,0,1,'arthas SAY_WATCH_BACKS'), +(-1595018,'Mal\'Ganis is not making this easy.',14305,0,0,396,'arthas SAY_NOT_EASY'), +(-1595019,'They\'re very persistent.',14306,0,0,396,'arthas SAY_PERSISTENT'), +(-1595020,'What else can he put in my way?',14307,0,0,396,'arthas SAY_ELSE'), +(-1595021,'Prince Arthas Menethil, on this day, a powerful darkness has taken hold of your soul. The death you are destined to visit upon others will this day be your own.',13408,1,0,0,'chrono-lord SAY_DARKNESS'), +(-1595022,'I do what I must for Lordaeron, and neither your words nor your actions will stop me.',14309,0,0,396,'arthas SAY_DO_WHAT_MUST'), +(-1595023,'The quickest path to Mal\'Ganis lies behind that bookshelf ahead.',14308,0,0,0,'arthas SAY_QUICK_PATH'), +(-1595024,'This will only take a moment.',14310,0,0,432,'arthas SAY_TAKE_A_MOMENT'), +(-1595025,'I\'m relieved this secret passage still works.',14311,0,0,0,'arthas SAY_PASSAGE'), +(-1595026,'Let\'s move through here as quickly as possible. If the undead don\'t kill us, the fires might.',14312,0,0,396,'arthas SAY_MOVE_QUICKLY'), +(-1595027,'Rest a moment and clear your lungs, but we must move again soon.',14313,0,0,396,'arthas SAY_REST'), +(-1595028,'That\'s enough; we must move again. Mal\'Ganis awaits.',14314,0,0,396,'arthas SAY_REST_COMPLETE'), +(-1595029,'At last some good luck. Market Row has not caught fire yet. Mal\'Ganis is supposed to be in Crusaders\' Square, which is just ahead. Tell me when you\'re ready to move forward.',14315,0,0,396,'arthas SAY_CRUSADER_SQUARE'), +(-1595030,'Justice will be done.',14316,0,0,0,'arthas SAY_JUSTICE'), +(-1595031,'We\'re going to finish this right now, Mal\'Ganis. Just you... and me.',14317,0,0,5,'arthas SAY_FINISH_MALGANIS'), +(-1595032,'Your journey has just begun, young prince. Gather your forces and meet me in the arctic land of Northrend. It is there that we shall settle the score between us. It is there that your true destiny will unfold.',14412,1,0,378,'malganis SAY_JOURNEY_BEGUN'), +(-1595033,'I\'ll hunt you to the ends of the earth if I have to! Do you hear me? To the ends of the earth!',14318,0,0,0,'arthas SAY_HUNT_MALGANIS'), +(-1595034,'You performed well this day. Anything that Mal\'Ganis has left behind is yours. Take it as your reward. I must now begin plans for an expedition to Northrend.',14319,0,0,1,'arthas SAY_ESCORT_COMPLETE'), +(-1595035,'Protect your prince, soldiers of Lordaeron! I am in need of aid!',14320,0,0,0,'arthas SAY_HALF_HP'), +(-1595036,'I am being overwhelmed, assist me!',14321,0,0,0,'arthas SAY_LOW_HP'), +(-1595037,'Mal\'Ganis will pay for this.',14322,0,0,0,'arthas SAY_SLAY_1'), +(-1595038,'I can\'t afford to spare you.',14323,0,0,0,'arthas SAY_SLAY_2'), +(-1595039,'One less obstacle to deal with.',14324,0,0,0,'arthas SAY_SLAY_3'), +(-1595040,'Agh! Damn you, Mal\'Ganis! Father...Jaina...I have failed Lordaeron...',14325,0,0,0,'arthas SAY_DEATH'), +(-1595041,'My work here is finished!',0,6,0,0,'infinite corruptor SAY_CORRUPTOR_DESPAWN'); + +DELETE FROM gossip_texts WHERE entry IN (-3595010,-3595011,-3595012,-3595013); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3595010,'Lead the way, Prince Arthas','arthas GOSSIP_ITEM_TOWN_HALL_2'), +(-3595011,'I\'m ready.','arthas GOSSIP_ITEM_EPOCH'), +(-3595012,'For Lordaeron!','arthas GOSSIP_ITEM_ESCORT'), +(-3595013,'I\'m ready to battle the dreadlord, sire.','arthas GOSSIP_ITEM_DREADLORD'); + +DELETE FROM script_waypoint WHERE entry=26499; +INSERT INTO script_waypoint VALUES +(26499, 0, 2366.184, 1197.285, 132.150, 0, ''), +(26499, 1, 2371.608, 1199.006, 134.727, 0, ''), +(26499, 2, 2376.157, 1200.552, 134.042, 0, ''), +(26499, 3, 2391.321, 1203.153, 134.125, 10000, 'SAY_ARRIVED'), +(26499, 4, 2391.321, 1203.153, 134.125, 0, 'SAY_GET_BEFORE_PLAGUE'), +(26499, 5, 2396.739, 1205.993, 134.125, 0, 'escort paused'), +(26499, 6, 2396.739, 1205.993, 134.125, 8000, ''), +(26499, 7, 2396.739, 1205.993, 134.125, 5000, 'SAY_MORE_THAN_SCOURGE'), +(26499, 8, 2412.033, 1207.823, 134.034, 0, ''), +(26499, 9, 2426.958, 1212.363, 134.000, 0, ''), +(26499, 10, 2438.589, 1217.005, 133.957, 0, ''), +(26499, 11, 2441.247, 1215.506, 133.951, 0, ''), +(26499, 12, 2446.155, 1197.135, 148.064, 0, ''), +(26499, 13, 2446.861, 1193.559, 148.076, 0, 'SAY_MORE_SORCERY'), +(26499, 14, 2443.582, 1189.773, 148.076, 0, 'escort paused'), +(26499, 15, 2443.582, 1189.773, 148.076, 8000, ''), +(26499, 16, 2443.582, 1189.773, 148.076, 5000, 'SAY_MOVE_ON'), +(26499, 17, 2430.986, 1193.844, 148.076, 0, ''), +(26499, 18, 2418.701, 1195.074, 148.076, 0, ''), +(26499, 19, 2410.825, 1193.033, 148.076, 0, ''), +(26499, 20, 2405.178, 1177.300, 148.076, 0, ''), +(26499, 21, 2409.676, 1155.144, 148.187, 0, 'SAY_WATCH_BACKS - escort paused'), +(26499, 22, 2409.676, 1155.144, 148.187, 8000, ''), +(26499, 23, 2409.676, 1155.144, 148.187, 3000, 'SAY_NOT_EASY'), +(26499, 24, 2413.030, 1138.769, 148.075, 0, ''), +(26499, 25, 2421.589, 1122.539, 148.125, 0, ''), +(26499, 26, 2425.375, 1119.325, 148.075, 0, 'SAY_PERSISTENT'), +(26499, 27, 2425.375, 1119.325, 148.075, 8000, ''), +(26499, 28, 2425.375, 1119.325, 148.075, 0, 'SAY_ELSE - escort paused'), +(26499, 29, 2447.376, 1114.935, 148.075, 0, ''), +(26499, 30, 2454.853, 1117.053, 150.007, 0, ''), +(26499, 31, 2459.909, 1125.710, 150.007, 0, ''), +(26499, 32, 2468.208, 1124.426, 150.027, 5000, 'SAY_TAKE_A_MOMENT'), +(26499, 33, 2468.208, 1124.426, 150.027, 0, 'SAY_PASSAGE'), +(26499, 34, 2482.697, 1122.354, 149.905, 0, ''), +(26499, 35, 2485.536, 1111.682, 149.907, 0, ''), +(26499, 36, 2486.997, 1103.307, 145.335, 0, ''), +(26499, 37, 2490.222, 1100.452, 144.860, 0, ''), +(26499, 38, 2496.676, 1102.510, 144.474, 0, ''), +(26499, 39, 2495.006, 1115.535, 143.825, 0, ''), +(26499, 40, 2493.206, 1123.732, 140.302, 0, ''), +(26499, 41, 2496.522, 1128.798, 140.010, 0, ''), +(26499, 42, 2500.956, 1127.101, 139.982, 0, ''), +(26499, 43, 2504.459, 1120.400, 139.976, 0, ''), +(26499, 44, 2506.478, 1120.344, 139.970, 0, ''), +(26499, 45, 2517.028, 1122.504, 132.064, 0, ''), +(26499, 46, 2523.487, 1124.808, 132.080, 0, 'encounter complete - despawn'), +(26499, 47, 2551.116, 1135.607, 129.797, 0, ''), +(26499, 48, 2562.692, 1147.900, 128.003, 0, ''), +(26499, 49, 2565.026, 1168.818, 127.007, 0, ''), +(26499, 50, 2562.405, 1189.934, 126.189, 0, ''), +(26499, 51, 2558.311, 1212.633, 125.739, 0, ''), +(26499, 52, 2551.082, 1231.603, 125.554, 0, ''), +(26499, 53, 2543.631, 1250.385, 126.103, 0, ''), +(26499, 54, 2534.270, 1272.281, 126.993, 0, ''), +(26499, 55, 2521.446, 1290.463, 130.194, 0, ''), +(26499, 56, 2517.060, 1312.327, 130.156, 0, ''), +(26499, 57, 2513.198, 1324.149, 131.843, 20000, 'SAY_REST'), +(26499, 58, 2513.198, 1324.149, 131.843, 0, 'SAY_REST_COMPLETE'), +(26499, 59, 2503.484, 1347.347, 132.952, 0, ''), +(26499, 60, 2491.935, 1367.205, 130.717, 0, ''), +(26499, 61, 2482.922, 1386.118, 130.029, 0, ''), +(26499, 62, 2471.576, 1404.726, 130.681, 0, ''), +(26499, 63, 2459.646, 1418.801, 130.662, 0, ''), +(26499, 64, 2440.002, 1423.901, 130.632, 0, ''), +(26499, 65, 2416.750, 1419.929, 130.669, 0, ''), +(26499, 66, 2401.423, 1415.888, 130.840, 0, ''), +(26499, 67, 2381.814, 1410.022, 128.147, 0, ''), +(26499, 68, 2367.663, 1406.689, 128.529, 0, ''), +(26499, 69, 2361.863, 1405.020, 128.714, 0, 'SAY_CRUSADER_SQUARE - escort paused'), +(26499, 70, 2341.932, 1406.359, 128.268, 0, ''), +(26499, 71, 2328.375, 1413.144, 127.687, 0, ''), +(26499, 72, 2319.288, 1435.609, 127.887, 0, ''), +(26499, 73, 2308.846, 1460.503, 127.840, 0, ''), +(26499, 74, 2301.277, 1487.081, 128.361, 0, 'SAY_FINISH_MALGANIS - escort paused'), +(26499, 75, 2301.277, 1487.081, 128.361, 18000, 'SAY_JOURNEY_BEGUN'), +(26499, 76, 2293.693, 1506.805, 128.737, 18000, 'SAY_HUNT_MALGANIS'), +(26499, 77, 2300.743, 1487.231, 128.362, 0, ''), +(26499, 78, 2308.582, 1460.863, 127.839, 0, ''), +(26499, 79, 2326.608, 1420.555, 127.780, 0, ''); diff --git a/sql/updates/r3068_mangos.sql b/sql/updates/r3068_mangos.sql new file mode 100644 index 000000000..4644052f1 --- /dev/null +++ b/sql/updates/r3068_mangos.sql @@ -0,0 +1,2 @@ +UPDATE instance_template SET ScriptName='instance_trial_of_the_champion' WHERE map=650; +UPDATE creature_template SET ScriptName='npc_toc_herald' WHERE entry IN (35004, 35005); diff --git a/sql/updates/r3068_scriptdev2.sql b/sql/updates/r3068_scriptdev2.sql new file mode 100644 index 000000000..f85a6db1f --- /dev/null +++ b/sql/updates/r3068_scriptdev2.sql @@ -0,0 +1,5 @@ +DELETE FROM gossip_texts WHERE entry IN (-3650000, -3650001, -3650002); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3650000,'I am ready.','herald GOSSIP_ITEM_READY'), +(-3650001,'I am ready. However, I\'d like to skip the pageantry.','herald GOSSIP_ITEM_READY_SKIP_INTRO'), +(-3650002,'I am ready for the next challenge.','herald GOSSIP_ITEM_READY_NEXT_CHALLENGE'); diff --git a/sql/updates/r3069_scriptdev2.sql b/sql/updates/r3069_scriptdev2.sql new file mode 100644 index 000000000..0538ab3c7 --- /dev/null +++ b/sql/updates/r3069_scriptdev2.sql @@ -0,0 +1,60 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1650051 AND -1650000; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1650000,'The Silver Covenant is pleased to present their contenders for this event, Highlord.',0,1,0,396,'toc herald SAY_HORDE_CHALLENGE'), +(-1650001,'Presenting the fierce Grand Champion of Orgrimmar, Mokra the Skullcrusher!',0,0,0,0,'toc herald SAY_HORDE_WARRIOR'), +(-1650002,'Coming out of the gate is Eressea Dawnsinger, skilled mage and Grand Champion of Silvermoon!',0,0,0,0,'toc herald SAY_HORDE_MAGE'), +(-1650003,'Tall in the saddle of his kodo, here is the venerable Runok Wildmane, Grand Champion of Thunder Bluff!',0,0,0,0,'toc herald SAY_HORDE_SHAMAN'), +(-1650004,'Entering the arena is the lean and dangerous Zul\'tore, Grand Champion of Sen\'jin!',0,0,0,0,'toc herald SAY_HORDE_HUNTER'), +(-1650005,'Representing the tenacity of the Forsaken, here is the Grand Champion of the Undercity, Deathstalker Visceri!',0,0,0,0,'toc herald SAY_HORDE_ROGUE'), + +(-1650006,'The Sunreavers are proud to present their representatives in this trial by combat.',0,1,0,396,'toc herald SAY_ALLIANCE_CHALLENGE'), +(-1650007,'Proud and strong, give a cheer for Marshal Jacob Alerius, the Grand Champion of Stormwind!',0,0,0,0,'toc herald SAY_ALLIANCE_WARRIOR'), +(-1650008,'Here comes the small but deadly Ambrose Boltspark, Grand Champion of Gnomeregan!',0,0,0,0,'toc herald SAY_ALLIANCE_MAGE'), +(-1650009,'Coming out of the gate is Colosos, the towering Grand Champion of the Exodar!',0,0,0,0,'toc herald SAY_ALLIANCE_SHAMAN'), +(-1650010,'Entering the arena is the Grand Champion of Darnassus, the skilled sentinel Jaelyne Evensong!',0,0,0,0,'toc herald SAY_ALLIANCE_HUNTER'), +(-1650011,'The might of the dwarves is represented today by the Grand Champion of Ironforge, Lana Stouthammer!',0,0,0,0,'toc herald SAY_ALLIANCE_ROGUE'), + +(-1650012,'Welcome, champions. Today, before the eyes of your leaders and peers, you will prove yourselves worthy combatants.',0,1,0,1,'tirion SAY_TIRION_WELCOME'), +(-1650013,'You will first be facing three of the Grand Champions of the Tournament! These fierce contenders have beaten out all others to reach the pinnacle of skill in the joust.',0,1,0,1,'tirion SAY_TIRION_FIRST_CHALLENGE'), +(-1650014,'Fight well, Horde! Lok\'tar Ogar!',0,1,0,22,'thrall SAY_THRALL_ALLIANCE_CHALLENGE'), +(-1650015,'Finally, a fight worth watching.',0,1,0,396,'garrosh SAY_GARROSH_ALLIANCE_CHALLENGE'), +(-1650016,'I have no taste for these games, Tirion. Still... I trust they will perform admirably.',0,1,0,1,'king varian SAY_VARIAN_HORDE_CHALLENGE'), +(-1650017,'Begin!',0,1,0,0,'tirion SAY_TIRION_CHAMPIONS_BEGIN'), +(-1650018,'The blood elves of Silvermoon cheer for $n.',0,2,0,0,'raid spectator EMOTE_BLOOD_ELVES'), +(-1650019,'The trolls of the Sen\'jin Village begin a chant to celebrate $n.',0,2,0,0,'raid spectator EMOTE_TROLLS'), +(-1650020,'The tauren of Thunder Bluff cheer for $n.',0,2,0,0,'raid spectator EMOTE_TAUREN'), +(-1650021,'The forsaken of the Undercity cheer for $n.',0,2,0,0,'raid spectator EMOTE_UNDEAD'), +(-1650022,'The orcs of Orgrimmar cheer for $n.',0,2,0,0,'raid spectator EMOTE_ORCS'), +(-1650023,'The dwarves of Ironforge begin a cheer for $n.',0,2,0,0,'raid spectator EMOTE_BLOOD_DWARVES'), +(-1650024,'The gnomes of Gnomeregan cheer for $n.',0,2,0,0,'raid spectator EMOTE_GNOMES'), +(-1650025,'The night elves of Darnassus cheer for $n.',0,2,0,0,'raid spectator EMOTE_NIGHT_ELVES'), +(-1650026,'The humans of Stormwind cheer for $n.',0,2,0,0,'raid spectator EMOTE_HUMANS'), +(-1650027,'The draenei of the Exodar cheer for $n.',0,2,0,0,'raid spectator EMOTE_DRAENEI'), + +(-1650028,'Well fought! Your next challenge comes from the Crusade\'s own ranks. You will be tested against their considerable prowess.',0,1,0,0,'tirion SAY_TIRION_ARGENT_CHAMPION'), +(-1650029,'You may begin!',0,1,0,22,'tirion SAY_TIRION_ARGENT_CHAMPION_BEGIN'), +(-1650030,'Entering the arena, a paladin who is no stranger to the battlefield or tournament ground, the Grand Champion of the Argent Crusade, Eadric the Pure!',0,1,0,0,'toc herald SAY_EADRIC'), +(-1650031,'The next combatant is second to none in her passion for upholding the Light. I give you Argent Confessor Paletress!',0,1,0,0,'toc herald SAY_PALETRESS'), +(-1650032,'The Horde spectators cheer for $n.',0,2,0,0,'raid spectator EMOTE_HORDE_ARGENT_CHAMPION'), +(-1650033,'The Alliance spectators cheer for $n.',0,2,0,0,'raid spectator EMOTE_ALLIANCE_ARGENT_CHAMPION'), +(-1650034,'Are you up to the challenge? I will not hold back.',16134,0,0,397,'eadric SAY_EADRIC_INTRO'), +(-1650035,'Thank you, good herald. Your words are too kind.',16245,0,0,2,'paletress SAY_PALETRESS_INTRO_1'), +(-1650036,'May the Light give me strength to provide a worthy challenge.',16246,0,0,16,'paletress SAY_PALETRESS_INTRO_2'), + +(-1650037,'Well done. You have proven yourself today-',0,1,0,0,'tirion SAY_ARGENT_CHAMPION_COMPLETE'), +(-1650038,'What\'s that, up near the rafters?',0,0,0,25,'toc herald SAY_BLACK_KNIGHT_SPAWN'), +(-1650039,'You spoiled my grand entrance, rat.',16256,0,0,0,'black knight SAY_BLACK_KNIGHT_INTRO_1'), +(-1650040,'What is the meaning of this?',0,1,0,0,'tirion SAY_TIRION_BLACK_KNIGHT_INTRO_2'), +(-1650041,'Did you honestly think an agent of the Lich King would be bested on the field of your pathetic little tournament?',16257,0,0,396,'black knight SAY_BLACK_KNIGHT_INTRO_3'), +(-1650042,'I\'ve come to finish my task.',16258,0,0,396,'black knight SAY_BLACK_KNIGHT_INTRO_4'), + +(-1650043,'My congratulations, champions. Through trials both planned and unexpected, you have triumphed.',0,1,0,0,'tirion SAY_EPILOG_1'), +(-1650044,'Go now and rest; you\'ve earned it.',0,1,0,0,'tirion SAY_EPILOG_2'), +(-1650045,'You fought well.',0,1,0,66,'king varian SAY_VARIAN_EPILOG_3'), +(-1650046,'Well done, Horde!',0,1,0,66,'thrall SAY_THRALL_HORDE_EPILOG_3'), + +(-1650047,'Tear him apart!',0,1,0,22,'garrosh SAY_GARROSH_OTHER_1'), +(-1650048,'Garrosh, enough.',0,1,0,396,'thrall SAY_THRALL_OTHER_2'), +(-1650049,'Admirably? Hah! I will enjoy watching your weak little champions fail, human.',0,1,0,22,'garrosh SAY_GARROSH_OTHER_3'), +(-1650050,'Don\'t just stand there; kill him!',0,1,0,22,'king varian SAY_VARIAN_OTHER_4'), +(-1650051,'I did not come here to watch animals tear at each other senselessly, Tirion.',0,1,0,1,'king varian SAY_VARIAN_OTHER_5'); diff --git a/sql/updates/r3070_mangos.sql b/sql/updates/r3070_mangos.sql new file mode 100644 index 000000000..4a82a582b --- /dev/null +++ b/sql/updates/r3070_mangos.sql @@ -0,0 +1,3 @@ +DELETE FROM scripted_areatrigger WHERE entry=3587; +INSERT INTO scripted_areatrigger VALUES +(3587,'at_ancient_leaf'); diff --git a/sql/updates/r3071_mangos.sql b/sql/updates/r3071_mangos.sql new file mode 100644 index 000000000..3cc689c21 --- /dev/null +++ b/sql/updates/r3071_mangos.sql @@ -0,0 +1 @@ +UPDATE gameobject_template SET ScriptName='go_fathom_stone' WHERE entry=177964; diff --git a/sql/updates/r3072_scriptdev2.sql b/sql/updates/r3072_scriptdev2.sql new file mode 100644 index 000000000..6d12c0b2d --- /dev/null +++ b/sql/updates/r3072_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12799+) '; diff --git a/sql/updates/r3075_mangos.sql b/sql/updates/r3075_mangos.sql new file mode 100644 index 000000000..b3e214516 --- /dev/null +++ b/sql/updates/r3075_mangos.sql @@ -0,0 +1,6 @@ +UPDATE creature_template SET ScriptName='boss_champion_warrior' WHERE entry IN (34705,35572); +UPDATE creature_template SET ScriptName='boss_champion_mage' WHERE entry IN (34702,35569); +UPDATE creature_template SET ScriptName='boss_champion_shaman' WHERE entry IN (34701,35571); +UPDATE creature_template SET ScriptName='boss_champion_hunter' WHERE entry IN (34657,35570); +UPDATE creature_template SET ScriptName='boss_champion_rogue' WHERE entry IN (34703,35617); +UPDATE creature_template SET ScriptName='npc_champion_mount' WHERE entry IN (35644,36559,35637,35633,35768,34658,35636,35638,35635,35640,35641,35634); diff --git a/sql/updates/r3077_scriptdev2.sql b/sql/updates/r3077_scriptdev2.sql new file mode 100644 index 000000000..a924a454f --- /dev/null +++ b/sql/updates/r3077_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12803+) '; diff --git a/sql/updates/r3078_scriptdev2.sql b/sql/updates/r3078_scriptdev2.sql new file mode 100644 index 000000000..9aeec68dc --- /dev/null +++ b/sql/updates/r3078_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1429003; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1429003,'The king is dead - OH NOES! Summon Mizzle da Crafty! He knows what to do next!',0,1,0,0,'cho\'rush SAY_KING_DEAD'); diff --git a/sql/updates/r3089_scriptdev2.sql b/sql/updates/r3089_scriptdev2.sql new file mode 100644 index 000000000..0524ad742 --- /dev/null +++ b/sql/updates/r3089_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12807+) '; diff --git a/sql/updates/r3091_mangos.sql b/sql/updates/r3091_mangos.sql new file mode 100644 index 000000000..bd4c2673a --- /dev/null +++ b/sql/updates/r3091_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_trial_grand_champion' WHERE entry IN (35328,35331,35330,35332,35329,35314,35326,35325,35323,35327); diff --git a/sql/updates/r3092_scriptdev2.sql b/sql/updates/r3092_scriptdev2.sql new file mode 100644 index 000000000..e03e69b77 --- /dev/null +++ b/sql/updates/r3092_scriptdev2.sql @@ -0,0 +1,2 @@ +UPDATE script_texts SET sound=13941 WHERE entry=-1601025; +UPDATE script_texts SET sound=13942 WHERE entry=-1601026; diff --git a/sql/updates/r3096_mangos.sql b/sql/updates/r3096_mangos.sql new file mode 100644 index 000000000..ca2063e11 --- /dev/null +++ b/sql/updates/r3096_mangos.sql @@ -0,0 +1,3 @@ +UPDATE instance_template SET ScriptName='instance_razorfen_downs' WHERE map=129; +DELETE FROM scripted_event_id WHERE id=3130; +INSERT INTO scripted_event_id VALUES (3130, 'event_go_tutenkash_gong'); diff --git a/sql/updates/r3097_scriptdev2.sql b/sql/updates/r3097_scriptdev2.sql new file mode 100644 index 000000000..543f094d8 --- /dev/null +++ b/sql/updates/r3097_scriptdev2.sql @@ -0,0 +1 @@ +UPDATE sd2_db_version SET version='ScriptDev2 (for CMaNGOS 12839+) '; diff --git a/sql/updates/r3098_mangos.sql b/sql/updates/r3098_mangos.sql new file mode 100644 index 000000000..9edf536b8 --- /dev/null +++ b/sql/updates/r3098_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_eadric' WHERE entry=35119; +UPDATE creature_template SET ScriptName='boss_paletress' WHERE entry=34928; diff --git a/sql/updates/r3099_scriptdev2.sql b/sql/updates/r3099_scriptdev2.sql new file mode 100644 index 000000000..9e0f3d0e7 --- /dev/null +++ b/sql/updates/r3099_scriptdev2.sql @@ -0,0 +1,16 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1650064 AND -1650052; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1650052,'Prepare yourselves!',16135,1,0,0,'eadric SAY_AGGRO'), +(-1650053,'Hammer of the Righteous!',16136,1,0,0,'eadric SAY_HAMMER'), +(-1650054,'You... You need more practice.',16137,1,0,0,'eadric SAY_KILL_1'), +(-1650055,'Nay! Nay! And I say yet again nay! Not good enough!',16138,1,0,0,'eadric SAY_KILL_2'), +(-1650056,'I yield! I submit. Excellent work. May I run away now?',16139,1,0,0,'eadric SAY_DEFEAT'), +(-1650057,'%s begins to radiate light. Shield your eyes!',0,3,0,0,'eadric EMOTE_RADIATE'), +(-1650058,'%s targets $N with the Hammer of the Righteous!',0,3,0,0,'eadric EMOTE_HAMMER'), + +(-1650059,'Well then, let us begin.',16247,1,0,0,'paletress SAY_AGGRO'), +(-1650060,'Take this time to consider your past deeds.',16248,1,0,0,'paletress SAY_MEMORY'), +(-1650061,'Even the darkest memory fades when confronted.',16249,1,0,0,'paletress SAY_MEMORY_DIES'), +(-1650062,'Take your rest.',16250,1,0,0,'paletress SAY_KILL_1'), +(-1650063,'Be at ease.',16251,1,0,0,'paletress SAY_KILL_2'), +(-1650064,'Excellent work!',16252,1,0,0,'paletress SAY_DEFEAT'); diff --git a/sql/updates/r3101_mangos.sql b/sql/updates/r3101_mangos.sql new file mode 100644 index 000000000..85bd02292 --- /dev/null +++ b/sql/updates/r3101_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='boss_black_knight' WHERE entry=35451; +UPDATE creature_template SET ScriptName='npc_black_knight_gryphon' WHERE entry=35491; diff --git a/sql/updates/r3102_scriptdev2.sql b/sql/updates/r3102_scriptdev2.sql new file mode 100644 index 000000000..83ba22bd4 --- /dev/null +++ b/sql/updates/r3102_scriptdev2.sql @@ -0,0 +1,8 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1650070 AND -1650065; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1650065,'This farce ends here!',16259,1,0,0,'black knight SAY_AGGRO'), +(-1650066,'My rotting flesh was just getting in the way!',16262,1,0,0,'black knight SAY_PHASE_2'), +(-1650067,'I have no need for bones to best you!',16263,1,0,0,'black knight SAY_PHASE_3'), +(-1650068,'A waste of flesh.',16260,1,0,0,'black knight SAY_KILL_1'), +(-1650069,'Pathetic.',16261,1,0,0,'black knight SAY_KILL_2'), +(-1650070,'No! I must not fail... again...',16264,1,0,0,'black knight SAY_DEATH'); diff --git a/sql/updates/r3103_mangos.sql b/sql/updates/r3103_mangos.sql new file mode 100644 index 000000000..212d67349 --- /dev/null +++ b/sql/updates/r3103_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_black_knight_ghoul' WHERE entry IN (35545,35564,35590); diff --git a/sql/updates/r3113_scriptdev2.sql b/sql/updates/r3113_scriptdev2.sql new file mode 100644 index 000000000..eb97dfab7 --- /dev/null +++ b/sql/updates/r3113_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1649076; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1649076,'As its companion perishes, %s becomes enraged!',0,3,0,0,'twin jormungars EMOTE_JORMUNGAR_ENRAGE'); diff --git a/sql/updates/r3114_scriptdev2.sql b/sql/updates/r3114_scriptdev2.sql new file mode 100644 index 000000000..d183d8ccb --- /dev/null +++ b/sql/updates/r3114_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=-1649077; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1649077,'%s crashes into the Coliseum wall and is stunned!',0,3,0,0,'icehowl EMOTE_WALL_CRASH'); diff --git a/sql/updates/r3115_scriptdev2.sql b/sql/updates/r3115_scriptdev2.sql new file mode 100644 index 000000000..238136cec --- /dev/null +++ b/sql/updates/r3115_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM gossip_texts WHERE entry=-3649011; +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3649011,'We\'re ready for the next challenge.','barrett GOSSIP_ITEM_JARAXXUS_START'); diff --git a/sql/updates/r3116_mangos.sql b/sql/updates/r3116_mangos.sql new file mode 100644 index 000000000..810a3e058 --- /dev/null +++ b/sql/updates/r3116_mangos.sql @@ -0,0 +1,14 @@ +UPDATE creature_template SET ScriptName='boss_crusader_death_knight' WHERE entry IN (34461,34458); +UPDATE creature_template SET ScriptName='boss_crusader_druid_balance' WHERE entry IN (34460,34451); +UPDATE creature_template SET ScriptName='boss_crusader_druid_resto' WHERE entry IN (34469,34459); +UPDATE creature_template SET ScriptName='boss_crusader_hunter' WHERE entry IN (34467,34448); +UPDATE creature_template SET ScriptName='boss_crusader_mage' WHERE entry IN (34468,34449); +UPDATE creature_template SET ScriptName='boss_crusader_paladin_holy' WHERE entry IN (34465,34445); +UPDATE creature_template SET ScriptName='boss_crusader_paladin_retri' WHERE entry IN (34471,34456); +UPDATE creature_template SET ScriptName='boss_crusader_priest_disc' WHERE entry IN (34466,34447); +UPDATE creature_template SET ScriptName='boss_crusader_priest_shadow' WHERE entry IN (34473,34441); +UPDATE creature_template SET ScriptName='boss_crusader_rogue' WHERE entry IN (34472,34454); +UPDATE creature_template SET ScriptName='boss_crusader_shaman_enha' WHERE entry IN (34463,34455); +UPDATE creature_template SET ScriptName='boss_crusader_shaman_resto' WHERE entry IN (34470,34444); +UPDATE creature_template SET ScriptName='boss_crusader_warlock' WHERE entry IN (34474,34450); +UPDATE creature_template SET ScriptName='boss_crusader_warrior' WHERE entry IN (34475,34453); diff --git a/sql/updates/r3116_scriptdev2.sql b/sql/updates/r3116_scriptdev2.sql new file mode 100644 index 000000000..b983d77e7 --- /dev/null +++ b/sql/updates/r3116_scriptdev2.sql @@ -0,0 +1,6 @@ +UPDATE script_texts SET emote=5 WHERE entry IN (-1649012,-1649014,-1649017,-1649021,-1649051,-1649015,-1649019,-1649033,-1649018,-1649026,-1649022,-1649024,-1649052); +UPDATE script_texts SET emote=1 WHERE entry IN (-1649025,-1649023,-1649003,-1649031,-1649004,-1649027); +UPDATE script_texts SET emote=274 WHERE entry IN (-1649049,-1649053); +UPDATE script_texts SET emote=6 WHERE entry IN (-1649055); +UPDATE script_texts SET emote=25 WHERE entry IN (-1649050,-1649035,-1649054); +UPDATE script_texts SET emote=397 WHERE entry IN (-1649013); diff --git a/sql/updates/r3117_scriptdev2.sql b/sql/updates/r3117_scriptdev2.sql new file mode 100644 index 000000000..e2554b5b0 --- /dev/null +++ b/sql/updates/r3117_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM gossip_texts WHERE entry IN (-3649012,-3649013); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3649012,'You\'ll be even more amazed after we take them out!','barrett GOSSIP_ITEM_PVP_WIPE_INIT'), +(-3649013,'We\'re ready for anything!','barrett GOSSIP_ITEM_PVP_WIPE_START'); diff --git a/sql/updates/r3121_scriptdev2.sql b/sql/updates/r3121_scriptdev2.sql new file mode 100644 index 000000000..f8eac5a4f --- /dev/null +++ b/sql/updates/r3121_scriptdev2.sql @@ -0,0 +1,6 @@ +DELETE FROM gossip_texts WHERE entry IN (-3649014,-3649015,-3649016,-3649017); +INSERT INTO gossip_texts (entry,content_default,comment) VALUES +(-3649014,'We\'re ready. This time things will be different.','barrett GOSSIP_ITEM_BEAST_WIPE_START'), +(-3649015,'Now.','barrett GOSSIP_ITEM_JARAXXUS_WIPE_START'), +(-3649016,'We\'ll just have to improve our teamwork to match the two of them.','barrett GOSSIP_ITEM_TWINS_WIPE_INIT'), +(-3649017,'Just bring them out again, then watch.','barrett GOSSIP_ITEM_TWINS_WIPE_START'); diff --git a/sql/updates/r3122_mangos.sql b/sql/updates/r3122_mangos.sql new file mode 100644 index 000000000..dfc66b228 --- /dev/null +++ b/sql/updates/r3122_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_light_orb_collector' WHERE entry IN (21926,22333); diff --git a/sql/updates/r3125_mangos.sql b/sql/updates/r3125_mangos.sql new file mode 100644 index 000000000..f3997130d --- /dev/null +++ b/sql/updates/r3125_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='' WHERE entry=28912; diff --git a/sql/updates/r3125_scriptdev2.sql b/sql/updates/r3125_scriptdev2.sql new file mode 100644 index 000000000..83e92b62a --- /dev/null +++ b/sql/updates/r3125_scriptdev2.sql @@ -0,0 +1,2 @@ +DELETE FROM script_waypoint WHERE entry=28912; +DELETE FROM script_texts WHERE entry BETWEEN -1609088 AND -1609079; diff --git a/sql/updates/r3126_mangos.sql b/sql/updates/r3126_mangos.sql new file mode 100644 index 000000000..8973f6f32 --- /dev/null +++ b/sql/updates/r3126_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_scarlet_courier' WHERE entry=29076; diff --git a/sql/updates/r3126_scriptdev2.sql b/sql/updates/r3126_scriptdev2.sql new file mode 100644 index 000000000..08c8fddf6 --- /dev/null +++ b/sql/updates/r3126_scriptdev2.sql @@ -0,0 +1,4 @@ +DELETE FROM script_texts WHERE entry IN (-1609079,-1609080); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609079,'Hrm, what a strange tree. I must investigate.',0,0,0,1,'scarlet courier SAY_TREE_1'), +(-1609080,'What\'s this!? This isn\'t a tree at all! Guards! Guards!',0,0,0,5,'scarlet courier SAY_TREE_2'); diff --git a/sql/updates/r3130_mangos.sql b/sql/updates/r3130_mangos.sql new file mode 100644 index 000000000..684053fd4 --- /dev/null +++ b/sql/updates/r3130_mangos.sql @@ -0,0 +1 @@ +UPDATE creature_template SET ScriptName='npc_grand_admiral_westwind' WHERE entry=29621; diff --git a/sql/updates/r3130_scriptdev2.sql b/sql/updates/r3130_scriptdev2.sql new file mode 100644 index 000000000..fe4f3070e --- /dev/null +++ b/sql/updates/r3130_scriptdev2.sql @@ -0,0 +1,9 @@ +DELETE FROM script_texts WHERE entry BETWEEN -1001190 AND -1001184; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1001184,'How did you find me? Did Landgren tell?',14201,0,0,0,'admiral_westwind SAY_AGGRO'), +(-1001185,'You thought I would just let you kill me?',14205,0,0,0,'admiral_westwind SAY_SPHERE'), +(-1001186,'WHAT?! No matter. Even without my sphere, I will crush you! Behold my true identity and despair!',14207,1,0,0,'admiral_westwind SAY_NO_MATTER'), +(-1001187,'Gah! I spent too much time in that weak little shell.',14426,1,0,0,'malganis_icecrown SAY_TRANSFORM'), +(-1001188,'Kirel narak! I am Mal\'Ganis. I AM ETERNAL!',14427,1,0,0,'malganis_icecrown SAY_20_HP'), +(-1001189,'ENOUGH! I waste my time here. I must gather my strength on the homeworld.',14428,1,0,0,'malganis_icecrown SAY_DEFEATED'), +(-1001190,'You\'ll never defeat the Lich King without my forces. I\'ll have my revenge... on him AND you!',14429,1,0,0,'malganis_icecrown SAY_ESCAPE'); diff --git a/sql/updates/r3131_mangos.sql b/sql/updates/r3131_mangos.sql new file mode 100644 index 000000000..e739a2893 --- /dev/null +++ b/sql/updates/r3131_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_concentrated_bullet' WHERE entry IN (34628,34630); +UPDATE creature_template SET ScriptName='npc_valkyr_stalker' WHERE entry IN (34704,34720); diff --git a/sql/updates/r3135_mangos.sql b/sql/updates/r3135_mangos.sql new file mode 100644 index 000000000..fa63be971 --- /dev/null +++ b/sql/updates/r3135_mangos.sql @@ -0,0 +1 @@ +UPDATE instance_template SET ScriptName='instance_halls_of_reflection' WHERE map=668; diff --git a/sql/updates/r3140_mangos.sql b/sql/updates/r3140_mangos.sql new file mode 100644 index 000000000..0e03f08d9 --- /dev/null +++ b/sql/updates/r3140_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='npc_bone_spike' WHERE entry IN (36619,38711,38712); +UPDATE creature_template SET ScriptName='npc_coldflame' WHERE entry=36672; diff --git a/sql/updates/r3143_scriptdev2.sql b/sql/updates/r3143_scriptdev2.sql new file mode 100644 index 000000000..ae3b739b5 --- /dev/null +++ b/sql/updates/r3143_scriptdev2.sql @@ -0,0 +1,6 @@ +UPDATE script_texts SET emote=25 WHERE entry=-1230005; +UPDATE script_texts SET emote=5 WHERE entry=-1230004; +UPDATE script_texts SET emote=15 WHERE entry=-1230006; +UPDATE script_texts SET emote=153 WHERE entry=-1230008; +UPDATE script_texts SET emote=1 WHERE entry=-1230007; +UPDATE script_texts SET emote=5 WHERE entry=-1230009; diff --git a/sql/updates/r3148_scriptdev2.sql b/sql/updates/r3148_scriptdev2.sql new file mode 100644 index 000000000..e15344214 --- /dev/null +++ b/sql/updates/r3148_scriptdev2.sql @@ -0,0 +1,3 @@ +DELETE FROM script_texts WHERE entry=1230035; +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1230035,'%s cries out an alarm!',0,2,0,0,'general_angerforge EMOTE_ALARM'); diff --git a/sql/updates/r3153_mangos.sql b/sql/updates/r3153_mangos.sql new file mode 100644 index 000000000..7cf5dae33 --- /dev/null +++ b/sql/updates/r3153_mangos.sql @@ -0,0 +1,2 @@ +UPDATE creature_template SET ScriptName='guard_orgrimmar' WHERE entry=14304; +UPDATE creature_template SET ScriptName='guard_stormwind' WHERE entry IN (68,1756,1976); diff --git a/sql/updates/r3153_scriptdev2.sql b/sql/updates/r3153_scriptdev2.sql new file mode 100644 index 000000000..641c7976c --- /dev/null +++ b/sql/updates/r3153_scriptdev2.sql @@ -0,0 +1,13 @@ +DELETE FROM script_texts WHERE entry IN (-1609081,-1609082,-1609083,-1609084,-1609085,-1609086,-1609087,-1609088,-1609287,-1609288,-1609289); +INSERT INTO script_texts (entry,content_default,sound,type,language,emote,comment) VALUES +(-1609081,'%s throws rotten apple on $N.',0,2,0,0,'city guard EMOTE_APPLE'), +(-1609082,'%s throws rotten banana on $N.',0,2,0,0,'city guard EMOTE_BANANA'), +(-1609083,'%s spits on $N.',0,2,0,0,'city guard EMOTE_SPIT'), +(-1609084,'Monster!',0,0,0,14,'city guard SAY_RANDOM_1'), +(-1609085,'Murderer!',0,0,0,14,'city guard SAY_RANDOM_2'), +(-1609086,'GET A ROPE!',0,0,0,25,'city guard SAY_RANDOM_3'), +(-1609087,'How dare you set foot in our city!',0,0,0,25,'city guard SAY_RANDOM_4'), +(-1609088,'You disgust me.',0,0,0,14,'city guard SAY_RANDOM_5'), +(-1609287,'Looks like we\'re going to have ourselves an execution.',0,0,0,25,'city guard SAY_RANDOM_6'), +(-1609288,'Traitorous dog.',0,0,0,14,'city guard SAY_RANDOM_7'), +(-1609289,'My family was wiped out by the Scourge! MONSTER!',0,0,0,25,'city guard SAY_RANDOM_8'); diff --git a/system/MangosdRev.cpp b/system/MangosdRev.cpp index 62a73dc04..5888ba623 100644 --- a/system/MangosdRev.cpp +++ b/system/MangosdRev.cpp @@ -1,9 +1,7 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ -#include "../../../shared/revision_nr.h" - #ifdef WIN32 # define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport) #elif defined( __GNUC__ ) @@ -11,9 +9,3 @@ #else # define MANGOS_DLL_EXPORT extern "C" export #endif - -MANGOS_DLL_EXPORT -char const* GetMangosRevStr() -{ - return REVISION_NR; -} diff --git a/system/ScriptLoader.cpp b/system/ScriptLoader.cpp index 1cb195bfc..881688966 100644 --- a/system/ScriptLoader.cpp +++ b/system/ScriptLoader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -26,32 +26,19 @@ extern void AddSC_npc_professions(); extern void AddSC_npcs_special(); extern void AddSC_spell_scripts(); extern void AddSC_world_map_scripts(); +extern void AddSC_world_map_ebon_hold(); // eastern kingdoms extern void AddSC_blackrock_depths(); // blackrock_depths extern void AddSC_boss_ambassador_flamelash(); -extern void AddSC_boss_anubshiah(); extern void AddSC_boss_coren_direbrew(); extern void AddSC_boss_draganthaurissan(); extern void AddSC_boss_general_angerforge(); -extern void AddSC_boss_gorosh_the_dervish(); -extern void AddSC_boss_grizzle(); extern void AddSC_boss_high_interrogator_gerstahn(); -extern void AddSC_boss_magmus(); -extern void AddSC_boss_tomb_of_seven(); extern void AddSC_instance_blackrock_depths(); -extern void AddSC_boss_drakkisath(); // blackrock_spire -extern void AddSC_boss_halycon(); -extern void AddSC_boss_highlordomokk(); -extern void AddSC_boss_mothersmolderweb(); -extern void AddSC_boss_overlordwyrmthalak(); -extern void AddSC_boss_shadowvosh(); -extern void AddSC_boss_thebeast(); -extern void AddSC_boss_warmastervoone(); -extern void AddSC_boss_quatermasterzigris(); +extern void AddSC_boss_overlordwyrmthalak(); // blackrock_spire extern void AddSC_boss_pyroguard_emberseer(); extern void AddSC_boss_gyth(); -extern void AddSC_boss_rend_blackhand(); extern void AddSC_instance_blackrock_spire(); extern void AddSC_boss_razorgore(); // blackwing_lair extern void AddSC_boss_vaelastrasz(); @@ -102,34 +89,19 @@ extern void AddSC_instance_molten_core(); extern void AddSC_molten_core(); extern void AddSC_ebon_hold(); // scarlet_enclave extern void AddSC_boss_arcanist_doan(); // scarlet_monastery -extern void AddSC_boss_azshir_the_sleepless(); -extern void AddSC_boss_bloodmage_thalnos(); extern void AddSC_boss_herod(); -extern void AddSC_boss_high_inquisitor_fairbanks(); -extern void AddSC_boss_houndmaster_loksey(); -extern void AddSC_boss_interrogator_vishas(); extern void AddSC_boss_mograine_and_whitemane(); -extern void AddSC_boss_scorn(); extern void AddSC_boss_headless_horseman(); extern void AddSC_instance_scarlet_monastery(); extern void AddSC_boss_darkmaster_gandling(); // scholomance -extern void AddSC_boss_death_knight_darkreaver(); extern void AddSC_boss_jandicebarov(); -extern void AddSC_boss_kormok(); -extern void AddSC_boss_vectus(); extern void AddSC_instance_scholomance(); extern void AddSC_boss_hummel(); // shadowfang_keep extern void AddSC_shadowfang_keep(); extern void AddSC_instance_shadowfang_keep(); -extern void AddSC_boss_magistrate_barthilas(); // stratholme -extern void AddSC_boss_maleki_the_pallid(); -extern void AddSC_boss_nerubenkan(); +extern void AddSC_boss_maleki_the_pallid(); // stratholme extern void AddSC_boss_cannon_master_willey(); extern void AddSC_boss_baroness_anastari(); -extern void AddSC_boss_ramstein_the_gorger(); -extern void AddSC_boss_timmy_the_cruel(); -extern void AddSC_boss_postmaster_malown(); -extern void AddSC_boss_baron_rivendare(); extern void AddSC_boss_dathrohan_balnazzar(); extern void AddSC_boss_order_of_silver_hand(); extern void AddSC_instance_stratholme(); @@ -155,8 +127,6 @@ extern void AddSC_instance_zulaman(); extern void AddSC_zulaman(); extern void AddSC_boss_zuljin(); extern void AddSC_boss_arlokk(); // zulgurub -extern void AddSC_boss_gahzranka(); -extern void AddSC_boss_grilek(); extern void AddSC_boss_hakkar(); extern void AddSC_boss_hazzarah(); extern void AddSC_boss_jeklik(); @@ -167,13 +137,11 @@ extern void AddSC_boss_ouro(); extern void AddSC_boss_renataki(); extern void AddSC_boss_thekal(); extern void AddSC_boss_venoxis(); -extern void AddSC_boss_wushoolay(); extern void AddSC_instance_zulgurub(); -//extern void AddSC_alterac_mountains(); +extern void AddSC_alterac_mountains(); extern void AddSC_arathi_highlands(); extern void AddSC_blasted_lands(); -extern void AddSC_boss_kruul(); extern void AddSC_burning_steppes(); extern void AddSC_dun_morogh(); extern void AddSC_eastern_plaguelands(); @@ -207,22 +175,16 @@ extern void AddSC_instance_dark_portal(); extern void AddSC_hyjal(); // COT, hyjal extern void AddSC_boss_archimonde(); extern void AddSC_instance_mount_hyjal(); -extern void AddSC_boss_captain_skarloc(); // COT, old_hillsbrad -extern void AddSC_boss_epoch_hunter(); -extern void AddSC_boss_lieutenant_drake(); -extern void AddSC_instance_old_hillsbrad(); +extern void AddSC_instance_old_hillsbrad(); // COT, old_hillsbrad extern void AddSC_old_hillsbrad(); extern void AddSC_culling_of_stratholme(); // COT, culling_of_stratholme extern void AddSC_instance_culling_of_stratholme(); extern void AddSC_dire_maul(); // dire_maul extern void AddSC_instance_dire_maul(); -extern void AddSC_boss_celebras_the_cursed(); // maraudon -extern void AddSC_boss_landslide(); -extern void AddSC_boss_noxxion(); -extern void AddSC_boss_ptheradras(); +extern void AddSC_boss_noxxion(); // maraudon extern void AddSC_boss_onyxia(); // onyxias_lair extern void AddSC_instance_onyxias_lair(); -extern void AddSC_boss_amnennar_the_coldbringer(); // razorfen_downs +extern void AddSC_instance_razorfen_downs(); // razorfen_downs extern void AddSC_razorfen_downs(); extern void AddSC_instance_razorfen_kraul(); // razorfen_kraul extern void AddSC_razorfen_kraul(); @@ -231,6 +193,7 @@ extern void AddSC_boss_buru(); extern void AddSC_boss_kurinnaxx(); extern void AddSC_boss_ossirian(); extern void AddSC_boss_moam(); +extern void AddSC_boss_rajaxx(); extern void AddSC_ruins_of_ahnqiraj(); extern void AddSC_instance_ruins_of_ahnqiraj(); extern void AddSC_boss_cthun(); // temple_of_ahnqiraj @@ -274,7 +237,8 @@ extern void AddSC_ungoro_crater(); extern void AddSC_winterspring(); // northrend -extern void AddSC_boss_jedoga(); // azjol-nerub, ahnkahet +extern void AddSC_boss_amanitar(); // azjol-nerub, ahnkahet +extern void AddSC_boss_jedoga(); extern void AddSC_boss_nadox(); extern void AddSC_boss_taldaram(); extern void AddSC_boss_volazj(); @@ -283,9 +247,11 @@ extern void AddSC_boss_anubarak(); // azjol-nerub, azjo extern void AddSC_boss_hadronox(); extern void AddSC_boss_krikthir(); extern void AddSC_instance_azjol_nerub(); -extern void AddSC_trial_of_the_champion(); // CC, trial_of_the_champion +extern void AddSC_boss_argent_challenge(); // CC, trial_of_the_champion +extern void AddSC_boss_black_knight(); extern void AddSC_boss_grand_champions(); extern void AddSC_instance_trial_of_the_champion(); +extern void AddSC_trial_of_the_champion(); extern void AddSC_boss_anubarak_trial(); // CC, trial_of_the_crusader extern void AddSC_boss_faction_champions(); extern void AddSC_boss_jaraxxus(); @@ -346,6 +312,7 @@ extern void AddSC_boss_sapphiron(); extern void AddSC_boss_thaddius(); extern void AddSC_instance_naxxramas(); extern void AddSC_boss_malygos(); // nexus, eye_of_eternity +extern void AddSC_instance_eye_of_eternity(); extern void AddSC_boss_anomalus(); // nexus, nexus extern void AddSC_boss_keristrasza(); extern void AddSC_boss_ormorok(); @@ -353,7 +320,9 @@ extern void AddSC_boss_telestra(); extern void AddSC_instance_nexus(); extern void AddSC_boss_eregos(); // nexus, oculus extern void AddSC_boss_urom(); +extern void AddSC_boss_varos(); extern void AddSC_instance_oculus(); +extern void AddSC_oculus(); extern void AddSC_boss_sartharion(); // obsidian_sanctum extern void AddSC_instance_obsidian_sanctum(); extern void AddSC_boss_baltharus(); // ruby_sanctum @@ -472,7 +441,9 @@ extern void AddSC_boss_warbringer_omrogg(); extern void AddSC_boss_warchief_kargath_bladefist(); extern void AddSC_instance_shattered_halls(); extern void AddSC_arcatraz(); // TK, arcatraz +extern void AddSC_boss_dalliah(); extern void AddSC_boss_harbinger_skyriss(); +extern void AddSC_boss_soccothrates(); extern void AddSC_instance_arcatraz(); extern void AddSC_boss_high_botanist_freywinn(); // TK, botanica extern void AddSC_boss_laj(); @@ -482,9 +453,7 @@ extern void AddSC_boss_high_astromancer_solarian(); extern void AddSC_boss_kaelthas(); extern void AddSC_boss_void_reaver(); extern void AddSC_instance_the_eye(); -extern void AddSC_the_eye(); -extern void AddSC_boss_gatewatcher_iron_hand(); // TK, the_mechanar -extern void AddSC_boss_nethermancer_sepethrea(); +extern void AddSC_boss_nethermancer_sepethrea(); // TK, the_mechanar extern void AddSC_boss_pathaleon_the_calculator(); extern void AddSC_instance_mechanar(); @@ -523,32 +492,19 @@ void AddScripts() AddSC_npcs_special(); AddSC_spell_scripts(); AddSC_world_map_scripts(); + AddSC_world_map_ebon_hold(); // eastern kingdoms AddSC_blackrock_depths(); // blackrock_depths AddSC_boss_ambassador_flamelash(); - AddSC_boss_anubshiah(); AddSC_boss_coren_direbrew(); AddSC_boss_draganthaurissan(); AddSC_boss_general_angerforge(); - AddSC_boss_gorosh_the_dervish(); - AddSC_boss_grizzle(); AddSC_boss_high_interrogator_gerstahn(); - AddSC_boss_magmus(); - AddSC_boss_tomb_of_seven(); AddSC_instance_blackrock_depths(); - AddSC_boss_drakkisath(); // blackrock_spire - AddSC_boss_halycon(); - AddSC_boss_highlordomokk(); - AddSC_boss_mothersmolderweb(); - AddSC_boss_overlordwyrmthalak(); - AddSC_boss_shadowvosh(); - AddSC_boss_thebeast(); - AddSC_boss_warmastervoone(); - AddSC_boss_quatermasterzigris(); + AddSC_boss_overlordwyrmthalak(); // blackrock_spire AddSC_boss_pyroguard_emberseer(); AddSC_boss_gyth(); - AddSC_boss_rend_blackhand(); AddSC_instance_blackrock_spire(); AddSC_boss_razorgore(); // blackwing_lair AddSC_boss_vaelastrasz(); @@ -599,34 +555,19 @@ void AddScripts() AddSC_molten_core(); AddSC_ebon_hold(); // scarlet_enclave AddSC_boss_arcanist_doan(); // scarlet_monastery - AddSC_boss_azshir_the_sleepless(); - AddSC_boss_bloodmage_thalnos(); AddSC_boss_herod(); - AddSC_boss_high_inquisitor_fairbanks(); - AddSC_boss_houndmaster_loksey(); - AddSC_boss_interrogator_vishas(); AddSC_boss_mograine_and_whitemane(); - AddSC_boss_scorn(); AddSC_boss_headless_horseman(); AddSC_instance_scarlet_monastery(); AddSC_boss_darkmaster_gandling(); // scholomance - AddSC_boss_death_knight_darkreaver(); AddSC_boss_jandicebarov(); - AddSC_boss_kormok(); - AddSC_boss_vectus(); AddSC_instance_scholomance(); AddSC_boss_hummel(); // shadowfang_keep AddSC_shadowfang_keep(); AddSC_instance_shadowfang_keep(); - AddSC_boss_magistrate_barthilas(); // stratholme - AddSC_boss_maleki_the_pallid(); - AddSC_boss_nerubenkan(); + AddSC_boss_maleki_the_pallid(); // stratholme AddSC_boss_cannon_master_willey(); AddSC_boss_baroness_anastari(); - AddSC_boss_ramstein_the_gorger(); - AddSC_boss_timmy_the_cruel(); - AddSC_boss_postmaster_malown(); - AddSC_boss_baron_rivendare(); AddSC_boss_dathrohan_balnazzar(); AddSC_boss_order_of_silver_hand(); AddSC_instance_stratholme(); @@ -652,8 +593,6 @@ void AddScripts() AddSC_zulaman(); AddSC_boss_zuljin(); AddSC_boss_arlokk(); // zulgurub - AddSC_boss_gahzranka(); - AddSC_boss_grilek(); AddSC_boss_hakkar(); AddSC_boss_hazzarah(); AddSC_boss_jeklik(); @@ -664,13 +603,11 @@ void AddScripts() AddSC_boss_renataki(); AddSC_boss_thekal(); AddSC_boss_venoxis(); - AddSC_boss_wushoolay(); AddSC_instance_zulgurub(); - //AddSC_alterac_mountains(); + AddSC_alterac_mountains(); AddSC_arathi_highlands(); AddSC_blasted_lands(); - AddSC_boss_kruul(); AddSC_burning_steppes(); AddSC_dun_morogh(); AddSC_eastern_plaguelands(); @@ -704,22 +641,16 @@ void AddScripts() AddSC_hyjal(); // CoT, hyjal AddSC_boss_archimonde(); AddSC_instance_mount_hyjal(); - AddSC_boss_captain_skarloc(); // CoT, old_hillsbrand - AddSC_boss_epoch_hunter(); - AddSC_boss_lieutenant_drake(); - AddSC_instance_old_hillsbrad(); + AddSC_instance_old_hillsbrad(); // CoT, old_hillsbrand AddSC_old_hillsbrad(); AddSC_culling_of_stratholme(); // CoT, culling_of_stratholme AddSC_instance_culling_of_stratholme(); AddSC_dire_maul(); // dire_maul AddSC_instance_dire_maul(); - AddSC_boss_celebras_the_cursed(); // maraudon - AddSC_boss_landslide(); - AddSC_boss_noxxion(); - AddSC_boss_ptheradras(); + AddSC_boss_noxxion(); // maraudon AddSC_boss_onyxia(); // onyxias_lair AddSC_instance_onyxias_lair(); - AddSC_boss_amnennar_the_coldbringer(); // razorfen_downs + AddSC_instance_razorfen_downs(); // razorfen_downs AddSC_razorfen_downs(); AddSC_instance_razorfen_kraul(); // razorfen_kraul AddSC_razorfen_kraul(); @@ -728,6 +659,7 @@ void AddScripts() AddSC_boss_kurinnaxx(); AddSC_boss_ossirian(); AddSC_boss_moam(); + AddSC_boss_rajaxx(); AddSC_ruins_of_ahnqiraj(); AddSC_instance_ruins_of_ahnqiraj(); AddSC_boss_cthun(); // temple_of_ahnqiraj @@ -771,7 +703,8 @@ void AddScripts() AddSC_winterspring(); // northrend - AddSC_boss_jedoga(); // azjol-nerub, ahnkahet + AddSC_boss_amanitar(); // azjol-nerub, ahnkahet + AddSC_boss_jedoga(); AddSC_boss_nadox(); AddSC_boss_taldaram(); AddSC_boss_volazj(); @@ -780,7 +713,9 @@ void AddScripts() AddSC_boss_hadronox(); AddSC_boss_krikthir(); AddSC_instance_azjol_nerub(); - AddSC_boss_grand_champions(); // CC, trial_of_the_champion + AddSC_boss_argent_challenge(); // CC, trial_of_the_champion + AddSC_boss_black_knight(); + AddSC_boss_grand_champions(); AddSC_instance_trial_of_the_champion(); AddSC_trial_of_the_champion(); AddSC_boss_anubarak_trial(); // CC, trial_of_the_crusader @@ -843,6 +778,7 @@ void AddScripts() AddSC_boss_thaddius(); AddSC_instance_naxxramas(); AddSC_boss_malygos(); // nexus, eye_of_eternity + AddSC_instance_eye_of_eternity(); AddSC_boss_anomalus(); // nexus, nexus AddSC_boss_keristrasza(); AddSC_boss_ormorok(); @@ -850,7 +786,9 @@ void AddScripts() AddSC_instance_nexus(); AddSC_boss_eregos(); // nexus, oculus AddSC_boss_urom(); + AddSC_boss_varos(); AddSC_instance_oculus(); + AddSC_oculus(); AddSC_boss_sartharion(); // obsidian_sanctum AddSC_instance_obsidian_sanctum(); AddSC_boss_baltharus(); // ruby_sanctum @@ -969,7 +907,9 @@ void AddScripts() AddSC_boss_warchief_kargath_bladefist(); AddSC_instance_shattered_halls(); AddSC_arcatraz(); // TK, arcatraz + AddSC_boss_dalliah(); AddSC_boss_harbinger_skyriss(); + AddSC_boss_soccothrates(); AddSC_instance_arcatraz(); AddSC_boss_high_botanist_freywinn(); // TK, botanica AddSC_boss_laj(); @@ -979,9 +919,7 @@ void AddScripts() AddSC_boss_kaelthas(); AddSC_boss_void_reaver(); AddSC_instance_the_eye(); - AddSC_the_eye(); - AddSC_boss_gatewatcher_iron_hand(); // TK, the_mechanar - AddSC_boss_nethermancer_sepethrea(); + AddSC_boss_nethermancer_sepethrea(); // TK, the_mechanar AddSC_boss_pathaleon_the_calculator(); AddSC_instance_mechanar(); diff --git a/system/ScriptLoader.h b/system/ScriptLoader.h index 8f27bae4f..e5b393ac5 100644 --- a/system/ScriptLoader.h +++ b/system/ScriptLoader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ diff --git a/system/system.cpp b/system/system.cpp index baaa44a4e..8ee414648 100644 --- a/system/system.cpp +++ b/system/system.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -24,7 +24,7 @@ SystemMgr& SystemMgr::Instance() void SystemMgr::LoadVersion() { - //Get Version information + // Get Version information QueryResult* pResult = SD2Database.PQuery("SELECT version FROM sd2_db_version LIMIT 1"); if (pResult) @@ -36,7 +36,7 @@ void SystemMgr::LoadVersion() delete pResult; } else - error_log("SD2: Missing `sd2_db_version` information."); + script_error_log("Missing `sd2_db_version` information."); // Setup version info and display it if (strSD2Version.empty()) @@ -51,125 +51,13 @@ void SystemMgr::LoadVersion() void SystemMgr::LoadScriptTexts() { outstring_log("SD2: Loading Script Texts..."); - LoadMangosStrings(SD2Database, "script_texts", TEXT_SOURCE_TEXT_START, TEXT_SOURCE_TEXT_END); - - QueryResult* pResult = SD2Database.PQuery("SELECT entry, sound, type, language, emote FROM script_texts WHERE entry BETWEEN %i AND %i", TEXT_SOURCE_GOSSIP_END, TEXT_SOURCE_TEXT_START); - - outstring_log("SD2: Loading Script Texts additional data..."); - - if (pResult) - { - BarGoLink bar(pResult->GetRowCount()); - uint32 uiCount = 0; - - do - { - bar.step(); - Field* pFields = pResult->Fetch(); - StringTextData pTemp; - - int32 iId = pFields[0].GetInt32(); - pTemp.uiSoundId = pFields[1].GetUInt32(); - pTemp.uiType = pFields[2].GetUInt32(); - pTemp.uiLanguage = pFields[3].GetUInt32(); - pTemp.uiEmote = pFields[4].GetUInt32(); - - if (iId >= 0) - { - error_db_log("SD2: Entry %i in table `script_texts` is not a negative value.", iId); - continue; - } - - if (pTemp.uiSoundId) - { - if (!GetSoundEntriesStore()->LookupEntry(pTemp.uiSoundId)) - error_db_log("SD2: Entry %i in table `script_texts` has soundId %u but sound does not exist.", iId, pTemp.uiSoundId); - } - - if (!GetLanguageDescByID(pTemp.uiLanguage)) - error_db_log("SD2: Entry %i in table `script_texts` using Language %u but Language does not exist.", iId, pTemp.uiLanguage); - - if (pTemp.uiType > CHAT_TYPE_ZONE_YELL) - error_db_log("SD2: Entry %i in table `script_texts` has Type %u but this Chat Type does not exist.", iId, pTemp.uiType); - - m_mTextDataMap[iId] = pTemp; - ++uiCount; - } while (pResult->NextRow()); - - delete pResult; - - outstring_log(""); - outstring_log(">> Loaded %u additional Script Texts data.", uiCount); - } - else - { - BarGoLink bar(1); - bar.step(); - outstring_log(""); - outstring_log(">> Loaded 0 additional Script Texts data. DB table `script_texts` is empty."); - } + LoadMangosStrings(SD2Database, "script_texts", TEXT_SOURCE_TEXT_START, TEXT_SOURCE_TEXT_END, true); } void SystemMgr::LoadScriptTextsCustom() { outstring_log("SD2: Loading Custom Texts..."); - LoadMangosStrings(SD2Database, "custom_texts", TEXT_SOURCE_CUSTOM_START, TEXT_SOURCE_CUSTOM_END); - - QueryResult* pResult = SD2Database.PQuery("SELECT entry, sound, type, language, emote FROM custom_texts WHERE entry BETWEEN %i AND %i", TEXT_SOURCE_CUSTOM_END, TEXT_SOURCE_CUSTOM_START); - - outstring_log("SD2: Loading Custom Texts additional data..."); - - if (pResult) - { - BarGoLink bar(pResult->GetRowCount()); - uint32 uiCount = 0; - - do - { - bar.step(); - Field* pFields = pResult->Fetch(); - StringTextData pTemp; - - int32 iId = pFields[0].GetInt32(); - pTemp.uiSoundId = pFields[1].GetUInt32(); - pTemp.uiType = pFields[2].GetUInt32(); - pTemp.uiLanguage = pFields[3].GetUInt32(); - pTemp.uiEmote = pFields[4].GetUInt32(); - - if (iId >= 0) - { - error_db_log("SD2: Entry %i in table `custom_texts` is not a negative value.", iId); - continue; - } - - if (pTemp.uiSoundId) - { - if (!GetSoundEntriesStore()->LookupEntry(pTemp.uiSoundId)) - error_db_log("SD2: Entry %i in table `custom_texts` has soundId %u but sound does not exist.", iId, pTemp.uiSoundId); - } - - if (!GetLanguageDescByID(pTemp.uiLanguage)) - error_db_log("SD2: Entry %i in table `custom_texts` using Language %u but Language does not exist.", iId, pTemp.uiLanguage); - - if (pTemp.uiType > CHAT_TYPE_ZONE_YELL) - error_db_log("SD2: Entry %i in table `custom_texts` has Type %u but this Chat Type does not exist.", iId, pTemp.uiType); - - m_mTextDataMap[iId] = pTemp; - ++uiCount; - } while (pResult->NextRow()); - - delete pResult; - - outstring_log(""); - outstring_log(">> Loaded %u additional Custom Texts data.", uiCount); - } - else - { - BarGoLink bar(1); - bar.step(); - outstring_log(""); - outstring_log(">> Loaded 0 additional Custom Texts data. DB table `custom_texts` is empty."); - } + LoadMangosStrings(SD2Database, "custom_texts", TEXT_SOURCE_CUSTOM_START, TEXT_SOURCE_CUSTOM_END, true); } void SystemMgr::LoadScriptGossipTexts() @@ -180,9 +68,6 @@ void SystemMgr::LoadScriptGossipTexts() void SystemMgr::LoadScriptWaypoints() { - // Drop Existing Waypoint list - m_mPointMoveMap.clear(); - uint64 uiCreatureCount = 0; // Load Waypoints @@ -195,7 +80,7 @@ void SystemMgr::LoadScriptWaypoints() outstring_log("SD2: Loading Script Waypoints for " UI64FMTD " creature(s)...", uiCreatureCount); - pResult = SD2Database.PQuery("SELECT entry, pointid, location_x, location_y, location_z, waittime FROM script_waypoint ORDER BY pointid"); + pResult = SD2Database.PQuery("SELECT entry, pointid, location_x, location_y, location_z, waittime FROM script_waypoint ORDER BY entry, pointid"); if (pResult) { @@ -206,30 +91,26 @@ void SystemMgr::LoadScriptWaypoints() { bar.step(); Field* pFields = pResult->Fetch(); - ScriptPointMove pTemp; - pTemp.uiCreatureEntry = pFields[0].GetUInt32(); - uint32 uiEntry = pTemp.uiCreatureEntry; - pTemp.uiPointId = pFields[1].GetUInt32(); - pTemp.fX = pFields[2].GetFloat(); - pTemp.fY = pFields[3].GetFloat(); - pTemp.fZ = pFields[4].GetFloat(); - pTemp.uiWaitTime = pFields[5].GetUInt32(); - - CreatureInfo const* pCInfo = GetCreatureTemplateStore(pTemp.uiCreatureEntry); + uint32 uiEntry = pFields[0].GetUInt32(); + int32 pathId = 1; // pFields[X].GetInt32(); + uint32 pointId = pFields[1].GetUInt32(); + uint32 delay = pFields[5].GetUInt32(); + CreatureInfo const* pCInfo = GetCreatureTemplateStore(uiEntry); if (!pCInfo) { - error_db_log("SD2: DB table script_waypoint has waypoint for nonexistent creature entry %u", pTemp.uiCreatureEntry); + error_db_log("SD2: DB table script_waypoint has waypoint for nonexistent creature entry %u", uiEntry); continue; } - if (!pCInfo->ScriptID) - error_db_log("SD2: DB table script_waypoint has waypoint for creature entry %u, but creature does not have ScriptName defined and then useless.", pTemp.uiCreatureEntry); - m_mPointMoveMap[uiEntry].push_back(pTemp); + if (AddWaypointFromExternal(uiEntry, pathId, pointId, pFields[2].GetFloat(), pFields[3].GetFloat(), pFields[4].GetFloat(), 100, delay)) + m_pathInfo[uiEntry][pathId].lastWaypoint = pointId; + ++uiNodeCount; - } while (pResult->NextRow()); + } + while (pResult->NextRow()); delete pResult; diff --git a/system/system.h b/system/system.h index 3c7547195..abaa9fcd5 100644 --- a/system/system.h +++ b/system/system.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 - 2012 ScriptDev2 +/* This file is part of the ScriptDev2 Project. See AUTHORS file for Copyright information * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ @@ -6,9 +6,9 @@ #define SC_SYSTEM_H extern DatabaseType SD2Database; -extern std::string strSD2Version; //version info: database entry and revision +extern std::string strSD2Version; // version info: database entry and revision -#define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available +#define TEXT_SOURCE_RANGE -1000000 // the amount of entries each text source has available #define TEXT_SOURCE_TEXT_START TEXT_SOURCE_RANGE #define TEXT_SOURCE_TEXT_END TEXT_SOURCE_RANGE*2 + 1 @@ -19,26 +19,13 @@ extern std::string strSD2Version; //version info: data #define TEXT_SOURCE_GOSSIP_START TEXT_SOURCE_RANGE*3 #define TEXT_SOURCE_GOSSIP_END TEXT_SOURCE_RANGE*4 + 1 -struct ScriptPointMove -{ - uint32 uiCreatureEntry; - uint32 uiPointId; - float fX; - float fY; - float fZ; - uint32 uiWaitTime; -}; +#define pSystemMgr SystemMgr::Instance() -struct StringTextData +struct PathInformation { - uint32 uiSoundId; - uint8 uiType; - uint32 uiLanguage; - uint32 uiEmote; + uint32 lastWaypoint; }; -#define pSystemMgr SystemMgr::Instance() - class SystemMgr { public: @@ -47,43 +34,29 @@ class SystemMgr static SystemMgr& Instance(); - //Maps and lists - typedef UNORDERED_MAP TextDataMap; - typedef UNORDERED_MAP > PointMoveMap; + typedef std::map < uint32 /*entry*/, std::map < int32 /*pathId*/, PathInformation > > EntryPathInfo; - //Database + // Database void LoadVersion(); void LoadScriptTexts(); void LoadScriptTextsCustom(); void LoadScriptGossipTexts(); void LoadScriptWaypoints(); - //Retrive from storage - StringTextData const* GetTextData(int32 uiTextId) const + PathInformation const* GetPathInfo(uint32 entry, int32 pathId) const { - TextDataMap::const_iterator itr = m_mTextDataMap.find(uiTextId); - - if (itr == m_mTextDataMap.end()) + EntryPathInfo::const_iterator findEntry = m_pathInfo.find(entry); + if (findEntry == m_pathInfo.end()) + return NULL; + std::map::const_iterator findPath = findEntry->second.find(pathId); + if (findPath == findEntry->second.end()) return NULL; - return &itr->second; - } - - std::vector const &GetPointMoveList(uint32 uiCreatureEntry) const - { - static std::vector vEmpty; - - PointMoveMap::const_iterator itr = m_mPointMoveMap.find(uiCreatureEntry); - - if (itr == m_mPointMoveMap.end()) - return vEmpty; - - return itr->second; + return &(findPath->second); } - protected: - TextDataMap m_mTextDataMap; //additional data for text strings - PointMoveMap m_mPointMoveMap; //coordinates for waypoints + private: + EntryPathInfo m_pathInfo; }; #endif diff --git a/tool/git_id/git_id.cpp b/tool/git_id/git_id.cpp index 9da1bee89..1b72cffa8 100644 --- a/tool/git_id/git_id.cpp +++ b/tool/git_id/git_id.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2005-2012 MaNGOS - * Copyright (C) 2005-2012 ScriptDev2 + * Copyright (C) 2005-2013 MaNGOS + * This file is part of the ScriptDev2 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 General Public License as published by @@ -53,9 +53,10 @@ #define NUM_REMOTES 2 #define NUM_DATABASES 2 -char remotes[NUM_REMOTES][MAX_REMOTE] = { +char remotes[NUM_REMOTES][MAX_REMOTE] = +{ "git@github.com:scriptdev2/scriptdev2.git", - "git://github.com/scriptdev2/scriptdev2.git" // used for fetch if present + "git:// github.com/scriptdev2/scriptdev2.git" // used for fetch if present }; char remote_branch[MAX_REMOTE] = "master"; @@ -64,27 +65,32 @@ char rev_sql_file[MAX_PATH] = "sd2_revision_sql.h"; char sql_update_dir[MAX_PATH] = "sql/updates"; char new_index_file[MAX_PATH] = ".git/git_id_index"; -char databases[NUM_DATABASES][MAX_DB] = { +char databases[NUM_DATABASES][MAX_DB] = +{ "scriptdev2", "mangos" }; -char db_version_table[NUM_DATABASES][MAX_DB] = { +char db_version_table[NUM_DATABASES][MAX_DB] = +{ "sd2_db_version", "db_version", }; -char db_sql_file[NUM_DATABASES][MAX_PATH] = { +char db_sql_file[NUM_DATABASES][MAX_PATH] = +{ "sql/scriptdev2_script_full.sql", "sql/mangos_scriptname_full.sql", }; -char db_sql_rev_field[NUM_DATABASES][MAX_PATH] = { +char db_sql_rev_field[NUM_DATABASES][MAX_PATH] = +{ "REVISION_DB_SCRIPTDEV2", "REVISION_DB_SD2_MANGOS", }; -bool db_sql_rev_parent[NUM_DATABASES] = { +bool db_sql_rev_parent[NUM_DATABASES] = +{ true, true }; @@ -106,8 +112,8 @@ bool generate_makefile = false; // not need for cmak char origins[NUM_REMOTES][MAX_REMOTE]; int rev; -int last_sql_rev[NUM_DATABASES] = {0,0}; -int last_sql_nr[NUM_DATABASES] = {0,0}; +int last_sql_rev[NUM_DATABASES] = {0, 0}; +int last_sql_nr[NUM_DATABASES] = {0, 0}; char head_message[MAX_MSG]; char path_prefix[MAX_PATH] = ""; @@ -121,18 +127,18 @@ char new_index_cmd[MAX_CMD]; std::set new_sql_updates; -FILE *cmd_pipe; +FILE* cmd_pipe; bool find_path() { printf("+ finding path\n"); - char *ptr; + char* ptr; char cur_path[MAX_PATH]; getcwd(cur_path, MAX_PATH); size_t len = strlen(cur_path); - strncpy(base_path, cur_path, len+1); + strncpy(base_path, cur_path, len + 1); - if(cur_path[len-1] == '/' || cur_path[len-1] == '\\') + if (cur_path[len - 1] == '/' || cur_path[len - 1] == '\\') { // we're in root, don't bother return false; @@ -140,15 +146,15 @@ bool find_path() // don't count the root int count_fwd = 0, count_back = 0; - for(ptr = cur_path-1; ptr = strchr(ptr+1, '/'); count_fwd++); - for(ptr = cur_path-1; ptr = strchr(ptr+1, '\\'); count_back++); + for (ptr = cur_path - 1; ptr = strchr(ptr + 1, '/'); count_fwd++); + for (ptr = cur_path - 1; ptr = strchr(ptr + 1, '\\'); count_back++); int count = std::max(count_fwd, count_back); char path[MAX_PATH]; - for(int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { snprintf(path, MAX_PATH, "%s.git", path_prefix); - if(0 == chdir(path)) + if (0 == chdir(path)) { chdir(cur_path); return true; @@ -156,11 +162,11 @@ bool find_path() strncat(path_prefix, "../", MAX_PATH); ptr = strrchr(base_path, '\\'); - if(ptr) *ptr = '\0'; + if (ptr) *ptr = '\0'; else { ptr = strrchr(base_path, '/'); - if(ptr) *ptr = '\0'; + if (ptr) *ptr = '\0'; } } @@ -170,17 +176,17 @@ bool find_path() bool find_origin() { printf("+ finding origin\n"); - if( (cmd_pipe = popen( "git remote -v", "r" )) == NULL ) + if ((cmd_pipe = popen("git remote -v", "r")) == NULL) return false; bool ret = false; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { char name[256], remote[MAX_REMOTE]; sscanf(buffer, "%s %s", name, remote); - for(int i = 0; i < NUM_REMOTES; i++) + for (int i = 0; i < NUM_REMOTES; i++) { - if(strcmp(remote, remotes[i]) == 0) + if (strcmp(remote, remotes[i]) == 0) { strncpy(origins[i], name, MAX_REMOTE); ret = true; @@ -204,21 +210,21 @@ bool check_fwd() { printf("+ checking fast forward\n"); snprintf(cmd, MAX_CMD, "git log -n 1 --pretty=\"format:%%H\" %s/%s", (origins[1][0] ? origins[1] : origins[0]), remote_branch); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) return false; - if(!fgets(buffer, MAX_BUF, cmd_pipe)) return false; + if (!fgets(buffer, MAX_BUF, cmd_pipe)) return false; strncpy(origin_hash, buffer, MAX_HASH); pclose(cmd_pipe); - if( (cmd_pipe = popen( "git log --pretty=\"format:%H\"", "r" )) == NULL ) + if ((cmd_pipe = popen("git log --pretty=\"format:%H\"", "r")) == NULL) return false; bool found = false; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { buffer[strlen(buffer) - 1] = '\0'; - if(strncmp(origin_hash, buffer, MAX_BUF) == 0) + if (strncmp(origin_hash, buffer, MAX_BUF) == 0) { found = true; break; @@ -226,23 +232,23 @@ bool check_fwd() } pclose(cmd_pipe); - if(!found) + if (!found) { // with fetch you still get the latest rev, you just rebase afterwards and push // without it you may not get the right rev - if(do_fetch) printf("WARNING: non-fastforward, use rebase!\n"); + if (do_fetch) printf("WARNING: non-fastforward, use rebase!\n"); else { printf("ERROR: non-fastforward, use rebase!\n"); return false; } } return true; } -int get_rev(const char *from_msg) +int get_rev(const char* from_msg) { // accept only the rev number format, not the sql update format char nr_str[256]; - if(sscanf(from_msg, "[" GIT_REV_PREFIX "%[0123456789]]", nr_str) != 1) return 0; + if (sscanf(from_msg, "[" GIT_REV_PREFIX "%[0123456789]]", nr_str) != 1) return 0; // ("[")+(REV_PREFIX)+("]")-1 - if(from_msg[strlen(nr_str)+strlen(GIT_REV_PREFIX)+2-1] != ']') return 0; + if (from_msg[strlen(nr_str) + strlen(GIT_REV_PREFIX) + 2 - 1] != ']') return 0; return atoi(nr_str); } @@ -251,26 +257,26 @@ bool find_rev() { printf("+ finding next revision number\n"); // find the highest rev number on either of the remotes - for(int i = 0; i < NUM_REMOTES; i++) + for (int i = 0; i < NUM_REMOTES; i++) { - if(!local && !origins[i][0]) continue; + if (!local && !origins[i][0]) continue; - if(local) snprintf(cmd, MAX_CMD, "git log HEAD --pretty=\"format:%%s\""); + if (local) snprintf(cmd, MAX_CMD, "git log HEAD --pretty=\"format:%%s\""); else sprintf(cmd, "git log %s/%s --pretty=\"format:%%s\"", origins[i], remote_branch); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) continue; int nr; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { nr = get_rev(buffer); - if(nr >= rev) - rev = nr+1; + if (nr >= rev) + rev = nr + 1; } pclose(cmd_pipe); } - if(rev > 0) printf("Found " GIT_REV_FORMAT ".\n", rev); + if (rev > 0) printf("Found " GIT_REV_FORMAT ".\n", rev); return rev > 0; } @@ -290,7 +296,7 @@ std::string generateSqlHeader() std::ostringstream newData; newData << "#ifndef __SD2_REVISION_SQL_H__" << std::endl; newData << "#define __SD2_REVISION_SQL_H__" << std::endl; - for(int i = 0; i < NUM_DATABASES; ++i) + for (int i = 0; i < NUM_DATABASES; ++i) { newData << " #define " << db_sql_rev_field[i] << " \"required_" << last_sql_update[i] << "\"" << std::endl; } @@ -298,17 +304,17 @@ std::string generateSqlHeader() return newData.str(); } -void system_switch_index(const char *cmd) +void system_switch_index(const char* cmd) { // do the command for the original index and then for the new index // both need to be updated with the changes before commit // but the new index will contains only the desired changes // while the old may contain others system(cmd); - if(!use_new_index) return; - if(putenv(new_index_cmd) != 0) return; + if (!use_new_index) return; + if (putenv(new_index_cmd) != 0) return; system(cmd); - if(putenv(old_index_cmd) != 0) return; + if (putenv(old_index_cmd) != 0) return; } bool write_rev_nr() @@ -321,9 +327,9 @@ bool write_rev_nr() char prefixed_file[MAX_PATH]; snprintf(prefixed_file, MAX_PATH, "%s%s", path_prefix, rev_nr_file); - if(FILE* OutputFile = fopen(prefixed_file, "wb")) + if (FILE* OutputFile = fopen(prefixed_file, "wb")) { - fprintf(OutputFile,"%s", header.c_str()); + fprintf(OutputFile, "%s", header.c_str()); fclose(OutputFile); // add the file to both indices, to be committed later @@ -338,16 +344,16 @@ bool write_rev_nr() bool write_rev_sql() { - if(new_sql_updates.empty()) return true; + if (new_sql_updates.empty()) return true; printf("+ writing sd2_revision_sql.h\n"); std::string header = generateSqlHeader(); char prefixed_file[MAX_PATH]; snprintf(prefixed_file, MAX_PATH, "%s%s", path_prefix, rev_sql_file); - if(FILE* OutputFile = fopen(prefixed_file, "wb")) + if (FILE* OutputFile = fopen(prefixed_file, "wb")) { - fprintf(OutputFile,"%s", header.c_str()); + fprintf(OutputFile, "%s", header.c_str()); fclose(OutputFile); // add the file to both indices, to be committed later @@ -363,28 +369,28 @@ bool write_rev_sql() bool find_head_msg() { printf("+ finding last message on HEAD\n"); - if( (cmd_pipe = popen( "git log -n 1 --pretty=\"format:%s%n%n%b\"", "r" )) == NULL ) + if ((cmd_pipe = popen("git log -n 1 --pretty=\"format:%s%n%n%b\"", "r")) == NULL) return false; int poz = 0; - while(poz < 16384-1 && EOF != (head_message[poz++] = fgetc(cmd_pipe))); - head_message[poz-1] = '\0'; + while (poz < 16384 - 1 && EOF != (head_message[poz++] = fgetc(cmd_pipe))); + head_message[poz - 1] = '\0'; pclose(cmd_pipe); - if(int head_rev = get_rev(head_message)) + if (int head_rev = get_rev(head_message)) { - if(!allow_replace) + if (!allow_replace) { printf("Last commit on HEAD is " GIT_REV_FORMAT ". Use -r to replace it with " GIT_REV_FORMAT ".\n", head_rev, rev); return false; } // skip the rev number in the commit - char *p = strchr(head_message, ']'), *q = head_message; - assert(p && *(p+1)); - p+=2; - while(*p) *q = *p, p++, q++; + char* p = strchr(head_message, ']'), *q = head_message; + assert(p && *(p + 1)); + p += 2; + while (*p) *q = *p, p++, q++; *q = 0; return true; } @@ -397,14 +403,14 @@ bool amend_commit() printf("+ amending last commit\n"); // commit the contents of the (new) index - if(use_new_index && putenv(new_index_cmd) != 0) return false; + if (use_new_index && putenv(new_index_cmd) != 0) return false; snprintf(cmd, MAX_CMD, "git commit --amend -F-"); - if( (cmd_pipe = popen( cmd, "w" )) == NULL ) + if ((cmd_pipe = popen(cmd, "w")) == NULL) return false; fprintf(cmd_pipe, GIT_REV_FORMAT " %s", rev, head_message); pclose(cmd_pipe); - if(use_new_index && putenv(old_index_cmd) != 0) return false; + if (use_new_index && putenv(old_index_cmd) != 0) return false; return true; } @@ -420,21 +426,21 @@ struct sql_update_info bool has_table; }; -bool get_sql_update_info(const char *buffer, sql_update_info &info) +bool get_sql_update_info(const char* buffer, sql_update_info& info) { info.table[0] = '\0'; int dummy[2]; char dummyStr[MAX_BUF]; - if(sscanf(buffer, SQL_REV_SCAN "_%[^_]_%d_%d", &dummy[0], &dummyStr, &dummy[1]) == 3) + if (sscanf(buffer, SQL_REV_SCAN "_%[^_]_%d_%d", &dummy[0], &dummyStr, &dummy[1]) == 3) return false; - if(sscanf(buffer, SQL_REV_SCAN "_%[^.].sql", &info.rev, info.db) != 2) + if (sscanf(buffer, SQL_REV_SCAN "_%[^.].sql", &info.rev, info.db) != 2) { return false; } - for(info.db_idx = 0; info.db_idx < NUM_DATABASES; info.db_idx++) - if(strncmp(info.db, databases[info.db_idx], MAX_DB) == 0) break; + for (info.db_idx = 0; info.db_idx < NUM_DATABASES; info.db_idx++) + if (strncmp(info.db, databases[info.db_idx], MAX_DB) == 0) break; info.has_table = (info.table[0] != '\0'); return true; } @@ -444,24 +450,24 @@ bool find_sql_updates() printf("+ finding new sql updates on HEAD\n"); // add all updates from HEAD snprintf(cmd, MAX_CMD, "git show HEAD:%s", sql_update_dir); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) return false; // skip first two lines - if(!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } - if(!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } sql_update_info info; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { buffer[strlen(buffer) - 1] = '\0'; - if(!get_sql_update_info(buffer, info)) continue; + if (!get_sql_update_info(buffer, info)) continue; - if(info.db_idx == NUM_DATABASES) + if (info.db_idx == NUM_DATABASES) { - if(info.rev > 0) printf("WARNING: incorrect database name for sql update %s\n", buffer); - continue; + if (info.rev > 0) printf("WARNING: incorrect database name for sql update %s\n", buffer); + continue; } new_sql_updates.insert(buffer); @@ -471,29 +477,29 @@ bool find_sql_updates() // remove updates from the last commit also found on origin snprintf(cmd, MAX_CMD, "git show %s:%s", origin_hash, sql_update_dir); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) return false; // skip first two lines - if(!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } - if(!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { buffer[strlen(buffer) - 1] = '\0'; - if(!get_sql_update_info(buffer, info)) continue; + if (!get_sql_update_info(buffer, info)) continue; // find the old update with the highest rev for each database // (will be the required version for the new update) std::set::iterator itr = new_sql_updates.find(buffer); - if(itr != new_sql_updates.end() ) + if (itr != new_sql_updates.end()) { - if(info.rev > 0 && (info.rev > last_sql_rev[info.db_idx] || - (info.rev == last_sql_rev[info.db_idx] && info.nr > last_sql_nr[info.db_idx]))) + if (info.rev > 0 && (info.rev > last_sql_rev[info.db_idx] || + (info.rev == last_sql_rev[info.db_idx] && info.nr > last_sql_nr[info.db_idx]))) { last_sql_rev[info.db_idx] = info.rev; last_sql_nr[info.db_idx] = info.nr; - if(db_sql_rev_parent[info.db_idx]) + if (db_sql_rev_parent[info.db_idx]) snprintf(last_sql_update[info.db_idx], MAX_PATH, "_%s%s%s", info.db, info.has_table ? "_" : "", info.table); else sscanf(buffer, "%[^.]", last_sql_update[info.db_idx]); @@ -504,9 +510,9 @@ bool find_sql_updates() pclose(cmd_pipe); - if(!new_sql_updates.empty()) + if (!new_sql_updates.empty()) { - for(std::set::iterator itr = new_sql_updates.begin(); itr != new_sql_updates.end(); ++itr) + for (std::set::iterator itr = new_sql_updates.begin(); itr != new_sql_updates.end(); ++itr) printf("%s\n", itr->c_str()); } else @@ -515,14 +521,14 @@ bool find_sql_updates() return true; } -bool copy_file(const char *src_file, const char *dst_file) +bool copy_file(const char* src_file, const char* dst_file) { - FILE * fin = fopen( src_file, "rb" ); - if(!fin) return false; - FILE * fout = fopen( dst_file, "wb" ); - if(!fout) { fclose(fin); return false; } + FILE* fin = fopen(src_file, "rb"); + if (!fin) return false; + FILE* fout = fopen(dst_file, "wb"); + if (!fout) { fclose(fin); return false; } - for(char c = getc(fin); !feof(fin); putc(c, fout), c = getc(fin)); + for (char c = getc(fin); !feof(fin); putc(c, fout), c = getc(fin)); fclose(fin); fclose(fout); @@ -531,16 +537,16 @@ bool copy_file(const char *src_file, const char *dst_file) bool convert_sql_updates() { - if(new_sql_updates.empty()) return true; + if (new_sql_updates.empty()) return true; printf("+ converting sql updates\n"); // rename the sql update files and add the required update statement - for(std::set::iterator itr = new_sql_updates.begin(); itr != new_sql_updates.end(); ++itr) + for (std::set::iterator itr = new_sql_updates.begin(); itr != new_sql_updates.end(); ++itr) { sql_update_info info; - if(!get_sql_update_info(itr->c_str(), info)) return false; - if(info.db_idx == NUM_DATABASES) return false; + if (!get_sql_update_info(itr->c_str(), info)) return false; + if (info.db_idx == NUM_DATABASES) return false; // generating the new name should work for updates with or without a rev char src_file[MAX_PATH], new_name[MAX_PATH], new_req_name[MAX_PATH], dst_file[MAX_PATH]; @@ -548,18 +554,18 @@ bool convert_sql_updates() snprintf(new_name, MAX_PATH, SQL_REV_PRINT "_%s%s%s", rev, info.db, info.has_table ? "_" : "", info.table); snprintf(dst_file, MAX_PATH, "%s%s/%s.sql", path_prefix, sql_update_dir, new_name); - if(db_sql_rev_parent[info.db_idx]) + if (db_sql_rev_parent[info.db_idx]) snprintf(new_req_name, MAX_PATH, "_%s%s%s", info.db, info.has_table ? "_" : "", info.table); else strncpy(new_req_name, new_name, MAX_PATH); - FILE * fin = fopen( src_file, "r" ); - if(!fin) return false; + FILE* fin = fopen(src_file, "r"); + if (!fin) return false; std::ostringstream out_buff; // add the update requirements for non-parent-controlled revision sql update - if(!db_sql_rev_parent[info.db_idx]) + if (!db_sql_rev_parent[info.db_idx]) { // add the update requirements out_buff << "ALTER TABLE " << db_version_table[info.db_idx] @@ -568,12 +574,12 @@ bool convert_sql_updates() // skip the first one or two lines from the input // if it already contains update requirements - if(fgets(buffer, MAX_BUF, fin)) + if (fgets(buffer, MAX_BUF, fin)) { char dummy[MAX_BUF]; - if(sscanf(buffer, "ALTER TABLE %s CHANGE COLUMN required_%s required_%s bit", dummy, dummy, dummy) == 3) + if (sscanf(buffer, "ALTER TABLE %s CHANGE COLUMN required_%s required_%s bit", dummy, dummy, dummy) == 3) { - if(fgets(buffer, MAX_BUF, fin) && buffer[0] != '\n') + if (fgets(buffer, MAX_BUF, fin) && buffer[0] != '\n') out_buff << buffer; } else @@ -582,15 +588,15 @@ bool convert_sql_updates() } // copy the rest of the file - while(fgets(buffer, MAX_BUF, fin)) + while (fgets(buffer, MAX_BUF, fin)) out_buff << buffer; fclose(fin); - FILE * fout = fopen( dst_file, "w" ); - if(!fout) { fclose(fin); return false; } + FILE* fout = fopen(dst_file, "w"); + if (!fout) { fclose(fin); return false; } - fprintf(fout, "%s",out_buff.str().c_str()); + fprintf(fout, "%s", out_buff.str().c_str()); fclose(fout); @@ -599,7 +605,7 @@ bool convert_sql_updates() system_switch_index(cmd); // delete src file if it different by name from dst file - if(strncmp(src_file,dst_file,MAX_PATH)) + if (strncmp(src_file, dst_file, MAX_PATH)) { snprintf(cmd, MAX_CMD, "git rm --quiet %s", src_file); system_switch_index(cmd); @@ -614,30 +620,30 @@ bool convert_sql_updates() bool generate_sql_makefile() { - if(new_sql_updates.empty()) return true; + if (new_sql_updates.empty()) return true; // find all files in the update dir snprintf(cmd, MAX_CMD, "git show HEAD:%s", sql_update_dir); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) return false; // skip first two lines - if(!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } - if(!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { pclose(cmd_pipe); return false; } char newname[MAX_PATH]; std::set file_list; sql_update_info info; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { buffer[strlen(buffer) - 1] = '\0'; - if(buffer[strlen(buffer) - 1] != '/' && - strncmp(buffer, "Makefile.am", MAX_BUF) != 0) + if (buffer[strlen(buffer) - 1] != '/' && + strncmp(buffer, "Makefile.am", MAX_BUF) != 0) { - if(new_sql_updates.find(buffer) != new_sql_updates.end()) + if (new_sql_updates.find(buffer) != new_sql_updates.end()) { - if(!get_sql_update_info(buffer, info)) return false; + if (!get_sql_update_info(buffer, info)) return false; snprintf(newname, MAX_PATH, SQL_REV_PRINT "_%s%s%s.sql", rev, info.db, info.has_table ? "_" : "", info.table); file_list.insert(newname); } @@ -651,41 +657,41 @@ bool generate_sql_makefile() // write the makefile char file_name[MAX_PATH]; snprintf(file_name, MAX_PATH, "%s%s/Makefile.am", path_prefix, sql_update_dir); - FILE *fout = fopen(file_name, "w"); - if(!fout) { pclose(cmd_pipe); return false; } + FILE* fout = fopen(file_name, "w"); + if (!fout) { pclose(cmd_pipe); return false; } fprintf(fout, - "# Copyright (C) 2005-2011 ScriptDev2 \n" - "#\n" - "# This program is free software; you can redistribute it and/or modify\n" - "# it under the terms of the GNU General Public License as published by\n" - "# the Free Software Foundation; either version 2 of the License, or\n" - "# (at your option) any later version.\n" - "#\n" - "# This program is distributed in the hope that it will be useful,\n" - "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "# GNU General Public License for more details.\n" - "#\n" - "# You should have received a copy of the GNU General Public License\n" - "# along with this program; if not, write to the Free Software\n" - "# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" - "\n" - "## Process this file with automake to produce Makefile.in\n" - "\n" - "## Sub-directories to parse\n" - "\n" - "## Change installation location\n" - "# datadir = ScriptDev2/%s\n" - "pkgdatadir = $(datadir)/ScriptDev2/%s\n" - "\n" - "## Files to be installed\n" - "# Install basic SQL files to datadir\n" - "pkgdata_DATA = \\\n", - sql_update_dir, sql_update_dir - ); - - for(std::set::iterator itr = file_list.begin(), next; itr != file_list.end(); ++itr) + "# Copyright (C) 2005-2011 ScriptDev2 \n" + "#\n" + "# This program is free software; you can redistribute it and/or modify\n" + "# it under the terms of the GNU General Public License as published by\n" + "# the Free Software Foundation; either version 2 of the License, or\n" + "# (at your option) any later version.\n" + "#\n" + "# This program is distributed in the hope that it will be useful,\n" + "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "# GNU General Public License for more details.\n" + "#\n" + "# You should have received a copy of the GNU General Public License\n" + "# along with this program; if not, write to the Free Software\n" + "# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" + "\n" + "## Process this file with automake to produce Makefile.in\n" + "\n" + "## Sub-directories to parse\n" + "\n" + "## Change installation location\n" + "# datadir = ScriptDev2/%s\n" + "pkgdatadir = $(datadir)/ScriptDev2/%s\n" + "\n" + "## Files to be installed\n" + "# Install basic SQL files to datadir\n" + "pkgdata_DATA = \\\n", + sql_update_dir, sql_update_dir + ); + + for (std::set::iterator itr = file_list.begin(), next; itr != file_list.end(); ++itr) { next = itr; ++next; fprintf(fout, "\t%s%s\n", itr->c_str(), next == file_list.end() ? "" : " \\"); @@ -701,14 +707,14 @@ bool generate_sql_makefile() bool change_sql_database() { - if(new_sql_updates.empty()) return true; + if (new_sql_updates.empty()) return true; printf("+ changing database sql files\n"); // rename the database files, copy their contents back // and change the required update line - for(int i = 0; i < NUM_DATABASES; i++) + for (int i = 0; i < NUM_DATABASES; i++) { - if(last_sql_update[i][0] == '\0') continue; + if (last_sql_update[i][0] == '\0') continue; char old_file[MAX_PATH], tmp_file[MAX_PATH], dummy[MAX_BUF]; @@ -717,29 +723,29 @@ bool change_sql_database() rename(old_file, tmp_file); - FILE *fin = fopen( tmp_file, "r" ); - if(!fin) return false; - FILE *fout = fopen( old_file, "w" ); - if(!fout) return false; + FILE* fin = fopen(tmp_file, "r"); + if (!fin) return false; + FILE* fout = fopen(old_file, "w"); + if (!fout) return false; snprintf(dummy, MAX_CMD, "CREATE TABLE `%s` (\n", db_version_table[i]); - while(fgets(buffer, MAX_BUF, fin)) + while (fgets(buffer, MAX_BUF, fin)) { fputs(buffer, fout); - if(strncmp(buffer, dummy, MAX_BUF) == 0) + if (strncmp(buffer, dummy, MAX_BUF) == 0) break; } - while(1) + while (1) { - if(!fgets(buffer, MAX_BUF, fin)) return false; - if(sscanf(buffer, " `required_%s`", dummy) == 1) break; + if (!fgets(buffer, MAX_BUF, fin)) return false; + if (sscanf(buffer, " `required_%s`", dummy) == 1) break; fputs(buffer, fout); } fprintf(fout, " `required_%s` bit(1) default NULL\n", last_sql_update[i]); - while(fgets(buffer, MAX_BUF, fin)) + while (fgets(buffer, MAX_BUF, fin)) fputs(buffer, fout); fclose(fin); @@ -755,26 +761,26 @@ bool change_sql_database() bool change_sql_history() { snprintf(cmd, MAX_CMD, "git log HEAD --pretty=\"format:%%H\""); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) return false; std::list hashes; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { buffer[strlen(buffer) - 1] = '\0'; - if(strncmp(origin_hash, buffer, MAX_HASH) == 0) + if (strncmp(origin_hash, buffer, MAX_HASH) == 0) break; hashes.push_back(buffer); } pclose(cmd_pipe); - if(hashes.empty()) return false; // must have at least one commit - if(hashes.size() < 2) return true; // only one commit, ok but nothing to do + if (hashes.empty()) return false; // must have at least one commit + if (hashes.size() < 2) return true; // only one commit, ok but nothing to do snprintf(cmd, MAX_CMD, "git reset --hard %s", origin_hash); system(cmd); - for(std::list::reverse_iterator next = hashes.rbegin(), itr = next++; next != hashes.rend(); ++itr, ++next) + for (std::list::reverse_iterator next = hashes.rbegin(), itr = next++; next != hashes.rend(); ++itr, ++next) { // stage the changes from the orignal commit snprintf(cmd, MAX_CMD, "git cherry-pick -n %s", itr->c_str()); @@ -786,10 +792,10 @@ bool change_sql_history() // remove the newly added files snprintf(cmd, MAX_CMD, "git diff --cached --diff-filter=A --name-only %s%s", path_prefix, sql_update_dir); - if( (cmd_pipe = popen( cmd, "r" )) == NULL ) + if ((cmd_pipe = popen(cmd, "r")) == NULL) return false; - while(fgets(buffer, MAX_BUF, cmd_pipe)) + while (fgets(buffer, MAX_BUF, cmd_pipe)) { buffer[strlen(buffer) - 1] = '\0'; snprintf(cmd, MAX_CMD, "git rm -f --quiet %s%s", path_prefix, buffer); @@ -812,15 +818,16 @@ bool change_sql_history() bool prepare_new_index() { - if(!use_new_index) return true; + if (!use_new_index) return true; // only use a new index if there are staged changes that should be preserved - if( (cmd_pipe = popen( "git diff --cached", "r" )) == NULL ) { + if ((cmd_pipe = popen("git diff --cached", "r")) == NULL) + { use_new_index = false; return false; } - if(!fgets(buffer, MAX_BUF, cmd_pipe)) + if (!fgets(buffer, MAX_BUF, cmd_pipe)) { use_new_index = false; pclose(cmd_pipe); @@ -834,29 +841,29 @@ bool prepare_new_index() // copy the existing index file to a new one char src_file[MAX_PATH], dst_file[MAX_PATH]; - char *old_index = getenv("GIT_INDEX_FILE"); - if(old_index) strncpy(src_file, old_index, MAX_PATH); + char* old_index = getenv("GIT_INDEX_FILE"); + if (old_index) strncpy(src_file, old_index, MAX_PATH); else snprintf(src_file, MAX_PATH, "%s.git/index", path_prefix); snprintf(dst_file, MAX_PATH, "%s%s", path_prefix, new_index_file); - if(!copy_file(src_file, dst_file)) return false; + if (!copy_file(src_file, dst_file)) return false; // doesn't seem to work with path_prefix snprintf(new_index_cmd, MAX_CMD, "GIT_INDEX_FILE=%s/%s", base_path, new_index_file); - if(putenv(new_index_cmd) != 0) return false; + if (putenv(new_index_cmd) != 0) return false; // clear the new index system("git reset -q --mixed HEAD"); // revert to old index snprintf(old_index_cmd, MAX_CMD, "GIT_INDEX_FILE="); - if(putenv(old_index_cmd) != 0) return false; + if (putenv(old_index_cmd) != 0) return false; return true; } bool cleanup_new_index() { - if(!use_new_index) return true; + if (!use_new_index) return true; printf("+ cleaning up the new index\n"); char idx_file[MAX_PATH]; snprintf(idx_file, MAX_PATH, "%s%s", path_prefix, new_index_file); @@ -866,22 +873,22 @@ bool cleanup_new_index() #define DO(cmd) if(!cmd) { printf("FAILED\n"); return 1; } -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - for(int i = 1; i < argc; i++) + for (int i = 1; i < argc; i++) { - if(argv[i] == NULL) continue; - if(strncmp(argv[i], "-r", 2) == 0 || strncmp(argv[i], "--replace", 9) == 0) + if (argv[i] == NULL) continue; + if (strncmp(argv[i], "-r", 2) == 0 || strncmp(argv[i], "--replace", 9) == 0) allow_replace = true; - else if(strncmp(argv[i], "-l", 2) == 0 || strncmp(argv[i], "--local", 7) == 0) + else if (strncmp(argv[i], "-l", 2) == 0 || strncmp(argv[i], "--local", 7) == 0) local = true; - else if(strncmp(argv[i], "-f", 2) == 0 || strncmp(argv[i], "--fetch", 7) == 0) + else if (strncmp(argv[i], "-f", 2) == 0 || strncmp(argv[i], "--fetch", 7) == 0) do_fetch = true; - else if(strncmp(argv[i], "-s", 2) == 0 || strncmp(argv[i], "--sql", 5) == 0) + else if (strncmp(argv[i], "-s", 2) == 0 || strncmp(argv[i], "--sql", 5) == 0) do_sql = true; - else if(strncmp(argv[i], "--branch=", 9) == 0) + else if (strncmp(argv[i], "--branch=", 9) == 0) snprintf(remote_branch, MAX_REMOTE, "%s", argv[i] + 9); - else if(strncmp(argv[i], "-h", 2) == 0 || strncmp(argv[i], "--help", 6) == 0) + else if (strncmp(argv[i], "-h", 2) == 0 || strncmp(argv[i], "--help", 6) == 0) { printf("Usage: git_id [OPTION]\n"); printf("Generates a new rev number and updates sd2_revision_nr.h and the commit message.\n"); @@ -905,31 +912,31 @@ int main(int argc, char *argv[]) return 1; } - DO( find_path() ); - if(!local) + DO(find_path()); + if (!local) { - DO( find_origin() ); - if(do_fetch) - DO( fetch_origin() ); - DO( check_fwd() ); + DO(find_origin()); + if (do_fetch) + DO(fetch_origin()); + DO(check_fwd()); } - DO( find_rev() ); - DO( find_head_msg() ); - if(do_sql) - DO( find_sql_updates() ); - DO( prepare_new_index() ); - DO( write_rev_nr() ); - if(do_sql) + DO(find_rev()); + DO(find_head_msg()); + if (do_sql) + DO(find_sql_updates()); + DO(prepare_new_index()); + DO(write_rev_nr()); + if (do_sql) { - DO( convert_sql_updates() ); + DO(convert_sql_updates()); if (generate_makefile) - DO( generate_sql_makefile() ); + DO(generate_sql_makefile()); // DO( change_sql_database() ); // Currently not supported - DO( write_rev_sql() ); + DO(write_rev_sql()); } - DO( amend_commit() ); - DO( cleanup_new_index() ); - //if(do_sql) + DO(amend_commit()); + DO(cleanup_new_index()); + // if(do_sql) // DO( change_sql_history() ); return 0; diff --git a/tool/git_id/git_id_vc80.sln b/tool/git_id/git_id_vc110.sln similarity index 83% rename from tool/git_id/git_id_vc80.sln rename to tool/git_id/git_id_vc110.sln index f1a9d8be7..3900fd907 100644 --- a/tool/git_id/git_id_vc80.sln +++ b/tool/git_id/git_id_vc110.sln @@ -1,7 +1,7 @@  -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "git_id", "git_id_vc80.vcproj", "{AD81BF86-050B-4605-8AF2-03C01967D784}" +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "git_id", "git_id_vc110.vcxproj", "{AD81BF86-050B-4605-8AF2-03C01967D784}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tool/git_id/git_id_vc110.vcxproj b/tool/git_id/git_id_vc110.vcxproj new file mode 100644 index 000000000..5a8d108d8 --- /dev/null +++ b/tool/git_id/git_id_vc110.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + git_id + {AD81BF86-050B-4605-8AF2-03C01967D784} + git_id + Win32Proj + + + + Application + Unicode + true + v110 + + + Application + Unicode + v110 + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + true + Console + false + + + MachineX86 + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + true + Console + true + true + false + + + MachineX86 + + + + + + + + + \ No newline at end of file diff --git a/tool/git_id/git_id_vc110.vcxproj.filters b/tool/git_id/git_id_vc110.vcxproj.filters new file mode 100644 index 000000000..158311880 --- /dev/null +++ b/tool/git_id/git_id_vc110.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + \ No newline at end of file diff --git a/tool/git_id/git_id_vc90.sln b/tool/git_id/git_id_vc120.sln similarity index 83% rename from tool/git_id/git_id_vc90.sln rename to tool/git_id/git_id_vc120.sln index 254218893..b66a2b770 100644 --- a/tool/git_id/git_id_vc90.sln +++ b/tool/git_id/git_id_vc120.sln @@ -1,7 +1,7 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "git_id", "git_id_vc90.vcproj", "{AD81BF86-050B-4605-8AF2-03C01967D784}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "git_id", "git_id_vc110.vcxproj", "{AD81BF86-050B-4605-8AF2-03C01967D784}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tool/git_id/git_id_vc120.vcxproj b/tool/git_id/git_id_vc120.vcxproj new file mode 100644 index 000000000..b8815fbe5 --- /dev/null +++ b/tool/git_id/git_id_vc120.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + git_id + {AD81BF86-050B-4605-8AF2-03C01967D784} + git_id + Win32Proj + + + + Application + Unicode + true + v120 + + + Application + Unicode + v120 + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + true + Console + false + + + MachineX86 + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + true + Console + true + true + false + + + MachineX86 + + + + + + + + + \ No newline at end of file diff --git a/tool/git_id/git_id_vc120.vcxproj.filters b/tool/git_id/git_id_vc120.vcxproj.filters new file mode 100644 index 000000000..1e584eb51 --- /dev/null +++ b/tool/git_id/git_id_vc120.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + \ No newline at end of file diff --git a/tool/git_id/git_id_vc80.vcproj b/tool/git_id/git_id_vc80.vcproj deleted file mode 100644 index 401c329af..000000000 --- a/tool/git_id/git_id_vc80.vcproj +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tool/git_id/git_id_vc90.vcproj b/tool/git_id/git_id_vc90.vcproj deleted file mode 100644 index 67cff60ca..000000000 --- a/tool/git_id/git_id_vc90.vcproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -